From d24a4766b4e332f5964165f66f57ae7d0f7d0f83 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 24 Mar 2024 17:12:40 +0100 Subject: [PATCH 001/897] Shade the Geyser api on modded platforms (#4520) --- bootstrap/mod/fabric/build.gradle.kts | 3 +++ bootstrap/mod/neoforge/build.gradle.kts | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index eb28e0e93..538147b15 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -39,6 +39,9 @@ dependencies { // Since we also relocate cloudburst protocol: shade erosion common shadow(libs.erosion.common) { isTransitive = false } + // Let's shade in our own api + shadow(projects.api) { isTransitive = false } + // Permissions modImplementation(libs.fabric.permissions) include(libs.fabric.permissions) diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts index 2a414e6dd..f7204332b 100644 --- a/bootstrap/mod/neoforge/build.gradle.kts +++ b/bootstrap/mod/neoforge/build.gradle.kts @@ -27,8 +27,12 @@ dependencies { shadow(project(path = ":mod", configuration = "transformProductionNeoForge")) { isTransitive = false } - shadow(project(path = ":core")) { isTransitive = false } + shadow(projects.core) { isTransitive = false } + // Let's shade in our own api + shadow(projects.api) { isTransitive = false } + + // Include all transitive deps of core via JiJ includeTransitive(projects.core) } From 4ea94f89a2a54775330fdca3096cbad6d89255d3 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 24 Mar 2024 21:30:00 +0000 Subject: [PATCH 002/897] Fix entity pick request for cherry and bamboo boats (#4522) --- .../bedrock/BedrockEntityPickRequestTranslator.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 f64ddeac6..e85456c33 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 @@ -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 @@ -62,13 +62,17 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator "birch"; case 3 -> "jungle"; case 4 -> "acacia"; - //case 5 -> "cherry"; TODO + case 5 -> "cherry"; case 6 -> "dark_oak"; case 7 -> "mangrove"; - //case 8 -> "bamboo"; + 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 -> From 85908690a340120f3cafe45eb2d286b15a1f83c2 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 27 Mar 2024 01:47:21 +0100 Subject: [PATCH 003/897] Revert inventory "fix" that's causing issues with quickly opening & closing inventories (#4523) --- .../bedrock/entity/player/BedrockInteractTranslator.java | 5 ----- 1 file changed, 5 deletions(-) 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 07e192bb7..a45690ab1 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 @@ -126,12 +126,7 @@ public class BedrockInteractTranslator extends PacketTranslator } else { InventoryUtils.openInventory(session, session.getPlayerInventory()); } - } else { - // Case: Player tries to open a player inventory, while we think it should be in a different inventory - // Now: Open the inventory that we're supposed to be in. - InventoryUtils.openInventory(session, session.getOpenInventory()); } - break; } } } From f1828419d631c43ef27b06d62a646229d2482236 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:28:49 -0700 Subject: [PATCH 004/897] Update raknet (#4528) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 377172346..b34f37d76 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" protocol = "3.0.0.Beta1-20240313.120922-126" protocol-connection = "3.0.0.Beta1-20240313.120922-125" -raknet = "1.0.0.CR1-20231206.145325-12" +raknet = "1.0.0.CR1-20240328.213920-13" blockstateupdater="1.20.70-20240303.125052-2" mcauthlib = "d9d773e" mcprotocollib = "1.20.4-2-20240116.220521-7" From 7da3afef603dad61b3504ab5486bf577c0d7d336 Mon Sep 17 00:00:00 2001 From: Redned Date: Fri, 29 Mar 2024 12:25:57 +0000 Subject: [PATCH 005/897] Update RakNet --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b34f37d76..35ba90597 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" protocol = "3.0.0.Beta1-20240313.120922-126" protocol-connection = "3.0.0.Beta1-20240313.120922-125" -raknet = "1.0.0.CR1-20240328.213920-13" +raknet = "1.0.0.CR1-20240329.101527-14" blockstateupdater="1.20.70-20240303.125052-2" mcauthlib = "d9d773e" mcprotocollib = "1.20.4-2-20240116.220521-7" From b469904951bfa38ad5e950d58bb3e0dcbe2b9d73 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Sat, 30 Mar 2024 03:27:55 -0700 Subject: [PATCH 006/897] Update Raknet (#4529) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 35ba90597..0e446a48f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" protocol = "3.0.0.Beta1-20240313.120922-126" protocol-connection = "3.0.0.Beta1-20240313.120922-125" -raknet = "1.0.0.CR1-20240329.101527-14" +raknet = "1.0.0.CR1-20240330.101522-15" blockstateupdater="1.20.70-20240303.125052-2" mcauthlib = "d9d773e" mcprotocollib = "1.20.4-2-20240116.220521-7" From fbafdbb2a708971917cb51e0d088e247370d601f Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 31 Mar 2024 12:01:59 +0100 Subject: [PATCH 007/897] Allow NonVanillaCustomItemData to have a block assigned (#4530) --- .../item/custom/NonVanillaCustomItemData.java | 11 ++++++++++- .../item/GeyserNonVanillaCustomItemData.java | 16 +++++++++++++++- .../populator/CustomItemRegistryPopulator.java | 7 ++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java index 59e2faad8..2c283780c 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.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 @@ -161,6 +161,13 @@ public interface NonVanillaCustomItemData extends CustomItemData { return displayHandheld(); } + /** + * Gets the block the item places. + * + * @return the block the item places + */ + String block(); + static NonVanillaCustomItemData.Builder builder() { return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class); } @@ -201,6 +208,8 @@ public interface NonVanillaCustomItemData extends CustomItemData { Builder chargeable(boolean isChargeable); + Builder block(String block); + /** * @deprecated Use {@link #displayHandheld(boolean)} instead. */ diff --git a/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java b/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java index 9d86bfa96..9c9269df3 100644 --- a/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java +++ b/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.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 @@ -55,6 +55,7 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i private final boolean isEdible; private final boolean canAlwaysEat; private final boolean isChargeable; + private final String block; public GeyserNonVanillaCustomItemData(Builder builder) { super(builder.name, builder.customItemOptions, builder.displayName, builder.icon, builder.allowOffhand, @@ -78,6 +79,7 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i this.isEdible = builder.edible; this.canAlwaysEat = builder.canAlwaysEat; this.isChargeable = builder.chargeable; + this.block = builder.block; } @Override @@ -160,6 +162,11 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i return isChargeable; } + @Override + public String block() { + return block; + } + public static class Builder extends GeyserCustomItemData.Builder implements NonVanillaCustomItemData.Builder { private String identifier = null; private int javaId = -1; @@ -186,6 +193,7 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i private boolean edible = false; private boolean canAlwaysEat = false; private boolean chargeable = false; + private String block = null; @Override public Builder name(@NonNull String name) { @@ -339,6 +347,12 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i return this; } + @Override + public Builder block(String block) { + this.block = block; + return this; + } + @Override public NonVanillaCustomItemData build() { if (identifier == null || javaId == -1) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index baaa61204..10d87a8a9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.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 @@ -248,6 +248,11 @@ public class CustomItemRegistryPopulator { itemProperties.putBoolean("foil", true); } + String block = customItemData.block(); + if (block != null) { + computeBlockItemProperties(block, componentBuilder); + } + componentBuilder.putCompound("item_properties", itemProperties.build()); builder.putCompound("components", componentBuilder.build()); From c9ca4c82f73f6ac0d8d5028753f73e4d7db3cdba Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Sun, 31 Mar 2024 21:42:31 -0700 Subject: [PATCH 008/897] Allow configuration of RakNet limits (#4532) * Allow configuration of RakNet limits Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Validate packet limiter system properties Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .../GeyserJacksonConfiguration.java | 15 ++++- .../geyser/network/netty/GeyserServer.java | 55 ++++++++++++++++++- .../org/geysermc/geyser/util/FileUtils.java | 3 + .../org/geysermc/geyser/util/WebUtils.java | 30 ++++++++++ core/src/main/resources/config.yml | 4 +- gradle/libs.versions.toml | 2 +- 6 files changed, 102 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index b3b7e8cd4..a55e4af8f 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -40,9 +40,11 @@ import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.network.CIDRMatcher; import org.geysermc.geyser.text.AsteriskSerializer; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.WebUtils; import java.io.IOException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -233,7 +235,18 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration List matchers = this.whitelistedIPsMatchers; if (matchers == null) { synchronized (this) { - this.whitelistedIPsMatchers = matchers = proxyProtocolWhitelistedIPs.stream() + // Check if proxyProtocolWhitelistedIPs contains URLs we need to fetch and parse by line + List whitelistedCIDRs = new ArrayList<>(); + for (String ip: proxyProtocolWhitelistedIPs) { + if (!ip.startsWith("http")) { + whitelistedCIDRs.add(ip); + continue; + } + + WebUtils.getLineStream(ip).forEach(whitelistedCIDRs::add); + } + + this.whitelistedIPsMatchers = matchers = whitelistedCIDRs.stream() .map(CIDRMatcher::new) .collect(Collectors.toList()); } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index ea1dcb509..ce904d465 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -46,6 +46,7 @@ import net.jodah.expiringmap.ExpiringMap; import org.cloudburstmc.netty.channel.raknet.RakChannelFactory; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerOfflineHandler; +import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerRateLimiter; import org.cloudburstmc.protocol.bedrock.BedrockPong; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.defaults.ConnectionTestCommand; @@ -71,6 +72,10 @@ import java.util.concurrent.TimeUnit; import java.util.function.IntFunction; import java.util.function.Supplier; +import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_GLOBAL_PACKET_LIMIT; +import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_OFFLINE_PACKET_LIMIT; +import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_PACKET_LIMIT; + public final class GeyserServer { private static final boolean PRINT_DEBUG_PINGS = Boolean.parseBoolean(System.getProperty("Geyser.PrintPingsInDebugMode", "true")); @@ -141,23 +146,31 @@ public final class GeyserServer { bootstrapFutures = new ChannelFuture[listenCount]; for (int i = 0; i < listenCount; i++) { ChannelFuture future = bootstrap.bind(address); - addHandlers(future); + modifyHandlers(future); bootstrapFutures[i] = future; } return Bootstraps.allOf(bootstrapFutures); } - private void addHandlers(ChannelFuture future) { + private void modifyHandlers(ChannelFuture future) { Channel channel = future.channel(); // Add our ping handler channel.pipeline() .addFirst(RakConnectionRequestHandler.NAME, new RakConnectionRequestHandler(this)) .addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this)); + // Add proxy handler - if (this.geyser.getConfig().getBedrock().isEnableProxyProtocol()) { + boolean isProxyProtocol = this.geyser.getConfig().getBedrock().isEnableProxyProtocol(); + if (isProxyProtocol) { channel.pipeline().addFirst("proxy-protocol-decoder", new ProxyServerHandler()); } + + boolean isWhitelistedProxyProtocol = isProxyProtocol && !this.geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs().isEmpty(); + if (Boolean.parseBoolean(System.getProperty("Geyser.RakRateLimitingDisabled", "false")) || isWhitelistedProxyProtocol) { + // We would already block any non-whitelisted IP addresses in onConnectionRequest so we can remove the rate limiter + channel.pipeline().remove(RakServerRateLimiter.NAME); + } } public void shutdown() { @@ -199,11 +212,26 @@ public final class GeyserServer { GeyserServerInitializer serverInitializer = new GeyserServerInitializer(this.geyser); playerGroup = serverInitializer.getEventLoopGroup(); this.geyser.getLogger().debug("Setting MTU to " + this.geyser.getConfig().getMtu()); + + int rakPacketLimit = positivePropOrDefault("Geyser.RakPacketLimit", DEFAULT_PACKET_LIMIT); + this.geyser.getLogger().debug("Setting RakNet packet limit to " + rakPacketLimit); + + boolean isWhitelistedProxyProtocol = this.geyser.getConfig().getBedrock().isEnableProxyProtocol() + && !this.geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs().isEmpty(); + int rakOfflinePacketLimit = positivePropOrDefault("Geyser.RakOfflinePacketLimit", isWhitelistedProxyProtocol ? Integer.MAX_VALUE : DEFAULT_OFFLINE_PACKET_LIMIT); + this.geyser.getLogger().debug("Setting RakNet offline packet limit to " + rakOfflinePacketLimit); + + int rakGlobalPacketLimit = positivePropOrDefault("Geyser.RakGlobalPacketLimit", DEFAULT_GLOBAL_PACKET_LIMIT); + this.geyser.getLogger().debug("Setting RakNet global packet limit to " + rakGlobalPacketLimit); + return new ServerBootstrap() .channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel())) .group(group, childGroup) .option(RakChannelOption.RAK_HANDLE_PING, true) .option(RakChannelOption.RAK_MAX_MTU, this.geyser.getConfig().getMtu()) + .option(RakChannelOption.RAK_PACKET_LIMIT, rakPacketLimit) + .option(RakChannelOption.RAK_OFFLINE_PACKET_LIMIT, rakOfflinePacketLimit) + .option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, rakGlobalPacketLimit) .childHandler(serverInitializer); } @@ -352,6 +380,27 @@ public final class GeyserServer { } } + private static int positivePropOrDefault(String property, int defaultValue) { + String value = System.getProperty(property); + try { + int parsed = value != null ? Integer.parseInt(value) : defaultValue; + + if (parsed < 1) { + GeyserImpl.getInstance().getLogger().warning( + "Non-postive integer value for " + property + ": " + value + ". Using default value: " + defaultValue + ); + return defaultValue; + } + + return parsed; + } catch (NumberFormatException e) { + GeyserImpl.getInstance().getLogger().warning( + "Invalid integer value for " + property + ": " + value + ". Using default value: " + defaultValue + ); + return defaultValue; + } + } + private static Transport compatibleTransport() { TransportHelper.TransportMethod transportMethod = TransportHelper.determineTransportMethod(); if (transportMethod == TransportHelper.TransportMethod.EPOLL) { diff --git a/core/src/main/java/org/geysermc/geyser/util/FileUtils.java b/core/src/main/java/org/geysermc/geyser/util/FileUtils.java index c8cd31058..c8423c3be 100644 --- a/core/src/main/java/org/geysermc/geyser/util/FileUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/FileUtils.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.util; import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.geysermc.geyser.GeyserBootstrap; @@ -56,6 +57,8 @@ public class FileUtils { */ public static T loadConfig(File src, Class valueType) throws IOException { ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()) + // Allow inference of single values as arrays + .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); return objectMapper.readValue(src, valueType); } diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index fbcbd4a3c..f453092b3 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -40,6 +40,7 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Map; +import java.util.stream.Stream; public class WebUtils { @@ -176,6 +177,13 @@ public class WebUtils { return connectionToString(con); } + /** + * Find a SRV record for the given address + * + * @param geyser Geyser instance + * @param remoteAddress Address to find the SRV record for + * @return The SRV record or null if not found + */ public static String @Nullable [] findSrvRecord(GeyserImpl geyser, String remoteAddress) { try { // Searches for a server address and a port from a SRV record of the specified host name @@ -193,4 +201,26 @@ public class WebUtils { } return null; } + + /** + * Get a stream of lines from the given URL + * + * @param reqURL URL to fetch + * @return Stream of lines from the URL or an empty stream if the request fails + */ + public static Stream getLineStream(String reqURL) { + try { + URL url = new URL(reqURL); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); // Otherwise Java 8 fails on checking updates + con.setConnectTimeout(10000); + con.setReadTimeout(10000); + + return connectionToString(con).lines(); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error("Error while trying to get a stream from " + reqURL, e); + return Stream.empty(); + } + } } diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 0617b316c..c70b0d7ab 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -39,8 +39,8 @@ bedrock: # A list of allowed PROXY protocol speaking proxy IP addresses/subnets. Only effective when "enable-proxy-protocol" is enabled, and # should really only be used when you are not able to use a proper firewall (usually true with shared hosting providers etc.). # Keeping this list empty means there is no IP address whitelist. - # Both IP addresses and subnets are supported. - #proxy-protocol-whitelisted-ips: [ "127.0.0.1", "172.18.0.0/16" ] + # IP addresses, subnets, and links to plain text files are supported. + #proxy-protocol-whitelisted-ips: [ "127.0.0.1", "172.18.0.0/16", "https://example.com/whitelist.txt" ] remote: # The IP address of the remote (Java Edition) server # If it is "auto", for standalone version the remote address will be set to 127.0.0.1, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0e446a48f..b194c5a4b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" protocol = "3.0.0.Beta1-20240313.120922-126" protocol-connection = "3.0.0.Beta1-20240313.120922-125" -raknet = "1.0.0.CR1-20240330.101522-15" +raknet = "1.0.0.CR1-20240330.103819-16" blockstateupdater="1.20.70-20240303.125052-2" mcauthlib = "d9d773e" mcprotocollib = "1.20.4-2-20240116.220521-7" From fa441f1c7b85da8174fc535a8efb00885b9de9ba Mon Sep 17 00:00:00 2001 From: Sage Date: Mon, 1 Apr 2024 23:33:12 +0200 Subject: [PATCH 009/897] Add ConnectionRequestEvent (#4533) * Add ConnectionRequestEvent and implement it * Add debug message and use InetSocketAddress instead of string * Provide both proxy and real client ip And add some minor javadocs * Make ProxyIp nullable * Apply changes from pr Co-authored-by: rtm516 * Apply changes from pr Co-authored-by: rtm516 * Apply changes from pr Co-authored-by: rtm516 * Bump API version * Dont JiJ common on mod platforms --------- Co-authored-by: rtm516 Co-authored-by: Kas-tle <26531652+Kas-tle@users.noreply.github.com> --- .../connection/ConnectionRequestEvent.java | 88 +++++++++++++++++++ bootstrap/mod/fabric/build.gradle.kts | 1 + bootstrap/mod/neoforge/build.gradle.kts | 1 + .../geyser/network/netty/GeyserServer.java | 9 ++ gradle.properties | 4 +- 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java diff --git a/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java new file mode 100644 index 000000000..5c1f4ef51 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java @@ -0,0 +1,88 @@ +/* + * 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.api.event.connection; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.event.Cancellable; +import org.geysermc.event.Event; + +import java.net.InetSocketAddress; + +/** + * Called whenever a client attempts to connect to the server, before the connection is accepted. + */ +public final class ConnectionRequestEvent implements Event, Cancellable { + + private boolean cancelled; + private final InetSocketAddress ip; + private final InetSocketAddress proxyIp; + + public ConnectionRequestEvent(@NonNull InetSocketAddress ip, @Nullable InetSocketAddress proxyIp) { + this.ip = ip; + this.proxyIp = proxyIp; + } + + /** + * The IP address of the client attempting to connect + * + * @return the IP address of the client attempting to connect + */ + @NonNull + public InetSocketAddress getInetSocketAddress() { + return ip; + } + + /** + * The IP address of the proxy handling the connection. It will return null if there is no proxy. + * + * @return the IP address of the proxy handling the connection + */ + @Nullable + public InetSocketAddress getProxyIp() { + return proxyIp; + } + + /** + * The cancel status of this event. If this event is cancelled, the connection will be rejected. + * + * @return the cancel status of this event + */ + @Override + public boolean isCancelled() { + return cancelled; + } + + /** + * Sets the cancel status of this event. If this event is canceled, the connection will be rejected. + * + * @param cancelled the cancel status of this event. + */ + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } +} diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index 538147b15..ec8ae03bc 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { // Let's shade in our own api shadow(projects.api) { isTransitive = false } + shadow(projects.common) { isTransitive = false } // Permissions modImplementation(libs.fabric.permissions) diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts index f7204332b..ff77bcc5c 100644 --- a/bootstrap/mod/neoforge/build.gradle.kts +++ b/bootstrap/mod/neoforge/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { // Let's shade in our own api shadow(projects.api) { isTransitive = false } + shadow(projects.common) { isTransitive = false } // Include all transitive deps of core via JiJ includeTransitive(projects.core) diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index ce904d465..f4059a9e7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -49,6 +49,7 @@ import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerOfflineHandle import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerRateLimiter; import org.cloudburstmc.protocol.bedrock.BedrockPong; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.event.connection.ConnectionRequestEvent; import org.geysermc.geyser.command.defaults.ConnectionTestCommand; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.event.type.GeyserBedrockPingEventImpl; @@ -261,6 +262,14 @@ public final class GeyserServer { } else { ip = ""; } + + ConnectionRequestEvent requestEvent = new ConnectionRequestEvent(inetSocketAddress, this.proxiedAddresses.get(inetSocketAddress)); + geyser.eventBus().fire(requestEvent); + if (requestEvent.isCancelled()) { + geyser.getLogger().debug("Connection request from " + ip + " was cancelled using the API!"); + return false; + } + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.attempt_connect", ip)); return true; } diff --git a/gradle.properties b/gradle.properties index a8e5eaaaf..a7c0bf93d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.2.2-SNAPSHOT -description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. \ No newline at end of file +version=2.2.3-SNAPSHOT +description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From 08aa5282d4a8e42acfaba3315e2e62c54e9efc06 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Mon, 1 Apr 2024 15:50:58 -0700 Subject: [PATCH 010/897] Ensure proxiedAddresses is not null before lookup (#4539) --- .../java/org/geysermc/geyser/network/netty/GeyserServer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index f4059a9e7..db103d10e 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -263,7 +263,10 @@ public final class GeyserServer { ip = ""; } - ConnectionRequestEvent requestEvent = new ConnectionRequestEvent(inetSocketAddress, this.proxiedAddresses.get(inetSocketAddress)); + ConnectionRequestEvent requestEvent = new ConnectionRequestEvent( + inetSocketAddress, + this.proxiedAddresses != null ? this.proxiedAddresses.get(inetSocketAddress) : null + ); geyser.eventBus().fire(requestEvent); if (requestEvent.isCancelled()) { geyser.getLogger().debug("Connection request from " + ip + " was cancelled using the API!"); From 47237e07b789e93056a0761376c688f03b86b8ae Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 2 Apr 2024 00:10:12 +0100 Subject: [PATCH 011/897] Fix block custom registration failing with simmilar named items (#4540) --- .../CustomBlockRegistryPopulator.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java index 36b1fc859..b2d238ddb 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java @@ -1,3 +1,28 @@ +/* + * 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.registry.populator; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -80,7 +105,6 @@ public class CustomBlockRegistryPopulator { } private static Set CUSTOM_BLOCKS; - private static Set CUSTOM_BLOCK_NAMES; private static Map CUSTOM_BLOCK_ITEM_OVERRIDES; private static Map NON_VANILLA_BLOCK_STATE_OVERRIDES; private static Map BLOCK_STATE_OVERRIDES_QUEUE; @@ -90,19 +114,19 @@ public class CustomBlockRegistryPopulator { */ private static void populateBedrock() { CUSTOM_BLOCKS = new ObjectOpenHashSet<>(); - CUSTOM_BLOCK_NAMES = new ObjectOpenHashSet<>(); CUSTOM_BLOCK_ITEM_OVERRIDES = new HashMap<>(); NON_VANILLA_BLOCK_STATE_OVERRIDES = new HashMap<>(); BLOCK_STATE_OVERRIDES_QUEUE = new HashMap<>(); + Set customBlockIdentifiers = new ObjectOpenHashSet<>(); GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() { @Override public void register(@NonNull CustomBlockData customBlockData) { if (customBlockData.name().isEmpty()) { throw new IllegalArgumentException("Custom block name must have at least 1 character."); } - if (!CUSTOM_BLOCK_NAMES.add(customBlockData.name())) { - throw new IllegalArgumentException("Another custom block was already registered under the name: " + customBlockData.name()); + if (!customBlockIdentifiers.add(customBlockData.identifier())) { + throw new IllegalArgumentException("Another custom block was already registered under the identifier: " + customBlockData.identifier()); } if (Character.isDigit(customBlockData.name().charAt(0))) { throw new IllegalArgumentException("Custom block can not start with a digit. Name: " + customBlockData.name()); From 29bd8966820c9e0bb836de870caff457c5f5fbf6 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 2 Apr 2024 02:11:03 +0100 Subject: [PATCH 012/897] Fix CreativeCategory enum numbers (#4542) --- .../org/geysermc/geyser/api/util/CreativeCategory.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java b/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java index 207320b1e..a3f9d069c 100644 --- a/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java +++ b/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 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 @@ -31,12 +31,11 @@ import org.checkerframework.checker.nullness.qual.NonNull; * Represents the creative menu categories or tabs. */ public enum CreativeCategory { - COMMANDS("commands", 1), - CONSTRUCTION("construction", 2), + CONSTRUCTION("construction", 1), + NATURE("nature", 2), EQUIPMENT("equipment", 3), ITEMS("items", 4), - NATURE("nature", 5), - NONE("none", 6); + NONE("none", 5); private final String internalName; private final int id; From 1819ed4dbdb328f559ed87361f5f7326028ed94e Mon Sep 17 00:00:00 2001 From: Eclipse <116838833+eclipseisoffline@users.noreply.github.com> Date: Thu, 4 Apr 2024 18:55:00 +0000 Subject: [PATCH 013/897] Remove Java custom armor trims when translating item to Bedrock to prevent visual issues (#4548) * Fix (or workaround) armor items with custom armor trims having no texture on bedrock * Fix armor items with custom trims causing issues on entity models by removing the Trim tag entirely * Refer to minecraft namespace inline for consistency --- .../java/org/geysermc/geyser/item/type/ArmorItem.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index 38144f318..b58f760d1 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -47,6 +47,14 @@ public class ArmorItem extends Item { if (tag.get("Trim") instanceof CompoundTag trim) { StringTag material = trim.remove("material"); StringTag pattern = trim.remove("pattern"); + + // discard custom trim patterns/materials to prevent visual glitches on bedrock + if (!material.getValue().startsWith("minecraft:") + || !pattern.getValue().startsWith("minecraft:")) { + tag.remove("Trim"); + return; + } + // bedrock has an uppercase first letter key, and the value is not namespaced trim.put(new StringTag("Material", stripNamespace(material.getValue()))); trim.put(new StringTag("Pattern", stripNamespace(pattern.getValue()))); From 0972e4f4d7892f1387a87eb918f3137b86a590aa Mon Sep 17 00:00:00 2001 From: rtm516 Date: Fri, 5 Apr 2024 22:21:27 +0100 Subject: [PATCH 014/897] Update CreativeCategory none to have the correct value (#4549) --- .../java/org/geysermc/geyser/api/util/CreativeCategory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java b/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java index a3f9d069c..245eb9bc2 100644 --- a/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java +++ b/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java @@ -35,7 +35,7 @@ public enum CreativeCategory { NATURE("nature", 2), EQUIPMENT("equipment", 3), ITEMS("items", 4), - NONE("none", 5); + NONE("none", 6); private final String internalName; private final int id; From 3d9f3ac64582886a85a9c5bb28e8d2a0ca6376fc Mon Sep 17 00:00:00 2001 From: Denys Loshkarev <26629861+denysloshkarev@users.noreply.github.com> Date: Sun, 7 Apr 2024 01:12:56 +0300 Subject: [PATCH 015/897] Show 1.20.73 as being supported (#4543) * update version supported by plugin * Update README.md --- README.md | 2 +- .../src/main/java/org/geysermc/geyser/network/GameProtocol.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a28e7177..8dcbfb186 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.72 and Minecraft Java 1.20.4 +### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.73 and Minecraft Java 1.20.4 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 900463c5c..d975ebbf6 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -72,7 +72,7 @@ public final class GameProtocol { .minecraftVersion("1.20.60/1.20.62") .build()); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.20.70/1.20.72") + .minecraftVersion("1.20.70/1.20.73") .build()); } From fa2e4e5a9418080cd9bd3b1ae464099928c49ffc Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 7 Apr 2024 22:44:58 -0400 Subject: [PATCH 016/897] Reduce processing for incoming TrimDataPackets --- .../geysermc/geyser/network/GameProtocol.java | 32 +++++++++++++------ .../geyser/network/LoggingPacketHandler.java | 5 +++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index d975ebbf6..f43706db0 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -27,13 +27,17 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; +import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; +import org.cloudburstmc.protocol.bedrock.codec.BedrockCodecHelper; +import org.cloudburstmc.protocol.bedrock.codec.v582.serializer.TrimDataSerializer_v582; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; +import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -48,7 +52,7 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v662.CODEC; + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = processCodec(Bedrock_v662.CODEC); /** * A list of all supported Bedrock versions that can join Geyser @@ -62,18 +66,18 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v622.CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(processCodec(Bedrock_v622.CODEC.toBuilder() .minecraftVersion("1.20.40/1.20.41") - .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v630.CODEC.toBuilder() + .build())); + SUPPORTED_BEDROCK_CODECS.add(processCodec(Bedrock_v630.CODEC.toBuilder() .minecraftVersion("1.20.50/1.20.51") - .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v649.CODEC.toBuilder() + .build())); + SUPPORTED_BEDROCK_CODECS.add(processCodec(Bedrock_v649.CODEC.toBuilder() .minecraftVersion("1.20.60/1.20.62") - .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .build())); + SUPPORTED_BEDROCK_CODECS.add(processCodec(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.20.70/1.20.73") - .build()); + .build())); } /** @@ -164,6 +168,16 @@ public final class GameProtocol { return joiner.toString(); } + private static BedrockCodec processCodec(BedrockCodec codec) { + return codec.toBuilder() + .updateSerializer(TrimDataPacket.class, new TrimDataSerializer_v582() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, TrimDataPacket packet) { + } + }) + .build(); + } + private GameProtocol() { } } diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index 0cfcc3d46..910f76ffb 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -891,4 +891,9 @@ public class LoggingPacketHandler implements BedrockPacketHandler { public PacketSignal handle(ToggleCrafterSlotRequestPacket packet) { return defaultHandler(packet); } + + @Override + public PacketSignal handle(TrimDataPacket packet) { + return defaultHandler(packet); + } } \ No newline at end of file From c91182132c78cb4575fce15260a9bf4abd4dce94 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 8 Apr 2024 10:05:48 +0100 Subject: [PATCH 017/897] Update Crowdin on README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8dcbfb186..ce2b67af1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](https://discord.gg/geysermc) -[![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/) +[![Crowdin](https://badges.crowdin.net/e/51361b7f8a01644a238d0fe8f3bddc62/localized.svg)](https://translate.geysermc.org/) Geyser is a bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition, closing the gap from those wanting to play true cross-platform. From ca0e226aac445ad8b0c213c10a3647a1874eae03 Mon Sep 17 00:00:00 2001 From: Eclipse <116838833+eclipseisoffline@users.noreply.github.com> Date: Thu, 11 Apr 2024 01:05:15 +0000 Subject: [PATCH 018/897] Fix breaking of custom head blocks added by Polymer by adding a default fallback to block mappings (#4557) --- .../bedrock/entity/player/BedrockActionTranslator.java | 4 ++-- .../protocol/java/level/JavaBlockDestructionTranslator.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) 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 index 90a841ac2..33410f240 100644 --- 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 @@ -163,7 +163,7 @@ public class BedrockActionTranslator extends PacketTranslator Date: Fri, 12 Apr 2024 13:12:38 +0100 Subject: [PATCH 019/897] Fix user agent strings (#4562) --- .../org/geysermc/geyser/skin/SkinProvider.java | 4 ++-- .../org/geysermc/geyser/util/WebUtils.java | 18 +++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index 12a1e8b2b..683712c22 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.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 @@ -674,7 +674,7 @@ public class SkinProvider { image = readFiveZigCape(imageUrl); } else { HttpURLConnection con = (HttpURLConnection) new URL(imageUrl).openConnection(); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); + con.setRequestProperty("User-Agent", WebUtils.getUserAgent()); con.setConnectTimeout(10000); con.setReadTimeout(10000); diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index f453092b3..1b7f2d9d9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.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 @@ -55,7 +55,7 @@ public class WebUtils { URL url = new URL(reqURL); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); // Otherwise Java 8 fails on checking updates + con.setRequestProperty("User-Agent", getUserAgent()); // Otherwise Java 8 fails on checking updates con.setConnectTimeout(10000); con.setReadTimeout(10000); @@ -73,7 +73,7 @@ public class WebUtils { */ public static JsonNode getJson(String reqURL) throws IOException { HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); + con.setRequestProperty("User-Agent", getUserAgent()); con.setConnectTimeout(10000); con.setReadTimeout(10000); return GeyserImpl.JSON_MAPPER.readTree(con.getInputStream()); @@ -88,7 +88,7 @@ public class WebUtils { public static void downloadFile(String reqURL, String fileLocation) { try { HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); + con.setRequestProperty("User-Agent", getUserAgent()); InputStream in = con.getInputStream(); Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING); } catch (Exception e) { @@ -109,7 +109,7 @@ public class WebUtils { HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "text/plain"); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); + con.setRequestProperty("User-Agent", getUserAgent()); con.setDoOutput(true); OutputStream out = con.getOutputStream(); @@ -164,7 +164,7 @@ public class WebUtils { HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); + con.setRequestProperty("User-Agent", getUserAgent()); con.setDoOutput(true); try (OutputStream out = con.getOutputStream()) { @@ -213,7 +213,7 @@ public class WebUtils { URL url = new URL(reqURL); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); // Otherwise Java 8 fails on checking updates + con.setRequestProperty("User-Agent", getUserAgent()); // Otherwise Java 8 fails on checking updates con.setConnectTimeout(10000); con.setReadTimeout(10000); @@ -223,4 +223,8 @@ public class WebUtils { return Stream.empty(); } } + + public static String getUserAgent() { + return "Geyser-" + GeyserImpl.getInstance().getPlatformType().platformName() + "/" + GeyserImpl.VERSION; + } } From a24f68412315fdabe93053d7722f9c9f15fc6511 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 14 Apr 2024 00:16:26 +0200 Subject: [PATCH 020/897] Update to Gradle 8.7, bump loom to 1.6 (#4565) * Update to Gradle 8.6, bump loom to 1.6 * update to gradle 8.7 --- bootstrap/mod/fabric/build.gradle.kts | 11 +------ gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 43462 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++- gradlew | 35 ++++++++++++++--------- gradlew.bat | 21 +++++++------- 6 files changed, 38 insertions(+), 35 deletions(-) diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index ec8ae03bc..53e4dfe53 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -22,16 +22,11 @@ dependencies { // These are NOT transitively included, and instead shadowed + relocated. // Avoids fabric complaining about non-SemVer versioning - // TODO: re-evaluate after loom 1.6 (https://github.com/FabricMC/fabric-loom/pull/1075) shadow(libs.protocol.connection) { isTransitive = false } shadow(libs.protocol.common) { isTransitive = false } shadow(libs.protocol.codec) { isTransitive = false } shadow(libs.mcauthlib) { isTransitive = false } shadow(libs.raknet) { isTransitive = false } - shadow(libs.netty.codec.haproxy) { isTransitive = false } - shadow("org.cloudburstmc:nbt:3.0.2.Final") { isTransitive = false } - shadow("io.netty:netty-codec-dns:4.1.103.Final") { isTransitive = false } - shadow("io.netty:netty-resolver-dns-classes-macos:4.1.103.Final") { isTransitive = false } // Consequences of shading + relocating mcauthlib: shadow/relocate mcpl! shadow(libs.mcprotocollib) { isTransitive = false } @@ -39,7 +34,7 @@ dependencies { // Since we also relocate cloudburst protocol: shade erosion common shadow(libs.erosion.common) { isTransitive = false } - // Let's shade in our own api + // Let's shade in our own api/common module shadow(projects.api) { isTransitive = false } shadow(projects.common) { isTransitive = false } @@ -52,12 +47,8 @@ application { mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain") } -relocate("org.cloudburstmc.nbt") relocate("org.cloudburstmc.netty") relocate("org.cloudburstmc.protocol") -relocate("io.netty.handler.codec.dns") -relocate("io.netty.handler.codec.haproxy") -relocate("io.netty.resolver.dns.macos") relocate("com.github.steveice10.mc.protocol") relocate("com.github.steveice10.mc.auth") relocate("com.github.steveice10.packetlib") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b194c5a4b..04c83ac78 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,7 +40,7 @@ mixin = "0.8.5" indra = "3.1.3" shadow = "8.1.1" architectury-plugin = "3.4-SNAPSHOT" -architectury-loom = "1.4-SNAPSHOT" +architectury-loom = "1.6-SNAPSHOT" minotaur = "2.8.7" lombok = "8.4" blossom = "1.2.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..d64cd4917707c1f8861d8cb53dd15194d4248596 100644 GIT binary patch literal 43462 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 literal 60756 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 /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index f127cfd49..25da30dbd 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -42,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail From 5151c25e1a28a9096a411711a9e6ae57b8314654 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:52:46 -0700 Subject: [PATCH 021/897] Support RakNet Cookies (#4554) * Support cookies Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Use cloudburst upstream raknet * Comment out mavenLocal() --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .../kotlin/geyser.modded-conventions.gradle.kts | 1 + core/build.gradle.kts | 4 ++++ .../java/org/geysermc/geyser/dump/DumpInfo.java | 3 +++ .../geyser/network/netty/GeyserServer.java | 17 +++++++++-------- gradle/libs.versions.toml | 2 +- settings.gradle.kts | 3 ++- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index 91bde525e..e011b7139 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -107,6 +107,7 @@ dependencies { } repositories { + // mavenLocal() maven("https://repo.opencollab.dev/maven-releases/") maven("https://repo.opencollab.dev/maven-snapshots/") maven("https://jitpack.io") diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 054f4f0ae..93c9f4f13 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -6,6 +6,10 @@ plugins { } dependencies { + constraints { + implementation(libs.raknet) // Ensure protocol does not override the RakNet version + } + api(projects.common) api(projects.api) diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 818607314..e54bbc1eb 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -78,6 +78,7 @@ public class DumpInfo { private final GeyserConfiguration config; private final Floodgate floodgate; private final Object2IntMap userPlatforms; + private final int connectionAttempts; private final HashInfo hashInfo; private final RamInfo ramInfo; private LogsInfo logsInfo; @@ -129,6 +130,8 @@ public class DumpInfo { userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1); } + this.connectionAttempts = GeyserImpl.getInstance().getGeyserServer().getConnectionAttempts(); + this.bootstrapInfo = GeyserImpl.getInstance().getBootstrap().getDumpInfo(); this.flagsInfo = new FlagsInfo(); diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index db103d10e..8ead16623 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -74,7 +74,6 @@ import java.util.function.IntFunction; import java.util.function.Supplier; import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_GLOBAL_PACKET_LIMIT; -import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_OFFLINE_PACKET_LIMIT; import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_PACKET_LIMIT; public final class GeyserServer { @@ -111,6 +110,10 @@ public final class GeyserServer { private ChannelFuture[] bootstrapFutures; + // Keep track of connection attempts for dump info + @Getter + private int connectionAttempts = 0; + /** * The port to broadcast in the pong. This can be different from the port the server is bound to, e.g. due to port forwarding. */ @@ -217,11 +220,6 @@ public final class GeyserServer { int rakPacketLimit = positivePropOrDefault("Geyser.RakPacketLimit", DEFAULT_PACKET_LIMIT); this.geyser.getLogger().debug("Setting RakNet packet limit to " + rakPacketLimit); - boolean isWhitelistedProxyProtocol = this.geyser.getConfig().getBedrock().isEnableProxyProtocol() - && !this.geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs().isEmpty(); - int rakOfflinePacketLimit = positivePropOrDefault("Geyser.RakOfflinePacketLimit", isWhitelistedProxyProtocol ? Integer.MAX_VALUE : DEFAULT_OFFLINE_PACKET_LIMIT); - this.geyser.getLogger().debug("Setting RakNet offline packet limit to " + rakOfflinePacketLimit); - int rakGlobalPacketLimit = positivePropOrDefault("Geyser.RakGlobalPacketLimit", DEFAULT_GLOBAL_PACKET_LIMIT); this.geyser.getLogger().debug("Setting RakNet global packet limit to " + rakGlobalPacketLimit); @@ -231,8 +229,8 @@ public final class GeyserServer { .option(RakChannelOption.RAK_HANDLE_PING, true) .option(RakChannelOption.RAK_MAX_MTU, this.geyser.getConfig().getMtu()) .option(RakChannelOption.RAK_PACKET_LIMIT, rakPacketLimit) - .option(RakChannelOption.RAK_OFFLINE_PACKET_LIMIT, rakOfflinePacketLimit) .option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, rakGlobalPacketLimit) + .option(RakChannelOption.RAK_SEND_COOKIE, true) .childHandler(serverInitializer); } @@ -248,6 +246,7 @@ public final class GeyserServer { } if (!isWhitelistedIP) { + connectionAttempts++; return false; } } @@ -270,10 +269,12 @@ public final class GeyserServer { geyser.eventBus().fire(requestEvent); if (requestEvent.isCancelled()) { geyser.getLogger().debug("Connection request from " + ip + " was cancelled using the API!"); + connectionAttempts++; return false; } - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.attempt_connect", ip)); + geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.network.attempt_connect", ip)); + connectionAttempts++; return true; } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 04c83ac78..3111750a8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" protocol = "3.0.0.Beta1-20240313.120922-126" protocol-connection = "3.0.0.Beta1-20240313.120922-125" -raknet = "1.0.0.CR1-20240330.103819-16" +raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.70-20240303.125052-2" mcauthlib = "d9d773e" mcprotocollib = "1.20.4-2-20240116.220521-7" diff --git a/settings.gradle.kts b/settings.gradle.kts index 68848bca4..a39bfa3d2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,6 +4,8 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") dependencyResolutionManagement { repositories { + // mavenLocal() + // Floodgate, Cumulus etc. maven("https://repo.opencollab.dev/main") @@ -30,7 +32,6 @@ dependencyResolutionManagement { mavenContent { releasesOnly() } } - mavenLocal() mavenCentral() // ViaVersion From c8475d8100f6272a9c892ac81635f720c4d0ee58 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 17 Apr 2024 03:18:17 -0400 Subject: [PATCH 022/897] Always remove entities from cache (#4577) * Always remove entities from cache * Despawn throwable entities in the void --- .../geysermc/geyser/entity/type/Entity.java | 7 ++----- .../geyser/entity/type/FireballEntity.java | 3 +++ .../geyser/entity/type/FishingHookEntity.java | 3 +++ .../geyser/entity/type/ItemEntity.java | 2 +- .../geyser/entity/type/ItemFrameEntity.java | 3 +-- .../geyser/entity/type/ThrowableEntity.java | 20 +++++++++++++++++-- .../entity/type/living/ArmorStandEntity.java | 4 ++-- .../living/monster/EnderDragonEntity.java | 4 ++-- .../geyser/session/cache/EntityCache.java | 12 ++++++----- .../entity/JavaRemoveEntitiesTranslator.java | 2 +- 10 files changed, 40 insertions(+), 20 deletions(-) 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 a2b7cc6ec..306c244b3 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 @@ -200,11 +200,9 @@ public class Entity implements GeyserEntity { /** * Despawns the entity - * - * @return can be deleted */ - public boolean despawnEntity() { - if (!valid) return true; + public void despawnEntity() { + if (!valid) return; for (Entity passenger : passengers) { // Make sure all passengers on the despawned entity are updated if (passenger == null) continue; @@ -218,7 +216,6 @@ public class Entity implements GeyserEntity { session.sendUpstreamPacket(removeEntityPacket); valid = false; - return true; } public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java index 3db032f0f..904596b3a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java @@ -72,6 +72,9 @@ public class FireballEntity extends ThrowableEntity { @Override public void tick() { + if (removedInVoid()) { + return; + } moveAbsoluteImmediate(tickMovement(position), getYaw(), getPitch(), getHeadYaw(), false, false); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java index bcbff16ce..0de11c382 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java @@ -133,6 +133,9 @@ public class FishingHookEntity extends ThrowableEntity { @Override public void tick() { + if (removedInVoid()) { + return; + } if (hooked || !isInAir() && !isInWater() || isOnGround()) { motion = Vector3f.ZERO; return; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java index bb67a60f6..69fb3faab 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java @@ -74,7 +74,7 @@ public class ItemEntity extends ThrowableEntity { @Override public void tick() { - if (isInWater()) { + if (removedInVoid() || isInWater()) { return; } if (!isOnGround() || (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) > 0.00001) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java index 295972200..ad1d4b928 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java @@ -148,7 +148,7 @@ public class ItemFrameEntity extends Entity { } @Override - public boolean despawnEntity() { + public void despawnEntity() { UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); updateBlockPacket.setBlockPosition(bedrockPosition); @@ -161,7 +161,6 @@ public class ItemFrameEntity extends Entity { session.getItemFrameCache().remove(bedrockPosition, this); valid = false; - return true; } private NbtMap getDefaultTag() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java index 60840e65b..47884e60a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java @@ -55,6 +55,9 @@ public class ThrowableEntity extends Entity implements Tickable { */ @Override public void tick() { + if (removedInVoid()) { + return; + } moveAbsoluteImmediate(position.add(motion), getYaw(), getPitch(), getHeadYaw(), isOnGround(), false); float drag = getDrag(); float gravity = getGravity(); @@ -170,14 +173,14 @@ public class ThrowableEntity extends Entity implements Tickable { } @Override - public boolean despawnEntity() { + public void despawnEntity() { if (definition.entityType() == EntityType.ENDER_PEARL) { LevelEventPacket particlePacket = new LevelEventPacket(); particlePacket.setType(LevelEvent.PARTICLE_TELEPORT); particlePacket.setPosition(position); session.sendUpstreamPacket(particlePacket); } - return super.despawnEntity(); + super.despawnEntity(); } @Override @@ -191,4 +194,17 @@ public class ThrowableEntity extends Entity implements Tickable { moveAbsoluteImmediate(position, yaw, pitch, headYaw, isOnGround, teleported); lastJavaPosition = position; } + + /** + * Removes the entity if it is 64 blocks below the world. + * + * @return true if the entity was removed + */ + public boolean removedInVoid() { + if (position.getY() < session.getDimensionType().minY() - 64) { + session.getEntityCache().removeEntity(this); + return true; + } + return false; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index c64776f18..9c56568c8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -99,11 +99,11 @@ public class ArmorStandEntity extends LivingEntity { } @Override - public boolean despawnEntity() { + public void despawnEntity() { if (secondEntity != null) { secondEntity.despawnEntity(); } - return super.despawnEntity(); + super.despawnEntity(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java index bb09a23f4..8c00d065a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java @@ -148,11 +148,11 @@ public class EnderDragonEntity extends MobEntity implements Tickable { } @Override - public boolean despawnEntity() { + public void despawnEntity() { for (EnderDragonPartEntity part : allParts) { part.despawnEntity(); } - return super.despawnEntity(); + super.despawnEntity(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java index 8a4b9cb6c..6524e1ddc 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java @@ -85,27 +85,29 @@ public class EntityCache { return false; } - public boolean removeEntity(Entity entity, boolean force) { + public void removeEntity(Entity entity) { if (entity instanceof PlayerEntity player) { session.getPlayerWithCustomHeads().remove(player.getUuid()); } - if (entity != null && entity.isValid() && (force || entity.despawnEntity())) { + if (entity != null) { + if (entity.isValid()) { + entity.despawnEntity(); + } + long geyserId = entityIdTranslations.remove(entity.getEntityId()); entities.remove(geyserId); if (entity instanceof Tickable) { tickableEntities.remove(entity); } - return true; } - return false; } public void removeAllEntities() { List entities = new ArrayList<>(this.entities.values()); for (Entity entity : entities) { - removeEntity(entity, false); + removeEntity(entity); } session.getPlayerWithCustomHeads().clear(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveEntitiesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveEntitiesTranslator.java index 65229f29d..776cfb4d7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveEntitiesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveEntitiesTranslator.java @@ -39,7 +39,7 @@ public class JavaRemoveEntitiesTranslator extends PacketTranslator Date: Wed, 17 Apr 2024 23:21:25 +0200 Subject: [PATCH 023/897] Feature: Structure block translation (#4521) * ported camotoy's attempt of implementing structure blocks, removal of a few TODO's * no more parsing of java structure templates * Don't attempt to re-request structure size * ensure we can load structures in even if we know the size * init: send correct structure size/offset/rotation to java, not fully working yet * restore offsets so we are sending correct values to the java server regarding where we want the structure to be placed * something something mirror * attempt at proper offsets for mirroring AND rotations. this was not fun at all * rotation, mirror, offsetting all seem to work * undo import changes * fix NPE * Proper handling of empty structures, ensure that we can clear the structure block outline when a zero vector was sent for structure size * oops * Update core/src/main/java/org/geysermc/geyser/session/cache/StructureBlockCache.java Co-authored-by: rtm516 * Update core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java Co-authored-by: rtm516 * Update core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureBlockUpdateTranslator.java Co-authored-by: rtm516 * Update core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java Co-authored-by: rtm516 * consolidate java structure sending into one method * fix merge conflict --------- Co-authored-by: rtm516 --- README.md | 1 - .../populator/BlockRegistryPopulator.java | 16 +- .../geyser/registry/type/BlockMappings.java | 5 + .../geyser/session/GeyserSession.java | 2 + .../session/cache/StructureBlockCache.java | 59 +++++++ .../StructureBlockBlockEntityTranslator.java | 138 +++++++++++++++ ...BedrockInventoryTransactionTranslator.java | 7 + ...BedrockStructureBlockUpdateTranslator.java | 65 +++++++ ...tructureTemplateDataRequestTranslator.java | 91 ++++++++++ .../level/JavaBlockEntityDataTranslator.java | 59 +++++++ .../geysermc/geyser/util/InventoryUtils.java | 2 +- .../geyser/util/StructureBlockUtils.java | 164 ++++++++++++++++++ 12 files changed, 606 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/StructureBlockCache.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureBlockUpdateTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java diff --git a/README.md b/README.md index ce2b67af1..0aa9d009a 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge ## What's Left to be Added/Fixed - Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you) - Some Entity Flags -- Structure block UI ## What can't be fixed There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page. diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 4c52a1530..c54431fbe 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -144,7 +144,7 @@ public final class BlockRegistryPopulator { builder.remove("version"); // Remove all nbt tags which are not needed for differentiating states builder.remove("name_hash"); // Quick workaround - was added in 1.19.20 builder.remove("network_id"); // Added in 1.19.80 - ???? - builder.remove("block_id"); // Added in 1.20.60 //TODO verify this can be just removed + builder.remove("block_id"); // Added in 1.20.60 //noinspection UnstableApiUsage builder.putCompound("states", statesInterner.intern((NbtMap) builder.remove("states"))); vanillaBlockStates.set(i, builder.build()); @@ -229,6 +229,7 @@ public final class BlockRegistryPopulator { Map itemFrames = new Object2ObjectOpenHashMap<>(); Set jigsawDefinitions = new ObjectOpenHashSet<>(); + Map structureBlockDefinitions = new Object2ObjectOpenHashMap<>(); BlockMappings.BlockMappingsBuilder builder = BlockMappings.builder(); while (blocksIterator.hasNext()) { @@ -272,6 +273,18 @@ public final class BlockRegistryPopulator { jigsawDefinitions.add(bedrockDefinition); } + if (javaId.contains("structure_block")) { + int modeIndex = javaId.indexOf("mode="); + if (modeIndex != -1) { + int startIndex = modeIndex + 5; // Length of "mode=" is 5 + int endIndex = javaId.indexOf("]", startIndex); + if (endIndex != -1) { + String modeValue = javaId.substring(startIndex, endIndex); + structureBlockDefinitions.put(modeValue.toUpperCase(), bedrockDefinition); + } + } + } + boolean waterlogged = entry.getKey().contains("waterlogged=true") || javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass"); @@ -358,6 +371,7 @@ public final class BlockRegistryPopulator { .itemFrames(itemFrames) .flowerPotBlocks(flowerPotBlocks) .jigsawStates(jigsawDefinitions) + .structureBlockStates(structureBlockDefinitions) .remappedVanillaIds(remappedVanillaIds) .blockProperties(customBlockProperties) .customBlockStateDefinitions(customBlockStateDefinitions) diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index 8c0414a6d..c76f024af 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -61,6 +61,7 @@ public class BlockMappings implements DefinitionRegistry { Map flowerPotBlocks; Set jigsawStates; + Map structureBlockStates; List blockProperties; Object2ObjectMap customBlockStateDefinitions; @@ -96,6 +97,10 @@ public class BlockMappings implements DefinitionRegistry { return false; } + public BlockDefinition getStructureBlockFromMode(String mode) { + return structureBlockStates.get(mode); + } + @Override public @Nullable GeyserBedrockBlock getDefinition(int bedrockId) { if (bedrockId < 0 || bedrockId >= this.bedrockRuntimeMap.length) { 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 7a4a8ff6f..c0749400a 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -214,6 +214,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final PistonCache pistonCache; private final PreferencesCache preferencesCache; private final SkullCache skullCache; + private final StructureBlockCache structureBlockCache; private final TagCache tagCache; private final WorldCache worldCache; @@ -625,6 +626,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.pistonCache = new PistonCache(this); this.preferencesCache = new PreferencesCache(this); this.skullCache = new SkullCache(this); + this.structureBlockCache = new StructureBlockCache(); this.tagCache = new TagCache(); this.worldCache = new WorldCache(this); this.cameraData = new GeyserCameraData(this); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/StructureBlockCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/StructureBlockCache.java new file mode 100644 index 000000000..170f80d0a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/StructureBlockCache.java @@ -0,0 +1,59 @@ +/* + * 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.session.cache; + +import lombok.Getter; +import lombok.Setter; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector3i; + +@Setter +@Getter +public final class StructureBlockCache { + + /** + * Stores the current structure's name to be able to detect changes in the loaded structure + */ + private @Nullable String currentStructureName; + + /** + * Stores the offset changes added by Geyser that ensure that structure bounds + * are the same for Java and Bedrock + */ + private @Nullable Vector3i bedrockOffset; + + /** + * Stores the current structure block position while we're waiting on the Java + * server to send the data we need. + */ + private @Nullable Vector3i currentStructureBlock; + + public void clear() { + this.currentStructureName = null; + this.currentStructureBlock = null; + this.bedrockOffset = null; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java new file mode 100644 index 000000000..a24d010b7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java @@ -0,0 +1,138 @@ +/* + * 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.level.block.entity; + +import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation; +import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.StructureBlockUtils; + +@BlockEntity(type = BlockEntityType.STRUCTURE_BLOCK) +public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { + + @Override + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, CompoundTag tag, int blockState) { + // Sending a structure with size 0 doesn't clear the outline. Hence, we have to force it by replacing the block :/ + int xStructureSize = getOrDefault(tag.get("sizeX"), 0); + int yStructureSize = getOrDefault(tag.get("sizeY"), 0); + int zStructureSize = getOrDefault(tag.get("sizeZ"), 0); + + Vector3i size = Vector3i.from(xStructureSize, yStructureSize, zStructureSize); + + if (size.equals(Vector3i.ZERO)) { + Vector3i position = Vector3i.from(x, y, z); + String mode = getOrDefault(tag.get("mode"), ""); + + // Set to air and back to reset the structure block + UpdateBlockPacket emptyBlockPacket = new UpdateBlockPacket(); + emptyBlockPacket.setDataLayer(0); + emptyBlockPacket.setBlockPosition(position); + emptyBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); + session.sendUpstreamPacket(emptyBlockPacket); + + UpdateBlockPacket spawnerBlockPacket = new UpdateBlockPacket(); + spawnerBlockPacket.setDataLayer(0); + spawnerBlockPacket.setBlockPosition(position); + spawnerBlockPacket.setDefinition(session.getBlockMappings().getStructureBlockFromMode(mode)); + session.sendUpstreamPacket(spawnerBlockPacket); + } + + return super.getBlockEntityTag(session, type, x, y, z, tag, blockState); + } + + @Override + public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + if (tag.size() < 5) { + return; // These values aren't here + } + + builder.putString("structureName", getOrDefault(tag.get("name"), "")); + + String mode = getOrDefault(tag.get("mode"), ""); + int bedrockData = switch (mode) { + case "LOAD" -> 2; + case "CORNER" -> 3; + case "DATA" -> 4; + default -> 1; // SAVE + }; + + builder.putInt("data", bedrockData); + builder.putString("dataField", ""); // ??? possibly related to Java's "metadata" + + // Mirror behaves different in Java and Bedrock - it requires modifying the position in space as well + String mirror = getOrDefault(tag.get("mirror"), ""); + StructureMirror bedrockMirror = switch (mirror) { + case "FRONT_BACK" -> StructureMirror.X; + case "LEFT_RIGHT" -> StructureMirror.Z; + default -> StructureMirror.NONE; + }; + builder.putByte("mirror", (byte) bedrockMirror.ordinal()); + + builder.putByte("ignoreEntities", getOrDefault(tag.get("ignoreEntities"), (byte) 0)); + builder.putByte("isPowered", getOrDefault(tag.get("powered"), (byte) 0)); + builder.putLong("seed", getOrDefault(tag.get("seed"), 0L)); + builder.putByte("showBoundingBox", getOrDefault(tag.get("showboundingbox"), (byte) 0)); + + String rotation = getOrDefault(tag.get("rotation"), ""); + StructureRotation bedrockRotation = switch (rotation) { + case "CLOCKWISE_90" -> StructureRotation.ROTATE_90; + case "CLOCKWISE_180" -> StructureRotation.ROTATE_180; + case "COUNTERCLOCKWISE_90" -> StructureRotation.ROTATE_270; + default -> StructureRotation.NONE; + }; + builder.putByte("rotation", (byte) bedrockRotation.ordinal()); + + int xStructureSize = getOrDefault(tag.get("sizeX"), 0); + int yStructureSize = getOrDefault(tag.get("sizeY"), 0); + int zStructureSize = getOrDefault(tag.get("sizeZ"), 0); + + // The "positions" are also offsets on Java + int posX = getOrDefault(tag.get("posX"), 0); + int posY = getOrDefault(tag.get("posY"), 0); + int posZ = getOrDefault(tag.get("posZ"), 0); + + Vector3i offset = StructureBlockUtils.calculateOffset(bedrockRotation, bedrockMirror, + xStructureSize, zStructureSize); + + builder.putInt("xStructureOffset", posX + offset.getX()); + builder.putInt("yStructureOffset", posY); + builder.putInt("zStructureOffset", posZ + offset.getZ()); + + builder.putInt("xStructureSize", xStructureSize); + builder.putInt("yStructureSize", yStructureSize); + builder.putInt("zStructureSize", zStructureSize); + + builder.putFloat("integrity", getOrDefault(tag.get("integrity"), 0f)); // Is 1.0f by default on Java but 100.0f on Bedrock + + // Java's "showair" is unrepresented + } +} \ No newline at end of file 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 101035cb5..4ac835268 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 @@ -348,6 +348,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, StructureBlockUpdatePacket packet) { + StructureEditorData data = packet.getEditorData(); + + UpdateStructureBlockAction action = UpdateStructureBlockAction.UPDATE_DATA; + if (packet.isPowered()) { + if (data.getType() == StructureBlockType.LOAD) { + action = UpdateStructureBlockAction.LOAD_STRUCTURE; + } else if (data.getType() == StructureBlockType.SAVE) { + action = UpdateStructureBlockAction.SAVE_STRUCTURE; + } + } + + UpdateStructureBlockMode mode = switch (data.getType()) { + case CORNER -> UpdateStructureBlockMode.CORNER; + case DATA -> UpdateStructureBlockMode.DATA; + case LOAD -> UpdateStructureBlockMode.LOAD; + default -> UpdateStructureBlockMode.SAVE; + }; + + StructureBlockUtils.sendJavaStructurePacket(session, packet.getBlockPosition(), data.getSettings().getSize(), mode, action, data.getSettings(), + data.isBoundingBoxVisible(), data.getName()); + session.getStructureBlockCache().clear(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java new file mode 100644 index 000000000..947946f36 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java @@ -0,0 +1,91 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockAction; +import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockMode; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureSettings; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateRequestOperation; +import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataRequestPacket; +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.StructureBlockUtils; + +/** + * Packet used in Bedrock to load structure size into the structure block GUI. It is sent every time the GUI is opened. + * Or, if the player updates the structure name. Which we can use to request the structure size from the Java server! + *

+ * Java does not have this preview, instead, Java clients are forced out of the GUI to look at the area. + */ +@Translator(packet = StructureTemplateDataRequestPacket.class) +public class BedrockStructureTemplateDataRequestTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, StructureTemplateDataRequestPacket packet) { + // All other operation types are ignored by Geyser since we do not support exporting/importing structures + if (packet.getOperation().equals(StructureTemplateRequestOperation.QUERY_SAVED_STRUCTURE)) { + Vector3i size = packet.getSettings().getSize(); + StructureSettings settings = packet.getSettings(); + + // If we send a load packet to the Java server when the structure size is known, it would place the structure. + String currentStructureName = session.getStructureBlockCache().getCurrentStructureName(); + + // Case 1: Opening a structure block with information about structure size, but not yet saved by us + // Case 2: Getting an update from Bedrock with new information, doesn't bother us if it's the same structure + if (!packet.getSettings().getSize().equals(Vector3i.ZERO)) { + if (currentStructureName == null) { + Vector3i offset = StructureBlockUtils.calculateOffset(settings.getRotation(), settings.getMirror(), + settings.getSize().getX(), settings.getSize().getZ()); + session.getStructureBlockCache().setBedrockOffset(offset); + session.getStructureBlockCache().setCurrentStructureName(packet.getName()); + StructureBlockUtils.sendStructureData(session, size, packet.getName()); + return; + } else if (packet.getName().equals(currentStructureName)) { + StructureBlockUtils.sendStructureData(session, size, packet.getName()); + return; + } + } + + // Request a "structure load" from Java server, so it sends us the structure's size + // See the block entity translator for more info + session.getStructureBlockCache().setCurrentStructureBlock(packet.getPosition()); + + StructureBlockUtils.sendJavaStructurePacket(session, + packet.getPosition(), + Vector3i.ZERO, // We expect the Java server to tell us the size + UpdateStructureBlockMode.LOAD, + UpdateStructureBlockAction.LOAD_STRUCTURE, + settings, + true, + packet.getName() + ); + } else { + StructureBlockUtils.sendEmptyStructureData(session); + } + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java index c67a6dee4..325bae593 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java @@ -28,9 +28,13 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockEntityDataPacket; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.level.block.BlockStateValues; @@ -41,6 +45,7 @@ import org.geysermc.geyser.translator.level.block.entity.SkullBlockEntityTransla import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.geyser.util.StructureBlockUtils; @Translator(packet = ClientboundBlockEntityDataPacket.class) public class JavaBlockEntityDataTranslator extends PacketTranslator { @@ -95,5 +100,59 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator 5 + ) { + CompoundTag map = packet.getNbt(); + + String mode = getOrDefault(map.get("mode"), ""); + if (!mode.equalsIgnoreCase("LOAD")) { + return; + } + + String mirror = getOrDefault(map.get("mirror"), ""); + StructureMirror bedrockMirror = switch (mirror) { + case "FRONT_BACK" -> StructureMirror.X; + case "LEFT_RIGHT" -> StructureMirror.Z; + default -> StructureMirror.NONE; + }; + + String rotation = getOrDefault(map.get("rotation"), ""); + StructureRotation bedrockRotation = switch (rotation) { + case "CLOCKWISE_90" -> StructureRotation.ROTATE_90; + case "CLOCKWISE_180" -> StructureRotation.ROTATE_180; + case "COUNTERCLOCKWISE_90" -> StructureRotation.ROTATE_270; + default -> StructureRotation.NONE; + }; + + String name = getOrDefault(map.get("name"), ""); + int sizeX = getOrDefault(map.get("sizeX"), 0); + int sizeY = getOrDefault(map.get("sizeY"), 0); + int sizeZ = getOrDefault(map.get("sizeZ"), 0); + + session.getStructureBlockCache().setCurrentStructureBlock(null); + + Vector3i size = Vector3i.from(sizeX, sizeY, sizeZ); + if (size.equals(Vector3i.ZERO)) { + StructureBlockUtils.sendEmptyStructureData(session); + return; + } + + Vector3i offset = StructureBlockUtils.calculateOffset(bedrockRotation, bedrockMirror, + sizeX, sizeZ); + session.getStructureBlockCache().setBedrockOffset(offset); + session.getStructureBlockCache().setCurrentStructureName(name); + StructureBlockUtils.sendStructureData(session, size, name); + } + } + + + protected T getOrDefault(Tag tag, T defaultValue) { + //noinspection unchecked + return (tag != null && tag.getValue() != null) ? (T) tag.getValue() : defaultValue; } } 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 30b2907cc..25976f0f5 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -125,7 +125,7 @@ public class InventoryUtils { InventoryTranslator translator = session.getInventoryTranslator(); translator.closeInventory(session, inventory); if (confirm && inventory.isDisplayed() && !inventory.isPending() - && !(translator instanceof LecternInventoryTranslator) // TODO: double-check + && !(translator instanceof LecternInventoryTranslator) // Closing lecterns is not followed with a close confirmation ) { session.setClosingInventory(true); } diff --git a/core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java b/core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java new file mode 100644 index 000000000..9b3cfb53f --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java @@ -0,0 +1,164 @@ +/* + * 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.util; + +import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockAction; +import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockMode; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetStructureBlockPacket; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureSettings; +import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateResponseType; +import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataResponsePacket; +import org.geysermc.geyser.session.GeyserSession; + +public class StructureBlockUtils { + + private static final NbtMap EMPTY_STRUCTURE_DATA; + + static { + NbtMapBuilder builder = NbtMap.builder(); + builder.putInt("format_version", 1); + builder.putCompound("structure", NbtMap.builder() + .putList("block_indices", NbtType.LIST, NbtList.EMPTY, NbtList.EMPTY) + .putList("entities", NbtType.COMPOUND) + .putCompound("palette", NbtMap.EMPTY) + .build()); + builder.putList("structure_world_origin", NbtType.INT, 0, 0, 0); + EMPTY_STRUCTURE_DATA = builder.build(); + } + + public static void sendEmptyStructureData(GeyserSession session) { + StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket(); + responsePacket.setName(""); + responsePacket.setSave(false); + responsePacket.setType(StructureTemplateResponseType.QUERY); + session.sendUpstreamPacket(responsePacket); + } + + public static void sendStructureData(GeyserSession session,Vector3i size, String name) { + StructureTemplateDataResponsePacket responsePacket = new StructureTemplateDataResponsePacket(); + responsePacket.setName(name); + responsePacket.setSave(true); + responsePacket.setTag(EMPTY_STRUCTURE_DATA.toBuilder() + // Bedrock does not like negative sizes here + .putList("size", NbtType.INT, Math.abs(size.getX()), size.getY(), Math.abs(size.getZ())) + .build()); + responsePacket.setType(StructureTemplateResponseType.QUERY); + session.sendUpstreamPacket(responsePacket); + } + + public static Vector3i calculateOffset(StructureRotation structureRotation, StructureMirror structureMirror, + int sizeX, int sizeZ) { + int newOffsetX = 0; + int newOffsetZ = 0; + + switch (structureRotation) { + case ROTATE_90 -> { + switch (structureMirror) { + case NONE -> newOffsetX -= sizeZ - 1; + case X -> { + newOffsetZ -= sizeX - 1; + newOffsetX -= sizeZ - 1; + } + } + } + case ROTATE_180 -> { + switch (structureMirror) { + case NONE -> { + newOffsetX -= sizeX - 1; + newOffsetZ -= sizeZ - 1; + } + case Z -> newOffsetX -= sizeX - 1; + case X -> newOffsetZ -= sizeZ - 1; + } + } + case ROTATE_270 -> { + switch (structureMirror) { + case NONE -> newOffsetZ -= sizeX - 1; + case Z -> { + newOffsetZ -= sizeX - 1; + newOffsetX -= sizeZ - 1; + } + } + } + default -> { + switch (structureMirror) { + case Z -> newOffsetZ -= sizeZ - 1; + case X -> newOffsetX -= sizeX - 1; + } + } + } + + return Vector3i.from(newOffsetX, 0, newOffsetZ); + } + + public static void sendJavaStructurePacket(GeyserSession session, Vector3i blockPosition, Vector3i size, UpdateStructureBlockMode mode, UpdateStructureBlockAction action, + StructureSettings settings, boolean boundingBoxVisible, String structureName) { + + com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror mirror = switch (settings.getMirror()) { + case X -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.FRONT_BACK; + case Z -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.LEFT_RIGHT; + default -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.NONE; + }; + + com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation rotation = switch (settings.getRotation()) { + case ROTATE_90 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.CLOCKWISE_90; + case ROTATE_180 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.CLOCKWISE_180; + case ROTATE_270 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.COUNTERCLOCKWISE_90; + default -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.NONE; + }; + + Vector3i offset = settings.getOffset(); + if (session.getStructureBlockCache().getBedrockOffset() != null) { + offset = settings.getOffset().sub(session.getStructureBlockCache().getBedrockOffset()); + } + + ServerboundSetStructureBlockPacket structureBlockPacket = new ServerboundSetStructureBlockPacket( + blockPosition, + action, + mode, + structureName, + offset, + settings.getSize(), + mirror, + rotation, + "", + settings.getIntegrityValue(), + settings.getIntegritySeed(), + settings.isIgnoringEntities(), + false, + boundingBoxVisible + ); + + session.sendDownstreamPacket(structureBlockPacket); + } +} From 576a1b7d7a6360bfffc4923c708446f4a92f7c96 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 17 Apr 2024 17:53:56 -0400 Subject: [PATCH 024/897] Remove map cache (#4576) --- .../geyser/session/GeyserSession.java | 2 - .../BedrockMapInfoRequestTranslator.java | 50 ------------------- .../java/level/JavaMapItemDataTranslator.java | 17 ++----- 3 files changed, 5 insertions(+), 64 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMapInfoRequestTranslator.java 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 c0749400a..2a7b9b3fc 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -262,8 +262,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private ItemMappings itemMappings; - private final Long2ObjectMap storedMaps = new Long2ObjectOpenHashMap<>(); - /** * Required to decode biomes correctly. */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMapInfoRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMapInfoRequestTranslator.java deleted file mode 100644 index 3e885b63f..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMapInfoRequestTranslator.java +++ /dev/null @@ -1,50 +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.cloudburstmc.protocol.bedrock.packet.ClientboundMapItemDataPacket; -import org.cloudburstmc.protocol.bedrock.packet.MapInfoRequestPacket; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; - -import java.util.concurrent.TimeUnit; - -@Translator(packet = MapInfoRequestPacket.class) -public class BedrockMapInfoRequestTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, MapInfoRequestPacket packet) { - long mapId = packet.getUniqueMapId(); - - ClientboundMapItemDataPacket mapPacket = session.getStoredMaps().remove(mapId); - if (mapPacket != null) { - // Delay the packet 100ms to prevent the client from ignoring the packet - session.scheduleInEventLoop(() -> session.sendUpstreamPacket(mapPacket), - 100, TimeUnit.MILLISECONDS); - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java index 34fbf2d9c..01b0f324f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java @@ -44,7 +44,6 @@ public class JavaMapItemDataTranslator extends PacketTranslator Date: Thu, 18 Apr 2024 00:16:41 -0400 Subject: [PATCH 025/897] Reset metadata and attributes if needed when respawning (#4566) * Reset metadata and attributes if needed when respawning * Minor edits * Reset attributes in JavaLoginTranslator * Fix client bug when updating absorption and health in the same tick --- .../entity/attribute/GeyserAttributeType.java | 6 ++- .../entity/type/player/PlayerEntity.java | 5 ++- .../type/player/SessionPlayerEntity.java | 39 +++++++++++++++++++ .../geyser/session/GeyserSession.java | 2 +- .../protocol/java/JavaLoginTranslator.java | 2 +- .../protocol/java/JavaRespawnTranslator.java | 8 ++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index 234c1afe9..88d493275 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -51,7 +51,7 @@ public enum GeyserAttributeType { MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f), // Bedrock Attributes - ABSORPTION(null, "minecraft:absorption", 0f, Float.MAX_VALUE, 0f), + ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f), EXHAUSTION(null, "minecraft:player.exhaustion", 0f, 5f, 0f), EXPERIENCE(null, "minecraft:player.experience", 0f, 1f, 0f), EXPERIENCE_LEVEL(null, "minecraft:player.level", 0f, 24791.00f, 0f), @@ -66,6 +66,10 @@ public enum GeyserAttributeType { private final float maximum; private final float defaultValue; + public AttributeData getAttribute() { + return getAttribute(defaultValue); + } + public AttributeData getAttribute(float value) { return getAttribute(value, maximum); } 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 9e3888138..20819f75e 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 @@ -55,6 +55,7 @@ import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; import org.geysermc.geyser.entity.EntityDefinitions; +import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.ParrotEntity; @@ -283,7 +284,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { attributesPacket.setRuntimeEntityId(geyserId); // Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit attributesPacket.setAttributes(Collections.singletonList( - new AttributeData("minecraft:absorption", 0.0f, 1024f, entityMetadata.getPrimitiveValue(), 0.0f))); + GeyserAttributeType.ABSORPTION.getAttribute(entityMetadata.getPrimitiveValue()))); session.sendUpstreamPacket(attributesPacket); } @@ -307,7 +308,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { * Sets the parrot occupying the shoulder. Bedrock Edition requires a full entity whereas Java Edition just * spawns it from the NBT data provided */ - private void setParrot(CompoundTag tag, boolean isLeft) { + protected void setParrot(CompoundTag tag, boolean isLeft) { if (tag != null && !tag.isEmpty()) { if ((isLeft && leftParrot != null) || (!isLeft && rightParrot != null)) { // No need to update a parrot's data when it already exists 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 751a24871..89aa540d8 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 @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeTyp import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; @@ -255,13 +256,51 @@ public class SessionPlayerEntity extends PlayerEntity { return session.getAuthData().uuid(); } + @Override + public void setAbsorptionHearts(FloatEntityMetadata entityMetadata) { + // The bedrock client can glitch when sending a health and absorption attribute in the same tick + // This can happen when switching servers. Resending the absorption attribute fixes the issue + attributes.put(GeyserAttributeType.ABSORPTION, GeyserAttributeType.ABSORPTION.getAttribute(entityMetadata.getPrimitiveValue())); + super.setAbsorptionHearts(entityMetadata); + } + public void resetMetadata() { // Reset all metadata to their default values // This is used when a player respawns + this.flags.clear(); this.initializeMetadata(); // Reset air this.resetAir(); + + // Explicitly reset all metadata not handled by initializeMetadata + setParrot(null, true); + setParrot(null, false); + + // Absorption is metadata in java edition + attributes.remove(GeyserAttributeType.ABSORPTION); + UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); + attributesPacket.setRuntimeEntityId(geyserId); + attributesPacket.setAttributes(Collections.singletonList( + GeyserAttributeType.ABSORPTION.getAttribute(0f))); + session.sendUpstreamPacket(attributesPacket); + + dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0); + dirtyMetadata.put(EntityDataTypes.EFFECT_AMBIENCE, (byte) 0); + dirtyMetadata.put(EntityDataTypes.FREEZING_EFFECT_STRENGTH, 0f); + + silent = false; + } + + public void resetAttributes() { + attributes.clear(); + maxHealth = GeyserAttributeType.MAX_HEALTH.getDefaultValue(); + + UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); + attributesPacket.setRuntimeEntityId(geyserId); + attributesPacket.setAttributes(Collections.singletonList( + GeyserAttributeType.MOVEMENT_SPEED.getAttribute())); + session.sendUpstreamPacket(attributesPacket); } public void resetAir() { 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 2a7b9b3fc..aff21182e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -712,7 +712,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Default move speed // Bedrock clients move very fast by default until they get an attribute packet correcting the speed attributesPacket.setAttributes(Collections.singletonList( - new AttributeData("minecraft:movement", 0.0f, 1024f, 0.1f, 0.1f))); + GeyserAttributeType.MOVEMENT_SPEED.getAttribute())); upstream.sendPacket(attributesPacket); GameRulesChangedPacket gamerulePacket = new GameRulesChangedPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 23c19e84f..4a15157f9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -71,7 +71,7 @@ public class JavaLoginTranslator extends PacketTranslator Date: Thu, 18 Apr 2024 07:29:40 -0700 Subject: [PATCH 026/897] Update release for preview builds (#4575) --- .github/workflows/build.yml | 47 +++++++++++++++----- .github/workflows/preview.yml | 73 +++++++++++++++++++++++++++++++ .github/workflows/pullrequest.yml | 18 ++++++++ 3 files changed, 127 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/preview.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1d70d9948..c7b439182 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,7 @@ on: paths-ignore: - '.github/ISSUE_TEMPLATE/*.yml' - '.github/actions/pullrequest.yml' + - '.github/actions/preview.yml' - '.idea/copyright/*.xml' - '.gitignore' - 'CONTRIBUTING.md' @@ -19,6 +20,8 @@ on: jobs: build: runs-on: ubuntu-latest + env: + PROJECT: 'geyser' steps: - name: Checkout repository and submodules # See https://github.com/actions/checkout/commits @@ -103,6 +106,34 @@ jobs: with: arguments: publish + - name: Get Release Metadata + if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # https://github.com/Kas-tle/base-release-action/releases/tag/main-11 + with: + appID: ${{ secrets.RELEASE_APP_ID }} + appPrivateKey: ${{ secrets.RELEASE_APP_PK }} + files: | + bungeecord:bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + fabric:bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar + neoforge:bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar + spigot:bootstrap/spigot/build/libs/Geyser-Spigot.jar + standalone:bootstrap/standalone/build/libs/Geyser-Standalone.jar + velocity:bootstrap/velocity/build/libs/Geyser-Velocity.jar + viaproxy:bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar + releaseEnabled: false + saveMetadata: true + - name: Update Generated Metadata + if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + run: | + cat metadata.json + echo + version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) + cat metadata.json | jq --arg project "${PROJECT}" --arg version "${version}" ' + . + | .changes |= map({"commit", "summary", "message"}) + | .downloads |= map_values({"name", "sha256"}) + | {$project, "repo", $version, "number": .build, "changes", "downloads"} + ' | tee metadata.json - name: Publish to Downloads API if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} shell: bash @@ -114,19 +145,13 @@ jobs: # Save the private key to a file echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa chmod 600 id_ecdsa - # Set the project - project=geyser - # Get the version from gradle.properties - version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) # Create the build folder - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$project/$GITHUB_RUN_NUMBER/" + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/" # Copy over artifacts - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/mod/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/mod/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ # Run the build script - # Push the metadata - echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ - name: Publish to Modrinth (Fabric) uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 @@ -152,4 +177,4 @@ jobs: uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff with: webhook_url: ${{ secrets.DISCORD_WEBHOOK }} - status: ${{ job.status }} + status: ${{ job.status }} \ No newline at end of file diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 000000000..794ade4d4 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,73 @@ +name: Upload Preview + +on: + workflow_dispatch: + inputs: + runId: + required: true + description: 'ID of the action to pull artifacts from' + build: + required: true + description: 'Build number for the release' + version: + required: true + description: 'Version under which to upload to the Downloads API' + +jobs: + upload: + runs-on: ubuntu-latest + env: + PROJECT: 'geyser-preview' + BUILD: ${{ github.event.inputs.build }} + VERSION: ${{ github.event.inputs.version }} + steps: + - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # https://github.com/actions/download-artifact/releases/tag/v4.1.4 + with: + run-id: ${{ github.event.inputs.runId }} + github-token: ${{ secrets.GITHUB_TOKEN }} + merge-multiple: true + - name: Get Preview Metadata + if: success() + uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # https://github.com/Kas-tle/base-release-action/releases/tag/main-11 + with: + appID: ${{ secrets.RELEASE_APP_ID }} + appPrivateKey: ${{ secrets.RELEASE_APP_PK }} + files: | + bungeecord:Geyser-BungeeCord.jar + fabric:Geyser-Fabric.jar + neoforge:Geyser-NeoForge.jar + spigot:Geyser-Spigot.jar + standalone:Geyser-Standalone.jar + velocity:Geyser-Velocity.jar + viaproxy:Geyser-ViaProxy.jar + releaseEnabled: false + saveMetadata: true + updateReleaseData: false + - name: Update Generated Metadata + if: success() + run: | + cat metadata.json + echo + cat metadata.json | jq --arg project "${PROJECT}" --arg version "${VERSION}" --arg number "${BUILD}" ' + . + | .downloads |= map_values({"name", "sha256"}) + | {$project, "repo", $version, "number": $number | tonumber, "changes": [], "downloads"} + ' | tee metadata.json + - name: Publish to Downloads API + if: success() + shell: bash + env: + DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }} + DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} + DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }} + run: | + # Save the private key to a file + echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa + chmod 600 id_ecdsa + # Create the build folder + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$PROJECT/$BUILD/" + # Copy over artifacts + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/ + # Run the build script + # Push the metadata + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/ \ No newline at end of file diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 93be4711e..18223e7dc 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -102,3 +102,21 @@ jobs: name: Geyser ViaProxy path: geyser/bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar if-no-files-found: error + + - name: Trigger Preview Deployment + if: >- + contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing') + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea + with: + script: | + github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'preview.yml', + ref: 'master', + inputs: { + runId: '${{ github.run_id }}', + build: '${{ github.run_number }}', + version: 'pr.${{ github.event.pull_request.number }}' + } + }); \ No newline at end of file From ae96ad2ec4afd81a7c1478ea8f52c10af0350ab0 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 18 Apr 2024 17:18:05 +0100 Subject: [PATCH 027/897] Change preview builds project --- .github/workflows/preview.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 794ade4d4..a2955a081 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -17,7 +17,7 @@ jobs: upload: runs-on: ubuntu-latest env: - PROJECT: 'geyser-preview' + PROJECT: 'geyserpreview' BUILD: ${{ github.event.inputs.build }} VERSION: ${{ github.event.inputs.version }} steps: @@ -70,4 +70,4 @@ jobs: rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/ # Run the build script # Push the metadata - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/ \ No newline at end of file + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/ From 0cc2921eda30e2fe44951d1886bdb7ec6c3acbdf Mon Sep 17 00:00:00 2001 From: ookiegajwa <91029880+ookiegajwa@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:23:33 -0500 Subject: [PATCH 028/897] Translate scoreboard display name and number format (#4567) The following caveats apply because selectively removing or modifying the score numbers on Bedrock cannot be done without removing all of them: * "blank" and "styled" number formats are ignored for "list" and "sidebar" display slots * The "fixed" number format is appended to the end of the "list" and "sidebar" entry names instead of replacing the score number * The "below_name" slot has no limitations and displays identically to Java --- .../entity/type/player/PlayerEntity.java | 54 +++++++++++++--- .../geysermc/geyser/scoreboard/Objective.java | 34 +++++++++- .../org/geysermc/geyser/scoreboard/Score.java | 62 ++++++++++++++++++- .../geyser/scoreboard/Scoreboard.java | 4 +- .../java/scoreboard/JavaResetScorePacket.java | 4 +- .../JavaSetObjectiveTranslator.java | 16 ++++- .../scoreboard/JavaSetScoreTranslator.java | 18 ++---- 7 files changed, 157 insertions(+), 35 deletions(-) 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 20819f75e..b957a0243 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,6 +25,11 @@ package org.geysermc.geyser.entity.type.player; +import com.github.steveice10.mc.protocol.codec.NbtComponentSerializer; +import com.github.steveice10.mc.protocol.data.game.chat.numbers.BlankFormat; +import com.github.steveice10.mc.protocol.data.game.chat.numbers.FixedFormat; +import com.github.steveice10.mc.protocol.data.game.chat.numbers.NumberFormat; +import com.github.steveice10.mc.protocol.data.game.chat.numbers.StyledFormat; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -33,6 +38,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEnt import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; import lombok.Getter; import lombok.Setter; import net.kyori.adventure.text.Component; @@ -64,6 +70,7 @@ import org.geysermc.geyser.scoreboard.Score; import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.scoreboard.UpdateType; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.ChunkUtils; @@ -415,14 +422,36 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { public void setBelowNameText(Objective objective) { if (objective != null && objective.getUpdateType() != UpdateType.REMOVE) { - int amount; Score score = objective.getScores().get(username); + String numberString; + NumberFormat numberFormat; + int amount; if (score != null) { - amount = score.getCurrentData().getScore(); + amount = score.getScore(); + numberFormat = score.getNumberFormat(); + if (numberFormat == null) { + numberFormat = objective.getNumberFormat(); + } } else { amount = 0; + numberFormat = objective.getNumberFormat(); } - String displayString = amount + " " + objective.getDisplayName(); + + if (numberFormat instanceof BlankFormat) { + numberString = ""; + } else if (numberFormat instanceof FixedFormat fixedFormat) { + numberString = MessageTranslator.convertMessage(fixedFormat.getValue()); + } else if (numberFormat instanceof StyledFormat styledFormat) { + CompoundTag styledAmount = styledFormat.getStyle().clone(); + styledAmount.put(new StringTag("text", String.valueOf(amount))); + + numberString = MessageTranslator.convertJsonMessage( + NbtComponentSerializer.tagComponentToJson(styledAmount).toString()); + } else { + numberString = String.valueOf(amount); + } + + String displayString = numberString + " " + ChatColor.RESET + objective.getDisplayName(); if (valid) { // Already spawned - we still need to run the rest of this code because the spawn packet will be @@ -431,13 +460,22 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { packet.setRuntimeEntityId(geyserId); packet.getMetadata().put(EntityDataTypes.SCORE, displayString); session.sendUpstreamPacket(packet); + } else { + // Not spawned yet, store score value in dirtyMetadata to be picked up by #spawnEntity + dirtyMetadata.put(EntityDataTypes.SCORE, displayString); + } + } else { + if (valid) { + SetEntityDataPacket packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(geyserId); + packet.getMetadata().put(EntityDataTypes.SCORE, ""); + session.sendUpstreamPacket(packet); + } else { + // Not spawned yet, store score value in dirtyMetadata to be picked up by #spawnEntity + dirtyMetadata.put(EntityDataTypes.SCORE, ""); } - } else if (valid) { - SetEntityDataPacket packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(geyserId); - packet.getMetadata().put(EntityDataTypes.SCORE, ""); - session.sendUpstreamPacket(packet); } + } /** diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java index fd9e0fbf3..c00c69660 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java @@ -25,13 +25,16 @@ package org.geysermc.geyser.scoreboard; +import com.github.steveice10.mc.protocol.data.game.chat.numbers.NumberFormat; import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @Getter @@ -47,6 +50,7 @@ public final class Objective { private ScoreboardPosition displaySlot; private String displaySlotName; private String displayName = "unknown"; + private NumberFormat numberFormat; private int type = 0; // 0 = integer, 1 = heart private Map scores = new ConcurrentHashMap<>(); @@ -85,25 +89,29 @@ public final class Objective { }; } - public void registerScore(String id, int score) { + public void registerScore(String id, int score, Component displayName, NumberFormat numberFormat) { if (!scores.containsKey(id)) { long scoreId = scoreboard.getNextId().getAndIncrement(); Score scoreObject = new Score(scoreId, id) .setScore(score) .setTeam(scoreboard.getTeamFor(id)) + .setDisplayName(displayName) + .setNumberFormat(numberFormat) .setUpdateType(UpdateType.ADD); scores.put(id, scoreObject); } } - public void setScore(String id, int score) { + public void setScore(String id, int score, Component displayName, NumberFormat numberFormat) { Score stored = scores.get(id); if (stored != null) { stored.setScore(score) + .setDisplayName(displayName) + .setNumberFormat(numberFormat) .setUpdateType(UpdateType.UPDATE); return; } - registerScore(id, score); + registerScore(id, score, displayName, numberFormat); } public void removeScore(String id) { @@ -128,6 +136,26 @@ public final class Objective { return this; } + public Objective setNumberFormat(NumberFormat numberFormat) { + if (Objects.equals(this.numberFormat, numberFormat)) { + return this; + } + + this.numberFormat = numberFormat; + if (updateType == UpdateType.NOTHING) { + updateType = UpdateType.UPDATE; + } + + // Update the number format for scores that are following this objective's number format + for (Score score : scores.values()) { + if (score.getNumberFormat() == null) { + score.setUpdateType(UpdateType.UPDATE); + } + } + + return this; + } + public Objective setType(int type) { this.type = type; if (updateType == UpdateType.NOTHING) { diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java index 0a6623e97..ec17818c4 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java @@ -25,9 +25,16 @@ package org.geysermc.geyser.scoreboard; +import com.github.steveice10.mc.protocol.data.game.chat.numbers.FixedFormat; +import com.github.steveice10.mc.protocol.data.game.chat.numbers.NumberFormat; +import net.kyori.adventure.text.Component; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import lombok.Getter; import lombok.experimental.Accessors; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.translator.text.MessageTranslator; + +import java.util.Objects; @Getter @Accessors(chain = true) @@ -52,6 +59,10 @@ public final class Score { } public String getDisplayName() { + String displayName = cachedData.displayName; + if (displayName != null) { + return displayName; + } Team team = cachedData.team; if (team != null) { return team.getDisplayName(name); @@ -88,6 +99,35 @@ public final class Score { return this; } + public Score setDisplayName(Component displayName) { + if (currentData.displayName != null && displayName != null) { + String convertedDisplayName = MessageTranslator.convertMessage(displayName); + if (!currentData.displayName.equals(convertedDisplayName)) { + currentData.displayName = convertedDisplayName; + setUpdateType(UpdateType.UPDATE); + } + return this; + } + // simplified from (this.displayName != null && displayName == null) || (this.displayName == null && displayName != null) + if (currentData.displayName != null || displayName != null) { + currentData.displayName = MessageTranslator.convertMessage(displayName); + setUpdateType(UpdateType.UPDATE); + } + return this; + } + + public NumberFormat getNumberFormat() { + return currentData.numberFormat; + } + + public Score setNumberFormat(NumberFormat numberFormat) { + if (!Objects.equals(currentData.numberFormat, numberFormat)) { + currentData.numberFormat = numberFormat; + setUpdateType(UpdateType.UPDATE); + } + return this; + } + public UpdateType getUpdateType() { return currentData.updateType; } @@ -105,7 +145,7 @@ public final class Score { (currentData.team != null && currentData.team.shouldUpdate()); } - public void update(String objectiveName) { + public void update(Objective objective) { if (cachedData == null) { cachedData = new ScoreData(); cachedData.updateType = UpdateType.ADD; @@ -119,13 +159,26 @@ public final class Score { currentData.changed = false; cachedData.team = currentData.team; cachedData.score = currentData.score; + cachedData.displayName = currentData.displayName; + cachedData.numberFormat = currentData.numberFormat; String name = this.name; - if (cachedData.team != null) { + if (cachedData.displayName != null) { + name = cachedData.displayName; + } else if (cachedData.team != null) { cachedData.team.prepareUpdate(); name = cachedData.team.getDisplayName(name); } - cachedInfo = new ScoreInfo(id, objectiveName, cachedData.score, name); + + NumberFormat numberFormat = cachedData.numberFormat; + if (numberFormat == null) { + numberFormat = objective.getNumberFormat(); + } + if (numberFormat instanceof FixedFormat fixedFormat) { + name += " " + ChatColor.RESET + MessageTranslator.convertMessage(fixedFormat.getValue()); + } + + cachedInfo = new ScoreInfo(id, objective.getObjectiveName(), cachedData.score, name); } @Getter @@ -136,6 +189,9 @@ public final class Score { private Team team; private int score; + private String displayName; + private NumberFormat numberFormat; + private ScoreData() { updateType = UpdateType.ADD; } diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java index 216370bde..dfd74a79e 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java @@ -240,7 +240,7 @@ public final class Scoreboard { boolean update = score.shouldUpdate(); if (update) { - score.update(objective.getObjectiveName()); + score.update(objective); } if (score.getUpdateType() != REMOVE && update) { @@ -281,7 +281,7 @@ public final class Scoreboard { } if (score.shouldUpdate()) { - score.update(objective.getObjectiveName()); + score.update(objective); add = true; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java index 418037760..01b4fddea 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java @@ -54,7 +54,7 @@ public class JavaResetScorePacket extends PacketTranslator objective.setDisplayName(MessageTranslator.convertMessage(packet.getDisplayName())) - .setType(packet.getType().ordinal()); + case ADD, UPDATE -> { + objective.setDisplayName(MessageTranslator.convertMessage(packet.getDisplayName())) + .setNumberFormat(packet.getNumberFormat()) + .setType(packet.getType().ordinal()); + if (objective == scoreboard.getObjectiveSlots().get(ScoreboardPosition.BELOW_NAME)) { + // Update the score tag of all players + for (PlayerEntity entity : session.getEntityCache().getAllPlayerEntities()) { + if (entity.isValid()) { + entity.setBelowNameText(objective); + } + } + } + } case REMOVE -> { scoreboard.unregisterObjective(packet.getName()); if (objective != null && objective == scoreboard.getObjectiveSlots().get(ScoreboardPosition.BELOW_NAME)) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java index 594e2cbed..6bffee3d3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java @@ -28,8 +28,6 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; -import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.entity.type.player.PlayerEntity; @@ -54,7 +52,6 @@ public class JavaSetScoreTranslator extends PacketTranslator Date: Fri, 19 Apr 2024 05:41:06 -0400 Subject: [PATCH 029/897] Fix default wolf and cat collar color (#4582) --- .../living/animal/tameable/CatEntity.java | 11 +++++----- .../living/animal/tameable/WolfEntity.java | 22 ++++++++++++++----- 2 files changed, 22 insertions(+), 11 deletions(-) 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 412157b5d..93cb92c7d 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 @@ -45,7 +45,7 @@ import java.util.UUID; public class CatEntity extends TameableEntity { - private byte collarColor; + private byte collarColor = 14; // Red - default public CatEntity(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); @@ -76,10 +76,7 @@ public class CatEntity extends TameableEntity { @Override public void setTameableFlags(ByteEntityMetadata entityMetadata) { super.setTameableFlags(entityMetadata); - // Update collar color if tamed - if (getFlag(EntityFlag.TAMED)) { - dirtyMetadata.put(EntityDataTypes.COLOR, collarColor); - } + updateCollarColor(); } public void setCatVariant(IntEntityMetadata entityMetadata) { @@ -101,6 +98,10 @@ public class CatEntity extends TameableEntity { public void setCollarColor(IntEntityMetadata entityMetadata) { collarColor = (byte) entityMetadata.getPrimitiveValue(); + updateCollarColor(); + } + + private void updateCollarColor() { // Needed or else wild cats are a red color if (getFlag(EntityFlag.TAMED)) { dirtyMetadata.put(EntityDataTypes.COLOR, collarColor); 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 0f5b36ec3..c75247fdf 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 @@ -32,6 +32,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; @@ -41,6 +42,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; +import java.util.Collections; import java.util.Set; import java.util.UUID; @@ -54,7 +56,7 @@ public class WolfEntity extends TameableEntity { Items.PORKCHOP, Items.BEEF, Items.RABBIT, Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.ROTTEN_FLESH, Items.MUTTON, Items.COOKED_MUTTON, Items.COOKED_RABBIT); - private byte collarColor; + private byte collarColor = 14; // Red - default public WolfEntity(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); @@ -64,19 +66,27 @@ public class WolfEntity extends TameableEntity { public void setTameableFlags(ByteEntityMetadata entityMetadata) { super.setTameableFlags(entityMetadata); // Reset wolf color - byte xd = entityMetadata.getPrimitiveValue(); - boolean angry = (xd & 0x02) == 0x02; - if (angry) { + if (getFlag(EntityFlag.ANGRY)) { dirtyMetadata.put(EntityDataTypes.COLOR, (byte) 0); + } else if (getFlag(EntityFlag.TAMED)) { + updateCollarColor(); + + // This fixes tail angle when taming + UpdateAttributesPacket packet = new UpdateAttributesPacket(); + packet.setRuntimeEntityId(geyserId); + packet.setAttributes(Collections.singletonList(createHealthAttribute())); + session.sendUpstreamPacket(packet); } } public void setCollarColor(IntEntityMetadata entityMetadata) { collarColor = (byte) entityMetadata.getPrimitiveValue(); - if (getFlag(EntityFlag.ANGRY)) { - return; + if (!getFlag(EntityFlag.ANGRY) && getFlag(EntityFlag.TAMED)) { + updateCollarColor(); } + } + private void updateCollarColor() { dirtyMetadata.put(EntityDataTypes.COLOR, collarColor); if (ownerBedrockId == 0) { // If a color is set and there is no owner entity ID, set one. From 94f664ad8d065df32d0ce23cabd1e698ea7faf1e Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 19 Apr 2024 11:50:40 +0200 Subject: [PATCH 030/897] Fix: Properly check whether the `so_reuseport` socket option is available (#4579) * Try to properly check if so_reuseport is available * io_uring "support" * comment out io_uring, for now * Make IO_uring opt-in via `-DGeyser.io_uring=true` flag * dont include io_uring * oops - bungee editing on mobile is hard * oops - spigot * oops - velocity * properly exclude all io_uring on all platforms except standalone --------- Co-authored-by: Kas-tle <26531652+Kas-tle@users.noreply.github.com> --- bootstrap/bungeecord/build.gradle.kts | 1 + bootstrap/spigot/build.gradle.kts | 1 + bootstrap/velocity/build.gradle.kts | 4 +- bootstrap/viaproxy/build.gradle.kts | 1 + .../geyser.modded-conventions.gradle.kts | 2 + core/build.gradle.kts | 7 +--- .../geyser/network/netty/Bootstraps.java | 17 +++++++- .../geyser/network/netty/GeyserServer.java | 40 ++++++++++++++----- gradle/libs.versions.toml | 2 + 9 files changed, 56 insertions(+), 19 deletions(-) diff --git a/bootstrap/bungeecord/build.gradle.kts b/bootstrap/bungeecord/build.gradle.kts index 1b57ffa5a..e93c096a1 100644 --- a/bootstrap/bungeecord/build.gradle.kts +++ b/bootstrap/bungeecord/build.gradle.kts @@ -22,6 +22,7 @@ tasks.withType { dependencies { exclude(dependency("com.google.*:.*")) + exclude(dependency("io.netty.incubator:.*")) exclude(dependency("io.netty:netty-transport-native-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-unix-common:.*")) exclude(dependency("io.netty:netty-handler:.*")) diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 41da1a0de..1d135c33d 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -41,6 +41,7 @@ tasks.withType { // We cannot shade Netty, or else native libraries will not load // Needed because older Spigot builds do not provide the haproxy module + exclude(dependency("io.netty.incubator:.*")) exclude(dependency("io.netty:netty-transport-classes-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-unix-common:.*")) diff --git a/bootstrap/velocity/build.gradle.kts b/bootstrap/velocity/build.gradle.kts index 97e9d1f57..da826803c 100644 --- a/bootstrap/velocity/build.gradle.kts +++ b/bootstrap/velocity/build.gradle.kts @@ -12,7 +12,8 @@ platformRelocate("org.yaml") exclude("com.google.*:*") -// Needed because Velocity provides every dependency except netty-resolver-dns +// Needed because Velocity provides every dependency except netty-resolver-dns +exclude("io.netty.incubator:.*") exclude("io.netty:netty-transport-native-epoll:*") exclude("io.netty:netty-transport-native-unix-common:*") exclude("io.netty:netty-transport-native-kqueue:*") @@ -57,6 +58,7 @@ tasks.withType { exclude(dependency("io.netty:netty-transport:.*")) exclude(dependency("io.netty:netty-codec:.*")) exclude(dependency("io.netty:netty-codec-haproxy:.*")) + exclude(dependency("io.netty.incubator:.*")) exclude(dependency("org.slf4j:.*")) exclude(dependency("org.ow2.asm:.*")) // Exclude all Kyori dependencies except the legacy NBT serializer diff --git a/bootstrap/viaproxy/build.gradle.kts b/bootstrap/viaproxy/build.gradle.kts index 01c5b5b34..6eadc790f 100644 --- a/bootstrap/viaproxy/build.gradle.kts +++ b/bootstrap/viaproxy/build.gradle.kts @@ -22,6 +22,7 @@ tasks.withType { dependencies { exclude(dependency("com.google.*:.*")) exclude(dependency("io.netty:.*")) + exclude(dependency("io.netty.incubator:.*")) exclude(dependency("org.slf4j:.*")) exclude(dependency("org.ow2.asm:.*")) } diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index e011b7139..3d41dbbb4 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -26,6 +26,8 @@ provided("io.netty", "netty-transport-native-epoll") provided("io.netty", "netty-transport-native-unix-common") provided("io.netty", "netty-transport-classes-kqueue") provided("io.netty", "netty-transport-native-kqueue") +provided("io.netty.incubator", "netty-incubator-transport-native-io_uring") +provided("io.netty.incubator", "netty-incubator-transport-classes-io_uring") provided("io.netty", "netty-handler") provided("io.netty", "netty-common") provided("io.netty", "netty-buffer") diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 93c9f4f13..b1244d55d 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -47,6 +47,8 @@ dependencies { implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-x86_64" } } implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-aarch_64" } } implementation(libs.netty.transport.native.kqueue) { artifact { classifier = "osx-x86_64" } } + implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-x86_64" } } + implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-aarch_64" } } // Adventure text serialization api(libs.bundles.adventure) @@ -66,11 +68,6 @@ dependencies { api(libs.events) } -configurations.api { - // This is still experimental - additionally, it could only really benefit standalone - exclude(group = "io.netty.incubator", module = "netty-incubator-transport-native-io_uring") -} - tasks.processResources { // This is solely for backwards compatibility for other programs that used this file before the switch to gradle. // It used to be generated by the maven Git-Commit-Id-Plugin diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/Bootstraps.java b/core/src/main/java/org/geysermc/geyser/network/netty/Bootstraps.java index 9f889a6e7..fbc333106 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/Bootstraps.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/Bootstraps.java @@ -49,6 +49,7 @@ public final class Bootstraps { String kernelVersion; try { kernelVersion = Native.KERNEL_VERSION; + GeyserImpl.getInstance().getLogger().debug("Kernel version: " + kernelVersion); } catch (Throwable e) { GeyserImpl.getInstance().getLogger().debug("Could not determine kernel version! " + e.getMessage()); kernelVersion = null; @@ -67,10 +68,22 @@ public final class Bootstraps { } @SuppressWarnings({"rawtypes, unchecked"}) - public static void setupBootstrap(AbstractBootstrap bootstrap) { + public static boolean setupBootstrap(AbstractBootstrap bootstrap) { + boolean success = true; if (REUSEPORT_AVAILABLE) { - bootstrap.option(UnixChannelOption.SO_REUSEPORT, true); + // Guessing whether so_reuseport is available based on kernel version is cool, but unreliable. + Channel channel = bootstrap.register().channel(); + if (channel.config().setOption(UnixChannelOption.SO_REUSEPORT, true)) { + bootstrap.option(UnixChannelOption.SO_REUSEPORT, true); + } else { + // If this occurs, we guessed wrong and reuseport is not available + GeyserImpl.getInstance().getLogger().debug("so_reuseport is not available despite version being " + Native.KERNEL_VERSION); + success = false; + } + // Now yeet that channel + channel.close(); } + return success; } private static int[] fromString(String input) { diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index 8ead16623..652901f36 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.network.netty; -import com.github.steveice10.packetlib.helper.TransportHelper; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -39,6 +38,9 @@ import io.netty.channel.kqueue.KQueueEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.incubator.channel.uring.IOUring; +import io.netty.incubator.channel.uring.IOUringDatagramChannel; +import io.netty.incubator.channel.uring.IOUringEventLoopGroup; import io.netty.util.concurrent.Future; import lombok.Getter; import net.jodah.expiringmap.ExpirationPolicy; @@ -106,7 +108,7 @@ public final class GeyserServer { @Getter private final ExpiringMap proxiedAddresses; - private final int listenCount; + private int listenCount; private ChannelFuture[] bootstrapFutures; @@ -127,8 +129,11 @@ public final class GeyserServer { this.childGroup = TRANSPORT.eventLoopGroupFactory().apply(threadCount); this.bootstrap = this.createBootstrap(); - // setup SO_REUSEPORT if exists - Bootstraps.setupBootstrap(this.bootstrap); + // setup SO_REUSEPORT if exists - or, if the option does not actually exist, reset listen count + // otherwise, we try to bind multiple times which wont work if so_reuseport is not valid + if (!Bootstraps.setupBootstrap(this.bootstrap)) { + this.listenCount = 1; + } if (this.geyser.getConfig().getBedrock().isEnableProxyProtocol()) { this.proxiedAddresses = ExpiringMap.builder() @@ -415,22 +420,35 @@ public final class GeyserServer { } private static Transport compatibleTransport() { - TransportHelper.TransportMethod transportMethod = TransportHelper.determineTransportMethod(); - if (transportMethod == TransportHelper.TransportMethod.EPOLL) { + if (isClassAvailable("io.netty.incubator.channel.uring.IOUring") + && IOUring.isAvailable() + && Boolean.parseBoolean(System.getProperty("Geyser.io_uring"))) { + return new Transport(IOUringDatagramChannel.class, IOUringEventLoopGroup::new); + } + + if (isClassAvailable("io.netty.channel.epoll.Epoll") && Epoll.isAvailable()) { return new Transport(EpollDatagramChannel.class, EpollEventLoopGroup::new); } - if (transportMethod == TransportHelper.TransportMethod.KQUEUE) { + if (isClassAvailable("io.netty.channel.kqueue.KQueue") && KQueue.isAvailable()) { return new Transport(KQueueDatagramChannel.class, KQueueEventLoopGroup::new); } - // if (transportMethod == TransportHelper.TransportMethod.IO_URING) { - // return new Transport(IOUringDatagramChannel.class, IOUringEventLoopGroup::new); - // } - return new Transport(NioDatagramChannel.class, NioEventLoopGroup::new); } private record Transport(Class datagramChannel, IntFunction eventLoopGroupFactory) { } + + /** + * Used so implementations can opt to remove these dependencies if so desired + */ + private static boolean isClassAvailable(String className) { + try { + Class.forName(className); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3111750a8..7feec84e0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,6 +6,7 @@ events = "1.1-SNAPSHOT" jackson = "2.17.0" fastutil = "8.5.2" netty = "4.1.107.Final" +netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" @@ -75,6 +76,7 @@ netty-codec-haproxy = { group = "io.netty", name = "netty-codec-haproxy", versio netty-handler = { group = "io.netty", name = "netty-handler", version.ref = "netty" } netty-transport-native-epoll = { group = "io.netty", name = "netty-transport-native-epoll", version.ref = "netty" } netty-transport-native-kqueue = { group = "io.netty", name = "netty-transport-native-kqueue", version.ref = "netty" } +netty-transport-native-io_uring = { group = "io.netty.incubator", name = "netty-incubator-transport-native-io_uring", version.ref = "netty-io-uring" } log4j-api = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" } log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4j" } From 525a9ccec4f3dfdcbec328c9b382a782540cb7d9 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Fri, 19 Apr 2024 18:47:00 -0700 Subject: [PATCH 031/897] Fix Preview Workflow (#4583) * Fix preview workflow * Correct path to artifacts * Uncomment repo checks * Don't enforce repo/branch on preview deploy * Correct paths-ignore for build --- .../{pullrequest.yml => build-remote.yml} | 68 +++++++------------ .github/workflows/build.yml | 22 ++++-- .github/workflows/preview.yml | 33 +++++++-- .github/workflows/pull-request.yml | 24 +++++++ core/build.gradle.kts | 5 +- 5 files changed, 92 insertions(+), 60 deletions(-) rename .github/workflows/{pullrequest.yml => build-remote.yml} (65%) create mode 100644 .github/workflows/pull-request.yml diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/build-remote.yml similarity index 65% rename from .github/workflows/pullrequest.yml rename to .github/workflows/build-remote.yml index 18223e7dc..75bcfaff5 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/build-remote.yml @@ -1,13 +1,27 @@ -name: Build Pull Request +name: Build Remote -on: - pull_request: - merge_group: +on: + workflow_call: + inputs: + repository: + required: true + description: 'The repo of the remote' + type: string + ref: + required: true + description: 'The ref of the remote' + type: string + +permissions: {} jobs: build: runs-on: ubuntu-latest steps: + - name: Set Build Number + run: | + echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + - name: Set up JDK 17 # See https://github.com/actions/setup-java/commits uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 @@ -15,29 +29,12 @@ jobs: java-version: 17 distribution: temurin - - name: Check if the author has forked the API repo - # See https://github.com/Kas-tle/find-forks-action/commits - uses: Kas-tle/find-forks-action@1b5447d1e3c7a8ed79583dd817cc5399686eed3a - id: find_forks - with: - owner: GeyserMC - repo: api - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Use author's API repo if it exists - if: ${{ steps.find_forks.outputs.target_branch_found == 'true' }} - env: - API_FORK_URL: ${{ steps.find_forks.outputs.user_fork_url }} - API_FORK_BRANCH: ${{ github.event.pull_request.head.ref }} - run: | - git clone "${API_FORK_URL}" --single-branch --branch "${API_FORK_BRANCH}" api - cd api - ./gradlew publishToMavenLocal - - name: Checkout repository and submodules # See https://github.com/actions/checkout/commits uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: + repository: ${{ inputs.repository }} + ref: ${{ inputs.ref }} submodules: recursive path: geyser @@ -46,11 +43,12 @@ jobs: uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1 - name: Build Geyser - # See https://github.com/gradle/gradle-build-action/commits - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 from https://github.com/gradle/actions/commits + # See https://github.com/gradle/actions/commits + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 with: arguments: build build-root-directory: geyser + cache-read-only: true - name: Archive artifacts (Geyser Fabric) # See https://github.com/actions/upload-artifact/commits @@ -101,22 +99,4 @@ jobs: with: name: Geyser ViaProxy path: geyser/bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar - if-no-files-found: error - - - name: Trigger Preview Deployment - if: >- - contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing') - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea - with: - script: | - github.rest.actions.createWorkflowDispatch({ - owner: context.repo.owner, - repo: context.repo.repo, - workflow_id: 'preview.yml', - ref: 'master', - inputs: { - runId: '${{ github.run_id }}', - build: '${{ github.run_number }}', - version: 'pr.${{ github.event.pull_request.number }}' - } - }); \ No newline at end of file + if-no-files-found: error \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c7b439182..9582df3e8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,8 +7,9 @@ on: - 'gh-readonly-queue/**' paths-ignore: - '.github/ISSUE_TEMPLATE/*.yml' - - '.github/actions/pullrequest.yml' - - '.github/actions/preview.yml' + - '.github/actions/workflows/build-remote.yml' + - '.github/actions/workflows/preview.yml' + - '.github/actions/workflows/pull-request.yml' - '.idea/copyright/*.xml' - '.gitignore' - 'CONTRIBUTING.md' @@ -23,6 +24,13 @@ jobs: env: PROJECT: 'geyser' steps: + - name: Set Build Number + env: + BUILD_JSON: ${{ vars.RELEASEACTION_PREVRELEASE }} + run: | + BUILD_NUMBER=$(echo $BUILD_JSON | jq --arg branch "${GITHUB_REF_NAME}" 'if .[$branch] == null then 1 else .[$branch] | .t | tonumber + 1 end // 1') + echo "BUILD_NUMBER=${BUILD_NUMBER}" >> $GITHUB_ENV + - name: Checkout repository and submodules # See https://github.com/actions/checkout/commits uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -40,8 +48,8 @@ jobs: distribution: temurin - name: Build - # See https://github.com/gradle/gradle-build-action/commits - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 from https://github.com/gradle/actions/commits + # See https://github.com/gradle/actions/commits + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 with: arguments: build gradle-home-cache-cleanup: true @@ -108,7 +116,8 @@ jobs: - name: Get Release Metadata if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} - uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # https://github.com/Kas-tle/base-release-action/releases/tag/main-11 + # See https://github.com/Kas-tle/base-release-action/releases/tag/main-11 + uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # main-11 with: appID: ${{ secrets.RELEASE_APP_ID }} appPrivateKey: ${{ secrets.RELEASE_APP_PK }} @@ -134,6 +143,7 @@ jobs: | .downloads |= map_values({"name", "sha256"}) | {$project, "repo", $version, "number": .build, "changes", "downloads"} ' | tee metadata.json + echo - name: Publish to Downloads API if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} shell: bash @@ -177,4 +187,4 @@ jobs: uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff with: webhook_url: ${{ secrets.DISCORD_WEBHOOK }} - status: ${{ job.status }} \ No newline at end of file + status: ${{ job.status }} diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index a2955a081..ccac3ba85 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -12,23 +12,44 @@ on: version: required: true description: 'Version under which to upload to the Downloads API' + workflow_call: + inputs: + build: + required: true + description: 'Build number for the release' + type: string + version: + required: true + description: 'Version under which to upload to the Downloads API' + type: string jobs: upload: runs-on: ubuntu-latest env: - PROJECT: 'geyserpreview' - BUILD: ${{ github.event.inputs.build }} - VERSION: ${{ github.event.inputs.version }} + PROJECT: 'geyser-preview' steps: - - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # https://github.com/actions/download-artifact/releases/tag/v4.1.4 + - name: Set Variables + id: setvars + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "BUILD=${{ github.event.inputs.build }}" >> $GITHUB_ENV + echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV + echo "RUN=${{ github.event.inputs.runId }}" >> $GITHUB_OUTPUT + else + echo "BUILD=${{ inputs.build }}" >> $GITHUB_ENV + echo "VERSION=${{ inputs.version }}" >> $GITHUB_ENV + echo "RUN=${{ github.run_id }}" >> $GITHUB_OUTPUT + fi + - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 with: - run-id: ${{ github.event.inputs.runId }} + run-id: ${{ steps.setvars.outputs.RUN }} github-token: ${{ secrets.GITHUB_TOKEN }} merge-multiple: true - name: Get Preview Metadata if: success() - uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # https://github.com/Kas-tle/base-release-action/releases/tag/main-11 + # See https://github.com/Kas-tle/base-release-action/releases/tag/main-11 + uses: Kas-tle/base-release-action@664c39985eb9d0d393ce98e7eb8414d3d98e762a # main-11 with: appID: ${{ secrets.RELEASE_APP_ID }} appPrivateKey: ${{ secrets.RELEASE_APP_PK }} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 000000000..bc5e57b6b --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,24 @@ +name: Process Pull Request + +on: + pull_request_target: + +jobs: + build: + # Forbid access to secrets nor GH Token perms while building the PR + permissions: {} + secrets: {} + uses: ./.github/workflows/build-remote.yml + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.sha }} + preview: + needs: [build] + if: >- + contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing') + # Allow access to secrets if we are uploading a preview + secrets: inherit + uses: ./.github/workflows/preview.yml + with: + build: ${{ github.run_number }} + version: pr.${{ github.event.pull_request.number }} \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index b1244d55d..42d4e13c5 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -98,7 +98,7 @@ configure { } fun Project.buildNumber(): Int = - (System.getenv("GITHUB_RUN_NUMBER") ?: jenkinsBuildNumber())?.let { Integer.parseInt(it) } ?: -1 + (System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1 inner class GitInfo { val branch: String @@ -131,9 +131,6 @@ inner class GitInfo { } } -// todo remove this when we're not using Jenkins anymore -fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER") - // Manual task to download the bedrock data files from the CloudburstMC/Data repository // Invoke with ./gradlew :core:downloadBedrockData --suffix=1_20_70 // Set suffix to the current Bedrock version From 1bca6421d30966fb4f1b7703df2885da43517d6c Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 20 Apr 2024 03:12:27 +0100 Subject: [PATCH 032/897] Update preview action to use correct project --- .github/workflows/preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index ccac3ba85..13712d5ef 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -27,7 +27,7 @@ jobs: upload: runs-on: ubuntu-latest env: - PROJECT: 'geyser-preview' + PROJECT: 'geyserpreview' steps: - name: Set Variables id: setvars From 810c9ced724360b3b52efa3b70eef1682e2bb86b Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 20 Apr 2024 17:21:39 -0400 Subject: [PATCH 033/897] Fix filled cauldrons only showing as water (#4585) * Fix filled cauldrons only showing as water * Update comment --- .../org/geysermc/geyser/level/block/BlockStateValues.java | 4 ++-- .../translator/level/block/entity/BedrockOnlyBlockEntity.java | 2 +- .../java/level/JavaLevelChunkWithLightTranslator.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index e665a22ef..52759c709 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -260,8 +260,6 @@ public final class BlockStateValues { } /** - * Non-water cauldrons (since Bedrock 1.18.30) must have a block entity packet sent on chunk load to fix rendering issues. - * * @return if this Java block state is a non-empty non-water cauldron */ public static boolean isNonWaterCauldron(int state) { @@ -269,6 +267,8 @@ public final class BlockStateValues { } /** + * Cauldrons (since Bedrock 1.18.30) must have a block entity packet sent on chunk load to fix rendering issues. + *

* When using a bucket on a cauldron sending a ServerboundUseItemPacket can result in the liquid being placed. * * @return if this Java block state is a cauldron diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java index 07b075690..051986473 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java @@ -63,7 +63,7 @@ public interface BedrockOnlyBlockEntity extends RequiresBlockState { return FlowerPotBlockEntityTranslator.getTag(session, blockState, position); } else if (PistonBlockEntityTranslator.isBlock(blockState)) { return PistonBlockEntityTranslator.getTag(blockState, position); - } else if (BlockStateValues.isNonWaterCauldron(blockState)) { + } else if (BlockStateValues.isCauldron(blockState)) { // As of 1.18.30: this is required to make rendering not look weird on chunk load (lava and snow cauldrons look dim) return NbtMap.builder() .putString("id", "Cauldron") diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index 8a35bbb5c..a98ead719 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -200,7 +200,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)), javaId @@ -259,7 +259,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator Date: Sat, 20 Apr 2024 19:07:39 -0700 Subject: [PATCH 034/897] Fallback to GITHUB_RUN_NUMBER if RELEASEACTION_PREVRELEASE is unset (#4587) This is so there is still a build number when built on other repositories --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9582df3e8..1ef0118ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,9 +7,9 @@ on: - 'gh-readonly-queue/**' paths-ignore: - '.github/ISSUE_TEMPLATE/*.yml' - - '.github/actions/workflows/build-remote.yml' - - '.github/actions/workflows/preview.yml' - - '.github/actions/workflows/pull-request.yml' + - '.github/workflows/build-remote.yml' + - '.github/workflows/preview.yml' + - '.github/workflows/pull-request.yml' - '.idea/copyright/*.xml' - '.gitignore' - 'CONTRIBUTING.md' @@ -29,7 +29,7 @@ jobs: BUILD_JSON: ${{ vars.RELEASEACTION_PREVRELEASE }} run: | BUILD_NUMBER=$(echo $BUILD_JSON | jq --arg branch "${GITHUB_REF_NAME}" 'if .[$branch] == null then 1 else .[$branch] | .t | tonumber + 1 end // 1') - echo "BUILD_NUMBER=${BUILD_NUMBER}" >> $GITHUB_ENV + echo "BUILD_NUMBER=${BUILD_NUMBER:=$GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - name: Checkout repository and submodules # See https://github.com/actions/checkout/commits From 3fa79529365e4ceae3fb4f95b2acde2f1305a13d Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 23 Apr 2024 09:16:18 -0700 Subject: [PATCH 035/897] 1.20.80 Support and Protocol Changes (#4561) * Make evil more harder Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Deregister more unused packets Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Add more unused packets Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Pin protocol to 68dc192 * Correction * Update Protocol * More kicking Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * stop reading when there is no item to read (#9) * Bump protocol Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * 1.20.80 Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Remove unused postinitchannel GeyserServerInitializer * Pull protocol jitpack from cloudburst again * Actually builds Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Bump protocol to fix BossEventPacket & EmotePacket Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Add remove before merge comment Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Bump protocol to fix BlockEntityDataPacket and ignore serverbound BossEventPacket Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Bump protocol & add more illegal/ignored packets Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Remove deprecated packet Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Ignore ClientCacheStatusPacket instead of disallow Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Define static serializers Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Less static class nonsense more correct order Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Remove unused import Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Bump protocol Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Move codec processing to CodecProcessor Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Falsify recipe symetry assumption Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Update Protocol for 2 wrong packet IDs & 5 wrong directions * Jitpack protocol from Geyser repo --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Co-authored-by: chris --- README.md | 2 +- .../geyser/network/CodecProcessor.java | 292 + .../geysermc/geyser/network/GameProtocol.java | 29 +- .../network/GeyserServerInitializer.java | 8 + .../geyser/network/InvalidPacketHandler.java | 58 + .../populator/BlockRegistryPopulator.java | 4 +- .../registry/populator/Conversion662_649.java | 4 + .../registry/populator/Conversion671_662.java | 182 + .../populator/ItemRegistryPopulator.java | 4 +- .../populator/RecipeRegistryPopulator.java | 2 +- .../java/JavaUpdateRecipesTranslator.java | 2 +- .../JavaContainerSetSlotTranslator.java | 3 +- .../bedrock/block_palette.1_20_80.nbt | Bin 0 -> 176786 bytes .../bedrock/creative_items.1_20_80.json | 5812 +++++++++++++++ .../resources/bedrock/entity_identifiers.dat | Bin 7886 -> 7951 bytes .../bedrock/runtime_item_states.1_20_80.json | 6274 +++++++++++++++++ core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 15 +- 18 files changed, 12661 insertions(+), 32 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java create mode 100644 core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java create mode 100644 core/src/main/resources/bedrock/block_palette.1_20_80.nbt create mode 100644 core/src/main/resources/bedrock/creative_items.1_20_80.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_20_80.json diff --git a/README.md b/README.md index 0aa9d009a..e17c9d2bb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.73 and Minecraft Java 1.20.4 +### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80 and Minecraft Java 1.20.4 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java new file mode 100644 index 000000000..4ad02a644 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -0,0 +1,292 @@ +/* + * 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.network; + +import io.netty.buffer.ByteBuf; +import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; +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.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.v486.serializer.BossEventSerializer_v486; +import org.cloudburstmc.protocol.bedrock.codec.v557.serializer.SetEntityDataSerializer_v557; +import org.cloudburstmc.protocol.bedrock.codec.v662.serializer.SetEntityMotionSerializer_v662; +import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket; +import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +import org.cloudburstmc.protocol.bedrock.packet.BossEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.ClientCacheBlobStatusPacket; +import org.cloudburstmc.protocol.bedrock.packet.ClientCacheStatusPacket; +import org.cloudburstmc.protocol.bedrock.packet.ClientCheatAbilityPacket; +import org.cloudburstmc.protocol.bedrock.packet.ClientToServerHandshakePacket; +import org.cloudburstmc.protocol.bedrock.packet.CodeBuilderSourcePacket; +import org.cloudburstmc.protocol.bedrock.packet.CraftingEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.CreatePhotoPacket; +import org.cloudburstmc.protocol.bedrock.packet.DebugInfoPacket; +import org.cloudburstmc.protocol.bedrock.packet.DisconnectPacket; +import org.cloudburstmc.protocol.bedrock.packet.EditorNetworkPacket; +import org.cloudburstmc.protocol.bedrock.packet.EntityFallPacket; +import org.cloudburstmc.protocol.bedrock.packet.GameTestRequestPacket; +import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; +import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; +import org.cloudburstmc.protocol.bedrock.packet.LabTablePacket; +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.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.PlayerSkinPacket; +import org.cloudburstmc.protocol.bedrock.packet.PurchaseReceiptPacket; +import org.cloudburstmc.protocol.bedrock.packet.RefreshEntitlementsPacket; +import org.cloudburstmc.protocol.bedrock.packet.ScriptMessagePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; +import org.cloudburstmc.protocol.bedrock.packet.SettingsCommandPacket; +import org.cloudburstmc.protocol.bedrock.packet.SimpleEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.SubChunkRequestPacket; +import org.cloudburstmc.protocol.bedrock.packet.SubClientLoginPacket; +import org.cloudburstmc.protocol.bedrock.packet.TickSyncPacket; +import org.cloudburstmc.protocol.common.util.VarInts; + +/** + * Processes the Bedrock codec to remove or modify unused or unsafe packets and fields. + */ +class CodecProcessor { + + /** + * Generic serializer that throws an exception when trying to serialize or deserialize a packet, leading to client disconnection. + */ + @SuppressWarnings("rawtypes") + private static final BedrockPacketSerializer ILLEGAL_SERIALIZER = new BedrockPacketSerializer<>() { + @Override + public void serialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { + throw new IllegalArgumentException("Server tried to send unused packet " + packet.getClass().getSimpleName() + "!"); + } + + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { + throw new IllegalArgumentException("Client tried to send unused packet " + packet.getClass().getSimpleName() + "!"); + } + }; + + /** + * Generic serializer that does nothing when trying to serialize or deserialize a packet. + */ + @SuppressWarnings("rawtypes") + private static final BedrockPacketSerializer IGNORED_SERIALIZER = new BedrockPacketSerializer<>() { + @Override + public void serialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { + } + + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { + } + }; + + /** + * Serializer that throws an exception when trying to deserialize InventoryContentPacket since server-auth inventory is used. + */ + private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER = new InventoryContentSerializer_v407() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { + throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!"); + } + }; + + /** + * Serializer that throws an exception when trying to deserialize InventorySlotPacket since server-auth inventory is used. + */ + private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER = new InventorySlotSerializer_v407() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { + throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!"); + } + }; + + /** + * Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer BOSS_EVENT_SERIALIZER = new BossEventSerializer_v486() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BossEventPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize MobArmorEquipmentPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer MOB_ARMOR_EQUIPMENT_SERIALIZER = new MobArmorEquipmentSerializer_v291() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobArmorEquipmentPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize PlayerHotbarPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer PLAYER_HOTBAR_SERIALIZER = new PlayerHotbarSerializer_v291() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, PlayerHotbarPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize PlayerSkinPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer PLAYER_SKIN_SERIALIZER = new PlayerSkinSerializer_v390() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, PlayerSkinPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize SetEntityDataPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer SET_ENTITY_DATA_SERIALIZER = new SetEntityDataSerializer_v557() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityDataPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer SET_ENTITY_MOTION_SERIALIZER = new SetEntityMotionSerializer_v662() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityMotionPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize SetEntityLinkPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer SET_ENTITY_LINK_SERIALIZER = new SetEntityLinkSerializer_v291() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityLinkPacket packet) { + } + }; + + /** + * Serializer that skips over the item when trying to deserialize MobEquipmentPacket since only the slot info is used. + */ + private static final BedrockPacketSerializer MOB_EQUIPMENT_SERIALIZER = new MobEquipmentSerializer_v291() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobEquipmentPacket packet) { + packet.setRuntimeEntityId(VarInts.readUnsignedLong(buffer)); + fakeItemRead(buffer); + packet.setInventorySlot(buffer.readUnsignedByte()); + packet.setHotbarSlot(buffer.readUnsignedByte()); + packet.setContainerId(buffer.readByte()); + } + }; + + @SuppressWarnings("unchecked") + static BedrockCodec processCodec(BedrockCodec codec) { + return codec.toBuilder() + // Illegal unused serverbound EDU packets + .updateSerializer(PhotoTransferPacket.class, ILLEGAL_SERIALIZER) + .updateSerializer(LabTablePacket.class, ILLEGAL_SERIALIZER) + .updateSerializer(CodeBuilderSourcePacket.class, ILLEGAL_SERIALIZER) + .updateSerializer(CreatePhotoPacket.class, ILLEGAL_SERIALIZER) + .updateSerializer(NpcRequestPacket.class, ILLEGAL_SERIALIZER) + .updateSerializer(PhotoInfoRequestPacket.class, ILLEGAL_SERIALIZER) + // Illegal unused serverbound packets for featured servers + .updateSerializer(PurchaseReceiptPacket.class, ILLEGAL_SERIALIZER) + // Illegal unused serverbound packets that are deprecated + .updateSerializer(ClientCheatAbilityPacket.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) + .updateSerializer(GameTestRequestPacket.class, ILLEGAL_SERIALIZER) + // Ignored serverbound packets + .updateSerializer(CraftingEventPacket.class, IGNORED_SERIALIZER) // Make illegal when 1.20.40 is removed + .updateSerializer(ClientToServerHandshakePacket.class, IGNORED_SERIALIZER) + .updateSerializer(EntityFallPacket.class, IGNORED_SERIALIZER) + .updateSerializer(MapCreateLockedCopyPacket.class, IGNORED_SERIALIZER) + .updateSerializer(MapInfoRequestPacket.class, IGNORED_SERIALIZER) + .updateSerializer(SettingsCommandPacket.class, IGNORED_SERIALIZER) + .updateSerializer(AnvilDamagePacket.class, IGNORED_SERIALIZER) + .updateSerializer(RefreshEntitlementsPacket.class, IGNORED_SERIALIZER) + // Illegal when serverbound due to Geyser specific setup + .updateSerializer(InventoryContentPacket.class, INVENTORY_CONTENT_SERIALIZER) + .updateSerializer(InventorySlotPacket.class, INVENTORY_SLOT_SERIALIZER) + // Ignored only when serverbound + .updateSerializer(BossEventPacket.class, BOSS_EVENT_SERIALIZER) + .updateSerializer(MobArmorEquipmentPacket.class, MOB_ARMOR_EQUIPMENT_SERIALIZER) + .updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER) + .updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER) + .updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER) + .updateSerializer(SetEntityMotionPacket.class, SET_ENTITY_MOTION_SERIALIZER) + .updateSerializer(SetEntityLinkPacket.class, SET_ENTITY_LINK_SERIALIZER) + // Valid serverbound packets where reading of some fields can be skipped + .updateSerializer(MobEquipmentPacket.class, MOB_EQUIPMENT_SERIALIZER) + // // Illegal bidirectional packets + .updateSerializer(DebugInfoPacket.class, ILLEGAL_SERIALIZER) + .updateSerializer(EditorNetworkPacket.class, ILLEGAL_SERIALIZER) + .updateSerializer(ScriptMessagePacket.class, ILLEGAL_SERIALIZER) + // // Ignored bidirectional packets + .updateSerializer(ClientCacheStatusPacket.class, IGNORED_SERIALIZER) + .updateSerializer(DisconnectPacket.class, IGNORED_SERIALIZER) + .updateSerializer(SimpleEventPacket.class, IGNORED_SERIALIZER) + .updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER) + .updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER) + .build(); + } + + /** + * Fake reading an item from the buffer to improve performance. + * + * @param buffer + */ + private static void fakeItemRead(ByteBuf buffer) { + int id = VarInts.readInt(buffer); // Runtime ID + if (id == 0) { // nothing more to read + return; + } + buffer.skipBytes(2); // count + VarInts.readUnsignedInt(buffer); // damage + boolean hasNetId = buffer.readBoolean(); + if (hasNetId) { + VarInts.readInt(buffer); + } + + VarInts.readInt(buffer); // Block runtime ID + int streamSize = VarInts.readUnsignedInt(buffer); + buffer.skipBytes(streamSize); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index f43706db0..b5fc4440c 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -27,17 +27,14 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; -import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; -import org.cloudburstmc.protocol.bedrock.codec.BedrockCodecHelper; -import org.cloudburstmc.protocol.bedrock.codec.v582.serializer.TrimDataSerializer_v582; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662; +import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; -import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -48,11 +45,12 @@ import java.util.StringJoiner; * Contains information about the supported protocols in Geyser. */ public final class GameProtocol { + /** * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = processCodec(Bedrock_v662.CODEC); + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v671.CODEC); /** * A list of all supported Bedrock versions that can join Geyser @@ -66,18 +64,21 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(processCodec(Bedrock_v622.CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v622.CODEC.toBuilder() .minecraftVersion("1.20.40/1.20.41") .build())); - SUPPORTED_BEDROCK_CODECS.add(processCodec(Bedrock_v630.CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v630.CODEC.toBuilder() .minecraftVersion("1.20.50/1.20.51") .build())); - SUPPORTED_BEDROCK_CODECS.add(processCodec(Bedrock_v649.CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v649.CODEC.toBuilder() .minecraftVersion("1.20.60/1.20.62") .build())); - SUPPORTED_BEDROCK_CODECS.add(processCodec(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v662.CODEC.toBuilder() .minecraftVersion("1.20.70/1.20.73") .build())); + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.20.80") + .build())); } /** @@ -168,16 +169,6 @@ public final class GameProtocol { return joiner.toString(); } - private static BedrockCodec processCodec(BedrockCodec codec) { - return codec.toBuilder() - .updateSerializer(TrimDataPacket.class, new TrimDataSerializer_v582() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, TrimDataPacket packet) { - } - }) - .build(); - } - private GameProtocol() { } } diff --git a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java index bb8e87440..662e2f4c7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java +++ b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java @@ -25,12 +25,16 @@ package org.geysermc.geyser.network; +import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; import io.netty.channel.DefaultEventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; import io.netty.util.concurrent.DefaultThreadFactory; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.BedrockPeer; import org.cloudburstmc.protocol.bedrock.BedrockServerSession; +import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.cloudburstmc.protocol.bedrock.netty.initializer.BedrockServerInitializer; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.bedrock.SessionInitializeEvent; @@ -63,6 +67,10 @@ public class GeyserServerInitializer extends BedrockServerInitializer { bedrockServerSession.setLogging(true); GeyserSession session = new GeyserSession(this.geyser, bedrockServerSession, this.eventLoopGroup.next()); + + Channel channel = bedrockServerSession.getPeer().getChannel(); + channel.pipeline().addAfter(BedrockPacketCodec.NAME, InvalidPacketHandler.NAME, new InvalidPacketHandler(session)); + bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(this.geyser, session)); this.geyser.eventBus().fire(new SessionInitializeEvent(session)); } catch (Throwable e) { diff --git a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java new file mode 100644 index 000000000..3e836711b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java @@ -0,0 +1,58 @@ +/* + * 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.network; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import lombok.RequiredArgsConstructor; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.stream.Stream; + +@RequiredArgsConstructor +public class InvalidPacketHandler extends ChannelInboundHandlerAdapter { + public static final String NAME = "rak-error-handler"; + + private final GeyserSession session; + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + Throwable rootCause = Stream.iterate(cause, Throwable::getCause) + .filter(element -> element.getCause() == null) + .findFirst() + .orElse(cause); + + + if (!(rootCause instanceof IllegalArgumentException)) { + super.exceptionCaught(ctx, cause); + return; + } + + // Kick users that try to send illegal packets + session.getGeyser().getLogger().warning(rootCause.getMessage()); + session.disconnect("Invalid packet received!"); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index c54431fbe..e76edc059 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -43,6 +43,7 @@ import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662; +import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -122,7 +123,8 @@ public final class BlockRegistryPopulator { .put(ObjectIntPair.of("1_20_50", Bedrock_v630.CODEC.getProtocolVersion()), Conversion649_630::remapBlock) // Only changes in 1.20.60 are hard_stained_glass (an EDU only block) .put(ObjectIntPair.of("1_20_60", Bedrock_v649.CODEC.getProtocolVersion()), Conversion662_649::remapBlock) - .put(ObjectIntPair.of("1_20_70", Bedrock_v662.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_20_70", Bedrock_v662.CODEC.getProtocolVersion()), Conversion671_662::remapBlock) + .put(ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), tag -> tag) .build(); // We can keep this strong as nothing should be garbage collected diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java index cddeae7bf..0fe1610f2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java @@ -44,6 +44,8 @@ public class Conversion662_649 { static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { + mapping = Conversion671_662.remapItem(item, mapping); + String identifer = mapping.getBedrockIdentifier(); if (identifer.equals("minecraft:grass_block")) { @@ -93,6 +95,8 @@ public class Conversion662_649 { } static NbtMap remapBlock(NbtMap tag) { + tag = Conversion671_662.remapBlock(tag); + final String name = tag.getString("name"); if (!NEW_BLOCKS.contains(name)) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java new file mode 100644 index 000000000..2c6db7567 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java @@ -0,0 +1,182 @@ +/* + * 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.registry.populator; + +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.type.GeyserMappingItem; + +import java.util.List; +import java.util.stream.Stream; + +public class Conversion671_662 { + private static final List NEW_CORAL_FANS = List.of("minecraft:tube_coral_fan", "minecraft:brain_coral_fan", "minecraft:bubble_coral_fan", "minecraft:fire_coral_fan", "minecraft:horn_coral_fan"); + private static final List NEW_DEAD_CORAL_FANS = List.of("minecraft:dead_tube_coral_fan", "minecraft:dead_brain_coral_fan", "minecraft:dead_bubble_coral_fan", "minecraft:dead_fire_coral_fan", "minecraft:dead_horn_coral_fan"); + private static final List NEW_FLOWERS = List.of("minecraft:poppy", "minecraft:blue_orchid", "minecraft:allium", "minecraft:azure_bluet", "minecraft:red_tulip", "minecraft:orange_tulip", "minecraft:white_tulip", "minecraft:pink_tulip", "minecraft:oxeye_daisy", "minecraft:cornflower", "minecraft:lily_of_the_valley"); + private static final List NEW_SAPLINGS = List.of("minecraft:oak_sapling", "minecraft:spruce_sapling", "minecraft:birch_sapling", "minecraft:jungle_sapling", "minecraft:acacia_sapling", "minecraft:dark_oak_sapling", "minecraft:bamboo_sapling"); + private static final List NEW_BLOCKS = Stream.of(NEW_CORAL_FANS, NEW_DEAD_CORAL_FANS, NEW_FLOWERS, NEW_SAPLINGS).flatMap(List::stream).toList(); + + static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { + String identifer = mapping.getBedrockIdentifier(); + + if (!NEW_BLOCKS.contains(identifer)) { + return mapping; + } + + if (NEW_FLOWERS.contains(identifer)) { + switch (identifer) { + case "minecraft:poppy" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(0); } + case "minecraft:blue_orchid" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(1); } + case "minecraft:allium" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(2); } + case "minecraft:azure_bluet" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(3); } + case "minecraft:red_tulip" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(4); } + case "minecraft:orange_tulip" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(5); } + case "minecraft:white_tulip" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(6); } + case "minecraft:pink_tulip" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(7); } + case "minecraft:oxeye_daisy" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(8); } + case "minecraft:cornflower" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(9); } + case "minecraft:lily_of_the_valley" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(10); } + } + } + + if (NEW_SAPLINGS.contains(identifer)) { + switch (identifer) { + case "minecraft:oak_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(0); } + case "minecraft:spruce_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(1); } + case "minecraft:birch_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(2); } + case "minecraft:jungle_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(3); } + case "minecraft:acacia_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(4); } + case "minecraft:dark_oak_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(5); } + } + } + + if (NEW_CORAL_FANS.contains(identifer)) { + switch (identifer) { + case "minecraft:tube_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(0); } + case "minecraft:brain_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(1); } + case "minecraft:bubble_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(2); } + case "minecraft:fire_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(3); } + case "minecraft:horn_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(4); } + } + } + + if (NEW_DEAD_CORAL_FANS.contains(identifer)) { + switch (identifer) { + case "minecraft:dead_tube_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(0); } + case "minecraft:dead_brain_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(1); } + case "minecraft:dead_bubble_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(2); } + case "minecraft:dead_fire_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(3); } + case "minecraft:dead_horn_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(4); } + } + } + + return mapping; + } + + static NbtMap remapBlock(NbtMap tag) { + final String name = tag.getString("name"); + + if (!NEW_BLOCKS.contains(name)) { + return tag; + } + + if (name.equals("minecraft:bamboo_sapling")) { + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("sapling_type", "oak") + .build(); + + return tag.toBuilder().putCompound("states", states).build(); + } + + String replacement; + + if (NEW_SAPLINGS.contains(name)) { + replacement = "minecraft:sapling"; + String saplingType = name.replaceAll("minecraft:|_sapling", "");; + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("sapling_type", saplingType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_FLOWERS.contains(name)) { + replacement = "minecraft:red_flower"; + String flowerType; + + switch (name) { + case "minecraft:poppy" -> flowerType = "poppy"; + case "minecraft:blue_orchid" -> flowerType = "orchid"; + case "minecraft:allium" -> flowerType = "allium"; + case "minecraft:azure_bluet" -> flowerType = "houstonia"; + case "minecraft:red_tulip" -> flowerType = "tulip_red"; + case "minecraft:orange_tulip" -> flowerType = "tulip_orange"; + case "minecraft:white_tulip" -> flowerType = "tulip_white"; + case "minecraft:pink_tulip" -> flowerType = "tulip_pink"; + case "minecraft:oxeye_daisy" -> flowerType = "oxeye"; + case "minecraft:cornflower" -> flowerType = "cornflower"; + case "minecraft:lily_of_the_valley" -> flowerType = "lily_of_the_valley"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("flower_type", flowerType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + boolean isLiveCoralFan = NEW_CORAL_FANS.contains(name); + boolean isDeadCoralFan = NEW_DEAD_CORAL_FANS.contains(name); + + if (isLiveCoralFan || isDeadCoralFan) { + replacement = isLiveCoralFan ? "minecraft:coral_fan" : "minecraft:coral_fan_dead"; + String coralColor; + + switch (name) { + case "minecraft:tube_coral_fan", "minecraft:dead_tube_coral_fan" -> coralColor = "blue"; + case "minecraft:brain_coral_fan", "minecraft:dead_brain_coral_fan" -> coralColor = "pink"; + case "minecraft:bubble_coral_fan", "minecraft:dead_bubble_coral_fan" -> coralColor = "purple"; + case "minecraft:fire_coral_fan", "minecraft:dead_fire_coral_fan" -> coralColor = "yellow"; + case "minecraft:horn_coral_fan", "minecraft:dead_horn_coral_fan" -> coralColor = "red"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("coral_color", coralColor) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + return tag; + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 708f92dc5..5b64da7a1 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -42,6 +42,7 @@ import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662; +import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -93,7 +94,8 @@ public class ItemRegistryPopulator { paletteVersions.add(new PaletteVersion("1_20_40", Bedrock_v622.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion630_622::remapItem)); paletteVersions.add(new PaletteVersion("1_20_50", Bedrock_v630.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion649_630::remapItem)); paletteVersions.add(new PaletteVersion("1_20_60", Bedrock_v649.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion662_649::remapItem)); - paletteVersions.add(new PaletteVersion("1_20_70", Bedrock_v662.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_20_70", Bedrock_v662.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion671_662::remapItem)); + paletteVersions.add(new PaletteVersion("1_20_80", Bedrock_v671.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java index f8929c900..5e4d5fc7a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java @@ -173,7 +173,7 @@ public class RecipeRegistryPopulator { /* Convert end */ return ShapedRecipeData.shaped(uuid.toString(), shape.get(0).length(), shape.size(), - inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId, false); } List inputs = new ObjectArrayList<>(); for (JsonNode entry : node.get("inputs")) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 7beb37af9..94c69b780 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -162,7 +162,7 @@ public class JavaUpdateRecipesTranslator extends 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 literal 0 HcmV?d00001 diff --git a/core/src/main/resources/bedrock/creative_items.1_20_80.json b/core/src/main/resources/bedrock/creative_items.1_20_80.json new file mode 100644 index 000000000..02feea34b --- /dev/null +++ b/core/src/main/resources/bedrock/creative_items.1_20_80.json @@ -0,0 +1,5812 @@ +{ + "items": [ + { + "id": "minecraft:oak_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19wbGFua3MECQBuYW1lX2hhc2ilMDLR92rQ4wMKAG5ldHdvcmtfaWS2GotyCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:spruce_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAwAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9wbGFua3MECQBuYW1lX2hhc2iumBkmFGFE8gMKAG5ldHdvcmtfaWSo8TFgCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:birch_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3BsYW5rcwQJAG5hbWVfaGFzaLrrAKJqV2WFAwoAbmV0d29ya19pZL+e3ZAKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:jungle_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAwAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9wbGFua3MECQBuYW1lX2hhc2iBM3k4T3FAugMKAG5ldHdvcmtfaWSXUmBCCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:acacia_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAwAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9wbGFua3MECQBuYW1lX2hhc2g60edJxO5/aAMKAG5ldHdvcmtfaWTUXozECgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dark_oak_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3BsYW5rcwQJAG5hbWVfaGFzaAr64wkQ9cA7AwoAbmV0d29ya19pZFbMeR0KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mangrove_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3BsYW5rcwQJAG5hbWVfaGFzaPvLtcEA0F8xAwoAbmV0d29ya19pZEvnlCYKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cherry_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9wbGFua3MECQBuYW1lX2hhc2hNIvVh/lVW7gMKAG5ldHdvcmtfaWQTXpRoCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bamboo_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19wbGFua3MECQBuYW1lX2hhc2gYnjNz7SCCjgMKAG5ldHdvcmtfaWTi8ySSCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bamboo_mosaic", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWMECQBuYW1lX2hhc2izSEgiMKOp/AMKAG5ldHdvcmtfaWQZ/p8xCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:crimson_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fcGxhbmtzBAkAbmFtZV9oYXNoJc5IKqNXJnwDCgBuZXR3b3JrX2lkwtJDdQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:warped_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9wbGFua3MECQBuYW1lX2hhc2g3yGXEWhe6LgMKAG5ldHdvcmtfaWStTABvCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSE4JosCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBjb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWTUvV6XCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9jb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWT4opb2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBncmFuaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQAMQTVCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBkaW9yaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQIbDOcCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCABhbmRlc2l0ZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSZKhusCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBzYW5kc3RvbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSp4zgCCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDQByZWRfc2FuZHN0b25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRbqVHTCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBzdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRr0ZT/CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9zdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRnLis3CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBQBicmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQNLzfSCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDABuZXRoZXJfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQ5h0xwCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEAByZWRfbmV0aGVyX2JyaWNrCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWS9J0B2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBlbmRfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRPbkJeCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCgBwcmlzbWFyaW5lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:blackstone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaMP8XppUSU1RAwoAbmV0d29ya19pZMbeBBsKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_blackstone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaP6SwV08YwzAAwoAbmV0d29ya19pZAJLsz8KBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_blackstone_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBBIDZbHxiEzAwoAbmV0d29ya19pZEbLV8cKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cobbled_deepslate_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3dhbGwECQBuYW1lX2hhc2iECY5oKxeT+gMKAG5ldHdvcmtfaWRCnPrFCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:deepslate_tile_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3dhbGwECQBuYW1lX2hhc2jz7N+PeuEXgQMKAG5ldHdvcmtfaWTqw4s4CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:polished_deepslate_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV93YWxsBAkAbmFtZV9oYXNoHxjTdj9pevMDCgBuZXR3b3JrX2lkIvBYYwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:deepslate_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja193YWxsBAkAbmFtZV9oYXNoEs3EQrjroyEDCgBuZXR3b3JrX2lkwlrCGwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:mud_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja193YWxsBAkAbmFtZV9oYXNov9b98ATpUSwDCgBuZXR3b3JrX2lkH/1WZQoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:oak_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAAAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZDvPEXcKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:spruce_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAwAACAQAbmFtZRYAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZQQJAG5hbWVfaGFzaPQCm+aX1ZQeAwoAbmV0d29ya19pZD1QUEoKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:birch_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AwAACAQAbmFtZRUAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlBAkAbmFtZV9oYXNo6CJ2ATpANfgDCgBuZXR3b3JrX2lkmCUV2QoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:jungle_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAwAACAQAbmFtZRYAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZQQJAG5hbWVfaGFzaOX4cD9uAmsdAwoAbmV0d29ya19pZHz1VxkKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:acacia_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AwAACAQAbmFtZRYAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZQQJAG5hbWVfaGFzaGjn+RlKVDH6AwoAbmV0d29ya19pZNVGubwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dark_oak_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAwAACAQAbmFtZRgAbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlBAkAbmFtZV9oYXNoGPj0gCgM0c0DCgBuZXR3b3JrX2lk2w+gEwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:mangrove_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlBAkAbmFtZV9oYXNowwAd7tPu9bsDCgBuZXR3b3JrX2lkKEcd0goGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cherry_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAwAACAQAbmFtZRYAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZQQJAG5hbWVfaGFzaFmtUfHfTxcxAwoAbmV0d29ya19pZPCBxAIKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:bamboo_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19mZW5jZQQJAG5hbWVfaGFzaCKRbxfXsfkiAwoAbmV0d29ya19pZJNXKFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:nether_brick_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAAAACAQAbmFtZRwAbWluZWNyYWZ0Om5ldGhlcl9icmlja19mZW5jZQQJAG5hbWVfaGFzaA6030ngawxcAwoAbmV0d29ya19pZLnjLF4KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crimson_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2UECQBuYW1lX2hhc2jhUhKv1HGj9AMKAG5ldHdvcmtfaWR3OH3OCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:warped_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9mZW5jZQQJAG5hbWVfaGFzaJfb3/YuKmOWAwoAbmV0d29ya19pZCpaGC8KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAAAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWR+T9kTCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:spruce_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AAAACAQAbmFtZRsAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoanTVB84HRbkDCgBuZXR3b3JrX2lkEnw5egoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:birch_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2jmfPklI8azSwMKAG5ldHdvcmtfaWQL77/BCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:jungle_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS5AAAACAQAbmFtZRsAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNobYVQkfBomIcDCgBuZXR3b3JrX2lkA1zgtgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:acacia_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS7AAAACAQAbmFtZRsAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoZnrLUx/XSekDCgBuZXR3b3JrX2lkHg/kTgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dark_oak_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS6AAAACAQAbmFtZR0AbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2j2PTvdJJHcVQMKAG5ldHdvcmtfaWTwjOCeCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:mangrove_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2i/kOhBKiI/dAMKAG5ldHdvcmtfaWSfweCSCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cherry_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAwAACAQAbmFtZRsAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoKWLgCk0z+PsDCgBuZXR3b3JrX2lk/9bTZQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:bamboo_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJhbWJvb19mZW5jZV9nYXRlBAkAbmFtZV9oYXNopH1JrUgwdIADCgBuZXR3b3JrX2lkzIpPywoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crimson_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2VfZ2F0ZQQJAG5hbWVfaGFzaHE3Gfd0Z2d2AwoAbmV0d29ya19pZDQzVbEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQsAaW5fd2FsbF9iaXQAAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:warped_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoy0oIBjDIG4kDCgBuZXR3b3JrX2lkkf+/3QoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:normal_stone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAQAACAQAbmFtZR0AbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hAEktZZOkGIwMKAG5ldHdvcmtfaWQeH1ALCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZDcCv+MKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mossy_cobblestone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSyAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3N0YWlycwQJAG5hbWVfaGFzaMVSTq5z9n1RAwoAbmV0d29ya19pZFIfrhkKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:oak_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19zdGFpcnMECQBuYW1lX2hhc2jk/HFzdXy0FQMKAG5ldHdvcmtfaWQJjyzBCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:spruce_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9zdGFpcnMECQBuYW1lX2hhc2iznygw7uBPBQMKAG5ldHdvcmtfaWTv+is3CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:birch_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3N0YWlycwQJAG5hbWVfaGFzaPfhbL619a3GAwoAbmV0d29ya19pZFyPlHAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:jungle_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9zdGFpcnMECQBuYW1lX2hhc2jodJsHUbOVxQMKAG5ldHdvcmtfaWR0z5d4CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:acacia_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9zdGFpcnMECQBuYW1lX2hhc2h3x1NmD43IqQMKAG5ldHdvcmtfaWS7Jwz6CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dark_oak_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3N0YWlycwQJAG5hbWVfaGFzaMfwkbYPbNmAAwoAbmV0d29ya19pZCmBYKAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mangrove_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3N0YWlycwQJAG5hbWVfaGFzaNpUDY+uGMpyAwoAbmV0d29ya19pZChzUAsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cherry_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9zdGFpcnMECQBuYW1lX2hhc2jMtr0v9JY4zwMKAG5ldHdvcmtfaWRQwq31CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bamboo_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19zdGFpcnMECQBuYW1lX2hhc2jFOzWL8PalKwMKAG5ldHdvcmtfaWTVPh42CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bamboo_mosaic_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc3RhaXJzBAkAbmFtZV9oYXNoNLPiveSHPaoDCgBuZXR3b3JrX2lk44PHjgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAAAACAQAbmFtZRwAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaN6tQViRo5cwAwoAbmV0d29ya19pZDMyMgIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mossy_stone_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaIB/Zv5YBPuYAwoAbmV0d29ya19pZANTOsMKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:sandstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAAAACAQAbmFtZRoAbWluZWNyYWZ0OnNhbmRzdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hOyA0BoYUOPQMKAG5ldHdvcmtfaWSV/834CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:smooth_sandstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSwAQAACAQAbmFtZSEAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoB+CuCd8Ruz8DCgBuZXR3b3JrX2lksR+m8QoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:red_sandstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS0AAAACAQAbmFtZR4AbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoPs0LpHPL24YDCgBuZXR3b3JrX2lkLYVt3woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:smooth_red_sandstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAQAACAQAbmFtZSUAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3N0YWlycwQJAG5hbWVfaGFzaBvjtQv5pf+MAwoAbmV0d29ya19pZMHNND8KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:granite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAQAACAQAbmFtZRgAbWluZWNyYWZ0OmdyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNoGzpvtoqKQjgDCgBuZXR3b3JrX2lkPkcB1goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_granite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNo3PvbSfEQklIDCgBuZXR3b3JrX2lkMmEm3AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:diorite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAQAACAQAbmFtZRgAbWluZWNyYWZ0OmRpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoi73T8VQuZmcDCgBuZXR3b3JrX2lk6i6nBQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_diorite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoFKRJd5Wk5L0DCgBuZXR3b3JrX2lkbt2ioAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:andesite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaO5w2FKBw76EAwoAbmV0d29ya19pZKhXEgUKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:polished_andesite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAQAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaNcZZ/zmLInIAwoAbmV0d29ya19pZJTHrlEKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJyaWNrX3N0YWlycwQJAG5hbWVfaGFzaMyt+cRDk5O2AwoAbmV0d29ya19pZNeMh58KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:nether_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAAAACAQAbmFtZR0AbWluZWNyYWZ0Om5ldGhlcl9icmlja19zdGFpcnMECQBuYW1lX2hhc2jRqIoOXgifBAMKAG5ldHdvcmtfaWQDiw5yCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:red_nether_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AQAACAQAbmFtZSEAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNogQvosSbcj7kDCgBuZXR3b3JrX2lkx2IMtAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:end_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSxAQAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2hmlAk+QhsUsQMKAG5ldHdvcmtfaWTN7KFaCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:quartz_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAAAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9zdGFpcnMECQBuYW1lX2hhc2hmvpvOqGi6egMKAG5ldHdvcmtfaWRmUTh7CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:smooth_quartz_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AQAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc3RhaXJzBAkAbmFtZV9oYXNoNZZ9rX0qZOsDCgBuZXR3b3JrX2lkzsgQyQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:purpur_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAAAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9zdGFpcnMECQBuYW1lX2hhc2ifwDxeezXD7gMKAG5ldHdvcmtfaWTT+rxiCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:prismarine_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAQAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfc3RhaXJzBAkAbmFtZV9oYXNooTHSZ+IrYtcDCgBuZXR3b3JrX2lkxTJfeAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:dark_prismarine_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAQAACAQAbmFtZSAAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zdGFpcnMECQBuYW1lX2hhc2hIciLmam4o4AMKAG5ldHdvcmtfaWTVu7TCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:prismarine_bricks_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAQAACAQAbmFtZSIAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzX3N0YWlycwQJAG5hbWVfaGFzaNIjq1oBlZMMAwoAbmV0d29ya19pZGEFwLYKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crimson_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fc3RhaXJzBAkAbmFtZV9oYXNoZJqIzCBpCq4DCgBuZXR3b3JrX2lktXE00AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:warped_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9zdGFpcnMECQBuYW1lX2hhc2hOkY27jLD4RQMKAG5ldHdvcmtfaWQ+E5VrCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:blackstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNokdoUb76p9McDCgBuZXR3b3JrX2lk5fWI5goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_blackstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNolCFtFIE8MmADCgBuZXR3b3JrX2lkGTf7sgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_blackstone_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAgAACAQAbmFtZSoAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNonks6UlfpOmkDCgBuZXR3b3JrX2lkgYeOdAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAgAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoHfoAXYq5G3MDCgBuZXR3b3JrX2lkeetf7woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:exposed_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAgAACAQAbmFtZSMAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2howneQGtZ9cgMKAG5ldHdvcmtfaWSg73zdCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:weathered_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAgAACAQAbmFtZSUAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaP+R5loXxrVgAwoAbmV0d29ya19pZOnbRf4KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:oxidized_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAgAACAQAbmFtZSQAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNo6Jeoq5rsPxsDCgBuZXR3b3JrX2lkmRjDnQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:waxed_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAgAACAQAbmFtZSEAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoh07CQj0/SR8DCgBuZXR3b3JrX2lkmYqoqAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:waxed_exposed_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2guVct1ilmxTwMKAG5ldHdvcmtfaWQgCPROCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:waxed_weathered_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAgAACAQAbmFtZSsAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaPXC8Sz/phCpAwoAbmV0d29ya19pZHlwHVsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS/AgAACAQAbmFtZSoAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoaqGdkuhxVZUDCgBuZXR3b3JrX2lkYQXzzgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cobbled_deepslate_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AgAACAQAbmFtZSIAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3N0YWlycwQJAG5hbWVfaGFzaPIfa+TpyJcIAwoAbmV0d29ya19pZJUvOYIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:deepslate_tile_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3N0YWlycwQJAG5hbWVfaGFzaGFRFzB72mN2AwoAbmV0d29ya19pZJEOgIsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:polished_deepslate_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAgAACAQAbmFtZSMAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zdGFpcnMECQBuYW1lX2hhc2iNCYxVik9sGAMKAG5ldHdvcmtfaWSRVPnYCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:deepslate_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zdGFpcnMECQBuYW1lX2hhc2hIasOahEf83wMKAG5ldHdvcmtfaWQ1qEDCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:mud_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAgAACAQAbmFtZRoAbWluZWNyYWZ0Om11ZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2gt3qxK1NWajAMKAG5ldHdvcmtfaWSm9N3MCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:wooden_door" + }, + { + "id": "minecraft:spruce_door" + }, + { + "id": "minecraft:birch_door" + }, + { + "id": "minecraft:jungle_door" + }, + { + "id": "minecraft:acacia_door" + }, + { + "id": "minecraft:dark_oak_door" + }, + { + "id": "minecraft:mangrove_door" + }, + { + "id": "minecraft:cherry_door" + }, + { + "id": "minecraft:bamboo_door" + }, + { + "id": "minecraft:iron_door" + }, + { + "id": "minecraft:crimson_door" + }, + { + "id": "minecraft:warped_door" + }, + { + "id": "minecraft:trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAAAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkyTAWkAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:spruce_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAQAACAQAbmFtZRkAbWluZWNyYWZ0OnNwcnVjZV90cmFwZG9vcgQJAG5hbWVfaGFzaOwlfbgBkUW4AwoAbmV0d29ya19pZPHy1K0KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:birch_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAQAACAQAbmFtZRgAbWluZWNyYWZ0OmJpcmNoX3RyYXBkb29yBAkAbmFtZV9oYXNoSLtLweOLJ7wDCgBuZXR3b3JrX2lkeJWDfgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:jungle_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAQAACAQAbmFtZRkAbWluZWNyYWZ0Omp1bmdsZV90cmFwZG9vcgQJAG5hbWVfaGFzaDP/TnM9wyCIAwoAbmV0d29ya19pZEy2fJoKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:acacia_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFjYWNpYV90cmFwZG9vcgQJAG5hbWVfaGFzaMj8xi3vmEKOAwoAbmV0d29ya19pZOHj8E8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:dark_oak_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAQAACAQAbmFtZRsAbWluZWNyYWZ0OmRhcmtfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNomB2GGJQ2aOMDCgBuZXR3b3JrX2lko5ZHTwoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:mangrove_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAgAACAQAbmFtZRsAbWluZWNyYWZ0Om1hbmdyb3ZlX3RyYXBkb29yBAkAbmFtZV9oYXNooV3kQsQUUmkDCgBuZXR3b3JrX2lkkF/mxAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cherry_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoZXJyeV90cmFwZG9vcgQJAG5hbWVfaGFzaH/PefpfdHgtAwoAbmV0d29ya19pZOA7eNgKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:bamboo_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJhbWJvb190cmFwZG9vcgQJAG5hbWVfaGFzaJrEOpsTwtKCAwoAbmV0d29ya19pZLvbPz8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:iron_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAAAACAQAbmFtZRcAbWluZWNyYWZ0Omlyb25fdHJhcGRvb3IECQBuYW1lX2hhc2gwA+IumsEiGQMKAG5ldHdvcmtfaWTvSVl/CgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crimson_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AQAACAQAbmFtZRoAbWluZWNyYWZ0OmNyaW1zb25fdHJhcGRvb3IECQBuYW1lX2hhc2jHXufTnwUkYgMKAG5ldHdvcmtfaWQLjMYVCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:warped_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AQAACAQAbmFtZRkAbWluZWNyYWZ0OndhcnBlZF90cmFwZG9vcgQJAG5hbWVfaGFzaA20wG/+vkd6AwoAbmV0d29ya19pZHKR/hYKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:iron_bars", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAAAACAQAbmFtZRMAbWluZWNyYWZ0Omlyb25fYmFycwQJAG5hbWVfaGFzaPuefWSNAe56AwoAbmV0d29ya19pZN2LB5IKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lk0hdLNwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:white_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAAAACAQAbmFtZR0AbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iHubqoMbu9fAMKAG5ldHdvcmtfaWRndBrUCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:light_gray_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaKKa+LrRsHQhAwoAbmV0d29ya19pZEv2giYKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:gray_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAwAACAQAbmFtZRwAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaIETy7Y/HZREAwoAbmV0d29ya19pZDomVrUKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:black_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iV6BCwpfDMmwMKAG5ldHdvcmtfaWSV7doJCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:brown_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2igsEiq5np8JgMKAG5ldHdvcmtfaWRMzE/lCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:red_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAwAACAQAbmFtZRsAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoCa2J12/lQoIDCgBuZXR3b3JrX2lk283lWAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:orange_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAwAACAQAbmFtZR4AbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNozgjAuvzhxGsDCgBuZXR3b3JrX2lkW5CkhQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:yellow_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAwAACAQAbmFtZR4AbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNo7EbHMd5WVugDCgBuZXR3b3JrX2lkkdDyXQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:lime_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAwAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBtZA1nZtwcFAwoAbmV0d29ya19pZDxX85UKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:green_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAwAACAQAbmFtZR0AbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2h91ptDgbehWwMKAG5ldHdvcmtfaWTlDhnECgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cyan_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAwAACAQAbmFtZRwAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBkIYQ8nQLqbAwoAbmV0d29ya19pZOL1lHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:light_blue_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaLt05n1G0fiSAwoAbmV0d29ya19pZNbwulIKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:blue_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaPhLocSfzduRAwoAbmV0d29ya19pZENsjFwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:purple_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAwAACAQAbmFtZR4AbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoJk0DhRO0szUDCgBuZXR3b3JrX2lkD98ZxgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:magenta_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAwAACAQAbmFtZR8AbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaFEDeFiJj3zSAwoAbmV0d29ya19pZG+iFRoKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:pink_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaDijTX87ywxhAwoAbmV0d29ya19pZKdEricKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:tinted_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAgAACAQAbmFtZRYAbWluZWNyYWZ0OnRpbnRlZF9nbGFzcwQJAG5hbWVfaGFzaAFZWSamk6KdAwoAbmV0d29ya19pZGSvWX8KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWRGwixuCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:white_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAAAACAQAbmFtZSIAbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaHgxQmgJVtRrAwoAbmV0d29ya19pZBEr/DYKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:light_gray_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNon0aQw9lNkSEDCgBuZXR3b3JrX2lk9dp5VgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:gray_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAwAACAQAbmFtZSEAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNors74IIw+2MMDCgBuZXR3b3JrX2lkmrGO5woGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:black_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaOK/5ZRRd+M1AwoAbmV0d29ya19pZDv++oQKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:brown_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaLHeGJyRFTIWAwoAbmV0d29ya19pZMz9L0wKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:red_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAwAACAQAbmFtZSAAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2gGr4x6JheAywMKAG5ldHdvcmtfaWQBjCTmCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:orange_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAwAACAQAbmFtZSMAbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hbHxPD2gEbEAMKAG5ldHdvcmtfaWSt/7a5CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:yellow_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAwAACAQAbmFtZSMAbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2g9tl4aOCyZBwMKAG5ldHdvcmtfaWTXRAS7CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:lime_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAwAACAQAbmFtZSEAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3CtUyLwoGegDCgBuZXR3b3JrX2lkYJDnggoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:green_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAwAACAQAbmFtZSIAbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaJo6YP7IMy9SAwoAbmV0d29ya19pZHOnixoKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cyan_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAwAACAQAbmFtZSEAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoti97c6QrbLQDCgBuZXR3b3JrX2lkUqFUeQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:light_blue_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNovDg/gQle104DCgBuZXR3b3JrX2lkFuy4MQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:blue_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAwAACAQAbmFtZSEAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoGc57tiexbQMDCgBuZXR3b3JrX2lk1eBLUAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:purple_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAwAACAQAbmFtZSMAbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hDJHYdd0FdfQMKAG5ldHdvcmtfaWSNsdK5CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:magenta_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAwAACAQAbmFtZSQAbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3pcOw5bs5XoDCgBuZXR3b3JrX2lkVbOR7AoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:pink_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAwAACAQAbmFtZSEAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoWRhSACMWgswDCgBuZXR3b3JrX2lkIR92xwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:ladder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxhZGRlcgQJAG5hbWVfaGFzaKBhqheJVOz+AwoAbmV0d29ya19pZCgvzlsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:scaffolding", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNjYWZmb2xkaW5nBAkAbmFtZV9oYXNoYrkevrqcljwDCgBuZXR3b3JrX2lkD13mlAoGAHN0YXRlcwMJAHN0YWJpbGl0eQAAAAABDwBzdGFiaWxpdHlfY2hlY2sAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWTkNl0JCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAc21vb3RoX3N0b25lAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab4", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkQJoxlgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNAUAc3RvbmUAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWRHh04KCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAY29iYmxlc3RvbmUAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab2", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkVRZB+woGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhEAbW9zc3lfY29iYmxlc3RvbmUAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:oak_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha19zbGFiBAkAbmFtZV9oYXNoJp1Cp1M4jlwDCgBuZXR3b3JrX2lkZH6+owoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:spruce_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV9zbGFiBAkAbmFtZV9oYXNodQi70jB238cDCgBuZXR3b3JrX2lkrriOYQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:birch_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3NsYWIECQBuYW1lX2hhc2gZPpfMxoOsTAMKAG5ldHdvcmtfaWThR9jyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:jungle_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV9zbGFiBAkAbmFtZV9oYXNo6gLs79NXak4DCgBuZXR3b3JrX2lk5ZiKgwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:acacia_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV9zbGFiBAkAbmFtZV9oYXNomSdFmDnv4OUDCgBuZXR3b3JrX2lkHttaXAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dark_oak_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3NsYWIECQBuYW1lX2hhc2hJjTohRFyhIQMKAG5ldHdvcmtfaWRMzDTyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:mangrove_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3NsYWIECQBuYW1lX2hhc2jYCcmhJPeNMwMKAG5ldHdvcmtfaWQx6U1yCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cherry_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV9zbGFiBAkAbmFtZV9oYXNoTt0MmVn/mqoDCgBuZXR3b3JrX2lk2VVsZQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:bamboo_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJhbWJvb19zbGFiBAkAbmFtZV9oYXNoo1xuFqINeLYDCgBuZXR3b3JrX2lkVC+0twoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:bamboo_mosaic_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc2xhYgQJAG5hbWVfaGFzaNbVRBZ/ChI3AwoAbmV0d29ya19pZOLZHFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWQSiInOCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab4", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkoF89tgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAbW9zc3lfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSkoAE4CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQkAc2FuZHN0b25lAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab4", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkWfF7pgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0AY3V0X3NhbmRzdG9uZQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab2", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkbKRChAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAc21vb3RoX3NhbmRzdG9uZQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab2", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkBlrvqAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg0AcmVkX3NhbmRzdG9uZQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab4", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkRWFXuwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAY3V0X3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab3", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkom8neQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxQAc21vb3RoX3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab3", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkd1ZaWgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZ3Jhbml0ZQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab3", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkISH4iwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZ3Jhbml0ZQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab3", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkqxEDMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZGlvcml0ZQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab3", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkSYs86QoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZGlvcml0ZQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab3", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkq6BU6goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwgAYW5kZXNpdGUAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab3", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkTSXY8AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxEAcG9saXNoZWRfYW5kZXNpdGUAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWQiYHKTCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQUAYnJpY2sAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone_block_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWTk/0LfCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAbmV0aGVyX2JyaWNrAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab2", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk/hXQ7AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcmVkX25ldGhlcl9icmljawADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab3", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkYJNxrwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMw8AZW5kX3N0b25lX2JyaWNrAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWRlj0/sCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQYAcXVhcnR6AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab4", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkMae+2goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0Ac21vb3RoX3F1YXJ0egADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab2", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk+kMHGAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMgYAcHVycHVyAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab2", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkKOSOMAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9yb3VnaAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stone_block_slab2", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk8igLCQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg8AcHJpc21hcmluZV9kYXJrAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_block_slab2", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkSFbyEwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9icmljawADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:crimson_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc2xhYgQJAG5hbWVfaGFzaKZ+EfP0ZYOZAwoAbmV0d29ya19pZAxRUWAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:warped_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zbGFiBAkAbmFtZV9oYXNo/AT0e/Z9W7UDCgBuZXR3b3JrX2lk1yq11AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:blackstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaF/DD4ZUlNgtAwoAbmV0d29ya19pZGy1DjwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:polished_blackstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaDYnuUs86EWfAwoAbmV0d29ya19pZJj2bXIKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:polished_blackstone_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaKySLqvHc4xXAwoAbmV0d29ya19pZOyWX94KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAgAACAQAbmFtZRkAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaDsNpb2qs4iBAwoAbmV0d29ya19pZOTm2nsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:exposed_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNoahQ5OwIQb7kDCgBuZXR3b3JrX2lkrUlZLwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:weathered_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2hBIuGIOVVXogMKAG5ldHdvcmtfaWQgnaDiCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:oxidized_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaOptj9ycfpaDAwoAbmV0d29ya19pZMzFSRgKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:waxed_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaAlx6DZOCTHzAwoAbmV0d29ya19pZFRBvDAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:waxed_exposed_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNo3KqS5OnhtRIDCgBuZXR3b3JrX2lkHTGcTgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:waxed_weathered_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2gzZ1oX0HCFtwMKAG5ldHdvcmtfaWSgJR+XCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTAAgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaMjjTnLu1KcqAwoAbmV0d29ya19pZIxsnFYKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cobbled_deepslate_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3NsYWIECQBuYW1lX2hhc2gwJIVWK1TM2QMKAG5ldHdvcmtfaWTYAoX5CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_deepslate_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zbGFiBAkAbmFtZV9oYXNoC/Adiz8k6RYDCgBuZXR3b3JrX2lkuFYMAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:deepslate_tile_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3NsYWIECQBuYW1lX2hhc2hPydV6emzIXAMKAG5ldHdvcmtfaWQwlbFCCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:deepslate_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zbGFiBAkAbmFtZV9oYXNoSv62V7iw10UDCgBuZXR3b3JrX2lkWMoragoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mud_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja19zbGFiBAkAbmFtZV9oYXNoq/tGBQWkv08DCgBuZXR3b3JrX2lkl4nnMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:brick_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAAAACAQAbmFtZRUAbWluZWNyYWZ0OmJyaWNrX2Jsb2NrBAkAbmFtZV9oYXNo5Qc2E005S3oDCgBuZXR3b3JrX2lkqeGWRgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:chiseled_nether_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX25ldGhlcl9icmlja3MECQBuYW1lX2hhc2g31SBPTcUK1QMKAG5ldHdvcmtfaWS8TJ+TCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cracked_nether_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAgAACAQAbmFtZR8AbWluZWNyYWZ0OmNyYWNrZWRfbmV0aGVyX2JyaWNrcwQJAG5hbWVfaGFzaAdC6eKzXT5tAwoAbmV0d29ya19pZIUSejwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:quartz_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9icmlja3MECQBuYW1lX2hhc2jSZO590dd8sAMKAG5ldHdvcmtfaWSc5xCLCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stonebrick", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQ5kni1CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAZGVmYXVsdAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stonebrick", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTDw813CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQUAbW9zc3kAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stonebrick", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWSTvQGECgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAY3JhY2tlZAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stonebrick", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQIM0OwCgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQgAY2hpc2VsZWQAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:end_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAAAACAQAbmFtZRQAbWluZWNyYWZ0OmVuZF9icmlja3MECQBuYW1lX2hhc2hIUFfxNLZaFgMKAG5ldHdvcmtfaWQ/vDihCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:prismarine", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWSH021WCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBgBicmlja3MAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:polished_blackstone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoIHgsgIdzKXcDCgBuZXR3b3JrX2lkUw9b3woGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cracked_polished_blackstone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAgAACAQAbmFtZSwAbWluZWNyYWZ0OmNyYWNrZWRfcG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3MECQBuYW1lX2hhc2jQIO1GQDk80AMKAG5ldHdvcmtfaWQ3UlRYCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:gilded_blackstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAgAACAQAbmFtZRsAbWluZWNyYWZ0OmdpbGRlZF9ibGFja3N0b25lBAkAbmFtZV9oYXNoNoWt1ocG0HEDCgBuZXR3b3JrX2lktL8gUwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:chiseled_polished_blackstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAgAACAQAbmFtZSYAbWluZWNyYWZ0OmNoaXNlbGVkX3BvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2gzFa+kEjCJgAMKAG5ldHdvcmtfaWR2NJX2CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:deepslate_tiles", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlcwQJAG5hbWVfaGFzaGcLLx3NXAFvAwoAbmV0d29ya19pZI/G/xYKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cracked_deepslate_tiles", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAgAACAQAbmFtZSEAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX3RpbGVzBAkAbmFtZV9oYXNo9zWgkFuMM1QDCgBuZXR3b3JrX2lkGwY6OgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:deepslate_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja3MECQBuYW1lX2hhc2gucvFmPdZxigMKAG5ldHdvcmtfaWSH4HDPCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cracked_deepslate_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAgAACAQAbmFtZSIAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX2JyaWNrcwQJAG5hbWVfaGFzaN40aqhh9WqHAwoAbmV0d29ya19pZO9GPBQKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:chiseled_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaEU7/uRG8HSBAwoAbmV0d29ya19pZEqmI0EKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cobblestone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYmJsZXN0b25lBAkAbmFtZV9oYXNoPoK7mGlSUz4DCgBuZXR3b3JrX2lkLm7RZwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:mossy_cobblestone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAAAACAQAbmFtZRsAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoGJ67FCbkChMDCgBuZXR3b3JrX2lk/pYs1AoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cobbled_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AgAACAQAbmFtZRsAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoLUz9Y/ywmLwDCgBuZXR3b3JrX2lkNwzZ+AoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:smooth_stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AQAACAQAbmFtZRYAbWluZWNyYWZ0OnNtb290aF9zdG9uZQQJAG5hbWVfaGFzaMwf87/JaTNvAwoAbmV0d29ya19pZLkZICEKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB2wApMKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUHAGRlZmF1bHQAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB7E+eQKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGULAGhlaXJvZ2x5cGhzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZFQnDaEKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUDAGN1dAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZPO4A3IKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUGAHNtb290aAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:red_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWRhNYiFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:red_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTqXJr1CgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlCwBoZWlyb2dseXBocwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:red_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTQRGkFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlAwBjdXQAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:red_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTvAHWDCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBgBzbW9vdGgAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:coal_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvYWxfYmxvY2sECQBuYW1lX2hhc2jH8QQP3t5PiAMKAG5ldHdvcmtfaWRo+sR+CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dried_kelp_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAQAACAQAbmFtZRoAbWluZWNyYWZ0OmRyaWVkX2tlbHBfYmxvY2sECQBuYW1lX2hhc2iRoucexkrl8wMKAG5ldHdvcmtfaWQQCCrvCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:gold_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdvbGRfYmxvY2sECQBuYW1lX2hhc2iYLshvjtXzFwMKAG5ldHdvcmtfaWTDJGBcCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:iron_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAAAACAQAbmFtZRQAbWluZWNyYWZ0Omlyb25fYmxvY2sECQBuYW1lX2hhc2jYINmJQbvV/gMKAG5ldHdvcmtfaWRf7AbICgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:copper_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZIiUodwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:exposed_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAgAACAQAbmFtZRgAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoQH3Fukmu3CEDCgBuZXR3b3JrX2lk72jFIwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:weathered_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAgAACAQAbmFtZRoAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2hJCQXbvobv+gMKAG5ldHdvcmtfaWQwM0lJCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:oxidized_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMDtJqR0G5Y7AwoAbmV0d29ya19pZGjN8bUKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:waxed_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAgAACAQAbmFtZRYAbWluZWNyYWZ0OndheGVkX2NvcHBlcgQJAG5hbWVfaGFzaPF+FG6Eh5fsAwoAbmV0d29ya19pZIjtz/0KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:waxed_exposed_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAgAACAQAbmFtZR4AbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoig8IOc+SCikDCgBuZXR3b3JrX2lklz8yWQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:waxed_weathered_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAgAACAQAbmFtZSAAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2gjtPq8MOdvKgMKAG5ldHdvcmtfaWSQ9Ln9CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:waxed_oxidized_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS9AgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMaORhsO+LzjAwoAbmV0d29ya19pZJhGfLEKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAgAACAQAbmFtZRQAbWluZWNyYWZ0OmN1dF9jb3BwZXIECQBuYW1lX2hhc2hAfN3NGax3eAMKAG5ldHdvcmtfaWTnFBtYCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:exposed_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAgAACAQAbmFtZRwAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaA85G3yv/w6pAwoAbmV0d29ya19pZMQhr0QKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:weathered_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAgAACAQAbmFtZR4AbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoVgRV0fBaz88DCgBuZXR3b3JrX2lk/0cYugoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:oxidized_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAgAACAQAbmFtZR0AbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2iP8WmFWOkriwMKAG5ldHdvcmtfaWQPdce7CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:waxed_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWReAgAACAQAbmFtZRoAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2jumiwOZIqv2AMKAG5ldHdvcmtfaWQvuxx9CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:waxed_exposed_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAgAACAQAbmFtZSIAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaPE/OfK6IoVMAwoAbmV0d29ya19pZHy5HkcKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:waxed_weathered_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoCA1xDp11bnwDCgBuZXR3b3JrX2lkDyEDVQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS+AgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2i1pZAsZYHLDAMKAG5ldHdvcmtfaWQ/wSkCCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:emerald_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAAAACAQAbmFtZRcAbWluZWNyYWZ0OmVtZXJhbGRfYmxvY2sECQBuYW1lX2hhc2hK6QunqJznNAMKAG5ldHdvcmtfaWRk5+otCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:diamond_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AAAACAQAbmFtZRcAbWluZWNyYWZ0OmRpYW1vbmRfYmxvY2sECQBuYW1lX2hhc2iGKrxuvkytFQMKAG5ldHdvcmtfaWQQeQZXCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:lapis_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxhcGlzX2Jsb2NrBAkAbmFtZV9oYXNoDZ44xdb2zVoDCgBuZXR3b3JrX2lktVy0BAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:raw_iron_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19pcm9uX2Jsb2NrBAkAbmFtZV9oYXNo9XyzNIQXxvwDCgBuZXR3b3JrX2lknms1QAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:raw_copper_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAgAACAQAbmFtZRoAbWluZWNyYWZ0OnJhd19jb3BwZXJfYmxvY2sECQBuYW1lX2hhc2hw1KG0TNUGgwMKAG5ldHdvcmtfaWS1vGo/CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:raw_gold_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19nb2xkX2Jsb2NrBAkAbmFtZV9oYXNo6YuwuLwfOBwDCgBuZXR3b3JrX2lkLiQ5gQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:quartz_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZEupC1AKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:quartz_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZM97+l0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:quartz_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZCbTfssKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQgAY2hpc2VsZWQICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:quartz_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZJss8V0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQYAc21vb3RoCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:prismarine", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWRFIsoGCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:prismarine", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWTDNWOvCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBABkYXJrAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:slime", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnNsaW1lBAkAbmFtZV9oYXNoHJiEEJx+JlkDCgBuZXR3b3JrX2lkfgfVzAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:honey_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAQAACAQAbmFtZRUAbWluZWNyYWZ0OmhvbmV5X2Jsb2NrBAkAbmFtZV9oYXNo9zLYSUlelywDCgBuZXR3b3JrX2lko+dyWgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:honeycomb_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAQAACAQAbmFtZRkAbWluZWNyYWZ0OmhvbmV5Y29tYl9ibG9jawQJAG5hbWVfaGFzaASIPuOCYd1oAwoAbmV0d29ya19pZKys4n4KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:hay_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAAAACAQAbmFtZRMAbWluZWNyYWZ0OmhheV9ibG9jawQJAG5hbWVfaGFzaIB2VxKxX8EpAwoAbmV0d29ya19pZKuQSloKBgBzdGF0ZXMDCgBkZXByZWNhdGVkAAAAAAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bone_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAAAACAQAbmFtZRQAbWluZWNyYWZ0OmJvbmVfYmxvY2sECQBuYW1lX2hhc2i4ZX576W9AWgMKAG5ldHdvcmtfaWTWGacQCgYAc3RhdGVzAwoAZGVwcmVjYXRlZAAAAAAICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:nether_brick", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAAAACAQAbmFtZRYAbWluZWNyYWZ0Om5ldGhlcl9icmljawQJAG5hbWVfaGFzaMxcRiheU+nXAwoAbmV0d29ya19pZMkmzloKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:red_nether_brick", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAAAACAQAbmFtZRoAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2sECQBuYW1lX2hhc2j8pRO4LfoECAMKAG5ldHdvcmtfaWRpdF0YCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:netherite_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcml0ZV9ibG9jawQJAG5hbWVfaGFzaMghh6Zib/ZKAwoAbmV0d29ya19pZIz0mq0KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:lodestone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAQAACAQAbmFtZRMAbWluZWNyYWZ0OmxvZGVzdG9uZQQJAG5hbWVfaGFzaJ2gmHOTlXv8AwoAbmV0d29ya19pZEfgB4wKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:white_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAAAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWSO8paQCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:light_gray_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfd29vbAQJAG5hbWVfaGFzaOpdQ1a2v4b3AwoAbmV0d29ya19pZIqZCYEKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:gray_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAwAACAQAbmFtZRMAbWluZWNyYWZ0OmdyYXlfd29vbAQJAG5hbWVfaGFzaLsc1Lp1xdIOAwoAbmV0d29ya19pZFUs+HgKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:black_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrX3dvb2wECQBuYW1lX2hhc2hP2HC6o0X4HAMKAG5ldHdvcmtfaWRUbORcCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:brown_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJyb3duX3dvb2wECQBuYW1lX2hhc2ig5IW89PrREwMKAG5ldHdvcmtfaWRjT9j8CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:red_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAwAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF93b29sBAkAbmFtZV9oYXNoY4TBDq+mFgUDCgBuZXR3b3JrX2lktn9lcAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:orange_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAwAACAQAbmFtZRUAbWluZWNyYWZ0Om9yYW5nZV93b29sBAkAbmFtZV9oYXNoFstfrTZfSCgDCgBuZXR3b3JrX2lk+rqywwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:yellow_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAwAACAQAbmFtZRUAbWluZWNyYWZ0OnllbGxvd193b29sBAkAbmFtZV9oYXNoTFyus2RHegcDCgBuZXR3b3JrX2lkkKBhXAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:lime_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAwAACAQAbmFtZRMAbWluZWNyYWZ0OmxpbWVfd29vbAQJAG5hbWVfaGFzaNVnnzKiMxmeAwoAbmV0d29ya19pZG9b32kKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:green_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAwAACAQAbmFtZRQAbWluZWNyYWZ0OmdyZWVuX3dvb2wECQBuYW1lX2hhc2i3mElRYHIcSQMKAG5ldHdvcmtfaWSssprwCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cyan_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAwAACAQAbmFtZRMAbWluZWNyYWZ0OmN5YW5fd29vbAQJAG5hbWVfaGFzaBNDfvHn8dqFAwoAbmV0d29ya19pZK0hAbgKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:light_blue_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfd29vbAQJAG5hbWVfaGFzaLWFAUfyxFPNAwoAbmV0d29ya19pZL2oEugKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:blue_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAwAACAQAbmFtZRMAbWluZWNyYWZ0OmJsdWVfd29vbAQJAG5hbWVfaGFzaLjHyxxbTWCLAwoAbmV0d29ya19pZPaLdFQKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:purple_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAwAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnBsZV93b29sBAkAbmFtZV9oYXNojvFtqzjAf/4DCgBuZXR3b3JrX2lklqASNQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:magenta_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AwAACAQAbmFtZRYAbWluZWNyYWZ0Om1hZ2VudGFfd29vbAQJAG5hbWVfaGFzaGuOHvf+Pd4yAwoAbmV0d29ya19pZI4UoDQKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:pink_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AwAACAQAbmFtZRMAbWluZWNyYWZ0OnBpbmtfd29vbAQJAG5hbWVfaGFzaPiVA2pFeoFLAwoAbmV0d29ya19pZOZRO6oKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:white_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAAAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZEahDFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:light_gray_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0BAkAbmFtZV9oYXNoHPw6ArBAsP0DCgBuZXR3b3JrX2lkQoAeUAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:gray_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FycGV0BAkAbmFtZV9oYXNoZVR0OI+1VRADCgBuZXR3b3JrX2lkETF4WwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:black_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhcnBldAQJAG5hbWVfaGFzaOk7LP9NptyhAwoAbmV0d29ya19pZFjmXtIKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:brown_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhcnBldAQJAG5hbWVfaGFzaNaXFyOsAvIvAwoAbmV0d29ya19pZHPjFuoKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:red_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAwAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYXJwZXQECQBuYW1lX2hhc2i9eSKBf6SO3wMKAG5ldHdvcmtfaWQuhI/KCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:orange_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAwAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQECQBuYW1lX2hhc2hIUkO4HlAdygMKAG5ldHdvcmtfaWSyKV9OCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:yellow_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAwAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYXJwZXQECQBuYW1lX2hhc2hSDKX3scCamwMKAG5ldHdvcmtfaWT8nq+ECgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:lime_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAwAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FycGV0BAkAbmFtZV9oYXNo+6KFOpzsib4DCgBuZXR3b3JrX2lkT+DS4woGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:green_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAwAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhcnBldAQJAG5hbWVfaGFzaCHPMP9ltqFJAwoAbmV0d29ya19pZBgwAvAKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cyan_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAwAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FycGV0BAkAbmFtZV9oYXNobXf62dQBJj8DCgBuZXR3b3JrX2lkKVppLgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:light_blue_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0BAkAbmFtZV9oYXNo20l4oktdZ3sDCgBuZXR3b3JrX2lkjdeMiwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:blue_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWReAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FycGV0BAkAbmFtZV9oYXNo3p3lsW0eQwsDCgBuZXR3b3JrX2lkAovdPQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:purple_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAwAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQECQBuYW1lX2hhc2jwIA9pW/qp7QMKAG5ldHdvcmtfaWTqJqhjCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:magenta_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAwAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0BAkAbmFtZV9oYXNoFXT36YNNZhMDCgBuZXR3b3JrX2lk+tqsGAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:pink_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FycGV0BAkAbmFtZV9oYXNoHll72oqk+OoDCgBuZXR3b3JrX2lkrnBYDwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:white_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTtAAAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZJPZY8AKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:light_gray_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo7EUk30hmUtYDCgBuZXR3b3JrX2lkh8jVIwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:gray_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmdyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoW77af6WihdwDCgBuZXR3b3JrX2lkSsqC1woGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:black_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTSAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaAfWYp0xtgcfAwoAbmV0d29ya19pZMWTC8EKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:brown_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaB74EeiLO46XAwoAbmV0d29ya19pZEDHKqwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:red_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAwAACAQAbmFtZR0AbWluZWNyYWZ0OnJlZF9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gjFut6Z/VH1gMKAG5ldHdvcmtfaWSvcmwYCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:orange_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAwAACAQAbmFtZSAAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gADDj2IJiw+gMKAG5ldHdvcmtfaWTHph0FCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:yellow_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAwAACAQAbmFtZSAAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iy6qKNn3ob5wMKAG5ldHdvcmtfaWQZAI39CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:lime_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAwAACAQAbmFtZR4AbWluZWNyYWZ0OmxpbWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo4dYIPslbXPUDCgBuZXR3b3JrX2lk2O8X0AoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:green_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAwAACAQAbmFtZR8AbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaM/c9x2aJh3HAwoAbmV0d29ya19pZA0VfBMKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cyan_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAwAACAQAbmFtZR4AbWluZWNyYWZ0OmN5YW5fY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNok+xKAe7XXjoDCgBuZXR3b3JrX2lkmkn6uwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:light_blue_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNogScpIQceyAEDCgBuZXR3b3JrX2lkOmVSbgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:blue_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoFp7mmeL86r0DCgBuZXR3b3JrX2lkS3b3RQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:purple_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAwAACAQAbmFtZSAAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iYcVU04hoStwMKAG5ldHdvcmtfaWQXimEjCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:magenta_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAwAACAQAbmFtZSEAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoy/70q6VPsWgDCgBuZXR3b3JrX2lkf9mxQwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:pink_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBpbmtfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoVikSAf8DwV0DCgBuZXR3b3JrX2lku2MivwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:white_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAAAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lk3MAYQAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:light_gray_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGUECQBuYW1lX2hhc2hEtet5wuDIKAMKAG5ldHdvcmtfaWQISs02CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:gray_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AwAACAQAbmFtZRcAbWluZWNyYWZ0OmdyYXlfY29uY3JldGUECQBuYW1lX2hhc2j92INnb0a83AMKAG5ldHdvcmtfaWQj8RHwCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:black_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAwAACAQAbmFtZRgAbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlBAkAbmFtZV9oYXNo2X7NDIQmZ70DCgBuZXR3b3JrX2lk2uiVDQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:brown_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AwAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlBAkAbmFtZV9oYXNoeka02BwXf6oDCgBuZXR3b3JrX2lkYf+xDQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:red_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAwAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9jb25jcmV0ZQQJAG5hbWVfaGFzaPWmNowLGubqAwoAbmV0d29ya19pZKwyx58KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:orange_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRzAwAACAQAbmFtZRkAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZQQJAG5hbWVfaGFzaAgE8XmaAi6+AwoAbmV0d29ya19pZMDQNz8KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:yellow_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR2AwAACAQAbmFtZRkAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZQQJAG5hbWVfaGFzaE6ONfJPBd0+AwoAbmV0d29ya19pZMarutwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:lime_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR3AwAACAQAbmFtZRcAbWluZWNyYWZ0OmxpbWVfY29uY3JldGUECQBuYW1lX2hhc2gnd8JW6wmJcAMKAG5ldHdvcmtfaWTd47aoCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:green_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AwAACAQAbmFtZRgAbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlBAkAbmFtZV9oYXNokbFxRKchQZkDCgBuZXR3b3JrX2lkmhZWUgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cyan_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AwAACAQAbmFtZRcAbWluZWNyYWZ0OmN5YW5fY29uY3JldGUECQBuYW1lX2hhc2hFRrWJ33qj1wMKAG5ldHdvcmtfaWQbi5b8CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:light_blue_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR1AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGUECQBuYW1lX2hhc2gHAe0kl0SE4AMKAG5ldHdvcmtfaWRL/GbSCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:blue_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AwAACAQAbmFtZRcAbWluZWNyYWZ0OmJsdWVfY29uY3JldGUECQBuYW1lX2hhc2hiay301nnj1wMKAG5ldHdvcmtfaWRMvFXNCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:purple_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AwAACAQAbmFtZRkAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZQQJAG5hbWVfaGFzaHBHflsPIwdXAwoAbmV0d29ya19pZCyKA5gKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:magenta_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AwAACAQAbmFtZRoAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGUECQBuYW1lX2hhc2gN7LuB/OvdZAMKAG5ldHdvcmtfaWTc6ZOdCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:pink_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpbmtfY29uY3JldGUECQBuYW1lX2hhc2ii2G5F0u3SOAMKAG5ldHdvcmtfaWSszGgrCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:clay", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmNsYXkECQBuYW1lX2hhc2j/S6sKXRcpzwMKAG5ldHdvcmtfaWRmsb8nCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:hardened_clay", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAAAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRBCOrrCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:white_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAAAACAQAbmFtZRoAbWluZWNyYWZ0OndoaXRlX3RlcnJhY290dGEECQBuYW1lX2hhc2j3RSdgmnAIewMKAG5ldHdvcmtfaWSimKw+CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:light_gray_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAz1Ri3wIxomAwoAbmV0d29ya19pZH5qgOcKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:gray_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAwAACAQAbmFtZRkAbWluZWNyYWZ0OmdyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAXdSLAaNZ9vAwoAbmV0d29ya19pZM1QDV0KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:black_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsYWNrX3RlcnJhY290dGEECQBuYW1lX2hhc2jxssdv5vlbpgMKAG5ldHdvcmtfaWRE3Ru/CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:brown_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJyb3duX3RlcnJhY290dGEECQBuYW1lX2hhc2gG4kPenmOF9gMKAG5ldHdvcmtfaWQ/i0iNCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:red_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAwAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo7fX56HXFejEDCgBuZXR3b3JrX2lk8tTF8QoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:orange_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAwAACAQAbmFtZRsAbWluZWNyYWZ0Om9yYW5nZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo0Hjmql3sruMDCgBuZXR3b3JrX2lklmqmkAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:yellow_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAwAACAQAbmFtZRsAbWluZWNyYWZ0OnllbGxvd190ZXJyYWNvdHRhBAkAbmFtZV9oYXNoqkyKKrmA3VcDCgBuZXR3b3JrX2lkaM/orAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:lime_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpbWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaANjADFOF9v7AwoAbmV0d29ya19pZJt0XsgKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:green_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyZWVuX3RlcnJhY290dGEECQBuYW1lX2hhc2j5Ybq36yYwRQMKAG5ldHdvcmtfaWQ8kGdHCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cyan_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAwAACAQAbmFtZRkAbWluZWNyYWZ0OmN5YW5fdGVycmFjb3R0YQQJAG5hbWVfaGFzaN09COzMuHwAAwoAbmV0d29ya19pZIWPCzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:light_blue_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaOMytez7cOZiAwoAbmV0d29ya19pZFHK1UsKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:blue_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaF6inyTK5RpAAwoAbmV0d29ya19pZF5mVZIKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:purple_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAwAACAQAbmFtZRsAbWluZWNyYWZ0OnB1cnBsZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoKF7YG61yTbEDCgBuZXR3b3JrX2lkhtRDlwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:magenta_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAwAACAQAbmFtZRwAbWluZWNyYWZ0Om1hZ2VudGFfdGVycmFjb3R0YQQJAG5hbWVfaGFzaLWvtpAVtztyAwoAbmV0d29ya19pZN5SoakKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:pink_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAwAACAQAbmFtZRkAbWluZWNyYWZ0OnBpbmtfdGVycmFjb3R0YQQJAG5hbWVfaGFzaJ7mzvyzSQZTAwoAbmV0d29ya19pZDJWe4YKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:white_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAAAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkIlj9AAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:silver_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAAAACAQAbmFtZSIAbWluZWNyYWZ0OnNpbHZlcl9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAVsA0CnhzA4AwoAbmV0d29ya19pZPnxtJEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:gray_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAAAACAQAbmFtZSAAbWluZWNyYWZ0OmdyYXlfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2jvLZt9u/lF/AMKAG5ldHdvcmtfaWQVU8eFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:black_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJsYWNrX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoe8I4xAXbO5UDCgBuZXR3b3JrX2lk2Icb9AoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:brown_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJyb3duX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoSiNZOobbpjoDCgBuZXR3b3JrX2lkJy0jwgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:red_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaBdWFGLmCLFVAwoAbmV0d29ya19pZMYBJSEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:orange_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAAAACAQAbmFtZSIAbWluZWNyYWZ0Om9yYW5nZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaMyJMrnPr7szAwoAbmV0d29ya19pZN6+7TUKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:yellow_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAAAACAQAbmFtZSIAbWluZWNyYWZ0OnllbGxvd19nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaN6NaIhf6m0uAwoAbmV0d29ya19pZKRHXeoKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:lime_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAAAACAQAbmFtZSAAbWluZWNyYWZ0OmxpbWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2iF3E68/rB2EAMKAG5ldHdvcmtfaWSP7qQWCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:green_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAAAACAQAbmFtZSEAbWluZWNyYWZ0OmdyZWVuX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNow5mo8aQDFboDCgBuZXR3b3JrX2lkoF11kgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:cyan_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAAAACAQAbmFtZSAAbWluZWNyYWZ0OmN5YW5fZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gnNB+cCFRJhwMKAG5ldHdvcmtfaWT9buMtCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:light_blue_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAAAACAQAbmFtZSYAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gladnCDBKCigMKAG5ldHdvcmtfaWS5CszFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:blue_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAAAACAQAbmFtZSAAbWluZWNyYWZ0OmJsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2giOZK+2nB1igMKAG5ldHdvcmtfaWR+e22CCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:purple_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAAAACAQAbmFtZSIAbWluZWNyYWZ0OnB1cnBsZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaIQU03txeAfHAwoAbmV0d29ya19pZLKbSE4KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:magenta_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAAAACAQAbmFtZSMAbWluZWNyYWZ0Om1hZ2VudGFfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2i/SNqDJbfjMgMKAG5ldHdvcmtfaWQKf9UvCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:pink_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAAAACAQAbmFtZSAAbWluZWNyYWZ0OnBpbmtfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2hik8DVt4g+twMKAG5ldHdvcmtfaWTKzav2CgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:purpur_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZLD8ox4KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:purpur_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZPSAFFsKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:packed_mud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9tdWQECQBuYW1lX2hhc2gHOMa121h4FgMKAG5ldHdvcmtfaWTUb6LyCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:mud_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAgAACAQAbmFtZRQAbWluZWNyYWZ0Om11ZF9icmlja3MECQBuYW1lX2hhc2iDL/SVl/PewQMKAG5ldHdvcmtfaWSkBjaDCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:nether_wart_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9XGS4GNnlV4DCgBuZXR3b3JrX2lkh3apIgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:warped_wart_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAQAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9IqDS9yUPJoDCgBuZXR3b3JrX2lkMpKAbAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:shroomlight", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNocm9vbWxpZ2h0BAkAbmFtZV9oYXNoZHCHcHX/HYADCgBuZXR3b3JrX2lkLG2JiwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:crimson_nylium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fbnlsaXVtBAkAbmFtZV9oYXNoOr6DJYW2bFYDCgBuZXR3b3JrX2lkuWpRDgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:warped_nylium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9ueWxpdW0ECQBuYW1lX2hhc2g0Zf89cfr3rwMKAG5ldHdvcmtfaWSu/kekCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:netherrack", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAAAACAQAbmFtZRQAbWluZWNyYWZ0Om5ldGhlcnJhY2sECQBuYW1lX2hhc2i/r5ZyRsvPyQMKAG5ldHdvcmtfaWTAiTOACgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:basalt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhc2FsdAQJAG5hbWVfaGFzaH+UQO2yWodiAwoAbmV0d29ya19pZBPNSV4KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_basalt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAQAACAQAbmFtZRkAbWluZWNyYWZ0OnBvbGlzaGVkX2Jhc2FsdAQJAG5hbWVfaGFzaMS+L0gMnRcBAwoAbmV0d29ya19pZF+/mHwKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:smooth_basalt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AgAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9iYXNhbHQECQBuYW1lX2hhc2jKPUdz89kuNAMKAG5ldHdvcmtfaWTkb/oVCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:soul_soil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAQAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc29pbAQJAG5hbWVfaGFzaC1/87ccutuTAwoAbmV0d29ya19pZKc63SMKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dirt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQmkQtoCgYAc3RhdGVzCAkAZGlydF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dirt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQId9pLCgYAc3RhdGVzCAkAZGlydF90eXBlBgBjb2Fyc2UAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:farmland", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AAAACAQAbmFtZRIAbWluZWNyYWZ0OmZhcm1sYW5kBAkAbmFtZV9oYXNoxyQ5ag7LolADCgBuZXR3b3JrX2lkX618FQoGAHN0YXRlcwMSAG1vaXN0dXJpemVkX2Ftb3VudAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:grass_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXNzX2Jsb2NrBAkAbmFtZV9oYXNojPyGp3/CSZwDCgBuZXR3b3JrX2lktCgx3goGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:grass_path", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdyYXNzX3BhdGgECQBuYW1lX2hhc2i0/KZV8Qsy+gMKAG5ldHdvcmtfaWT7CcdzCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:podzol", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTzAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBvZHpvbAQJAG5hbWVfaGFzaBzqokRjH4Z1AwoAbmV0d29ya19pZPPS/GUKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mycelium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAAAACAQAbmFtZRIAbWluZWNyYWZ0Om15Y2VsaXVtBAkAbmFtZV9oYXNojTN09cKickIDCgBuZXR3b3JrX2lkLNPxXQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:mud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAgAACAQAbmFtZQ0AbWluZWNyYWZ0Om11ZAQJAG5hbWVfaGFzaPb/3P+uLy+9AwoAbmV0d29ya19pZPIUlUkKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkIQ4xgAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:iron_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAAAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lk3loneQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:gold_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAAAACAQAbmFtZRIAbWluZWNyYWZ0OmdvbGRfb3JlBAkAbmFtZV9oYXNoC5Y+DUGXLC4DCgBuZXR3b3JrX2lkNhvMfwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:diamond_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AAAACAQAbmFtZRUAbWluZWNyYWZ0OmRpYW1vbmRfb3JlBAkAbmFtZV9oYXNokUOJ2wZZrGQDCgBuZXR3b3JrX2lk/dChVAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:lapis_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAAAACAQAbmFtZRMAbWluZWNyYWZ0OmxhcGlzX29yZQQJAG5hbWVfaGFzaMrmrUrSzb7qAwoAbmV0d29ya19pZMg+qK4KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:redstone_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZHN0b25lX29yZQQJAG5hbWVfaGFzaFHVnp8Wc4JbAwoAbmV0d29ya19pZKDYvQoKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:coal_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAAAACAQAbmFtZRIAbWluZWNyYWZ0OmNvYWxfb3JlBAkAbmFtZV9oYXNo1OjA+Iuy51oDCgBuZXR3b3JrX2lk+R/aKAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:copper_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcHBlcl9vcmUECQBuYW1lX2hhc2iSZduSntOzOwMKAG5ldHdvcmtfaWQtIuCnCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:emerald_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVtZXJhbGRfb3JlBAkAbmFtZV9oYXNoJTovr+VgINsDCgBuZXR3b3JrX2lknbkqCgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:quartz_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAAAACAQAbmFtZRQAbWluZWNyYWZ0OnF1YXJ0el9vcmUECQBuYW1lX2hhc2g0yNHLMK9TaQMKAG5ldHdvcmtfaWSzN7nzCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:nether_gold_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcl9nb2xkX29yZQQJAG5hbWVfaGFzaEJZ7segIBgBAwoAbmV0d29ya19pZNI9pDgKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:ancient_debris", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFuY2llbnRfZGVicmlzBAkAbmFtZV9oYXNoNrbxMc9AwKcDCgBuZXR3b3JrX2lkrSNjEAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:deepslate_iron_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9pcm9uX29yZQQJAG5hbWVfaGFzaB/fDL9pgvXXAwoAbmV0d29ya19pZFA0bz4KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:deepslate_gold_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9nb2xkX29yZQQJAG5hbWVfaGFzaF9G7WYhKFinAwoAbmV0d29ya19pZHQTfBUKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:deepslate_diamond_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9kaWFtb25kX29yZQQJAG5hbWVfaGFzaEUH5USh+iD3AwoAbmV0d29ya19pZHP6VzAKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:deepslate_lapis_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV9sYXBpc19vcmUECQBuYW1lX2hhc2j+yFxU/KZs1gMKAG5ldHdvcmtfaWRKINzICgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:deepslate_redstone_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9yZWRzdG9uZV9vcmUECQBuYW1lX2hhc2iVgM3wWWD6ugMKAG5ldHdvcmtfaWReBdYRCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:deepslate_emerald_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9lbWVyYWxkX29yZQQJAG5hbWVfaGFzaNlfo5HTwS6wAwoAbmV0d29ya19pZNeie6sKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:deepslate_coal_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb2FsX29yZQQJAG5hbWVfaGFzaIjikmcbRrPPAwoAbmV0d29ya19pZD9TiygKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:deepslate_copper_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb3BwZXJfb3JlBAkAbmFtZV9oYXNottjV4Ev5LAQDCgBuZXR3b3JrX2lkP23rgQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:gravel", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAAAACAQAbmFtZRAAbWluZWNyYWZ0OmdyYXZlbAQJAG5hbWVfaGFzaOFxz8XJd2r/AwoAbmV0d29ya19pZBpfI1sKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:granite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAwAACAQAbmFtZREAbWluZWNyYWZ0OmdyYW5pdGUECQBuYW1lX2hhc2iq+Dur2pw4AwMKAG5ldHdvcmtfaWT2NMfJCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:diorite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAwAACAQAbmFtZREAbWluZWNyYWZ0OmRpb3JpdGUECQBuYW1lX2hhc2iaFsq2iinZBQMKAG5ldHdvcmtfaWQqGE6XCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:andesite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAwAACAQAbmFtZRIAbWluZWNyYWZ0OmFuZGVzaXRlBAkAbmFtZV9oYXNosaLIEnQQoSYDCgBuZXR3b3JrX2lkEApRZAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:blackstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrc3RvbmUECQBuYW1lX2hhc2iMFYziD80D6QMKAG5ldHdvcmtfaWSrUryHCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AgAACAQAbmFtZRMAbWluZWNyYWZ0OmRlZXBzbGF0ZQQJAG5hbWVfaGFzaKX5pAblxz8TAwoAbmV0d29ya19pZOJoQjsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_granite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGUECQBuYW1lX2hhc2iLiEfys8pFIAMKAG5ldHdvcmtfaWTCxxcHCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:polished_diorite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGUECQBuYW1lX2hhc2hTxY4fKmNmlAMKAG5ldHdvcmtfaWTmtjdRCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:polished_andesite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAwAACAQAbmFtZRsAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlBAkAbmFtZV9oYXNovl28uFk4HuQDCgBuZXR3b3JrX2lklFjuCwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:polished_blackstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAgAACAQAbmFtZR0AbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2jT9fHCl6vWQQMKAG5ldHdvcmtfaWR/Ho6oCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:polished_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaHC1edoaWF3uAwoAbmV0d29ya19pZCPeQsEKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:sand", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWTekU/mCgYAc3RhdGVzCAkAc2FuZF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:sand", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWSTgcqmCgYAc3RhdGVzCAkAc2FuZF90eXBlAwByZWQAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cactus", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAAAACAQAbmFtZRAAbWluZWNyYWZ0OmNhY3R1cwQJAG5hbWVfaGFzaCG9zL0N4wvGAwoAbmV0d29ya19pZDeCERAKBgBzdGF0ZXMDAwBhZ2UAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAAAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWQjfjoxCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stripped_oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQJAQAACAQAbmFtZRoAbWluZWNyYWZ0OnN0cmlwcGVkX29ha19sb2cECQBuYW1lX2hhc2h8dqh+OOHU4wMKAG5ldHdvcmtfaWSYKjdrCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:spruce_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AwAACAQAbmFtZRQAbWluZWNyYWZ0OnNwcnVjZV9sb2cECQBuYW1lX2hhc2hZ03qaLoF3WgMKAG5ldHdvcmtfaWRlFD8eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stripped_spruce_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV9sb2cECQBuYW1lX2hhc2iNrhKjS5IyrgMKAG5ldHdvcmtfaWRQcEC3CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:birch_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AwAACAQAbmFtZRMAbWluZWNyYWZ0OmJpcmNoX2xvZwQJAG5hbWVfaGFzaBUzT3NxsZAnAwoAbmV0d29ya19pZBKN3VQKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stripped_birch_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAQAACAQAbmFtZRwAbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX2xvZwQJAG5hbWVfaGFzaCFKS4AeuSidAwoAbmV0d29ya19pZN0IONIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:jungle_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AwAACAQAbmFtZRQAbWluZWNyYWZ0Omp1bmdsZV9sb2cECQBuYW1lX2hhc2gkwW0KNulqDgMKAG5ldHdvcmtfaWQaziU/CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stripped_jungle_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV9sb2cECQBuYW1lX2hhc2hAwMsgOk02JAMKAG5ldHdvcmtfaWQvls0eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:acacia_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAAAACAQAbmFtZRQAbWluZWNyYWZ0OmFjYWNpYV9sb2cECQBuYW1lX2hhc2iV48VpYhjoYQMKAG5ldHdvcmtfaWRxEqe0CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stripped_acacia_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV9sb2cECQBuYW1lX2hhc2hJb0lQqnEqlgMKAG5ldHdvcmtfaWRg3IdRCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dark_oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AwAACAQAbmFtZRYAbWluZWNyYWZ0OmRhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaIWfVRd0XUo3AwoAbmV0d29ya19pZPMM7LYKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stripped_dark_oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaPFTdxRdPwkOAwoAbmV0d29ya19pZDIzenIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:mangrove_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaHZe6DzPZBobAwoAbmV0d29ya19pZG6DuYkKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stripped_mangrove_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaLqIBo4hwA//AwoAbmV0d29ya19pZPtRn7UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cherry_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAwAACAQAbmFtZRQAbWluZWNyYWZ0OmNoZXJyeV9sb2cECQBuYW1lX2hhc2hwFlaioppB1wMKAG5ldHdvcmtfaWS2sdXECgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stripped_cherry_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAwAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV9sb2cECQBuYW1lX2hhc2i85H6G+WhXaAMKAG5ldHdvcmtfaWRjzoglCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crimson_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAQAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc3RlbQQJAG5hbWVfaGFzaM0FzfL0UTKZAwoAbmV0d29ya19pZKvzID0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stripped_crimson_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25fc3RlbQQJAG5hbWVfaGFzaDlA6nood57EAwoAbmV0d29ya19pZHrIqjIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:warped_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAQAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zdGVtBAkAbmFtZV9oYXNon7cKfPZxdrUDCgBuZXR3b3JrX2lkerWyMwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stripped_warped_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAQAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9zdGVtBAkAbmFtZV9oYXNoEw+y0dDPSd8DCgBuZXR3b3JrX2lkIQ9vBAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha193b29kBAkAbmFtZV9oYXNoqQIkuVPyJX0DCgBuZXR3b3JrX2lku2G1YAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:spruce_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV93b29kBAkAbmFtZV9oYXNoTrIJ5TAQ+OgDCgBuZXR3b3JrX2lkaXLxCwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:birch_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3dvb2QECQBuYW1lX2hhc2iqVjG4xt0cKQMKAG5ldHdvcmtfaWS06c5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:jungle_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV93b29kBAkAbmFtZV9oYXNo9bYW29ORWCoDCgBuZXR3b3JrX2lkyFyKLQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:acacia_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV93b29kBAkAbmFtZV9oYXNoKkDfgzlJUcIDCgBuZXR3b3JrX2lkuTWlcgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dark_oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2jaKv4ORLadAAMKAG5ldHdvcmtfaWSDrNQ8CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stripped_oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyBAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0cmlwcGVkX29ha193b29kBAkAbmFtZV9oYXNovW6KCv+VZnsDCgBuZXR3b3JrX2lkkhWGegoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stripped_spruce_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzBAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV93b29kBAkAbmFtZV9oYXNoMnuUk4Xo6icDCgBuZXR3b3JrX2lkes2ydAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stripped_birch_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0BAAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX3dvb2QECQBuYW1lX2hhc2hm88R604TKbAMKAG5ldHdvcmtfaWRleEMJCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stripped_jungle_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV93b29kBAkAbmFtZV9oYXNoUVs6KsZQRBoDCgBuZXR3b3JrX2lk92k8HQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stripped_acacia_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV93b29kBAkAbmFtZV9oYXNo/kOPN2bCJhUDCgBuZXR3b3JrX2lktl6LwQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stripped_dark_oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3BAAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2h2jFDfKVFgfAMKAG5ldHdvcmtfaWTgZQ5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mangrove_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2iXVxG0JG2fVAMKAG5ldHdvcmtfaWTok1JCCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stripped_mangrove_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2h7CkbaBF7/WAMKAG5ldHdvcmtfaWQLAX88CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cherry_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV93b29kBAkAbmFtZV9oYXNoAW8srlmpBM8DCgBuZXR3b3JrX2lkEALMfAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AQwAc3RyaXBwZWRfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stripped_cherry_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAwAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV93b29kBAkAbmFtZV9oYXNo/e7KXv+CB38DCgBuZXR3b3JrX2lkg5aVtQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:crimson_hyphae", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNouRmKmfSqEWADCgBuZXR3b3JrX2lk+Tm5rQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stripped_crimson_hyphae", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAgAACAQAbmFtZSEAbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNoFffwmABq4LUDCgBuZXR3b3JrX2lkZAlUbgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:warped_hyphae", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2hn8plQUr6pmQMKAG5ldHdvcmtfaWRU2AIBCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:stripped_warped_hyphae", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2irKq+HYPSgjQMKAG5ldHdvcmtfaWSbrOPDCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:bamboo_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19ibG9jawQJAG5hbWVfaGFzaAbDeur6stIBAwoAbmV0d29ya19pZCJAwn0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:stripped_bamboo_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAwAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2JhbWJvb19ibG9jawQJAG5hbWVfaGFzaJpwytpZOZM9AwoAbmV0d29ya19pZKuRbNEKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:oak_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19sZWF2ZXMECQBuYW1lX2hhc2h6O4xGqA2oKgMKAG5ldHdvcmtfaWT98c59CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:spruce_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfBAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9sZWF2ZXMECQBuYW1lX2hhc2i9x1CtNAuqZwMKAG5ldHdvcmtfaWSzF7pTCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:birch_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgBAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2xlYXZlcwQJAG5hbWVfaGFzaBlAGHaoaLZSAwoAbmV0d29ya19pZOjtvWcKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:jungle_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhBAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9sZWF2ZXMECQBuYW1lX2hhc2iW1uAH07zGhgMKAG5ldHdvcmtfaWSA5KX0CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:acacia_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9sZWF2ZXMECQBuYW1lX2hhc2iZJf8dAgDRNQMKAG5ldHdvcmtfaWQ/G7VuCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dark_oak_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiBAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2xlYXZlcwQJAG5hbWVfaGFzaCk7rDipWFSjAwoAbmV0d29ya19pZJ2AkbYKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:mangrove_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2xlYXZlcwQJAG5hbWVfaGFzaKyI/dWvhEG8AwoAbmV0d29ya19pZPQxCZ8KBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cherry_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9sZWF2ZXMECQBuYW1lX2hhc2giTs9ChhYBlQMKAG5ldHdvcmtfaWR8bPpwCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:azalea_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAgAACAQAbmFtZRcAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXMECQBuYW1lX2hhc2iXFhD57wFS7AMKAG5ldHdvcmtfaWTNB/9ECgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:azalea_leaves_flowered", + "block_state_b64": "CgAAAwgAYmxvY2tfaWREAgAACAQAbmFtZSAAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXNfZmxvd2VyZWQECQBuYW1lX2hhc2gs8jxlS/pMrwMKAG5ldHdvcmtfaWQ7W4PyCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:oak_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZRUAbWluZWNyYWZ0Om9ha19zYXBsaW5nBAkAbmFtZV9oYXNoogXcT9QfjiUDCgBuZXR3b3JrX2lkG22C+AoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:spruce_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4BAAACAQAbmFtZRgAbWluZWNyYWZ0OnNwcnVjZV9zYXBsaW5nBAkAbmFtZV9oYXNoe8hz4uYP0FcDCgBuZXR3b3JrX2lkUQmhaQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:birch_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5BAAACAQAbmFtZRcAbWluZWNyYWZ0OmJpcmNoX3NhcGxpbmcECQBuYW1lX2hhc2h348iJQ/tK4wMKAG5ldHdvcmtfaWQ2Uh53CgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:jungle_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6BAAACAQAbmFtZRgAbWluZWNyYWZ0Omp1bmdsZV9zYXBsaW5nBAkAbmFtZV9oYXNo7tyTOdSrxaADCgBuZXR3b3JrX2lkXmBAdAoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:acacia_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7BAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjYWNpYV9zYXBsaW5nBAkAbmFtZV9oYXNo99sg15uoX7ADCgBuZXR3b3JrX2lkPXX1KgoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dark_oak_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8BAAACAQAbmFtZRoAbWluZWNyYWZ0OmRhcmtfb2FrX3NhcGxpbmcECQBuYW1lX2hhc2jnVzFplW7cHgMKAG5ldHdvcmtfaWTD4giHCgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mangrove_propagule", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hbmdyb3ZlX3Byb3BhZ3VsZQQJAG5hbWVfaGFzaJGeox6hkfLFAwoAbmV0d29ya19pZAIpvpYKBgBzdGF0ZXMBBwBoYW5naW5nAAMPAHByb3BhZ3VsZV9zdGFnZQAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cherry_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAwAACAQAbmFtZRgAbWluZWNyYWZ0OmNoZXJyeV9zYXBsaW5nBAkAbmFtZV9oYXNoGrPpNMf1LtcDCgBuZXR3b3JrX2lkypakXQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bee_nest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJlZV9uZXN0BAkAbmFtZV9oYXNo2R2WBxUHEZIDCgBuZXR3b3JrX2lkiXWLEAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAADCwBob25leV9sZXZlbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:wheat_seeds" + }, + { + "id": "minecraft:pumpkin_seeds" + }, + { + "id": "minecraft:melon_seeds" + }, + { + "id": "minecraft:beetroot_seeds" + }, + { + "id": "minecraft:torchflower_seeds" + }, + { + "id": "minecraft:pitcher_pod" + }, + { + "id": "minecraft:wheat" + }, + { + "id": "minecraft:beetroot" + }, + { + "id": "minecraft:potato" + }, + { + "id": "minecraft:poisonous_potato" + }, + { + "id": "minecraft:carrot" + }, + { + "id": "minecraft:golden_carrot" + }, + { + "id": "minecraft:apple" + }, + { + "id": "minecraft:golden_apple" + }, + { + "id": "minecraft:enchanted_golden_apple" + }, + { + "id": "minecraft:melon_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1lbG9uX2Jsb2NrBAkAbmFtZV9oYXNoXxSm0iYpAx8DCgBuZXR3b3JrX2lkC9rqygoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:melon_slice" + }, + { + "id": "minecraft:glistering_melon_slice" + }, + { + "id": "minecraft:sweet_berries" + }, + { + "id": "minecraft:glow_berries" + }, + { + "id": "minecraft:pumpkin", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAAAACAQAbmFtZREAbWluZWNyYWZ0OnB1bXBraW4ECQBuYW1lX2hhc2gc8A3jaSzWbgMKAG5ldHdvcmtfaWRFGA+xCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:carved_pumpkin", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNhcnZlZF9wdW1wa2luBAkAbmFtZV9oYXNoPu1T0MJuG90DCgBuZXR3b3JrX2lkXNNn5QoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:lit_pumpkin", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxpdF9wdW1wa2luBAkAbmFtZV9oYXNo7gWtEm2uPL0DCgBuZXR3b3JrX2lki8sU4AoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:honeycomb" + }, + { + "id": "minecraft:tallgrass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZOh33DMKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAGZlcm4AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:double_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZMx1sfgKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAZmVybgEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:tallgrass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZErptfIKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAHRhbGwAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:double_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZAbadmIKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQUAZ3Jhc3MBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:nether_sprouts" + }, + { + "id": "minecraft:fire_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAwAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWS9vF0UCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:brain_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWREAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJyYWluX2NvcmFsBAkAbmFtZV9oYXNoRiWlLCwA2ycDCgBuZXR3b3JrX2lkrjAuhgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:bubble_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbAQJAG5hbWVfaGFzaJz6rWnl+v2qAwoAbmV0d29ya19pZImIWy0KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:tube_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1YmVfY29yYWwECQBuYW1lX2hhc2iYa8oO/tgk7wMKAG5ldHdvcmtfaWRTfND5CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:horn_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAwAACAQAbmFtZRQAbWluZWNyYWZ0Omhvcm5fY29yYWwECQBuYW1lX2hhc2iZnRHjZbnLPgMKAG5ldHdvcmtfaWR+GGp8CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dead_fire_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbAQJAG5hbWVfaGFzaEPU6tFy/latAwoAbmV0d29ya19pZNMa7V4KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dead_brain_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAwAACAQAbmFtZRoAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWwECQBuYW1lX2hhc2j5L6QJCISvzwMKAG5ldHdvcmtfaWQkKzeiCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dead_bubble_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAwAACAQAbmFtZRsAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsBAkAbmFtZV9oYXNoSTOZ/8wpeNYDCgBuZXR3b3JrX2lka6w9DAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:dead_tube_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbAQJAG5hbWVfaGFzaJGjNWhlaIJeAwoAbmV0d29ya19pZO3Z0ygKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dead_horn_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbAQJAG5hbWVfaGFzaJBkz3qt+g2cAwoAbmV0d29ya19pZBAN+eYKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:fire_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJBAAACAQAbmFtZRgAbWluZWNyYWZ0OmZpcmVfY29yYWxfZmFuBAkAbmFtZV9oYXNosOTxYYxsDLgDCgBuZXR3b3JrX2lkFKxbEgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:brain_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHBAAACAQAbmFtZRkAbWluZWNyYWZ0OmJyYWluX2NvcmFsX2ZhbgQJAG5hbWVfaGFzaAi5uHizSNcqAwoAbmV0d29ya19pZFtLjNwKBgBzdGF0ZXMDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:bubble_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIBAAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hy/rX2on17DgMKAG5ldHdvcmtfaWQof60VCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:tube_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRgAbWluZWNyYWZ0OnR1YmVfY29yYWxfZmFuBAkAbmFtZV9oYXNo9pbJbo+PphIDCgBuZXR3b3JrX2lkenDTYgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:horn_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKBAAACAQAbmFtZRgAbWluZWNyYWZ0Omhvcm5fY29yYWxfZmFuBAkAbmFtZV9oYXNoA+ri6NPDkbUDCgBuZXR3b3JrX2lkezoHNwoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dead_fire_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNBAAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hpQO02NDxPvwMKAG5ldHdvcmtfaWTaOJgLCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dead_brain_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLBAAACAQAbmFtZR4AbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWxfZmFuBAkAbmFtZV9oYXNoI9/+Z4YqMhIDCgBuZXR3b3JrX2lkqYXxYgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dead_bubble_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsX2ZhbgQJAG5hbWVfaGFzaBNECtIM6VIOAwoAbmV0d29ya19pZLrNtBEKBgBzdGF0ZXMDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:dead_tube_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hbBBM9jFKWvQMKAG5ldHdvcmtfaWSkJKUWCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:dead_horn_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROBAAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbF9mYW4ECQBuYW1lX2hhc2hObElFrHfPygMKAG5ldHdvcmtfaWQ1ZxvmCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crimson_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fcm9vdHMECQBuYW1lX2hhc2j1fWgQLViv5QMKAG5ldHdvcmtfaWRLh5DXCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:warped_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAQAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9yb290cwQJAG5hbWVfaGFzaBc3WvbJOLlkAwoAbmV0d29ya19pZNLgDnAKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:yellow_flower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlAAAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19mbG93ZXIECQBuYW1lX2hhc2jWbU1pF0OUGAMKAG5ldHdvcmtfaWQgO3hpCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:poppy", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnBvcHB5BAkAbmFtZV9oYXNocMF8pITMbkcDCgBuZXR3b3JrX2lk8im6ywoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:blue_orchid", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9BAAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfb3JjaGlkBAkAbmFtZV9oYXNoBjz2MsgB21EDCgBuZXR3b3JrX2lk/iLsSwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:allium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+BAAACAQAbmFtZRAAbWluZWNyYWZ0OmFsbGl1bQQJAG5hbWVfaGFzaDCGQBHNDTkcAwoAbmV0d29ya19pZD9Dgr0KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:azure_bluet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/BAAACAQAbmFtZRUAbWluZWNyYWZ0OmF6dXJlX2JsdWV0BAkAbmFtZV9oYXNo9N5egqMT2QcDCgBuZXR3b3JrX2lkwIgDnwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:red_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRABAAACAQAbmFtZRMAbWluZWNyYWZ0OnJlZF90dWxpcAQJAG5hbWVfaGFzaAjMi9Rd+6rhAwoAbmV0d29ya19pZAZCnt8KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:orange_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBBAAACAQAbmFtZRYAbWluZWNyYWZ0Om9yYW5nZV90dWxpcAQJAG5hbWVfaGFzaP+NjxMBZ8vAAwoAbmV0d29ya19pZPYatsMKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:white_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCBAAACAQAbmFtZRUAbWluZWNyYWZ0OndoaXRlX3R1bGlwBAkAbmFtZV9oYXNo5vbU4VRPh3ADCgBuZXR3b3JrX2lkok+4rQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:pink_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDBAAACAQAbmFtZRQAbWluZWNyYWZ0OnBpbmtfdHVsaXAECQBuYW1lX2hhc2hxDHZa6OaNXAMKAG5ldHdvcmtfaWTiOT+VCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:oxeye_daisy", + "block_state_b64": "CgAAAwgAYmxvY2tfaWREBAAACAQAbmFtZRUAbWluZWNyYWZ0Om94ZXllX2RhaXN5BAkAbmFtZV9oYXNoXwxsqNQTN9gDCgBuZXR3b3JrX2lkw7R7dwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cornflower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFBAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcm5mbG93ZXIECQBuYW1lX2hhc2gnhyC3EeqHgAMKAG5ldHdvcmtfaWR4VrvACgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:lily_of_the_valley", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGBAAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbHlfb2ZfdGhlX3ZhbGxleQQJAG5hbWVfaGFzaI64TJSf9mgQAwoAbmV0d29ya19pZFE9+nwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:double_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZOemRt4KBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQkAc3VuZmxvd2VyAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:double_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZOFugoEKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAc3lyaW5nYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:double_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZN4O+/gKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAcm9zZQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:double_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZI3w4GMKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAcGFlb25pYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:pitcher_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpdGNoZXJfcGxhbnQECQBuYW1lX2hhc2hRJHzsbDH+SQMKAG5ldHdvcmtfaWRnY76VCgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:pink_petals", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfcGV0YWxzBAkAbmFtZV9oYXNo6DQwN9SwV3QDCgBuZXR3b3JrX2lkNWneGgoGAHN0YXRlcwMGAGdyb3d0aAAAAAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:wither_rose", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAQAACAQAbmFtZRUAbWluZWNyYWZ0OndpdGhlcl9yb3NlBAkAbmFtZV9oYXNoaSKxl3I516gDCgBuZXR3b3JrX2lkATXLPwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:torchflower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AwAACAQAbmFtZRUAbWluZWNyYWZ0OnRvcmNoZmxvd2VyBAkAbmFtZV9oYXNoL+mHtElwbqQDCgBuZXR3b3JrX2lkI34O+AoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:white_dye" + }, + { + "id": "minecraft:light_gray_dye" + }, + { + "id": "minecraft:gray_dye" + }, + { + "id": "minecraft:black_dye" + }, + { + "id": "minecraft:brown_dye" + }, + { + "id": "minecraft:red_dye" + }, + { + "id": "minecraft:orange_dye" + }, + { + "id": "minecraft:yellow_dye" + }, + { + "id": "minecraft:lime_dye" + }, + { + "id": "minecraft:green_dye" + }, + { + "id": "minecraft:cyan_dye" + }, + { + "id": "minecraft:light_blue_dye" + }, + { + "id": "minecraft:blue_dye" + }, + { + "id": "minecraft:purple_dye" + }, + { + "id": "minecraft:magenta_dye" + }, + { + "id": "minecraft:pink_dye" + }, + { + "id": "minecraft:ink_sac" + }, + { + "id": "minecraft:glow_ink_sac" + }, + { + "id": "minecraft:cocoa_beans" + }, + { + "id": "minecraft:lapis_lazuli" + }, + { + "id": "minecraft:bone_meal" + }, + { + "id": "minecraft:vine", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnZpbmUECQBuYW1lX2hhc2j0Sj8/XeXOLAMKAG5ldHdvcmtfaWSUkDtbCgYAc3RhdGVzAxMAdmluZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:weeping_vines", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAQAACAQAbmFtZRcAbWluZWNyYWZ0OndlZXBpbmdfdmluZXMECQBuYW1lX2hhc2jrLgLHkQygiwMKAG5ldHdvcmtfaWQ8NHSJCgYAc3RhdGVzAxEAd2VlcGluZ192aW5lc19hZ2UAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:twisting_vines", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAgAACAQAbmFtZRgAbWluZWNyYWZ0OnR3aXN0aW5nX3ZpbmVzBAkAbmFtZV9oYXNoDYR5QgVUQJADCgBuZXR3b3JrX2lk5kYVIQoGAHN0YXRlcwMSAHR3aXN0aW5nX3ZpbmVzX2FnZQAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:waterlily", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAAAACAQAbmFtZRMAbWluZWNyYWZ0OndhdGVybGlseQQJAG5hbWVfaGFzaEHgC4c1SXg0AwoAbmV0d29ya19pZOOerp8KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:seagrass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAQAACAQAbmFtZRIAbWluZWNyYWZ0OnNlYWdyYXNzBAkAbmFtZV9oYXNoHSBFtoHdWxIDCgBuZXR3b3JrX2lkd3lhEAoGAHN0YXRlcwgOAHNlYV9ncmFzc190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:kelp" + }, + { + "id": "minecraft:deadbush", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAAAACAQAbmFtZRIAbWluZWNyYWZ0OmRlYWRidXNoBAkAbmFtZV9oYXNoPFODe4IScnYDCgBuZXR3b3JrX2lkVfnl+goGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:bamboo", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhbWJvbwQJAG5hbWVfaGFzaBgpGmyzhedCAwoAbmV0d29ya19pZIZv1nYKBgBzdGF0ZXMBBwBhZ2VfYml0AAgQAGJhbWJvb19sZWFmX3NpemUJAG5vX2xlYXZlcwgWAGJhbWJvb19zdGFsa190aGlja25lc3MEAHRoaW4AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:snow", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNub3cECQBuYW1lX2hhc2gVHr5XXdETWAMKAG5ldHdvcmtfaWQ0zCeHCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:ice", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAAAACAQAbmFtZQ0AbWluZWNyYWZ0OmljZQQJAG5hbWVfaGFzaNF26f+uUT29AwoAbmV0d29ya19pZOUMaQYKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:packed_ice", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAAAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9pY2UECQBuYW1lX2hhc2hk4bu123ZrFgMKAG5ldHdvcmtfaWTr/ooaCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:blue_ice", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJsdWVfaWNlBAkAbmFtZV9oYXNo+EKxYgFhKcgDCgBuZXR3b3JrX2lkxfsA8goGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:snow_layer", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAAAACAQAbmFtZRQAbWluZWNyYWZ0OnNub3dfbGF5ZXIECQBuYW1lX2hhc2hXka6atMYUCQMKAG5ldHdvcmtfaWRCrIPcCgYAc3RhdGVzAQsAY292ZXJlZF9iaXQAAwYAaGVpZ2h0AAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:pointed_dripstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvaW50ZWRfZHJpcHN0b25lBAkAbmFtZV9oYXNoJMISzmHQgt8DCgBuZXR3b3JrX2lkbWrtYgoGAHN0YXRlcwgTAGRyaXBzdG9uZV90aGlja25lc3MDAHRpcAEHAGhhbmdpbmcBAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dripstone_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRyaXBzdG9uZV9ibG9jawQJAG5hbWVfaGFzaIIXnEqY77YsAwoAbmV0d29ya19pZMZi2kwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:moss_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vc3NfY2FycGV0BAkAbmFtZV9oYXNo/NEDxRPTshYDCgBuZXR3b3JrX2lkaGG3QwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:moss_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AgAACAQAbmFtZRQAbWluZWNyYWZ0Om1vc3NfYmxvY2sECQBuYW1lX2hhc2iovcsPUYX2tgMKAG5ldHdvcmtfaWT3JSbfCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dirt_with_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRpcnRfd2l0aF9yb290cwQJAG5hbWVfaGFzaLCNDYPviDCIAwoAbmV0d29ya19pZNCkwzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:hanging_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AgAACAQAbmFtZRcAbWluZWNyYWZ0Omhhbmdpbmdfcm9vdHMECQBuYW1lX2hhc2jaXn+Y5UZpDAMKAG5ldHdvcmtfaWRU4c2vCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:mangrove_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNoa786PzQGZ6kDCgBuZXR3b3JrX2lklA0AHgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:muddy_mangrove_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAgAACAQAbmFtZR4AbWluZWNyYWZ0Om11ZGR5X21hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNo9YApdHpo1RkDCgBuZXR3b3JrX2lkH0Oc4woGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:big_dripleaf", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpZ19kcmlwbGVhZgQJAG5hbWVfaGFzaGBEhXjo6qSdAwoAbmV0d29ya19pZMETsb8KBgBzdGF0ZXMBEQBiaWdfZHJpcGxlYWZfaGVhZAEIEQBiaWdfZHJpcGxlYWZfdGlsdAQAbm9uZQgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:small_dripleaf_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtYWxsX2RyaXBsZWFmX2Jsb2NrBAkAbmFtZV9oYXNojxRAgXP9uWADCgBuZXR3b3JrX2lkozbVPwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24EAGVhc3QBDwB1cHBlcl9ibG9ja19iaXQBAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:spore_blossom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwb3JlX2Jsb3Nzb20ECQBuYW1lX2hhc2il3U72Gbco2gMKAG5ldHdvcmtfaWSbbbgcCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:azalea", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAgAACAQAbmFtZRAAbWluZWNyYWZ0OmF6YWxlYQQJAG5hbWVfaGFzaNyUl+BW9JrBAwoAbmV0d29ya19pZO/XZtQKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:flowering_azalea", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAgAACAQAbmFtZRoAbWluZWNyYWZ0OmZsb3dlcmluZ19hemFsZWEECQBuYW1lX2hhc2ie9r33wz8kiwMKAG5ldHdvcmtfaWQ3ij0VCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:glow_lichen", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAgAACAQAbmFtZRUAbWluZWNyYWZ0Omdsb3dfbGljaGVuBAkAbmFtZV9oYXNobyPUrIYlo44DCgBuZXR3b3JrX2lkCh8lSAoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHM/AAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:amethyst_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFtZXRoeXN0X2Jsb2NrBAkAbmFtZV9oYXNob+JK1iiAthcDCgBuZXR3b3JrX2lk8HtpzgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:budding_amethyst", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAgAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1ZGRpbmdfYW1ldGh5c3QECQBuYW1lX2hhc2gJvAwfI14fxgMKAG5ldHdvcmtfaWTQYqfACgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:amethyst_cluster", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAgAACAQAbmFtZRoAbWluZWNyYWZ0OmFtZXRoeXN0X2NsdXN0ZXIECQBuYW1lX2hhc2jK82S88Jgm8wMKAG5ldHdvcmtfaWSCPMPGCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:large_amethyst_bud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAgAACAQAbmFtZRwAbWluZWNyYWZ0OmxhcmdlX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaAHhdpWD+sd5AwoAbmV0d29ya19pZKkQxOcKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:medium_amethyst_bud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1lZGl1bV9hbWV0aHlzdF9idWQECQBuYW1lX2hhc2g5lBGtC0DzZQMKAG5ldHdvcmtfaWSYiP4gCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:small_amethyst_bud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAgAACAQAbmFtZRwAbWluZWNyYWZ0OnNtYWxsX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaEnb4+q9PO4YAwoAbmV0d29ya19pZGWzxrQKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:tuff", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAgAACAQAbmFtZQ4AbWluZWNyYWZ0OnR1ZmYECQBuYW1lX2hhc2h1Rwc1XYsBGwMKAG5ldHdvcmtfaWRwQGn0CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:calcite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAgAACAQAbmFtZREAbWluZWNyYWZ0OmNhbGNpdGUECQBuYW1lX2hhc2ixKLu8ZIdzDQMKAG5ldHdvcmtfaWQlSbJDCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:chicken" + }, + { + "id": "minecraft:porkchop" + }, + { + "id": "minecraft:beef" + }, + { + "id": "minecraft:mutton" + }, + { + "id": "minecraft:rabbit" + }, + { + "id": "minecraft:cod" + }, + { + "id": "minecraft:salmon" + }, + { + "id": "minecraft:tropical_fish" + }, + { + "id": "minecraft:pufferfish" + }, + { + "id": "minecraft:brown_mushroom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAAAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkLh1OXAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:red_mushroom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9tdXNocm9vbQQJAG5hbWVfaGFzaPpzJua7669xAwoAbmV0d29ya19pZCvWPYkKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crimson_fungus", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fZnVuZ3VzBAkAbmFtZV9oYXNolIcCUuFM2u0DCgBuZXR3b3JrX2lkD2NN0QoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:warped_fungus", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9mdW5ndXMECQBuYW1lX2hhc2gq8bSnRVTAFgMKAG5ldHdvcmtfaWTkwS+rCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:brown_mushroom_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkdOMhDAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw4AAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:red_mushroom_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9tdXNocm9vbV9ibG9jawQJAG5hbWVfaGFzaJTTyJbth9M9AwoAbmV0d29ya19pZM+AyboKBgBzdGF0ZXMDEgBodWdlX211c2hyb29tX2JpdHMOAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:brown_mushroom_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkbdt3CAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw8AAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:brown_mushroom_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkSrMl9goGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cwAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:egg" + }, + { + "id": "minecraft:sugar_cane" + }, + { + "id": "minecraft:sugar" + }, + { + "id": "minecraft:rotten_flesh" + }, + { + "id": "minecraft:bone" + }, + { + "id": "minecraft:web", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAAAACAQAbmFtZQ0AbWluZWNyYWZ0OndlYgQJAG5hbWVfaGFzaA4GKQCvG4i9AwoAbmV0d29ya19pZApt+jgKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:spider_eye" + }, + { + "id": "minecraft:mob_spawner", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vYl9zcGF3bmVyBAkAbmFtZV9oYXNoNwGrCV/Fkh8DCgBuZXR3b3JrX2lkM1wTmgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:end_portal_frame", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9wb3J0YWxfZnJhbWUECQBuYW1lX2hhc2gqofyUIjGOpQMKAG5ldHdvcmtfaWRbGHf8CgYAc3RhdGVzARIAZW5kX3BvcnRhbF9leWVfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:monster_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqXH7RgoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUFAHN0b25lAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:monster_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkeIBb6QoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAGNvYmJsZXN0b25lAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:monster_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkDZ2cFQoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAHN0b25lX2JyaWNrAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:monster_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkOR/cTAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGURAG1vc3N5X3N0b25lX2JyaWNrAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:monster_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqdwlHAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUTAGNyYWNrZWRfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:monster_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFqqPggoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUUAGNoaXNlbGVkX3N0b25lX2JyaWNrAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:infested_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAgAACAQAbmFtZRwAbWluZWNyYWZ0OmluZmVzdGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaICF2VYccxF1AwoAbmV0d29ya19pZDa/624KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:dragon_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AAAACAQAbmFtZRQAbWluZWNyYWZ0OmRyYWdvbl9lZ2cECQBuYW1lX2hhc2inMzXrV+/e1wMKAG5ldHdvcmtfaWTgO1yRCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:turtle_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1cnRsZV9lZ2cECQBuYW1lX2hhc2iwSRcxOJIJ9gMKAG5ldHdvcmtfaWSIRNUhCgYAc3RhdGVzCA0AY3JhY2tlZF9zdGF0ZQkAbm9fY3JhY2tzCBAAdHVydGxlX2VnZ19jb3VudAcAb25lX2VnZwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:sniffer_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAwAACAQAbmFtZRUAbWluZWNyYWZ0OnNuaWZmZXJfZWdnBAkAbmFtZV9oYXNoY1lozc8lPcYDCgBuZXR3b3JrX2lk7yb/2QoGAHN0YXRlcwgNAGNyYWNrZWRfc3RhdGUJAG5vX2NyYWNrcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:frog_spawn", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAgAACAQAbmFtZRQAbWluZWNyYWZ0OmZyb2dfc3Bhd24ECQBuYW1lX2hhc2iWmd7idp3ZZwMKAG5ldHdvcmtfaWRFzJudCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:pearlescent_froglight", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAgAACAQAbmFtZR8AbWluZWNyYWZ0OnBlYXJsZXNjZW50X2Zyb2dsaWdodAQJAG5hbWVfaGFzaKkcFRyycYGyAwoAbmV0d29ya19pZJqYakAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:verdant_froglight", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAgAACAQAbmFtZRsAbWluZWNyYWZ0OnZlcmRhbnRfZnJvZ2xpZ2h0BAkAbmFtZV9oYXNoA+eXuTBohrQDCgBuZXR3b3JrX2lkDIVnsQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:ochre_froglight", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om9jaHJlX2Zyb2dsaWdodAQJAG5hbWVfaGFzaMY59kjPe+c3AwoAbmV0d29ya19pZO2TD50KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:chicken_spawn_egg" + }, + { + "id": "minecraft:bee_spawn_egg" + }, + { + "id": "minecraft:cow_spawn_egg" + }, + { + "id": "minecraft:pig_spawn_egg" + }, + { + "id": "minecraft:sheep_spawn_egg" + }, + { + "id": "minecraft:wolf_spawn_egg" + }, + { + "id": "minecraft:polar_bear_spawn_egg" + }, + { + "id": "minecraft:ocelot_spawn_egg" + }, + { + "id": "minecraft:cat_spawn_egg" + }, + { + "id": "minecraft:mooshroom_spawn_egg" + }, + { + "id": "minecraft:bat_spawn_egg" + }, + { + "id": "minecraft:parrot_spawn_egg" + }, + { + "id": "minecraft:rabbit_spawn_egg" + }, + { + "id": "minecraft:llama_spawn_egg" + }, + { + "id": "minecraft:horse_spawn_egg" + }, + { + "id": "minecraft:donkey_spawn_egg" + }, + { + "id": "minecraft:mule_spawn_egg" + }, + { + "id": "minecraft:skeleton_horse_spawn_egg" + }, + { + "id": "minecraft:zombie_horse_spawn_egg" + }, + { + "id": "minecraft:tropical_fish_spawn_egg" + }, + { + "id": "minecraft:cod_spawn_egg" + }, + { + "id": "minecraft:pufferfish_spawn_egg" + }, + { + "id": "minecraft:salmon_spawn_egg" + }, + { + "id": "minecraft:dolphin_spawn_egg" + }, + { + "id": "minecraft:turtle_spawn_egg" + }, + { + "id": "minecraft:panda_spawn_egg" + }, + { + "id": "minecraft:fox_spawn_egg" + }, + { + "id": "minecraft:creeper_spawn_egg" + }, + { + "id": "minecraft:enderman_spawn_egg" + }, + { + "id": "minecraft:silverfish_spawn_egg" + }, + { + "id": "minecraft:skeleton_spawn_egg" + }, + { + "id": "minecraft:wither_skeleton_spawn_egg" + }, + { + "id": "minecraft:stray_spawn_egg" + }, + { + "id": "minecraft:slime_spawn_egg" + }, + { + "id": "minecraft:spider_spawn_egg" + }, + { + "id": "minecraft:zombie_spawn_egg" + }, + { + "id": "minecraft:zombie_pigman_spawn_egg" + }, + { + "id": "minecraft:husk_spawn_egg" + }, + { + "id": "minecraft:drowned_spawn_egg" + }, + { + "id": "minecraft:squid_spawn_egg" + }, + { + "id": "minecraft:glow_squid_spawn_egg" + }, + { + "id": "minecraft:cave_spider_spawn_egg" + }, + { + "id": "minecraft:witch_spawn_egg" + }, + { + "id": "minecraft:guardian_spawn_egg" + }, + { + "id": "minecraft:elder_guardian_spawn_egg" + }, + { + "id": "minecraft:endermite_spawn_egg" + }, + { + "id": "minecraft:magma_cube_spawn_egg" + }, + { + "id": "minecraft:strider_spawn_egg" + }, + { + "id": "minecraft:hoglin_spawn_egg" + }, + { + "id": "minecraft:piglin_spawn_egg" + }, + { + "id": "minecraft:zoglin_spawn_egg" + }, + { + "id": "minecraft:piglin_brute_spawn_egg" + }, + { + "id": "minecraft:goat_spawn_egg" + }, + { + "id": "minecraft:axolotl_spawn_egg" + }, + { + "id": "minecraft:warden_spawn_egg" + }, + { + "id": "minecraft:allay_spawn_egg" + }, + { + "id": "minecraft:frog_spawn_egg" + }, + { + "id": "minecraft:tadpole_spawn_egg" + }, + { + "id": "minecraft:trader_llama_spawn_egg" + }, + { + "id": "minecraft:camel_spawn_egg" + }, + { + "id": "minecraft:ghast_spawn_egg" + }, + { + "id": "minecraft:blaze_spawn_egg" + }, + { + "id": "minecraft:shulker_spawn_egg" + }, + { + "id": "minecraft:vindicator_spawn_egg" + }, + { + "id": "minecraft:evoker_spawn_egg" + }, + { + "id": "minecraft:vex_spawn_egg" + }, + { + "id": "minecraft:villager_spawn_egg" + }, + { + "id": "minecraft:wandering_trader_spawn_egg" + }, + { + "id": "minecraft:zombie_villager_spawn_egg" + }, + { + "id": "minecraft:phantom_spawn_egg" + }, + { + "id": "minecraft:pillager_spawn_egg" + }, + { + "id": "minecraft:ravager_spawn_egg" + }, + { + "id": "minecraft:iron_golem_spawn_egg" + }, + { + "id": "minecraft:snow_golem_spawn_egg" + }, + { + "id": "minecraft:sniffer_spawn_egg" + }, + { + "id": "minecraft:armadillo_spawn_egg" + }, + { + "id": "minecraft:obsidian", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2lkaWFuBAkAbmFtZV9oYXNoiz4qrb8QjyEDCgBuZXR3b3JrX2lkuqnPpQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:crying_obsidian", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAgAACAQAbmFtZRkAbWluZWNyYWZ0OmNyeWluZ19vYnNpZGlhbgQJAG5hbWVfaGFzaKT0JlA7Z1K+AwoAbmV0d29ya19pZCjbPV4KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:bedrock", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAAAACAQAbmFtZREAbWluZWNyYWZ0OmJlZHJvY2sECQBuYW1lX2hhc2hWfFrh4LVtxwMKAG5ldHdvcmtfaWT7fKz1CgYAc3RhdGVzAQ4AaW5maW5pYnVybl9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:soul_sand", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc2FuZAQJAG5hbWVfaGFzaMaf+bccu+KTAwoAbmV0d29ya19pZBQSHrMKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:magma", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAAAACAQAbmFtZQ8AbWluZWNyYWZ0Om1hZ21hBAkAbmFtZV9oYXNoqyTjKaIsWfYDCgBuZXR3b3JrX2lkyfWAZgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:nether_wart" + }, + { + "id": "minecraft:end_stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AAAACAQAbmFtZRMAbWluZWNyYWZ0OmVuZF9zdG9uZQQJAG5hbWVfaGFzaH1J9jA39GJNAwoAbmV0d29ya19pZFeFQ7UKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:chorus_flower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAAAACAQAbmFtZRcAbWluZWNyYWZ0OmNob3J1c19mbG93ZXIECQBuYW1lX2hhc2iMpSodli5uawMKAG5ldHdvcmtfaWRnd1ZWCgYAc3RhdGVzAwMAYWdlAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:chorus_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAAAACAQAbmFtZRYAbWluZWNyYWZ0OmNob3J1c19wbGFudAQJAG5hbWVfaGFzaJhSrmNGKwaMAwoAbmV0d29ya19pZA3uVqMKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:chorus_fruit" + }, + { + "id": "minecraft:popped_chorus_fruit" + }, + { + "id": "minecraft:sponge", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZF01rO0KBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAZHJ5AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:sponge", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZPiOc4QKBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAd2V0AAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkGnlaAwoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkSnHuagoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkmkHyegoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkdpUDxgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkYNWvYgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkZSxBQgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lklSTVqQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lk5fTYuQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkwUjqBAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkq4iWoQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:sculk", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lkyqUPPgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:sculk_vein", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNjdWxrX3ZlaW4ECQBuYW1lX2hhc2gJUdhVooV4zwMKAG5ldHdvcmtfaWSUfn1XCgYAc3RhdGVzAxkAbXVsdGlfZmFjZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:sculk_catalyst", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX2NhdGFseXN0BAkAbmFtZV9oYXNo+gCpbrCHST4DCgBuZXR3b3JrX2lkMJ2n/woGAHN0YXRlcwEFAGJsb29tAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:sculk_shrieker", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX3Nocmlla2VyBAkAbmFtZV9oYXNo5OXtyObniQ4DCgBuZXR3b3JrX2lkxapoNAoGAHN0YXRlcwEGAGFjdGl2ZQABCgBjYW5fc3VtbW9uAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:sculk_sensor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNjdWxrX3NlbnNvcgQJAG5hbWVfaGFzaCkmHreeTgNnAwoAbmV0d29ya19pZLj2WPcKBgBzdGF0ZXMDEgBzY3Vsa19zZW5zb3JfcGhhc2UAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:calibrated_sculk_sensor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAwAACAQAbmFtZSEAbWluZWNyYWZ0OmNhbGlicmF0ZWRfc2N1bGtfc2Vuc29yBAkAbmFtZV9oYXNoffAcXXN/iJUDCgBuZXR3b3JrX2lkwOx3QQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAxIAc2N1bGtfc2Vuc29yX3BoYXNlAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:reinforced_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlaW5mb3JjZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoldDmj91EapQDCgBuZXR3b3JrX2lkHIt+aQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:leather_helmet" + }, + { + "id": "minecraft:chainmail_helmet" + }, + { + "id": "minecraft:iron_helmet" + }, + { + "id": "minecraft:golden_helmet" + }, + { + "id": "minecraft:diamond_helmet" + }, + { + "id": "minecraft:netherite_helmet" + }, + { + "id": "minecraft:leather_chestplate" + }, + { + "id": "minecraft:chainmail_chestplate" + }, + { + "id": "minecraft:iron_chestplate" + }, + { + "id": "minecraft:golden_chestplate" + }, + { + "id": "minecraft:diamond_chestplate" + }, + { + "id": "minecraft:netherite_chestplate" + }, + { + "id": "minecraft:leather_leggings" + }, + { + "id": "minecraft:chainmail_leggings" + }, + { + "id": "minecraft:iron_leggings" + }, + { + "id": "minecraft:golden_leggings" + }, + { + "id": "minecraft:diamond_leggings" + }, + { + "id": "minecraft:netherite_leggings" + }, + { + "id": "minecraft:leather_boots" + }, + { + "id": "minecraft:chainmail_boots" + }, + { + "id": "minecraft:iron_boots" + }, + { + "id": "minecraft:golden_boots" + }, + { + "id": "minecraft:diamond_boots" + }, + { + "id": "minecraft:netherite_boots" + }, + { + "id": "minecraft:wooden_sword" + }, + { + "id": "minecraft:stone_sword" + }, + { + "id": "minecraft:iron_sword" + }, + { + "id": "minecraft:golden_sword" + }, + { + "id": "minecraft:diamond_sword" + }, + { + "id": "minecraft:netherite_sword" + }, + { + "id": "minecraft:wooden_axe" + }, + { + "id": "minecraft:stone_axe" + }, + { + "id": "minecraft:iron_axe" + }, + { + "id": "minecraft:golden_axe" + }, + { + "id": "minecraft:diamond_axe" + }, + { + "id": "minecraft:netherite_axe" + }, + { + "id": "minecraft:wooden_pickaxe" + }, + { + "id": "minecraft:stone_pickaxe" + }, + { + "id": "minecraft:iron_pickaxe" + }, + { + "id": "minecraft:golden_pickaxe" + }, + { + "id": "minecraft:diamond_pickaxe" + }, + { + "id": "minecraft:netherite_pickaxe" + }, + { + "id": "minecraft:wooden_shovel" + }, + { + "id": "minecraft:stone_shovel" + }, + { + "id": "minecraft:iron_shovel" + }, + { + "id": "minecraft:golden_shovel" + }, + { + "id": "minecraft:diamond_shovel" + }, + { + "id": "minecraft:netherite_shovel" + }, + { + "id": "minecraft:wooden_hoe" + }, + { + "id": "minecraft:stone_hoe" + }, + { + "id": "minecraft:iron_hoe" + }, + { + "id": "minecraft:golden_hoe" + }, + { + "id": "minecraft:diamond_hoe" + }, + { + "id": "minecraft:netherite_hoe" + }, + { + "id": "minecraft:bow" + }, + { + "id": "minecraft:crossbow" + }, + { + "id": "minecraft:arrow" + }, + { + "id": "minecraft:arrow", + "damage": 6 + }, + { + "id": "minecraft:arrow", + "damage": 7 + }, + { + "id": "minecraft:arrow", + "damage": 8 + }, + { + "id": "minecraft:arrow", + "damage": 9 + }, + { + "id": "minecraft:arrow", + "damage": 10 + }, + { + "id": "minecraft:arrow", + "damage": 11 + }, + { + "id": "minecraft:arrow", + "damage": 12 + }, + { + "id": "minecraft:arrow", + "damage": 13 + }, + { + "id": "minecraft:arrow", + "damage": 14 + }, + { + "id": "minecraft:arrow", + "damage": 15 + }, + { + "id": "minecraft:arrow", + "damage": 16 + }, + { + "id": "minecraft:arrow", + "damage": 17 + }, + { + "id": "minecraft:arrow", + "damage": 18 + }, + { + "id": "minecraft:arrow", + "damage": 19 + }, + { + "id": "minecraft:arrow", + "damage": 20 + }, + { + "id": "minecraft:arrow", + "damage": 21 + }, + { + "id": "minecraft:arrow", + "damage": 22 + }, + { + "id": "minecraft:arrow", + "damage": 23 + }, + { + "id": "minecraft:arrow", + "damage": 24 + }, + { + "id": "minecraft:arrow", + "damage": 25 + }, + { + "id": "minecraft:arrow", + "damage": 26 + }, + { + "id": "minecraft:arrow", + "damage": 27 + }, + { + "id": "minecraft:arrow", + "damage": 28 + }, + { + "id": "minecraft:arrow", + "damage": 29 + }, + { + "id": "minecraft:arrow", + "damage": 30 + }, + { + "id": "minecraft:arrow", + "damage": 31 + }, + { + "id": "minecraft:arrow", + "damage": 32 + }, + { + "id": "minecraft:arrow", + "damage": 33 + }, + { + "id": "minecraft:arrow", + "damage": 34 + }, + { + "id": "minecraft:arrow", + "damage": 35 + }, + { + "id": "minecraft:arrow", + "damage": 36 + }, + { + "id": "minecraft:arrow", + "damage": 37 + }, + { + "id": "minecraft:arrow", + "damage": 38 + }, + { + "id": "minecraft:arrow", + "damage": 39 + }, + { + "id": "minecraft:arrow", + "damage": 40 + }, + { + "id": "minecraft:arrow", + "damage": 41 + }, + { + "id": "minecraft:arrow", + "damage": 42 + }, + { + "id": "minecraft:arrow", + "damage": 43 + }, + { + "id": "minecraft:shield" + }, + { + "id": "minecraft:cooked_chicken" + }, + { + "id": "minecraft:cooked_porkchop" + }, + { + "id": "minecraft:cooked_beef" + }, + { + "id": "minecraft:cooked_mutton" + }, + { + "id": "minecraft:cooked_rabbit" + }, + { + "id": "minecraft:cooked_cod" + }, + { + "id": "minecraft:cooked_salmon" + }, + { + "id": "minecraft:bread" + }, + { + "id": "minecraft:mushroom_stew" + }, + { + "id": "minecraft:beetroot_soup" + }, + { + "id": "minecraft:rabbit_stew" + }, + { + "id": "minecraft:baked_potato" + }, + { + "id": "minecraft:cookie" + }, + { + "id": "minecraft:pumpkin_pie" + }, + { + "id": "minecraft:cake" + }, + { + "id": "minecraft:dried_kelp" + }, + { + "id": "minecraft:fishing_rod" + }, + { + "id": "minecraft:carrot_on_a_stick" + }, + { + "id": "minecraft:warped_fungus_on_a_stick" + }, + { + "id": "minecraft:snowball" + }, + { + "id": "minecraft:shears" + }, + { + "id": "minecraft:flint_and_steel" + }, + { + "id": "minecraft:lead" + }, + { + "id": "minecraft:clock" + }, + { + "id": "minecraft:compass" + }, + { + "id": "minecraft:recovery_compass" + }, + { + "id": "minecraft:goat_horn" + }, + { + "id": "minecraft:goat_horn", + "damage": 1 + }, + { + "id": "minecraft:goat_horn", + "damage": 2 + }, + { + "id": "minecraft:goat_horn", + "damage": 3 + }, + { + "id": "minecraft:goat_horn", + "damage": 4 + }, + { + "id": "minecraft:goat_horn", + "damage": 5 + }, + { + "id": "minecraft:goat_horn", + "damage": 6 + }, + { + "id": "minecraft:goat_horn", + "damage": 7 + }, + { + "id": "minecraft:empty_map" + }, + { + "id": "minecraft:empty_map", + "damage": 2 + }, + { + "id": "minecraft:saddle" + }, + { + "id": "minecraft:leather_horse_armor" + }, + { + "id": "minecraft:iron_horse_armor" + }, + { + "id": "minecraft:golden_horse_armor" + }, + { + "id": "minecraft:diamond_horse_armor" + }, + { + "id": "minecraft:wolf_armor" + }, + { + "id": "minecraft:trident" + }, + { + "id": "minecraft:turtle_helmet" + }, + { + "id": "minecraft:elytra" + }, + { + "id": "minecraft:totem_of_undying" + }, + { + "id": "minecraft:glass_bottle" + }, + { + "id": "minecraft:experience_bottle" + }, + { + "id": "minecraft:potion" + }, + { + "id": "minecraft:potion", + "damage": 1 + }, + { + "id": "minecraft:potion", + "damage": 2 + }, + { + "id": "minecraft:potion", + "damage": 3 + }, + { + "id": "minecraft:potion", + "damage": 4 + }, + { + "id": "minecraft:potion", + "damage": 5 + }, + { + "id": "minecraft:potion", + "damage": 6 + }, + { + "id": "minecraft:potion", + "damage": 7 + }, + { + "id": "minecraft:potion", + "damage": 8 + }, + { + "id": "minecraft:potion", + "damage": 9 + }, + { + "id": "minecraft:potion", + "damage": 10 + }, + { + "id": "minecraft:potion", + "damage": 11 + }, + { + "id": "minecraft:potion", + "damage": 12 + }, + { + "id": "minecraft:potion", + "damage": 13 + }, + { + "id": "minecraft:potion", + "damage": 14 + }, + { + "id": "minecraft:potion", + "damage": 15 + }, + { + "id": "minecraft:potion", + "damage": 16 + }, + { + "id": "minecraft:potion", + "damage": 17 + }, + { + "id": "minecraft:potion", + "damage": 18 + }, + { + "id": "minecraft:potion", + "damage": 19 + }, + { + "id": "minecraft:potion", + "damage": 20 + }, + { + "id": "minecraft:potion", + "damage": 21 + }, + { + "id": "minecraft:potion", + "damage": 22 + }, + { + "id": "minecraft:potion", + "damage": 23 + }, + { + "id": "minecraft:potion", + "damage": 24 + }, + { + "id": "minecraft:potion", + "damage": 25 + }, + { + "id": "minecraft:potion", + "damage": 26 + }, + { + "id": "minecraft:potion", + "damage": 27 + }, + { + "id": "minecraft:potion", + "damage": 28 + }, + { + "id": "minecraft:potion", + "damage": 29 + }, + { + "id": "minecraft:potion", + "damage": 30 + }, + { + "id": "minecraft:potion", + "damage": 31 + }, + { + "id": "minecraft:potion", + "damage": 32 + }, + { + "id": "minecraft:potion", + "damage": 33 + }, + { + "id": "minecraft:potion", + "damage": 34 + }, + { + "id": "minecraft:potion", + "damage": 35 + }, + { + "id": "minecraft:potion", + "damage": 36 + }, + { + "id": "minecraft:potion", + "damage": 37 + }, + { + "id": "minecraft:potion", + "damage": 38 + }, + { + "id": "minecraft:potion", + "damage": 39 + }, + { + "id": "minecraft:potion", + "damage": 40 + }, + { + "id": "minecraft:potion", + "damage": 41 + }, + { + "id": "minecraft:potion", + "damage": 42 + }, + { + "id": "minecraft:splash_potion" + }, + { + "id": "minecraft:splash_potion", + "damage": 1 + }, + { + "id": "minecraft:splash_potion", + "damage": 2 + }, + { + "id": "minecraft:splash_potion", + "damage": 3 + }, + { + "id": "minecraft:splash_potion", + "damage": 4 + }, + { + "id": "minecraft:splash_potion", + "damage": 5 + }, + { + "id": "minecraft:splash_potion", + "damage": 6 + }, + { + "id": "minecraft:splash_potion", + "damage": 7 + }, + { + "id": "minecraft:splash_potion", + "damage": 8 + }, + { + "id": "minecraft:splash_potion", + "damage": 9 + }, + { + "id": "minecraft:splash_potion", + "damage": 10 + }, + { + "id": "minecraft:splash_potion", + "damage": 11 + }, + { + "id": "minecraft:splash_potion", + "damage": 12 + }, + { + "id": "minecraft:splash_potion", + "damage": 13 + }, + { + "id": "minecraft:splash_potion", + "damage": 14 + }, + { + "id": "minecraft:splash_potion", + "damage": 15 + }, + { + "id": "minecraft:splash_potion", + "damage": 16 + }, + { + "id": "minecraft:splash_potion", + "damage": 17 + }, + { + "id": "minecraft:splash_potion", + "damage": 18 + }, + { + "id": "minecraft:splash_potion", + "damage": 19 + }, + { + "id": "minecraft:splash_potion", + "damage": 20 + }, + { + "id": "minecraft:splash_potion", + "damage": 21 + }, + { + "id": "minecraft:splash_potion", + "damage": 22 + }, + { + "id": "minecraft:splash_potion", + "damage": 23 + }, + { + "id": "minecraft:splash_potion", + "damage": 24 + }, + { + "id": "minecraft:splash_potion", + "damage": 25 + }, + { + "id": "minecraft:splash_potion", + "damage": 26 + }, + { + "id": "minecraft:splash_potion", + "damage": 27 + }, + { + "id": "minecraft:splash_potion", + "damage": 28 + }, + { + "id": "minecraft:splash_potion", + "damage": 29 + }, + { + "id": "minecraft:splash_potion", + "damage": 30 + }, + { + "id": "minecraft:splash_potion", + "damage": 31 + }, + { + "id": "minecraft:splash_potion", + "damage": 32 + }, + { + "id": "minecraft:splash_potion", + "damage": 33 + }, + { + "id": "minecraft:splash_potion", + "damage": 34 + }, + { + "id": "minecraft:splash_potion", + "damage": 35 + }, + { + "id": "minecraft:splash_potion", + "damage": 36 + }, + { + "id": "minecraft:splash_potion", + "damage": 37 + }, + { + "id": "minecraft:splash_potion", + "damage": 38 + }, + { + "id": "minecraft:splash_potion", + "damage": 39 + }, + { + "id": "minecraft:splash_potion", + "damage": 40 + }, + { + "id": "minecraft:splash_potion", + "damage": 41 + }, + { + "id": "minecraft:splash_potion", + "damage": 42 + }, + { + "id": "minecraft:lingering_potion" + }, + { + "id": "minecraft:lingering_potion", + "damage": 1 + }, + { + "id": "minecraft:lingering_potion", + "damage": 2 + }, + { + "id": "minecraft:lingering_potion", + "damage": 3 + }, + { + "id": "minecraft:lingering_potion", + "damage": 4 + }, + { + "id": "minecraft:lingering_potion", + "damage": 5 + }, + { + "id": "minecraft:lingering_potion", + "damage": 6 + }, + { + "id": "minecraft:lingering_potion", + "damage": 7 + }, + { + "id": "minecraft:lingering_potion", + "damage": 8 + }, + { + "id": "minecraft:lingering_potion", + "damage": 9 + }, + { + "id": "minecraft:lingering_potion", + "damage": 10 + }, + { + "id": "minecraft:lingering_potion", + "damage": 11 + }, + { + "id": "minecraft:lingering_potion", + "damage": 12 + }, + { + "id": "minecraft:lingering_potion", + "damage": 13 + }, + { + "id": "minecraft:lingering_potion", + "damage": 14 + }, + { + "id": "minecraft:lingering_potion", + "damage": 15 + }, + { + "id": "minecraft:lingering_potion", + "damage": 16 + }, + { + "id": "minecraft:lingering_potion", + "damage": 17 + }, + { + "id": "minecraft:lingering_potion", + "damage": 18 + }, + { + "id": "minecraft:lingering_potion", + "damage": 19 + }, + { + "id": "minecraft:lingering_potion", + "damage": 20 + }, + { + "id": "minecraft:lingering_potion", + "damage": 21 + }, + { + "id": "minecraft:lingering_potion", + "damage": 22 + }, + { + "id": "minecraft:lingering_potion", + "damage": 23 + }, + { + "id": "minecraft:lingering_potion", + "damage": 24 + }, + { + "id": "minecraft:lingering_potion", + "damage": 25 + }, + { + "id": "minecraft:lingering_potion", + "damage": 26 + }, + { + "id": "minecraft:lingering_potion", + "damage": 27 + }, + { + "id": "minecraft:lingering_potion", + "damage": 28 + }, + { + "id": "minecraft:lingering_potion", + "damage": 29 + }, + { + "id": "minecraft:lingering_potion", + "damage": 30 + }, + { + "id": "minecraft:lingering_potion", + "damage": 31 + }, + { + "id": "minecraft:lingering_potion", + "damage": 32 + }, + { + "id": "minecraft:lingering_potion", + "damage": 33 + }, + { + "id": "minecraft:lingering_potion", + "damage": 34 + }, + { + "id": "minecraft:lingering_potion", + "damage": 35 + }, + { + "id": "minecraft:lingering_potion", + "damage": 36 + }, + { + "id": "minecraft:lingering_potion", + "damage": 37 + }, + { + "id": "minecraft:lingering_potion", + "damage": 38 + }, + { + "id": "minecraft:lingering_potion", + "damage": 39 + }, + { + "id": "minecraft:lingering_potion", + "damage": 40 + }, + { + "id": "minecraft:lingering_potion", + "damage": 41 + }, + { + "id": "minecraft:lingering_potion", + "damage": 42 + }, + { + "id": "minecraft:spyglass" + }, + { + "id": "minecraft:brush" + }, + { + "id": "minecraft:stick" + }, + { + "id": "minecraft:bed" + }, + { + "id": "minecraft:bed", + "damage": 8 + }, + { + "id": "minecraft:bed", + "damage": 7 + }, + { + "id": "minecraft:bed", + "damage": 15 + }, + { + "id": "minecraft:bed", + "damage": 12 + }, + { + "id": "minecraft:bed", + "damage": 14 + }, + { + "id": "minecraft:bed", + "damage": 1 + }, + { + "id": "minecraft:bed", + "damage": 4 + }, + { + "id": "minecraft:bed", + "damage": 5 + }, + { + "id": "minecraft:bed", + "damage": 13 + }, + { + "id": "minecraft:bed", + "damage": 9 + }, + { + "id": "minecraft:bed", + "damage": 3 + }, + { + "id": "minecraft:bed", + "damage": 11 + }, + { + "id": "minecraft:bed", + "damage": 10 + }, + { + "id": "minecraft:bed", + "damage": 2 + }, + { + "id": "minecraft:bed", + "damage": 6 + }, + { + "id": "minecraft:torch", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnRvcmNoBAkAbmFtZV9oYXNoagn7rmDBzisDCgBuZXR3b3JrX2lk+BwwuQoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:soul_torch", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNvdWxfdG9yY2gECQBuYW1lX2hhc2huixOT04BRdQMKAG5ldHdvcmtfaWShbFILCgYAc3RhdGVzCBYAdG9yY2hfZmFjaW5nX2RpcmVjdGlvbgcAdW5rbm93bgADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:sea_pickle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAQAACAQAbmFtZRQAbWluZWNyYWZ0OnNlYV9waWNrbGUECQBuYW1lX2hhc2iONEfZJB+glgMKAG5ldHdvcmtfaWSINWQyCgYAc3RhdGVzAw0AY2x1c3Rlcl9jb3VudAAAAAABCABkZWFkX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:lantern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAQAACAQAbmFtZREAbWluZWNyYWZ0OmxhbnRlcm4ECQBuYW1lX2hhc2hMw44VI2HWygMKAG5ldHdvcmtfaWRkjQvzCgYAc3RhdGVzAQcAaGFuZ2luZwAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:soul_lantern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNvdWxfbGFudGVybgQJAG5hbWVfaGFzaGjIpjxk9z+RAwoAbmV0d29ya19pZGfoP8cKBgBzdGF0ZXMBBwBoYW5naW5nAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZHsBMA0KBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:white_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhbmRsZQQJAG5hbWVfaGFzaN1EG5Q1mHiEAwoAbmV0d29ya19pZKN1mmgKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:orange_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSdAgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYW5kbGUECQBuYW1lX2hhc2jySEVWHgUIHQMKAG5ldHdvcmtfaWSfVz82CgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:magenta_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FuZGxlBAkAbmFtZV9oYXNoG0u6YIOoBSEDCgBuZXR3b3JrX2lk9xGNkQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:light_blue_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FuZGxlBAkAbmFtZV9oYXNocXGeK0zgrG0DCgBuZXR3b3JrX2lk2m1y8goGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:yellow_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYW5kbGUECQBuYW1lX2hhc2i00dtusU3CqQMKAG5ldHdvcmtfaWR9LTmpCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:lime_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FuZGxlBAkAbmFtZV9oYXNokcmrw5xvz7ADCgBuZXR3b3JrX2lkIAUu6QoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:pink_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FuZGxlBAkAbmFtZV9oYXNoQJdEY4sZ0dwDCgBuZXR3b3JrX2lk23Rn5AoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:gray_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FuZGxlBAkAbmFtZV9oYXNoS5poSo9wBDEDCgBuZXR3b3JrX2lk3trRCAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:light_gray_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FuZGxlBAkAbmFtZV9oYXNo9ruTZLBNMasDCgBuZXR3b3JrX2lkb6DOegoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cyan_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FuZGxlBAkAbmFtZV9oYXNoc/M8PNVcjOwDCgBuZXR3b3JrX2lkZoIQOQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:purple_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYW5kbGUECQBuYW1lX2hhc2jaI3xUW0/myQMKAG5ldHdvcmtfaWSnLI2BCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:blue_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FuZGxlBAkAbmFtZV9oYXNoAASSPW6TgQADCgBuZXR3b3JrX2lkrxrjQAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:brown_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhbmRsZQQJAG5hbWVfaGFzaDia0l6s1+WYAwoAbmV0d29ya19pZKSkBXYKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:green_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhbmRsZQQJAG5hbWVfaGFzaLeFPO1l+fIoAwoAbmV0d29ya19pZBkznDsKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:red_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYW5kbGUECQBuYW1lX2hhc2jjAQpGf59ZdwMKAG5ldHdvcmtfaWRbb88GCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:black_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhbmRsZQQJAG5hbWVfaGFzaB+wRDpOqREKAwoAbmV0d29ya19pZNnOnuEKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crafting_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AAAACAQAbmFtZRgAbWluZWNyYWZ0OmNyYWZ0aW5nX3RhYmxlBAkAbmFtZV9oYXNoe76VAmjvbpYDCgBuZXR3b3JrX2lkwCxwaAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cartography_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAQAACAQAbmFtZRsAbWluZWNyYWZ0OmNhcnRvZ3JhcGh5X3RhYmxlBAkAbmFtZV9oYXNomaWiiD/znP8DCgBuZXR3b3JrX2lkI6FzMwoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:fletching_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAQAACAQAbmFtZRkAbWluZWNyYWZ0OmZsZXRjaGluZ190YWJsZQQJAG5hbWVfaGFzaPFibh8unKyUAwoAbmV0d29ya19pZJ2mW0oKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:smithing_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAQAACAQAbmFtZRgAbWluZWNyYWZ0OnNtaXRoaW5nX3RhYmxlBAkAbmFtZV9oYXNo4tFES2xOXEYDCgBuZXR3b3JrX2lkXWMBzQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:beehive", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAQAACAQAbmFtZREAbWluZWNyYWZ0OmJlZWhpdmUECQBuYW1lX2hhc2hCcqn12UbNpwMKAG5ldHdvcmtfaWR/idcaCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAMLAGhvbmV5X2xldmVsAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:suspicious_sand", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAwAACAQAbmFtZRkAbWluZWNyYWZ0OnN1c3BpY2lvdXNfc2FuZAQJAG5hbWVfaGFzaL67QsuvLP00AwoAbmV0d29ya19pZKnkaIAKBgBzdGF0ZXMDEABicnVzaGVkX3Byb2dyZXNzAAAAAAEHAGhhbmdpbmcBAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:suspicious_gravel", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AwAACAQAbmFtZRsAbWluZWNyYWZ0OnN1c3BpY2lvdXNfZ3JhdmVsBAkAbmFtZV9oYXNoJSVbGNk7C3oDCgBuZXR3b3JrX2lkvIEJAAoGAHN0YXRlcwMQAGJydXNoZWRfcHJvZ3Jlc3MAAAAAAQcAaGFuZ2luZwEAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:campfire" + }, + { + "id": "minecraft:soul_campfire" + }, + { + "id": "minecraft:furnace", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AAAACAQAbmFtZREAbWluZWNyYWZ0OmZ1cm5hY2UECQBuYW1lX2hhc2ioOQrludYY8wMKAG5ldHdvcmtfaWRZxnDOCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:blast_furnace", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAQAACAQAbmFtZRcAbWluZWNyYWZ0OmJsYXN0X2Z1cm5hY2UECQBuYW1lX2hhc2ivDbnjkpGm5QMKAG5ldHdvcmtfaWTcEbV/CgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:smoker", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAQAACAQAbmFtZRAAbWluZWNyYWZ0OnNtb2tlcgQJAG5hbWVfaGFzaJd1rDMkRWomAwoAbmV0d29ya19pZGWswMwKBgBzdGF0ZXMIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:respawn_anchor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlc3Bhd25fYW5jaG9yBAkAbmFtZV9oYXNoZOdcjW05qigDCgBuZXR3b3JrX2lkmhMcaQoGAHN0YXRlcwMVAHJlc3Bhd25fYW5jaG9yX2NoYXJnZQAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:brewing_stand" + }, + { + "id": "minecraft:anvil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lk8Z3VowoGAHN0YXRlcwgGAGRhbWFnZQkAdW5kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:anvil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkpiv8BAoGAHN0YXRlcwgGAGRhbWFnZRAAc2xpZ2h0bHlfZGFtYWdlZAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:anvil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkFu+pdwoGAHN0YXRlcwgGAGRhbWFnZQwAdmVyeV9kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:grindstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAQAACAQAbmFtZRQAbWluZWNyYWZ0OmdyaW5kc3RvbmUECQBuYW1lX2hhc2id56zc0nk99wMKAG5ldHdvcmtfaWS4Es07CgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:enchanting_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuY2hhbnRpbmdfdGFibGUECQBuYW1lX2hhc2jgIx24VLvMvwMKAG5ldHdvcmtfaWRliFFJCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bookshelf", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAAAACAQAbmFtZRMAbWluZWNyYWZ0OmJvb2tzaGVsZgQJAG5hbWVfaGFzaDU04DrgJCS9AwoAbmV0d29ya19pZBcWwIwKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:chiseled_bookshelf", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAwAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2Jvb2tzaGVsZgQJAG5hbWVfaGFzaNXDBnsIsywYAwoAbmV0d29ya19pZIprt5IKBgBzdGF0ZXMDDABib29rc19zdG9yZWQAAAAAAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:lectern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTBAQAACAQAbmFtZREAbWluZWNyYWZ0OmxlY3Rlcm4ECQBuYW1lX2hhc2j5Z4Mmi/1QxAMKAG5ldHdvcmtfaWR4JfDHCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cauldron" + }, + { + "id": "minecraft:composter", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvbXBvc3RlcgQJAG5hbWVfaGFzaPAADHptzeWJAwoAbmV0d29ya19pZHIL6i4KBgBzdGF0ZXMDFABjb21wb3N0ZXJfZmlsbF9sZXZlbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:chest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AAAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkDkOFvAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:trapped_chest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyYXBwZWRfY2hlc3QECQBuYW1lX2hhc2g2qpF9stsEjgMKAG5ldHdvcmtfaWTjJWYxCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAbm9ydGgAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:ender_chest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVuZGVyX2NoZXN0BAkAbmFtZV9oYXNohEZzOFdg0WUDCgBuZXR3b3JrX2lkx4jiSQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:barrel", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhcnJlbAQJAG5hbWVfaGFzaHDkRPGymiRqAwoAbmV0d29ya19pZPnxzgsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:undyed_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAAAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZJ8rxp0KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:white_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAAAACAQAbmFtZRsAbWluZWNyYWZ0OndoaXRlX3NodWxrZXJfYm94BAkAbmFtZV9oYXNosK79m1rPUBwDCgBuZXR3b3JrX2lkjrET6goGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:light_gray_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iBe5zq7PxHmgMKAG5ldHdvcmtfaWSCVJv0CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:gray_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2ga2s8ctjHUhgMKAG5ldHdvcmtfaWS3WMsWCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:black_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoPm03OZphrp8DCgBuZXR3b3JrX2lkXHztNAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:brown_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJyb3duX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoT3DD6qAL9cADCgBuZXR3b3JrX2lkaXxpYQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:red_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAwAACAQAbmFtZRkAbWluZWNyYWZ0OnJlZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaMIlKSCzqSZoAwoAbmV0d29ya19pZNrf+icKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:orange_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAwAACAQAbmFtZRwAbWluZWNyYWZ0Om9yYW5nZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaG2MAXU67wGrAwoAbmV0d29ya19pZGoO05gKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:yellow_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAwAACAQAbmFtZRwAbWluZWNyYWZ0OnllbGxvd19zaHVsa2VyX2JveAQJAG5hbWVfaGFzaIsLwQHYjcIEAwoAbmV0d29ya19pZBCBSiYKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:lime_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAwAACAQAbmFtZRoAbWluZWNyYWZ0OmxpbWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hUwBkg+faUGAMKAG5ldHdvcmtfaWRJeKqqCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:green_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAwAACAQAbmFtZRsAbWluZWNyYWZ0OmdyZWVuX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoZgUeT3LupLUDCgBuZXR3b3JrX2lkzJiohQoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:cyan_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAwAACAQAbmFtZRoAbWluZWNyYWZ0OmN5YW5fc2h1bGtlcl9ib3gECQBuYW1lX2hhc2gSfbjteXg5yAMKAG5ldHdvcmtfaWTHeliECgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:light_blue_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2h0VFCX0qsRxQMKAG5ldHdvcmtfaWQXD8U0CgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:blue_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hn9gS0XIe6rAMKAG5ldHdvcmtfaWTO4PJaCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:purple_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAwAACAQAbmFtZRwAbWluZWNyYWZ0OnB1cnBsZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaEV/lkNPxRDdAwoAbmV0d29ya19pZFK25GAKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:magenta_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAwAACAQAbmFtZR0AbWluZWNyYWZ0Om1hZ2VudGFfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iqWM7IJHxcFgMKAG5ldHdvcmtfaWTyyudTCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:pink_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBpbmtfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2in1tkJ1GNcZgMKAG5ldHdvcmtfaWQOEGXjCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:armor_stand" + }, + { + "id": "minecraft:noteblock", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAAAACAQAbmFtZRMAbWluZWNyYWZ0Om5vdGVibG9jawQJAG5hbWVfaGFzaHPA8dBBH0UaAwoAbmV0d29ya19pZH1U5QkKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:jukebox", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAAAACAQAbmFtZREAbWluZWNyYWZ0Omp1a2Vib3gECQBuYW1lX2hhc2ieAIPExf/ZfgMKAG5ldHdvcmtfaWSmR7JfCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:music_disc_13" + }, + { + "id": "minecraft:music_disc_cat" + }, + { + "id": "minecraft:music_disc_blocks" + }, + { + "id": "minecraft:music_disc_chirp" + }, + { + "id": "minecraft:music_disc_far" + }, + { + "id": "minecraft:music_disc_mall" + }, + { + "id": "minecraft:music_disc_mellohi" + }, + { + "id": "minecraft:music_disc_stal" + }, + { + "id": "minecraft:music_disc_strad" + }, + { + "id": "minecraft:music_disc_ward" + }, + { + "id": "minecraft:music_disc_11" + }, + { + "id": "minecraft:music_disc_wait" + }, + { + "id": "minecraft:music_disc_otherside" + }, + { + "id": "minecraft:music_disc_5" + }, + { + "id": "minecraft:music_disc_pigstep" + }, + { + "id": "minecraft:music_disc_relic" + }, + { + "id": "minecraft:disc_fragment_5" + }, + { + "id": "minecraft:glowstone_dust" + }, + { + "id": "minecraft:glowstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAAAACAQAbmFtZRMAbWluZWNyYWZ0Omdsb3dzdG9uZQQJAG5hbWVfaGFzaFYqXNkefIlPAwoAbmV0d29ya19pZGT7WYYKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:redstone_lamp", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZHN0b25lX2xhbXAECQBuYW1lX2hhc2hJ9V80caPvEgMKAG5ldHdvcmtfaWRvNPwnCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:sea_lantern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNlYV9sYW50ZXJuBAkAbmFtZV9oYXNoLPsv1TX9M+QDCgBuZXR3b3JrX2lk1PPVyAoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:oak_sign" + }, + { + "id": "minecraft:spruce_sign" + }, + { + "id": "minecraft:birch_sign" + }, + { + "id": "minecraft:jungle_sign" + }, + { + "id": "minecraft:acacia_sign" + }, + { + "id": "minecraft:dark_oak_sign" + }, + { + "id": "minecraft:mangrove_sign" + }, + { + "id": "minecraft:cherry_sign" + }, + { + "id": "minecraft:bamboo_sign" + }, + { + "id": "minecraft:crimson_sign" + }, + { + "id": "minecraft:warped_sign" + }, + { + "id": "minecraft:oak_hanging_sign" + }, + { + "id": "minecraft:spruce_hanging_sign" + }, + { + "id": "minecraft:birch_hanging_sign" + }, + { + "id": "minecraft:jungle_hanging_sign" + }, + { + "id": "minecraft:acacia_hanging_sign" + }, + { + "id": "minecraft:dark_oak_hanging_sign" + }, + { + "id": "minecraft:mangrove_hanging_sign" + }, + { + "id": "minecraft:cherry_hanging_sign" + }, + { + "id": "minecraft:bamboo_hanging_sign" + }, + { + "id": "minecraft:crimson_hanging_sign" + }, + { + "id": "minecraft:warped_hanging_sign" + }, + { + "id": "minecraft:painting" + }, + { + "id": "minecraft:frame" + }, + { + "id": "minecraft:glow_frame" + }, + { + "id": "minecraft:honey_bottle" + }, + { + "id": "minecraft:flower_pot" + }, + { + "id": "minecraft:bowl" + }, + { + "id": "minecraft:bucket" + }, + { + "id": "minecraft:milk_bucket" + }, + { + "id": "minecraft:water_bucket" + }, + { + "id": "minecraft:lava_bucket" + }, + { + "id": "minecraft:cod_bucket" + }, + { + "id": "minecraft:salmon_bucket" + }, + { + "id": "minecraft:tropical_fish_bucket" + }, + { + "id": "minecraft:pufferfish_bucket" + }, + { + "id": "minecraft:powder_snow_bucket" + }, + { + "id": "minecraft:axolotl_bucket" + }, + { + "id": "minecraft:tadpole_bucket" + }, + { + "id": "minecraft:skull", + "damage": 3 + }, + { + "id": "minecraft:skull", + "damage": 2 + }, + { + "id": "minecraft:skull", + "damage": 4 + }, + { + "id": "minecraft:skull", + "damage": 5 + }, + { + "id": "minecraft:skull" + }, + { + "id": "minecraft:skull", + "damage": 1 + }, + { + "id": "minecraft:skull", + "damage": 6 + }, + { + "id": "minecraft:beacon", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAAAACAQAbmFtZRAAbWluZWNyYWZ0OmJlYWNvbgQJAG5hbWVfaGFzaACwhhfSkdkHAwoAbmV0d29ya19pZF8jfiEKBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:bell", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAQAACAQAbmFtZQ4AbWluZWNyYWZ0OmJlbGwECQBuYW1lX2hhc2iPqsgDXRcsxAMKAG5ldHdvcmtfaWT7zhOoCgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAQoAdG9nZ2xlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:conduit", + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAQAACAQAbmFtZREAbWluZWNyYWZ0OmNvbmR1aXQECQBuYW1lX2hhc2jqxKAxq2EaWQMKAG5ldHdvcmtfaWTWcBVnCgYAc3RhdGVzAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stonecutter_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lY3V0dGVyX2Jsb2NrBAkAbmFtZV9oYXNoQAXTbAM3MeYDCgBuZXR3b3JrX2lkWS4RjAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:coal" + }, + { + "id": "minecraft:charcoal" + }, + { + "id": "minecraft:diamond" + }, + { + "id": "minecraft:iron_nugget" + }, + { + "id": "minecraft:raw_iron" + }, + { + "id": "minecraft:raw_gold" + }, + { + "id": "minecraft:raw_copper" + }, + { + "id": "minecraft:copper_ingot" + }, + { + "id": "minecraft:iron_ingot" + }, + { + "id": "minecraft:netherite_scrap" + }, + { + "id": "minecraft:netherite_ingot" + }, + { + "id": "minecraft:gold_nugget" + }, + { + "id": "minecraft:gold_ingot" + }, + { + "id": "minecraft:emerald" + }, + { + "id": "minecraft:quartz" + }, + { + "id": "minecraft:clay_ball" + }, + { + "id": "minecraft:brick" + }, + { + "id": "minecraft:netherbrick" + }, + { + "id": "minecraft:prismarine_shard" + }, + { + "id": "minecraft:amethyst_shard" + }, + { + "id": "minecraft:prismarine_crystals" + }, + { + "id": "minecraft:nautilus_shell" + }, + { + "id": "minecraft:heart_of_the_sea" + }, + { + "id": "minecraft:turtle_scute" + }, + { + "id": "minecraft:armadillo_scute" + }, + { + "id": "minecraft:phantom_membrane" + }, + { + "id": "minecraft:string" + }, + { + "id": "minecraft:feather" + }, + { + "id": "minecraft:flint" + }, + { + "id": "minecraft:gunpowder" + }, + { + "id": "minecraft:leather" + }, + { + "id": "minecraft:rabbit_hide" + }, + { + "id": "minecraft:rabbit_foot" + }, + { + "id": "minecraft:fire_charge" + }, + { + "id": "minecraft:blaze_rod" + }, + { + "id": "minecraft:blaze_powder" + }, + { + "id": "minecraft:magma_cream" + }, + { + "id": "minecraft:fermented_spider_eye" + }, + { + "id": "minecraft:echo_shard" + }, + { + "id": "minecraft:dragon_breath" + }, + { + "id": "minecraft:shulker_shell" + }, + { + "id": "minecraft:ghast_tear" + }, + { + "id": "minecraft:slime_ball" + }, + { + "id": "minecraft:ender_pearl" + }, + { + "id": "minecraft:ender_eye" + }, + { + "id": "minecraft:nether_star" + }, + { + "id": "minecraft:end_rod", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAAAACAQAbmFtZREAbWluZWNyYWZ0OmVuZF9yb2QECQBuYW1lX2hhc2jx/q5cEA0hmQMKAG5ldHdvcmtfaWQ2eM8kCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:lightning_rod", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpZ2h0bmluZ19yb2QECQBuYW1lX2hhc2ioXQF1xvfHNQMKAG5ldHdvcmtfaWRLuHyACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:end_crystal" + }, + { + "id": "minecraft:paper" + }, + { + "id": "minecraft:book" + }, + { + "id": "minecraft:writable_book" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:oak_boat" + }, + { + "id": "minecraft:spruce_boat" + }, + { + "id": "minecraft:birch_boat" + }, + { + "id": "minecraft:jungle_boat" + }, + { + "id": "minecraft:acacia_boat" + }, + { + "id": "minecraft:dark_oak_boat" + }, + { + "id": "minecraft:mangrove_boat" + }, + { + "id": "minecraft:cherry_boat" + }, + { + "id": "minecraft:bamboo_raft" + }, + { + "id": "minecraft:oak_chest_boat" + }, + { + "id": "minecraft:spruce_chest_boat" + }, + { + "id": "minecraft:birch_chest_boat" + }, + { + "id": "minecraft:jungle_chest_boat" + }, + { + "id": "minecraft:acacia_chest_boat" + }, + { + "id": "minecraft:dark_oak_chest_boat" + }, + { + "id": "minecraft:mangrove_chest_boat" + }, + { + "id": "minecraft:cherry_chest_boat" + }, + { + "id": "minecraft:bamboo_chest_raft" + }, + { + "id": "minecraft:rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWR+Sp6YCgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:golden_rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdvbGRlbl9yYWlsBAkAbmFtZV9oYXNoOoV5MaKipoUDCgBuZXR3b3JrX2lkfAcxLwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:detector_rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAAAACAQAbmFtZRcAbWluZWNyYWZ0OmRldGVjdG9yX3JhaWwECQBuYW1lX2hhc2gVUk31qOysUQMKAG5ldHdvcmtfaWRVW/aICgYAc3RhdGVzAQ0AcmFpbF9kYXRhX2JpdAADDgByYWlsX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:activator_rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjdGl2YXRvcl9yYWlsBAkAbmFtZV9oYXNosIL91qriCRkDCgBuZXR3b3JrX2lkZfckmwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:minecart" + }, + { + "id": "minecraft:chest_minecart" + }, + { + "id": "minecraft:hopper_minecart" + }, + { + "id": "minecraft:tnt_minecart" + }, + { + "id": "minecraft:redstone" + }, + { + "id": "minecraft:redstone_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX2Jsb2NrBAkAbmFtZV9oYXNoRhULL0r8o0sDCgBuZXR3b3JrX2lklayOHgoGAHN0YXRlcwADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:redstone_torch", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX3RvcmNoBAkAbmFtZV9oYXNoizFRjpYMIDgDCgBuZXR3b3JrX2lkuHz7yAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:lever", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxldmVyBAkAbmFtZV9oYXNoGMJeLJsUMLYDCgBuZXR3b3JrX2lkEF/GuAoGAHN0YXRlcwgPAGxldmVyX2RpcmVjdGlvbg4AZG93bl9lYXN0X3dlc3QBCABvcGVuX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:wooden_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAAAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWSU07kYCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:spruce_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAQAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9idXR0b24ECQBuYW1lX2hhc2jBW9Z8aYE7YQMKAG5ldHdvcmtfaWTkUIGuCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:birch_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAQAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2J1dHRvbgQJAG5hbWVfaGFzaJXYgGuSHbTwAwoAbmV0d29ya19pZGWp3yoKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:jungle_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAQAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9idXR0b24ECQBuYW1lX2hhc2iCgNANcJs+BQMKAG5ldHdvcmtfaWT9fImWCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:acacia_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAQAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9idXR0b24ECQBuYW1lX2hhc2gVvmcT7LTO0wMKAG5ldHdvcmtfaWRQnxIJCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dark_oak_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAQAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaIV10ZGGrCIEAwoAbmV0d29ya19pZN5vAmIKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mangrove_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2J1dHRvbgQJAG5hbWVfaGFzaNzeYYKLgOzJAwoAbmV0d29ya19pZAFEGQ0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cherry_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9idXR0b24ECQBuYW1lX2hhc2j2/IHjeAbUcwMKAG5ldHdvcmtfaWRJ1irQCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bamboo_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19idXR0b24ECQBuYW1lX2hhc2j7AddMi+6nsgMKAG5ldHdvcmtfaWSa9w4/CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2J1dHRvbgQJAG5hbWVfaGFzaM4ejMctmvohAwoAbmV0d29ya19pZMw+aC0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:crimson_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fYnV0dG9uBAkAbmFtZV9oYXNofnjYHaYIeWgDCgBuZXR3b3JrX2lk+n1vyQoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:warped_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9idXR0b24ECQBuYW1lX2hhc2jwkV2EU6Cn1QMKAG5ldHdvcmtfaWTnHnk1CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:polished_blackstone_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnV0dG9uBAkAbmFtZV9oYXNojmxzQKS0S/EDCgBuZXR3b3JrX2lkDtQ95woGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:tripwire_hook", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaXB3aXJlX2hvb2sECQBuYW1lX2hhc2gQdp+oGZLNnAMKAG5ldHdvcmtfaWSy+1KJCgYAc3RhdGVzAQwAYXR0YWNoZWRfYml0AAMJAGRpcmVjdGlvbgAAAAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:wooden_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAAAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZDRzPNwKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:spruce_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAQAACAQAbmFtZR8AbWluZWNyYWZ0OnNwcnVjZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNmwuq549fJKAwoAbmV0d29ya19pZLQMCw0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:birch_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAQAACAQAbmFtZR4AbWluZWNyYWZ0OmJpcmNoX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNorQkT9kDdlTwDCgBuZXR3b3JrX2lkH0G97AoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:jungle_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAQAACAQAbmFtZR8AbWluZWNyYWZ0Omp1bmdsZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaJ7DcteCkb8/AwoAbmV0d29ya19pZLdPBSAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:acacia_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAQAACAQAbmFtZR8AbWluZWNyYWZ0OmFjYWNpYV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaC2frZtfoYqCAwoAbmV0d29ya19pZIDdI18KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:dark_oak_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAQAACAQAbmFtZSEAbWluZWNyYWZ0OmRhcmtfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoHUCJsTy52pwDCgBuZXR3b3JrX2lkKpi8rAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:mangrove_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hbmdyb3ZlX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoiDsTfJaX100DCgBuZXR3b3JrX2lkuwWDyQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:cherry_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAwAACAQAbmFtZR8AbWluZWNyYWZ0OmNoZXJyeV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaALMqYEZDUQHAwoAbmV0d29ya19pZPNT+r0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:bamboo_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJhbWJvb19wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNvxJ7NIAaqlAwoAbmV0d29ya19pZIZ8XnYKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:crimson_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNyaW1zb25fcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2hqBDVDAd31/gMKAG5ldHdvcmtfaWRmV18LCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:warped_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAgAACAQAbmFtZR8AbWluZWNyYWZ0OndhcnBlZF9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaBxFoQksWtYUAwoAbmV0d29ya19pZJVRoIcKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:stone_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0b25lX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNounJuTBUTrU8DCgBuZXR3b3JrX2lkjDydwQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:light_weighted_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAAAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoOyOJkNxLtkEDCgBuZXR3b3JrX2lkrr2AjgoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:heavy_weighted_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAAAACAQAbmFtZScAbWluZWNyYWZ0OmhlYXZ5X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoltgDmDvTajUDCgBuZXR3b3JrX2lkFxVKuQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:polished_blackstone_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAgAACAQAbmFtZSwAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2h65Ci6/CeGqwMKAG5ldHdvcmtfaWTaSW5xCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:observer", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2VydmVyBAkAbmFtZV9oYXNoYhlh1lpmHTgDCgBuZXR3b3JrX2lkQEh55goGAHN0YXRlcwgaAG1pbmVjcmFmdDpmYWNpbmdfZGlyZWN0aW9uBABkb3duAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:daylight_detector", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAAAACAQAbmFtZRsAbWluZWNyYWZ0OmRheWxpZ2h0X2RldGVjdG9yBAkAbmFtZV9oYXNoV0F0s7B7PVgDCgBuZXR3b3JrX2lkri5afQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:repeater" + }, + { + "id": "minecraft:comparator" + }, + { + "id": "minecraft:hopper" + }, + { + "id": "minecraft:dropper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AAAACAQAbmFtZREAbWluZWNyYWZ0OmRyb3BwZXIECQBuYW1lX2hhc2joXP7XqU0l3QMKAG5ldHdvcmtfaWQfQN6zCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgMAAAABDQB0cmlnZ2VyZWRfYml0AAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:dispenser", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRpc3BlbnNlcgQJAG5hbWVfaGFzaP1RR+zAbYP2AwoAbmV0d29ya19pZGAayD0KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAwAAAAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24DUBQBAA==" + }, + { + "id": "minecraft:piston", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBpc3RvbgQJAG5hbWVfaGFzaDs3AFh1fL0uAwoAbmV0d29ya19pZLD/5XQKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAQAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:sticky_piston", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQdAAAACAQAbmFtZRcAbWluZWNyYWZ0OnN0aWNreV9waXN0b24ECQBuYW1lX2hhc2hPFJFJSiJ0ZQMKAG5ldHdvcmtfaWT/MzCJCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgEAAAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:tnt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAAAACAQAbmFtZQ0AbWluZWNyYWZ0OnRudAQJAG5hbWVfaGFzaEYOHwCvJH29AwoAbmV0d29ya19pZCGfjU4KBgBzdGF0ZXMBFABhbGxvd191bmRlcndhdGVyX2JpdAABCwBleHBsb2RlX2JpdAAAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:name_tag" + }, + { + "id": "minecraft:loom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAQAACAQAbmFtZQ4AbWluZWNyYWZ0Omxvb20ECQBuYW1lX2hhc2i7DKjAXNq8TAMKAG5ldHdvcmtfaWR/49HXCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:banner", + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 8, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 7, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 15, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 12, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 14, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 1, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 4, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 5, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 13, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 9, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 3, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 11, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 10, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 2, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 6, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 15, + "nbt_b64": "CgAAAwQAVHlwZQEAAAAA" + }, + { + "id": "minecraft:creeper_banner_pattern" + }, + { + "id": "minecraft:skull_banner_pattern" + }, + { + "id": "minecraft:flower_banner_pattern" + }, + { + "id": "minecraft:mojang_banner_pattern" + }, + { + "id": "minecraft:field_masoned_banner_pattern" + }, + { + "id": "minecraft:bordure_indented_banner_pattern" + }, + { + "id": "minecraft:piglin_banner_pattern" + }, + { + "id": "minecraft:globe_banner_pattern" + }, + { + "id": "minecraft:angler_pottery_sherd" + }, + { + "id": "minecraft:archer_pottery_sherd" + }, + { + "id": "minecraft:arms_up_pottery_sherd" + }, + { + "id": "minecraft:blade_pottery_sherd" + }, + { + "id": "minecraft:brewer_pottery_sherd" + }, + { + "id": "minecraft:burn_pottery_sherd" + }, + { + "id": "minecraft:danger_pottery_sherd" + }, + { + "id": "minecraft:explorer_pottery_sherd" + }, + { + "id": "minecraft:friend_pottery_sherd" + }, + { + "id": "minecraft:heart_pottery_sherd" + }, + { + "id": "minecraft:heartbreak_pottery_sherd" + }, + { + "id": "minecraft:howl_pottery_sherd" + }, + { + "id": "minecraft:miner_pottery_sherd" + }, + { + "id": "minecraft:mourner_pottery_sherd" + }, + { + "id": "minecraft:plenty_pottery_sherd" + }, + { + "id": "minecraft:prize_pottery_sherd" + }, + { + "id": "minecraft:sheaf_pottery_sherd" + }, + { + "id": "minecraft:shelter_pottery_sherd" + }, + { + "id": "minecraft:skull_pottery_sherd" + }, + { + "id": "minecraft:snort_pottery_sherd" + }, + { + "id": "minecraft:netherite_upgrade_smithing_template" + }, + { + "id": "minecraft:sentry_armor_trim_smithing_template" + }, + { + "id": "minecraft:vex_armor_trim_smithing_template" + }, + { + "id": "minecraft:wild_armor_trim_smithing_template" + }, + { + "id": "minecraft:coast_armor_trim_smithing_template" + }, + { + "id": "minecraft:dune_armor_trim_smithing_template" + }, + { + "id": "minecraft:wayfinder_armor_trim_smithing_template" + }, + { + "id": "minecraft:shaper_armor_trim_smithing_template" + }, + { + "id": "minecraft:raiser_armor_trim_smithing_template" + }, + { + "id": "minecraft:host_armor_trim_smithing_template" + }, + { + "id": "minecraft:ward_armor_trim_smithing_template" + }, + { + "id": "minecraft:silence_armor_trim_smithing_template" + }, + { + "id": "minecraft:tide_armor_trim_smithing_template" + }, + { + "id": "minecraft:snout_armor_trim_smithing_template" + }, + { + "id": "minecraft:rib_armor_trim_smithing_template" + }, + { + "id": "minecraft:eye_armor_trim_smithing_template" + }, + { + "id": "minecraft:spire_armor_trim_smithing_template" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_star", + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 8, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 7, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 15, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 12, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 14, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 1, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 4, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 5, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 13, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 9, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 3, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 11, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 10, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 2, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 6, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" + }, + { + "id": "minecraft:chain" + }, + { + "id": "minecraft:target", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAQAACAQAbmFtZRAAbWluZWNyYWZ0OnRhcmdldAQJAG5hbWVfaGFzaJc66SVbYlaxAwoAbmV0d29ya19pZPBozs0KBgBzdGF0ZXMAAwcAdmVyc2lvbgNQFAEA" + }, + { + "id": "minecraft:decorated_pot", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAwAACAQAbmFtZRcAbWluZWNyYWZ0OmRlY29yYXRlZF9wb3QECQBuYW1lX2hhc2jjQgckn8VTvwMKAG5ldHdvcmtfaWRwvkUUCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uA1AUAQA=" + }, + { + "id": "minecraft:lodestone_compass" + }, + { + "id": "minecraft:wither_spawn_egg" + }, + { + "id": "minecraft:ender_dragon_spawn_egg" + } + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/entity_identifiers.dat b/core/src/main/resources/bedrock/entity_identifiers.dat index 9a986cf5c435ac467cac73c25a0ba160cbfbb0be..9a123f8d8834e6af5c98b000778665b6e2022887 100644 GIT binary patch delta 62 zcmX?S+i%Cq#lXpynUa%PT*CE@ak3+$#N;#F+#3y|$w#lXpynUa%PT*CE*ak3+$#N;#F+#3y| Date: Tue, 23 Apr 2024 12:34:24 -0400 Subject: [PATCH 036/897] Serialize disconnects --- .../main/java/org/geysermc/geyser/network/CodecProcessor.java | 1 - 1 file changed, 1 deletion(-) 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 4ad02a644..0516b1601 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -261,7 +261,6 @@ class CodecProcessor { .updateSerializer(ScriptMessagePacket.class, ILLEGAL_SERIALIZER) // // Ignored bidirectional packets .updateSerializer(ClientCacheStatusPacket.class, IGNORED_SERIALIZER) - .updateSerializer(DisconnectPacket.class, IGNORED_SERIALIZER) .updateSerializer(SimpleEventPacket.class, IGNORED_SERIALIZER) .updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER) .updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER) From 3bd5ab7f35c52d9a76990cedc30151b03b402a82 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:23:09 -0700 Subject: [PATCH 037/897] Use old SetEntityMotionSerializer for codec < 662 (#4593) --- .../geyser/network/CodecProcessor.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) 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 0516b1601..6bd767fb7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -33,6 +33,7 @@ import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobArmorEquipment import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobEquipmentSerializer_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.v291.serializer.SetEntityMotionSerializer_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; @@ -50,7 +51,6 @@ import org.cloudburstmc.protocol.bedrock.packet.CodeBuilderSourcePacket; import org.cloudburstmc.protocol.bedrock.packet.CraftingEventPacket; import org.cloudburstmc.protocol.bedrock.packet.CreatePhotoPacket; import org.cloudburstmc.protocol.bedrock.packet.DebugInfoPacket; -import org.cloudburstmc.protocol.bedrock.packet.DisconnectPacket; import org.cloudburstmc.protocol.bedrock.packet.EditorNetworkPacket; import org.cloudburstmc.protocol.bedrock.packet.EntityFallPacket; import org.cloudburstmc.protocol.bedrock.packet.GameTestRequestPacket; @@ -182,9 +182,18 @@ class CodecProcessor { }; /** - * Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client. + * Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v291. */ - private static final BedrockPacketSerializer SET_ENTITY_MOTION_SERIALIZER = new SetEntityMotionSerializer_v662() { + private static final BedrockPacketSerializer SET_ENTITY_MOTION_SERIALIZER_V291 = new SetEntityMotionSerializer_v291() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityMotionPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v662. + */ + private static final BedrockPacketSerializer SET_ENTITY_MOTION_SERIALIZER_V662 = new SetEntityMotionSerializer_v662() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityMotionPacket packet) { } @@ -251,7 +260,9 @@ class CodecProcessor { .updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER) .updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER) .updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER) - .updateSerializer(SetEntityMotionPacket.class, SET_ENTITY_MOTION_SERIALIZER) + .updateSerializer(SetEntityMotionPacket.class, codec.getProtocolVersion() < 662 ? + SET_ENTITY_MOTION_SERIALIZER_V291 : + SET_ENTITY_MOTION_SERIALIZER_V662) .updateSerializer(SetEntityLinkPacket.class, SET_ENTITY_LINK_SERIALIZER) // Valid serverbound packets where reading of some fields can be skipped .updateSerializer(MobEquipmentPacket.class, MOB_EQUIPMENT_SERIALIZER) From c34295829f17b16c5d3d3a321a472c5c1d40117b Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 23 Apr 2024 23:14:54 +0200 Subject: [PATCH 038/897] update actions to use java 21 (#4594) * update actions to use java 21 * jdk name correction --- .github/workflows/build-remote.yml | 4 ++-- .github/workflows/build.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-remote.yml b/.github/workflows/build-remote.yml index 75bcfaff5..d49920785 100644 --- a/.github/workflows/build-remote.yml +++ b/.github/workflows/build-remote.yml @@ -22,11 +22,11 @@ jobs: run: | echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - - name: Set up JDK 17 + - name: Set up JDK 21 # See https://github.com/actions/setup-java/commits uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 with: - java-version: 17 + java-version: 21 distribution: temurin - name: Checkout repository and submodules diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1ef0118ff..284fa265a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,7 @@ jobs: # See https://github.com/actions/setup-java/commits - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 with: - java-version: 17 + java-version: 21 distribution: temurin - name: Build From 16385a4e2b5db5c049fc28af5e032b459cdfc64a Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 24 Apr 2024 01:39:37 -0400 Subject: [PATCH 039/897] Check if session is closed when running scheduled tasks (#4595) --- .../main/java/org/geysermc/geyser/session/GeyserSession.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 aff21182e..95d5acb47 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1171,7 +1171,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public ScheduledFuture scheduleInEventLoop(Runnable runnable, long duration, TimeUnit timeUnit) { return eventLoop.schedule(() -> { try { - runnable.run(); + if (!closed) { + runnable.run(); + } } catch (Throwable e) { geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); } From c19b4ad306b92b146999b374fffe965012ebf55b Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 24 Apr 2024 08:41:57 -0400 Subject: [PATCH 040/897] Check if boat is valid when updating paddles (#4597) * Check if boat is valid when updating paddles * Add comment * Refactor boat paddling to use ticks * Null check --- .../geyser/entity/type/BoatEntity.java | 58 ++++++------------- .../geyser/session/GeyserSession.java | 2 + 2 files changed, 21 insertions(+), 39 deletions(-) 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 5527e773a..e3420abeb 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 @@ -42,7 +42,7 @@ import org.geysermc.geyser.util.InteractiveTag; import java.util.UUID; import java.util.concurrent.TimeUnit; -public class BoatEntity extends Entity { +public class BoatEntity extends Entity implements Tickable { /** * Required when IS_BUOYANT is sent in order for boats to work in the water.
@@ -58,6 +58,7 @@ public class BoatEntity extends Entity { private float paddleTimeLeft; private boolean isPaddlingRight; private float paddleTimeRight; + private boolean doTick; /** * Saved for using the "pick" functionality on a boat. @@ -133,34 +134,16 @@ public class BoatEntity extends Entity { public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) { isPaddlingLeft = entityMetadata.getPrimitiveValue(); - if (isPaddlingLeft) { - // Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing - // This is an asynchronous method that emulates Bedrock rowing until "false" is sent. - paddleTimeLeft = 0f; - if (!this.passengers.isEmpty()) { - // Get the entity by the first stored passenger and convey motion in this manner - Entity entity = this.passengers.get(0); - if (entity != null) { - updateLeftPaddle(session, entity); - } - } - } else { - // Indicate that the row position should be reset + if (!isPaddlingLeft) { + paddleTimeLeft = 0.0f; dirtyMetadata.put(EntityDataTypes.ROW_TIME_LEFT, 0.0f); } } public void setPaddlingRight(BooleanEntityMetadata entityMetadata) { isPaddlingRight = entityMetadata.getPrimitiveValue(); - if (isPaddlingRight) { - paddleTimeRight = 0f; - if (!this.passengers.isEmpty()) { - Entity entity = this.passengers.get(0); - if (entity != null) { - updateRightPaddle(session, entity); - } - } - } else { + if (!isPaddlingRight) { + paddleTimeRight = 0.0f; dirtyMetadata.put(EntityDataTypes.ROW_TIME_RIGHT, 0.0f); } } @@ -186,29 +169,26 @@ public class BoatEntity extends Entity { } } - private void updateLeftPaddle(GeyserSession session, Entity rower) { + @Override + public void tick() { + // Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing + doTick = !doTick; // Run every 100 ms + if (!doTick || passengers.isEmpty()) { + return; + } + + Entity rower = passengers.get(0); + if (rower == null) { + return; + } + if (isPaddlingLeft) { paddleTimeLeft += ROWING_SPEED; sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft); - - session.scheduleInEventLoop(() -> - updateLeftPaddle(session, rower), - 100, - TimeUnit.MILLISECONDS - ); } - } - - private void updateRightPaddle(GeyserSession session, Entity rower) { if (isPaddlingRight) { paddleTimeRight += ROWING_SPEED; sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight); - - session.scheduleInEventLoop(() -> - updateRightPaddle(session, rower), - 100, - TimeUnit.MILLISECONDS - ); } } 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 95d5acb47..63022636c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1167,6 +1167,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * Schedules a task and prints a stack trace if an error occurs. + *

+ * The task will not run if the session is closed. */ public ScheduledFuture scheduleInEventLoop(Runnable runnable, long duration, TimeUnit timeUnit) { return eventLoop.schedule(() -> { From 2471de100be3f229bfa415ec887e48a29002d2b2 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Wed, 24 Apr 2024 06:56:15 -0700 Subject: [PATCH 041/897] Add system property Geyser.RakSendCookie to allow disabling cookie send (#4598) --- .../java/org/geysermc/geyser/network/netty/GeyserServer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index 652901f36..a67bd8a32 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -228,6 +228,9 @@ public final class GeyserServer { int rakGlobalPacketLimit = positivePropOrDefault("Geyser.RakGlobalPacketLimit", DEFAULT_GLOBAL_PACKET_LIMIT); this.geyser.getLogger().debug("Setting RakNet global packet limit to " + rakGlobalPacketLimit); + boolean rakSendCookie = Boolean.parseBoolean(System.getProperty("Geyser.RakSendCookie", "true")); + this.geyser.getLogger().debug("Setting RakNet send cookie to " + rakSendCookie); + return new ServerBootstrap() .channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel())) .group(group, childGroup) @@ -235,7 +238,7 @@ public final class GeyserServer { .option(RakChannelOption.RAK_MAX_MTU, this.geyser.getConfig().getMtu()) .option(RakChannelOption.RAK_PACKET_LIMIT, rakPacketLimit) .option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, rakGlobalPacketLimit) - .option(RakChannelOption.RAK_SEND_COOKIE, true) + .option(RakChannelOption.RAK_SEND_COOKIE, rakSendCookie) .childHandler(serverInitializer); } From 099e968bde8e9981c7467b4f82c87a85cd0bc8e0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 19 Apr 2024 19:21:44 -0400 Subject: [PATCH 042/897] Initial, incomplete pass at Java 1.20.5 --- .../geyser/entity/type/FireworkEntity.java | 2 +- .../geyser/entity/type/ItemEntity.java | 4 +- .../geyser/entity/type/ItemFrameEntity.java | 4 +- .../entity/type/ThrowableItemEntity.java | 2 +- .../entity/type/ThrownPotionEntity.java | 2 +- .../geyser/inventory/GeyserItemStack.java | 31 +++--- .../geysermc/geyser/inventory/Inventory.java | 2 +- .../geyser/inventory/click/ClickPlan.java | 2 +- .../inventory/recipe/GeyserShapedRecipe.java | 2 +- .../recipe/GeyserShapelessRecipe.java | 2 +- .../recipe/GeyserStonecutterData.java | 2 +- .../geysermc/geyser/item/type/ArmorItem.java | 6 +- .../geysermc/geyser/item/type/ArrowItem.java | 8 +- .../geyser/item/type/AxolotlBucketItem.java | 7 +- .../geysermc/geyser/item/type/BannerItem.java | 6 +- .../geysermc/geyser/item/type/ChestItem.java | 7 +- .../geyser/item/type/CompassItem.java | 8 +- .../geyser/item/type/CrossbowItem.java | 10 +- .../geyser/item/type/DecoratedPotItem.java | 6 +- .../geyser/item/type/DyeableArmorItem.java | 6 +- .../item/type/DyeableHorseArmorItem.java | 6 +- .../geyser/item/type/EnchantedBookItem.java | 6 +- .../geyser/item/type/FilledMapItem.java | 2 +- .../geyser/item/type/FireworkRocketItem.java | 6 +- .../geyser/item/type/FireworkStarItem.java | 6 +- .../geyser/item/type/FishingRodItem.java | 7 +- .../geyser/item/type/GoatHornItem.java | 2 +- .../org/geysermc/geyser/item/type/Item.java | 63 +++++++----- .../geysermc/geyser/item/type/MapItem.java | 6 +- .../geyser/item/type/PlayerHeadItem.java | 6 +- .../geysermc/geyser/item/type/PotionItem.java | 16 +-- .../geysermc/geyser/item/type/ShieldItem.java | 6 +- .../geyser/item/type/ShulkerBoxItem.java | 71 ++++++------- .../geyser/item/type/TippedArrowItem.java | 4 +- .../item/type/TropicalFishBucketItem.java | 6 +- .../geyser/item/type/WritableBookItem.java | 6 +- .../geyser/item/type/WrittenBookItem.java | 6 +- .../populator/RecipeRegistryPopulator.java | 4 +- .../geyser/registry/type/ItemMappings.java | 2 +- .../inventory/InventoryTranslator.java | 2 +- .../inventory/PlayerInventoryTranslator.java | 4 +- .../StonecutterInventoryTranslator.java | 2 +- .../item/CustomItemTranslator.java | 30 +++--- .../{inventory => }/item/ItemTranslator.java | 99 +++++++++---------- .../BedrockBlockPickRequestTranslator.java | 2 +- .../bedrock/BedrockBookEditTranslator.java | 2 +- ...BedrockInventoryTransactionTranslator.java | 4 +- .../player/BedrockActionTranslator.java | 2 +- .../java/JavaUpdateRecipesTranslator.java | 4 +- .../entity/JavaSetEquipmentTranslator.java | 4 +- .../JavaContainerSetSlotTranslator.java | 4 +- .../JavaMerchantOffersTranslator.java | 4 +- .../level/JavaLevelParticlesTranslator.java | 4 +- .../geysermc/geyser/util/InventoryUtils.java | 2 +- 54 files changed, 285 insertions(+), 234 deletions(-) rename core/src/main/java/org/geysermc/geyser/translator/{inventory => }/item/CustomItemTranslator.java (80%) rename core/src/main/java/org/geysermc/geyser/translator/{inventory => }/item/ItemTranslator.java (88%) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java index 7a544f23c..171849ce5 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java index 69fb3faab..226ad7df8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; @@ -37,7 +37,7 @@ import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import java.util.UUID; import java.util.concurrent.CompletableFuture; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java index ad1d4b928..453125945 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; @@ -42,7 +42,7 @@ import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InventoryUtils; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java index 39c8386bd..3c080345e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java index 1b5c1d2d0..cea371963 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.math.vector.Vector3f; 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 4ff8db9f0..dd1aaea81 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -25,7 +25,8 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import lombok.AccessLevel; import lombok.Data; @@ -34,12 +35,13 @@ import lombok.Getter; 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; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; @Data public class GeyserItemStack { @@ -47,26 +49,26 @@ public class GeyserItemStack { private final int javaId; private int amount; - private CompoundTag nbt; + private DataComponentPatch components; private int netId; @Getter(AccessLevel.NONE) @EqualsAndHashCode.Exclude private Item item; - private GeyserItemStack(int javaId, int amount, CompoundTag nbt) { - this(javaId, amount, nbt, 1); + private GeyserItemStack(int javaId, int amount, DataComponentPatch components) { + this(javaId, amount, components, 1); } - private GeyserItemStack(int javaId, int amount, CompoundTag nbt, int netId) { + private GeyserItemStack(int javaId, int amount, DataComponentPatch components, int netId) { this.javaId = javaId; this.amount = amount; - this.nbt = nbt; + this.components = components; this.netId = netId; } public static @NonNull GeyserItemStack from(@Nullable ItemStack itemStack) { - return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getNbt()); + return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponentPatch()); } public int getJavaId() { @@ -78,7 +80,12 @@ public class GeyserItemStack { } public @Nullable CompoundTag getNbt() { - return isEmpty() ? null : nbt; + Thread.dumpStack(); + return null; + } + + public @Nullable DataComponentPatch getComponents() { + return isEmpty() ? null : components; } public int getNetId() { @@ -98,14 +105,14 @@ public class GeyserItemStack { } public @Nullable ItemStack getItemStack(int newAmount) { - return isEmpty() ? null : new ItemStack(javaId, newAmount, nbt); + return isEmpty() ? null : new ItemStack(javaId, newAmount, components); } public ItemData getItemData(GeyserSession session) { if (isEmpty()) { return ItemData.AIR; } - ItemData.Builder itemData = ItemTranslator.translateToBedrock(session, javaId, amount, nbt); + ItemData.Builder itemData = ItemTranslator.translateToBedrock(session, javaId, amount, components); itemData.netId(getNetId()); itemData.usingNetId(true); return itemData.build(); @@ -131,6 +138,6 @@ public class GeyserItemStack { } public GeyserItemStack copy(int newAmount) { - return isEmpty() ? EMPTY : new GeyserItemStack(javaId, newAmount, nbt == null ? null : nbt.clone(), netId); + return isEmpty() ? EMPTY : new GeyserItemStack(javaId, newAmount, components == null ? null : components.clone(), netId); } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index 3376d6c26..b78bbe1b3 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -38,7 +38,7 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.jetbrains.annotations.Range; import java.util.Arrays; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index f31f6d82f..a118670af 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory.click; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerActionType; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.data.game.inventory.MoveToHotbarAction; 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 05c17cf9f..d420170f4 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,7 +25,7 @@ package org.geysermc.geyser.inventory.recipe; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import org.checkerframework.checker.nullness.qual.Nullable; 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 e300e3ec8..e6eabea2d 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,7 +25,7 @@ package org.geysermc.geyser.inventory.recipe; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java index 22163eced..ce044e745 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory.recipe; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import org.checkerframework.checker.nullness.qual.Nullable; /** diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index b58f760d1..669791705 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -25,9 +25,11 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -41,8 +43,8 @@ public class ArmorItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); if (tag.get("Trim") instanceof CompoundTag trim) { StringTag material = trim.remove("material"); 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 938d4a79a..2462f374c 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 @@ -25,7 +25,9 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -44,9 +46,9 @@ public class ArrowItem extends Item { TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (tippedArrowPotion != null) { - itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getNbt()); + itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getDataComponentPatch()); StringTag potionTag = new StringTag("Potion", tippedArrowPotion.getJavaIdentifier()); - itemStack.getNbt().put(potionTag); + itemStack.getDataComponentPatch().put(DataComponentType.POTION_CONTENTS, new PotionContents()); } return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java index 81d7bf116..6e4e6c6fc 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java @@ -25,10 +25,11 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; @@ -38,8 +39,8 @@ public class AxolotlBucketItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); // Bedrock Edition displays the properties of the axolotl. Java does not. // To work around this, set the custom name to the Axolotl translation and it's displayed correctly diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 344668836..9cd7aea42 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; @@ -32,6 +33,7 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -120,8 +122,8 @@ public class BannerItem extends BlockItem { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); CompoundTag blockEntityTag = tag.remove("BlockEntityTag"); if (blockEntityTag != null && blockEntityTag.get("Patterns") instanceof ListTag patterns) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java index 99857006c..2611c8ff6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java @@ -25,8 +25,9 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; public class ChestItem extends BlockItem { @@ -36,8 +37,8 @@ public class ChestItem extends BlockItem { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); // Strip the BlockEntityTag from the chests contents // sent to the client. The client does not parse this 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 87da96447..f3933d83b 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 @@ -25,12 +25,14 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; @@ -58,8 +60,8 @@ public class CompassItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); Tag lodestoneTag = tag.get("LodestoneTracked"); if (lodestoneTag instanceof ByteTag) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java index e409dccfb..1ea468721 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java @@ -25,14 +25,16 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; public class CrossbowItem extends Item { public CrossbowItem(String javaIdentifier, Builder builder) { @@ -40,8 +42,8 @@ public class CrossbowItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); ListTag chargedProjectiles = tag.get("ChargedProjectiles"); if (chargedProjectiles != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index 10d2a1bcc..bfa86d2ad 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -25,9 +25,11 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; public class DecoratedPotItem extends BlockItem { @@ -37,8 +39,8 @@ public class DecoratedPotItem extends BlockItem { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { if (blockEntityTag.remove("sherds") instanceof ListTag sherds) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index dbcff7d0b..f1b10474d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -25,8 +25,10 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.item.DyeableLeatherItem; import org.geysermc.geyser.registry.type.ItemMapping; @@ -38,8 +40,8 @@ public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); DyeableLeatherItem.translateNbtToBedrock(tag); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java index 0d37f5eab..39787ae2f 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java @@ -25,8 +25,10 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.DyeableLeatherItem; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -37,8 +39,8 @@ public class DyeableHorseArmorItem extends Item implements DyeableLeatherItem { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); DyeableLeatherItem.translateNbtToBedrock(tag); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index ac0751c73..c51278947 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -25,10 +25,12 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -40,8 +42,8 @@ public class EnchantedBookItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); List newTags = new ArrayList<>(); Tag enchantmentTag = tag.remove("StoredEnchantments"); 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 963373523..8125ce101 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMap; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index 3559cdf4d..6be1be15d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -25,8 +25,10 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.FireworkColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -38,8 +40,8 @@ public class FireworkRocketItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); CompoundTag fireworks = tag.get("Fireworks"); if (fireworks == null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 9c13d7793..6d4347e9e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -25,11 +25,13 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -39,8 +41,8 @@ public class FireworkStarItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); Tag explosion = tag.remove("Explosion"); if (explosion instanceof CompoundTag) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java index f63a1ec5a..50a0bddbc 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java @@ -25,10 +25,11 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; public class FishingRodItem extends Item { @@ -37,8 +38,8 @@ public class FishingRodItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); // Fix damage inconsistency Tag damage = tag.get("Damage"); 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 aacb906c9..60b201961 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; 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 3701b5189..df3c5effe 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 @@ -26,10 +26,18 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.Identifier; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments; import com.github.steveice10.opennbt.tag.builtin.*; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Enchantment; @@ -38,7 +46,7 @@ import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.InventoryUtils; @@ -107,7 +115,7 @@ public class Item { public @NonNull ItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { if (itemData.getTag() == null) { - return new ItemStack(javaId, itemData.getCount(), new CompoundTag("")); + return new ItemStack(javaId, itemData.getCount(), null); } return new ItemStack(javaId, itemData.getCount(), ItemTranslator.translateToJavaNBT("", itemData.getTag())); } @@ -117,22 +125,31 @@ public class Item { } /** - * Takes NBT from Java Edition and converts any value that Bedrock parses differently. + * Takes components from Java Edition and map them into Bedrock. */ - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - if (tag.get("display") instanceof CompoundTag displayTag) { - if (displayTag.get("Lore") instanceof ListTag listTag) { - List lore = new ArrayList<>(); - for (Tag subTag : listTag.getValue()) { - if (!(subTag instanceof StringTag)) continue; - lore.add(new StringTag("", MessageTranslator.convertMessageLenient(((StringTag) subTag).getValue(), session.locale()))); - } - displayTag.put(new ListTag("Lore", lore)); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { +// // Basing off of ItemStack#getHoverName as of 1.20.5. VERIFY?? +// Component customName = components.get(DataComponentType.CUSTOM_NAME); +// if (customName == null) { +// customName = components.get(DataComponentType.ITEM_NAME); +// } +// if (customName != null) { +// +// } + List loreComponents = components.get(DataComponentType.LORE); + if (loreComponents != null) { + List lore = new ArrayList<>(); + for (Component loreComponent : loreComponents) { + lore.add(MessageTranslator.convertMessage(loreComponent, session.locale())); } + builder.putList("Lore", NbtType.STRING, lore); } List newTags = new ArrayList<>(); - Tag enchantmentTag = tag.remove("Enchantments"); + ItemEnchantments enchantments = components.get(DataComponentType.ENCHANTMENTS); + if (enchantments != null) { + + } if (enchantmentTag instanceof ListTag listTag) { for (Tag subTag : listTag.getValue()) { if (!(subTag instanceof CompoundTag)) continue; @@ -211,10 +228,7 @@ public class Item { } } - protected final @Nullable CompoundTag remapEnchantment(GeyserSession session, CompoundTag tag, CompoundTag rootTag) { - Tag javaEnchId = tag.get("id"); - if (!(javaEnchId instanceof StringTag)) - return null; + protected final @Nullable NbtMap remapEnchantment(GeyserSession session, ItemEnchantments, NbtMapBuilder rootBuilder) { Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); if (enchantment == null) { @@ -231,11 +245,10 @@ public class Item { Tag javaEnchLvl = tag.get("lvl"); - CompoundTag bedrockTag = new CompoundTag(""); - bedrockTag.put(new ShortTag("id", (short) enchantment.ordinal())); - // If the tag cannot parse, Java Edition 1.18.2 sets to 0 - bedrockTag.put(new ShortTag("lvl", javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.shortValue() : (short) 0)); - return bedrockTag; + NbtMapBuilder builder = NbtMap.builder(); + builder.putShort("id", (short) enchantment.ordinal()); + builder.putShort("lvl", ); + return builder.build(); } private void addSweeping(GeyserSession session, CompoundTag itemTag, int level) { @@ -258,8 +271,8 @@ public class Item { /* Translation methods end */ - public ItemStack newItemStack(int count, CompoundTag tag) { - return new ItemStack(this.javaId, count, tag); + public ItemStack newItemStack(int count, DataComponentPatch components) { + return new ItemStack(this.javaId, count, components); } public void setJavaId(int javaId) { // TODO like this? diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java index 4405b66ad..8dbeeb57f 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java @@ -25,8 +25,10 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -36,8 +38,8 @@ public class MapItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); Tag mapId = tag.remove("map"); if (mapId == null || !(mapId.getValue() instanceof Number number)) return; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index 662448a52..4aefcf765 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -25,10 +25,12 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; @@ -40,8 +42,8 @@ public class PlayerHeadItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); CompoundTag displayTag; if (tag.get("display") instanceof CompoundTag existingDisplayTag) { 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 24dd56ef2..26c468fb1 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 @@ -25,7 +25,9 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; @@ -35,8 +37,8 @@ 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.translator.inventory.item.CustomItemTranslator; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.CustomItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; public class PotionItem extends Item { public PotionItem(String javaIdentifier, Builder builder) { @@ -45,10 +47,10 @@ public class PotionItem extends Item { @Override public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, mapping, mappings); - Tag potionTag = itemStack.getNbt().get("Potion"); - if (potionTag instanceof StringTag) { - ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(itemStack.getNbt(), mapping); + if (itemStack.getDataComponentPatch() == null) return super.translateToBedrock(itemStack, mapping, mappings); + PotionContents potionContents = itemStack.getDataComponentPatch().get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(itemStack.getDataComponentPatch(), mapping); if (customItemDefinition == null) { Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); if (potion != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index c13dd4fcf..cd940c87c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -25,11 +25,13 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.session.GeyserSession; @@ -39,8 +41,8 @@ public class ShieldItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { if (blockEntityTag.get("Patterns") instanceof ListTag patterns) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index 717bad9a4..e2259eb5d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -26,68 +26,61 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.Identifier; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.MathUtils; +import java.util.ArrayList; +import java.util.List; + public class ShulkerBoxItem extends BlockItem { public ShulkerBoxItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); - CompoundTag blockEntityTag = tag.get("BlockEntityTag"); - if (blockEntityTag == null) { + List contents = components.get(DataComponentType.CONTAINER); + if (contents == null || contents.isEmpty()) { // Empty shulker box return; } - if (blockEntityTag.get("Items") == null) return; - ListTag itemsList = new ListTag("Items"); - for (Tag item : (ListTag) blockEntityTag.get("Items")) { - CompoundTag itemData = (CompoundTag) item; // Information about the item - CompoundTag boxItemTag = new CompoundTag(""); // Final item tag to add to the list - boxItemTag.put(new ByteTag("Slot", (byte) (MathUtils.getNbtByte(itemData.get("Slot").getValue()) & 255))); - boxItemTag.put(new ByteTag("WasPickedUp", (byte) 0)); // ??? - - ItemMapping boxMapping = session.getItemMappings().getMapping(Identifier.formalize(((StringTag) itemData.get("id")).getValue())); - - if (boxMapping == null) { - // If invalid ID + List itemsList = new ArrayList<>(); + for (int slot = 0; slot < contents.size(); slot++) { + ItemStack item = contents.get(slot); + if (item.getId() == Items.AIR_ID) { continue; } + NbtMapBuilder boxItemNbt = NbtMap.builder(); // Final item tag to add to the list + boxItemNbt.putByte("Slot", (byte) slot); + boxItemNbt.putByte("WasPickedUp", (byte) 0); // ??? - boxItemTag.put(new StringTag("Name", boxMapping.getBedrockIdentifier())); - boxItemTag.put(new ShortTag("Damage", (short) boxMapping.getBedrockData())); - boxItemTag.put(new ByteTag("Count", MathUtils.getNbtByte(itemData.get("Count").getValue()))); + ItemMapping boxMapping = session.getItemMappings().getMapping(item.getId()); + + boxItemNbt.putString("Name", boxMapping.getBedrockIdentifier()); + boxItemNbt.putShort("Damage", (short) boxMapping.getBedrockData()); + boxItemNbt.putByte("Count", (byte) item.getAmount()); // Only the display name is what we have interest in, so just translate that if relevant - CompoundTag displayTag = itemData.get("tag"); - if (displayTag == null && boxMapping.hasTranslation()) { - displayTag = new CompoundTag("tag"); - } - if (displayTag != null) { - boxItemTag.put(ItemTranslator.translateDisplayProperties(session, displayTag, boxMapping, '7')); + DataComponentPatch boxComponents = item.getDataComponentPatch(); + if (boxComponents != null) { + boxItemNbt.put(ItemTranslator.translateDisplayProperties(session, displayTag, boxMapping, '7')); } - itemsList.add(boxItemTag); + itemsList.add(boxItemNbt.build()); } - tag.put(itemsList); - - // Strip the BlockEntityTag from the chests contents - // sent to the client. The client does not parse this - // or use it for anything, as this tag is fully - // server-side, so we remove it to reduce bandwidth and - // solve potential issues with very large tags. - - // There was a problem in the past where this would strip - // NBT data in creative mode, however with the new server - // authoritative inventories, this is no longer a concern. - tag.remove("BlockEntityTag"); + builder.putList("Items", NbtType.COMPOUND, itemsList); } @Override 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 f78836d16..fcf562ba5 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -33,7 +33,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.TippedArrowPotion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; public class TippedArrowItem extends ArrowItem { public TippedArrowItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index 8b4e35d1e..17f90ca12 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -25,12 +25,14 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.entity.type.living.animal.TropicalFishEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; @@ -47,8 +49,8 @@ public class TropicalFishBucketItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); // Prevent name from appearing as "Bucket of" tag.put(new ByteTag("AppendCustomName", (byte) 1)); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java index dfebecf7d..67221b1c6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java @@ -25,11 +25,13 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -43,8 +45,8 @@ public class WritableBookItem extends Item { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { - super.translateNbtToBedrock(session, tag); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); ListTag pagesTag = tag.remove("pages"); if (pagesTag == null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index 045aaa416..0198e73ff 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; @@ -32,6 +33,7 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -48,13 +50,13 @@ public class WrittenBookItem extends WritableBookItem { } @Override - public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { boolean isValid = isValidWrittenBook(tag); if (!isValid) { tag.remove("pages"); } - super.translateNbtToBedrock(session, tag); + super.translateComponentsToBedrock(session, components, builder); if (!isValid) { CompoundTag invalidTagPage = new CompoundTag(""); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java index 5e4d5fc7a..34e855212 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.registry.populator; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -48,7 +48,7 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import java.io.ByteArrayInputStream; import java.io.IOException; diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index 40359b437..33908a7e7 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.registry.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Builder; 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 95ec99412..e6e0c6340 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,7 +25,7 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.opennbt.tag.builtin.IntTag; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 1447f2b5b..429b577ce 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; @@ -53,7 +53,7 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.FakeHeadProvider; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.InventoryUtils; import java.util.Arrays; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java index 50c040a0b..d3d15680a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java similarity index 80% rename from core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java index 06d1e3aa6..d5f85dcc3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.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,11 +23,10 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.inventory.item; +package org.geysermc.geyser.translator.item; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import it.unimi.dsi.fastutil.Pair; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -44,8 +43,8 @@ import java.util.OptionalInt; public final class CustomItemTranslator { @Nullable - public static ItemDefinition getCustomItem(CompoundTag nbt, ItemMapping mapping) { - if (nbt == null) { + public static ItemDefinition getCustomItem(DataComponentPatch components, ItemMapping mapping) { + if (components == null) { return null; } List> customMappings = mapping.getCustomItemOptions(); @@ -53,10 +52,11 @@ public final class CustomItemTranslator { return null; } - int customModelData = nbt.get("CustomModelData") instanceof IntTag customModelDataTag ? customModelDataTag.getValue() : 0; + // TODO getOrDefault + int customModelData = components.get(DataComponentType.CUSTOM_MODEL_DATA); boolean checkDamage = mapping.getJavaItem().maxDamage() > 0; - int damage = !checkDamage ? 0 : nbt.get("Damage") instanceof IntTag damageTag ? damageTag.getValue() : 0; - boolean unbreakable = checkDamage && !isDamaged(nbt, damage); + int damage = !checkDamage ? 0 : components.get(DataComponentType.DAMAGE); + boolean unbreakable = checkDamage && !isDamaged(components, damage); for (Pair mappingTypes : customMappings) { CustomItemOptions options = mappingTypes.key(); @@ -105,15 +105,15 @@ public final class CustomItemTranslator { /* These two functions are based off their Mojmap equivalents from 1.19.2 */ - private static boolean isDamaged(CompoundTag nbt, int damage) { - return isDamagableItem(nbt) && damage > 0; + private static boolean isDamaged(DataComponentPatch components, int damage) { + return isDamagableItem(components) && damage > 0; } - private static boolean isDamagableItem(CompoundTag nbt) { + private static boolean isDamagableItem(DataComponentPatch components) { // mapping.getMaxDamage > 0 should also be checked (return false if not true) but we already check prior to this function - Tag unbreakableTag = nbt.get("Unbreakable"); + Boolean unbreakable = components.get(DataComponentType.UNBREAKABLE); // Tag must either not be present or be set to false - return unbreakableTag == null || !(unbreakableTag.getValue() instanceof Number number) || number.byteValue() == 0; + return unbreakable == null || !unbreakable; } private CustomItemTranslator() { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java similarity index 88% rename from core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java index d1a256551..027c6b5ba 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.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,11 +23,15 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.inventory.item; +package org.geysermc.geyser.translator.item; import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOperation; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.AdventureModePredicate; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.ItemAttributeModifiers; import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; @@ -133,20 +137,20 @@ public final class ItemTranslator { .build(); } - private static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, CompoundTag tag) { - CompoundTag nbt = tag != null ? tag.clone() : null; + private static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, DataComponentPatch components) { + NbtMapBuilder builder = NbtMap.builder(); - if (nbt != null) { - javaItem.translateNbtToBedrock(session, nbt); + if (components != null) { + javaItem.translateComponentsToBedrock(session, components, builder); } - nbt = translateDisplayProperties(session, nbt, bedrockItem); + translateDisplayProperties(session, components, bedrockItem); - if (nbt != null) { - Tag hideFlags = nbt.get("HideFlags"); - if (hideFlags == null || !hasFlagPresent(hideFlags, HIDE_ATTRIBUTES_FLAG)) { - // only add if the hide attribute modifiers flag is not present - addAttributeLore(nbt, session.locale()); + if (components != null) { + ItemAttributeModifiers attributeModifiers = components.get(DataComponentType.ATTRIBUTE_MODIFIERS); + if (attributeModifiers != null && attributeModifiers.isShowInTooltip()) { + // only add if attribute modifiers do not indicate to hide them + addAttributeLore(attributeModifiers, builder, session.locale()); } } @@ -173,10 +177,10 @@ public final class ItemTranslator { translateCustomItem(nbt, builder, bedrockItem); - if (nbt != null) { + if (components != null) { // Translate the canDestroy and canPlaceOn Java NBT - ListTag canDestroy = nbt.get("CanDestroy"); - ListTag canPlaceOn = nbt.get("CanPlaceOn"); + AdventureModePredicate canDestroy = components.get(DataComponentType.CAN_BREAK); + AdventureModePredicate canPlaceOn = components.get(DataComponentType.CAN_PLACE_ON); String[] canBreak = getCanModify(canDestroy); String[] canPlace = getCanModify(canPlaceOn); if (canBreak != null) { @@ -197,13 +201,8 @@ public final class ItemTranslator { * @param nbt the NBT of the ItemStack * @param language the locale of the player */ - private static void addAttributeLore(CompoundTag nbt, String language) { - ListTag attributeModifiers = nbt.get("AttributeModifiers"); - if (attributeModifiers == null) { - return; // nothing to convert to lore - } - - CompoundTag displayTag = nbt.get("display"); + private static void addAttributeLore(ItemAttributeModifiers modifiers, NbtMapBuilder builder, String language) { + CompoundTag displayTag = builder.get("display"); if (displayTag == null) { displayTag = new CompoundTag("display"); } @@ -214,25 +213,23 @@ public final class ItemTranslator { // maps each slot to the modifiers applied when in such slot Map> slotsToModifiers = new HashMap<>(); - for (Tag modifier : attributeModifiers) { - CompoundTag modifierTag = (CompoundTag) modifier; - + for (ItemAttributeModifiers.Entry entry : modifiers.getModifiers()) { // convert the modifier tag to a lore entry - String loreEntry = attributeToLore(modifierTag, language); + String loreEntry = attributeToLore(entry.getModifier(), language); if (loreEntry == null) { continue; // invalid or failed } StringTag loreTag = new StringTag("", loreEntry); - StringTag slotTag = modifierTag.get("Slot"); - if (slotTag == null) { + ItemAttributeModifiers.EquipmentSlotGroup slotGroup = entry.getSlot(); + if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ANY) { // modifier applies to all slots implicitly for (String slot : ALL_SLOTS) { slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreTag); } } else { // modifier applies to only the specified slot - slotsToModifiers.computeIfAbsent(slotTag.getValue(), s -> new ArrayList<>()).add(loreTag); + slotsToModifiers.computeIfAbsent(slotGroup, s -> new ArrayList<>()).add(loreTag); } } @@ -262,31 +259,23 @@ public final class ItemTranslator { } @Nullable - private static String attributeToLore(CompoundTag modifier, String language) { - Tag amountTag = modifier.get("Amount"); - if (amountTag == null || !(amountTag.getValue() instanceof Number number)) { - return null; - } - double amount = number.doubleValue(); + private static String attributeToLore(ItemAttributeModifiers.AttributeModifier modifier, String language) { + double amount = modifier.getAmount(); if (amount == 0) { return null; } - if (!(modifier.get("AttributeName") instanceof StringTag nameTag)) { - return null; - } - String name = nameTag.getValue().replace("minecraft:", ""); - // the namespace does not need to be present, but if it is, the java client ignores it + String name = modifier.getName().replace("minecraft:", ""); + // the namespace does not need to be present, but if it is, the java client ignores it as of pre-1.20.5 String operationTotal; - Tag operationTag = modifier.get("Operation"); - ModifierOperation operation; - if (operationTag == null || (operation = ModifierOperation.from((int) operationTag.getValue())) == ModifierOperation.ADD) { + ModifierOperation operation = modifier.getOperation(); + if (operation == ModifierOperation.ADD) { if (name.equals("generic.knockback_resistance")) { amount *= 10; } operationTotal = ATTRIBUTE_FORMAT.format(amount); - } else if (operation == ModifierOperation.ADD_MULTIPLIED || operation == ModifierOperation.MULTIPLY) { + } else if (operation == ModifierOperation.ADD_MULTIPLIED_BASE || operation == ModifierOperation.ADD_MULTIPLIED_TOTAL) { operationTotal = ATTRIBUTE_FORMAT.format(amount * 100) + "%"; } else { GeyserImpl.getInstance().getLogger().warning("Unhandled ModifierOperation while adding item attributes: " + operation); @@ -363,12 +352,22 @@ public final class ItemTranslator { * @param canModifyJava the list of items in Java * @return the new list of items in Bedrock */ - private static String @Nullable [] getCanModify(ListTag canModifyJava) { - if (canModifyJava != null && canModifyJava.size() > 0) { - String[] canModifyBedrock = new String[canModifyJava.size()]; + // TODO this is now more complicated in 1.20.5. Yippee! + private static String @Nullable [] getCanModify(@Nullable AdventureModePredicate canModifyJava) { + if (canModifyJava == null) { + return null; + } + List predicates = canModifyJava.getPredicates(); + if (predicates.size() > 0) { + String[] canModifyBedrock = new String[predicates.size()]; for (int i = 0; i < canModifyBedrock.length; i++) { // Get the Java identifier of the block that can be placed - String block = Identifier.formalize(((StringTag) canModifyJava.get(i)).getValue()); + String location = predicates.get(i).getLocation(); + if (location == null) { + canModifyBedrock[i] = ""; // So it'll serialize + continue; // ??? + } + String block = Identifier.formalize(location); // Get the Bedrock identifier of the item and replace it. // This will unfortunately be limited - for example, beds and banners will be translated weirdly canModifyBedrock[i] = BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.getOrDefault(block, block).replace("minecraft:", ""); @@ -403,7 +402,7 @@ public final class ItemTranslator { } } - ItemDefinition definition = CustomItemTranslator.getCustomItem(itemStack.getNbt(), mapping); + ItemDefinition definition = CustomItemTranslator.getCustomItem(itemStack, mapping); if (definition == null) { // No custom item return itemDefinition; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 381adf2b7..59317fd7c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java index 6547044c3..ec1d62d16 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundEditBookPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; 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 4ac835268..8d005e515 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; @@ -70,7 +70,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.skin.FakeHeadProvider; import org.geysermc.geyser.translator.inventory.InventoryTranslator; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +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.BlockUtils; 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 index 33410f240..f5122b256 100644 --- 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 @@ -52,7 +52,7 @@ import org.geysermc.geyser.registry.type.BlockMapping; 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.inventory.item.CustomItemTranslator; +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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 94c69b780..aca02feab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; @@ -56,7 +56,7 @@ import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index 0c344bddc..c178f27d4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Equipment; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundSetEquipmentPacket; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.entity.type.Entity; @@ -35,7 +35,7 @@ import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.FakeHeadProvider; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; 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 605a40d75..594c99291 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetSlotPacket; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; @@ -41,7 +41,7 @@ import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; 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.item.ItemTranslator; +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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java index 17a4314ec..68d2bcab3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.inventory.VillagerTrade; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket; import org.cloudburstmc.nbt.NbtMap; @@ -41,7 +41,7 @@ import org.geysermc.geyser.inventory.MerchantContainer; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java index 11d9dbddf..78290f6bd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.level.particle.BlockParticleData; import com.github.steveice10.mc.protocol.data.game.level.particle.DustParticleData; import com.github.steveice10.mc.protocol.data.game.level.particle.FallingDustParticleData; @@ -49,7 +49,7 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ParticleMapping; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +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.DimensionUtils; 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 25976f0f5..e56aea8c9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemPacket; From c1edf20734099c7d75933c25c2e388a6d2a9f5f8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 20 Apr 2024 13:29:14 -0400 Subject: [PATCH 043/897] Here's the idea so far --- .../geyser/inventory/GeyserItemStack.java | 13 +- .../geysermc/geyser/item/type/ArmorItem.java | 4 +- .../geysermc/geyser/item/type/ArrowItem.java | 4 +- .../geyser/item/type/AxolotlBucketItem.java | 4 +- .../geysermc/geyser/item/type/BannerItem.java | 4 +- .../geysermc/geyser/item/type/ChestItem.java | 4 +- .../geyser/item/type/CompassItem.java | 4 +- .../geyser/item/type/CrossbowItem.java | 4 +- .../geyser/item/type/DecoratedPotItem.java | 4 +- .../geyser/item/type/DyeableArmorItem.java | 4 +- .../item/type/DyeableHorseArmorItem.java | 4 +- .../geyser/item/type/EnchantedBookItem.java | 4 +- .../geyser/item/type/FireworkRocketItem.java | 4 +- .../geyser/item/type/FireworkStarItem.java | 4 +- .../geyser/item/type/FishingRodItem.java | 4 +- .../org/geysermc/geyser/item/type/Item.java | 14 +- .../geysermc/geyser/item/type/MapItem.java | 4 +- .../geyser/item/type/PlayerHeadItem.java | 4 +- .../geysermc/geyser/item/type/PotionItem.java | 6 +- .../geysermc/geyser/item/type/ShieldItem.java | 4 +- .../geyser/item/type/ShulkerBoxItem.java | 19 +- .../item/type/TropicalFishBucketItem.java | 4 +- .../geyser/item/type/WritableBookItem.java | 4 +- .../geyser/item/type/WrittenBookItem.java | 4 +- .../translator/item/BedrockItemBuilder.java | 93 ++++++++ .../translator/item/CustomItemTranslator.java | 13 +- .../translator/item/ItemTranslator.java | 207 +++++++----------- 27 files changed, 241 insertions(+), 204 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java 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 dd1aaea81..7e621d3aa 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.inventory; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import lombok.AccessLevel; import lombok.Data; @@ -35,7 +35,6 @@ import lombok.Getter; 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; @@ -49,18 +48,18 @@ public class GeyserItemStack { private final int javaId; private int amount; - private DataComponentPatch components; + private DataComponents components; private int netId; @Getter(AccessLevel.NONE) @EqualsAndHashCode.Exclude private Item item; - private GeyserItemStack(int javaId, int amount, DataComponentPatch components) { + private GeyserItemStack(int javaId, int amount, DataComponents components) { this(javaId, amount, components, 1); } - private GeyserItemStack(int javaId, int amount, DataComponentPatch components, int netId) { + private GeyserItemStack(int javaId, int amount, DataComponents components, int netId) { this.javaId = javaId; this.amount = amount; this.components = components; @@ -68,7 +67,7 @@ public class GeyserItemStack { } public static @NonNull GeyserItemStack from(@Nullable ItemStack itemStack) { - return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponentPatch()); + return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponents()); } public int getJavaId() { @@ -84,7 +83,7 @@ public class GeyserItemStack { return null; } - public @Nullable DataComponentPatch getComponents() { + public @Nullable DataComponents getComponents() { return isEmpty() ? null : components; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index 669791705..eb5233b88 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; @@ -43,7 +43,7 @@ public class ArmorItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); if (tag.get("Trim") instanceof CompoundTag trim) { 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 2462f374c..cf66b036b 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 @@ -46,9 +46,9 @@ public class ArrowItem extends Item { TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (tippedArrowPotion != null) { - itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getDataComponentPatch()); + itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getDataComponents()); StringTag potionTag = new StringTag("Potion", tippedArrowPotion.getJavaIdentifier()); - itemStack.getDataComponentPatch().put(DataComponentType.POTION_CONTENTS, new PotionContents()); + itemStack.getDataComponents().put(DataComponentType.POTION_CONTENTS, new PotionContents()); } return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java index 6e4e6c6fc..d0aa1e901 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; @@ -39,7 +39,7 @@ public class AxolotlBucketItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); // Bedrock Edition displays the properties of the axolotl. Java does not. diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 9cd7aea42..2a8ca9f15 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; @@ -122,7 +122,7 @@ public class BannerItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); CompoundTag blockEntityTag = tag.remove("BlockEntityTag"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java index 2611c8ff6..8644ec8be 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; @@ -37,7 +37,7 @@ public class ChestItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); // Strip the BlockEntityTag from the chests contents 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 f3933d83b..605d19852 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 @@ -26,7 +26,7 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; @@ -60,7 +60,7 @@ public class CompassItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); Tag lodestoneTag = tag.get("LodestoneTracked"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java index 1ea468721..c38e2f2ba 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -42,7 +42,7 @@ public class CrossbowItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); ListTag chargedProjectiles = tag.get("ChargedProjectiles"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index bfa86d2ad..74cabc3d9 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import org.checkerframework.checker.nullness.qual.NonNull; @@ -39,7 +39,7 @@ public class DecoratedPotItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index f1b10474d..fbe0222bc 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -40,7 +40,7 @@ public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); DyeableLeatherItem.translateNbtToBedrock(tag); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java index 39787ae2f..09878e652 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -39,7 +39,7 @@ public class DyeableHorseArmorItem extends Item implements DyeableLeatherItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); DyeableLeatherItem.translateNbtToBedrock(tag); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index c51278947..d3aa72cbc 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; @@ -42,7 +42,7 @@ public class EnchantedBookItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); List newTags = new ArrayList<>(); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index 6be1be15d..b44dc08eb 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -40,7 +40,7 @@ public class FireworkRocketItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); CompoundTag fireworks = tag.get("Fireworks"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 6d4347e9e..80a32fc44 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; @@ -41,7 +41,7 @@ public class FireworkStarItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); Tag explosion = tag.remove("Explosion"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java index 50a0bddbc..0e1a4cc0e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; @@ -38,7 +38,7 @@ public class FishingRodItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); // Fix damage inconsistency 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 df3c5effe..3ecf3be1b 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 @@ -27,7 +27,7 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments; import com.github.steveice10.opennbt.tag.builtin.*; @@ -103,12 +103,12 @@ public class Item { .definition(mapping.getBedrockDefinition()) .damage(mapping.getBedrockData()) .count(itemStack.getAmount()); - if (itemStack.getNbt() != null) { - builder.tag(ItemTranslator.translateNbtToBedrock(itemStack.getNbt())); + if (itemStack.getDataComponents() != null) { + builder.tag(ItemTranslator.translateNbtToBedrock(itemStack.getDataComponents())); } - CompoundTag nbt = itemStack.getNbt(); - ItemTranslator.translateCustomItem(nbt, builder, mapping); + DataComponents components = itemStack.getDataComponents(); + ItemTranslator.translateCustomItem(components, builder, mapping); return builder; } @@ -127,7 +127,7 @@ public class Item { /** * Takes components from Java Edition and map them into Bedrock. */ - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { // // Basing off of ItemStack#getHoverName as of 1.20.5. VERIFY?? // Component customName = components.get(DataComponentType.CUSTOM_NAME); // if (customName == null) { @@ -271,7 +271,7 @@ public class Item { /* Translation methods end */ - public ItemStack newItemStack(int count, DataComponentPatch components) { + public ItemStack newItemStack(int count, DataComponents components) { return new ItemStack(this.javaId, count, components); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java index 8dbeeb57f..64e505800 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -38,7 +38,7 @@ public class MapItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); Tag mapId = tag.remove("map"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index 4aefcf765..6ebc728cb 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; @@ -42,7 +42,7 @@ public class PlayerHeadItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); CompoundTag displayTag; 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 26c468fb1..bed2945ba 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 @@ -47,10 +47,10 @@ public class PotionItem extends Item { @Override public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - if (itemStack.getDataComponentPatch() == null) return super.translateToBedrock(itemStack, mapping, mappings); - PotionContents potionContents = itemStack.getDataComponentPatch().get(DataComponentType.POTION_CONTENTS); + if (itemStack.getDataComponents() == null) return super.translateToBedrock(itemStack, mapping, mappings); + PotionContents potionContents = itemStack.getDataComponents().get(DataComponentType.POTION_CONTENTS); if (potionContents != null) { - ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(itemStack.getDataComponentPatch(), mapping); + ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(itemStack.getDataComponents(), mapping); if (customItemDefinition == null) { Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); if (potion != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index cd940c87c..b3f9f57e3 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; @@ -41,7 +41,7 @@ public class ShieldItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index e2259eb5d..3d5fa2444 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -25,11 +25,10 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.opennbt.tag.builtin.*; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -38,7 +37,6 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; -import org.geysermc.geyser.util.MathUtils; import java.util.ArrayList; import java.util.List; @@ -49,7 +47,7 @@ public class ShulkerBoxItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); List contents = components.get(DataComponentType.CONTAINER); @@ -73,9 +71,16 @@ public class ShulkerBoxItem extends BlockItem { boxItemNbt.putShort("Damage", (short) boxMapping.getBedrockData()); boxItemNbt.putByte("Count", (byte) item.getAmount()); // Only the display name is what we have interest in, so just translate that if relevant - DataComponentPatch boxComponents = item.getDataComponentPatch(); + DataComponents boxComponents = item.getDataComponents(); if (boxComponents != null) { - boxItemNbt.put(ItemTranslator.translateDisplayProperties(session, displayTag, boxMapping, '7')); + String customName = ItemTranslator.getCustomName(session, boxComponents, boxMapping, '7'); + if (customName != null) { + boxItemNbt.putCompound("tag", NbtMap.builder() + .putCompound("display", NbtMap.builder() + .putString("Name", customName) + .build()) + .build()); + } } itemsList.add(boxItemNbt.build()); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index 17f90ca12..2ce0dd071 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -49,7 +49,7 @@ public class TropicalFishBucketItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); // Prevent name from appearing as "Bucket of" diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java index 67221b1c6..46b9b80ce 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; @@ -45,7 +45,7 @@ public class WritableBookItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { super.translateComponentsToBedrock(session, components, builder); ListTag pagesTag = tag.remove("pages"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index 0198e73ff..46eceaa86 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; @@ -50,7 +50,7 @@ public class WrittenBookItem extends WritableBookItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponentPatch components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { boolean isValid = isValidWrittenBook(tag); if (!isValid) { tag.remove("pages"); diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java new file mode 100644 index 000000000..162d57120 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java @@ -0,0 +1,93 @@ +/* + * 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.item; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; + +import java.util.ArrayList; +import java.util.List; + +/** + * An intermediary class made to allow easy access to work-in-progress NBT, such as lore and display. + */ +public final class BedrockItemBuilder { + // All Bedrock-style + @Nullable + private String customName; + @Nullable + private List lore; + /** + * Miscellaneous NBT that will be put into the final item. + */ + @Nullable + private NbtMapBuilder builder; + + public BedrockItemBuilder setCustomName(String customName) { + this.customName = customName; + return this; + } + + @NonNull + public List getOrCreateLore() { + if (lore == null) { + lore = new ArrayList<>(); + } + return lore; + } + + @NonNull + public NbtMapBuilder getOrCreateNbt() { + if (builder == null) { + builder = NbtMap.builder(); + } + return builder; + } + + /** + * @return null if no NBT is needed on this item. + */ + @Nullable + public NbtMap build() { + if (customName != null || lore != null) { + NbtMapBuilder display = NbtMap.builder(); + if (customName != null) { + display.putString("Name", customName); + } + if (lore != null) { + display.putList("Lore", NbtType.STRING, lore); + } + getOrCreateNbt().put("display", display.build()); + } + if (builder == null) { + return null; + } + return builder.build(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java index d5f85dcc3..8a541fb9b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.item; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import it.unimi.dsi.fastutil.Pair; import org.checkerframework.checker.nullness.qual.Nullable; @@ -43,7 +43,7 @@ import java.util.OptionalInt; public final class CustomItemTranslator { @Nullable - public static ItemDefinition getCustomItem(DataComponentPatch components, ItemMapping mapping) { + public static ItemDefinition getCustomItem(DataComponents components, ItemMapping mapping) { if (components == null) { return null; } @@ -52,10 +52,9 @@ public final class CustomItemTranslator { return null; } - // TODO getOrDefault - int customModelData = components.get(DataComponentType.CUSTOM_MODEL_DATA); + int customModelData = components.getOrDefault(DataComponentType.CUSTOM_MODEL_DATA, 0); boolean checkDamage = mapping.getJavaItem().maxDamage() > 0; - int damage = !checkDamage ? 0 : components.get(DataComponentType.DAMAGE); + int damage = !checkDamage ? 0 : components.getOrDefault(DataComponentType.DAMAGE, 0); boolean unbreakable = checkDamage && !isDamaged(components, damage); for (Pair mappingTypes : customMappings) { @@ -105,11 +104,11 @@ public final class CustomItemTranslator { /* These two functions are based off their Mojmap equivalents from 1.19.2 */ - private static boolean isDamaged(DataComponentPatch components, int damage) { + private static boolean isDamaged(DataComponents components, int damage) { return isDamagableItem(components) && damage > 0; } - private static boolean isDamagableItem(DataComponentPatch components) { + private static boolean isDamagableItem(DataComponents components) { // mapping.getMaxDamage > 0 should also be checked (return false if not true) but we already check prior to this function Boolean unbreakable = components.get(DataComponentType.UNBREAKABLE); // Tag must either not be present or be set to false 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 027c6b5ba..b52861b35 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 @@ -25,11 +25,12 @@ package org.geysermc.geyser.translator.item; +import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOperation; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.item.component.AdventureModePredicate; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentPatch; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.ItemAttributeModifiers; import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; @@ -83,7 +84,6 @@ public final class ItemTranslator { */ private static final String[] ALL_SLOTS = new String[]{"mainhand", "offhand", "feet", "legs", "chest", "head"}; private static final DecimalFormat ATTRIBUTE_FORMAT = new DecimalFormat("0.#####"); - private static final byte HIDE_ATTRIBUTES_FLAG = 1 << 1; private ItemTranslator() { } @@ -102,23 +102,23 @@ public final class ItemTranslator { ItemStack itemStack = javaItem.translateToJava(data, bedrockItem, mappings); - if (itemStack.getNbt() != null) { - javaItem.translateNbtToJava(itemStack.getNbt(), bedrockItem); - if (itemStack.getNbt().isEmpty()) { - // Otherwise, seems to cause issues with villagers accepting books, and I don't see how this will break anything else. - Camotoy - itemStack = new ItemStack(itemStack.getId(), itemStack.getAmount(), null); - } - } +// if (itemStack.getNbt() != null) { +// javaItem.translateNbtToJava(itemStack.getNbt(), bedrockItem); +// if (itemStack.getNbt().isEmpty()) { +// // Otherwise, seems to cause issues with villagers accepting books, and I don't see how this will break anything else. - Camotoy +// itemStack = new ItemStack(itemStack.getId(), itemStack.getAmount(), null); +// } +// } return itemStack; } - public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, int javaId, int count, CompoundTag tag) { + public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, int javaId, int count, DataComponents components) { ItemMapping bedrockItem = session.getItemMappings().getMapping(javaId); if (bedrockItem == ItemMapping.AIR) { session.getGeyser().getLogger().debug("ItemMapping returned air: " + javaId); return ItemData.builder(); } - return translateToBedrock(session, Registries.JAVA_ITEMS.get().get(javaId), bedrockItem, count, tag); + return translateToBedrock(session, Registries.JAVA_ITEMS.get().get(javaId), bedrockItem, count, components); } @NonNull @@ -133,32 +133,35 @@ public final class ItemTranslator { return ItemData.AIR; } // Java item needs to be loaded separately. The mapping for tipped arrow would - return translateToBedrock(session, Registries.JAVA_ITEMS.get().get(stack.getId()), bedrockItem, stack.getAmount(), stack.getNbt()) + return translateToBedrock(session, Registries.JAVA_ITEMS.get().get(stack.getId()), bedrockItem, stack.getAmount(), stack.getDataComponents()) .build(); } - private static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, DataComponentPatch components) { - NbtMapBuilder builder = NbtMap.builder(); + private static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, DataComponents components) { + BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); if (components != null) { - javaItem.translateComponentsToBedrock(session, components, builder); + javaItem.translateComponentsToBedrock(session, components, nbtBuilder.getOrCreateNbt()); } - translateDisplayProperties(session, components, bedrockItem); + String customName = getCustomName(session, components, bedrockItem); + if (customName != null) { + nbtBuilder.setCustomName(customName); + } if (components != null) { ItemAttributeModifiers attributeModifiers = components.get(DataComponentType.ATTRIBUTE_MODIFIERS); if (attributeModifiers != null && attributeModifiers.isShowInTooltip()) { // only add if attribute modifiers do not indicate to hide them - addAttributeLore(attributeModifiers, builder, session.locale()); + addAttributeLore(attributeModifiers, nbtBuilder, session.locale()); } } if (session.isAdvancedTooltips()) { - nbt = addAdvancedTooltips(nbt, javaItem, session.locale()); + addAdvancedTooltips(components, nbtBuilder, javaItem, session.locale()); } - ItemStack itemStack = new ItemStack(javaItem.javaId(), count, nbt); + ItemStack itemStack = new ItemStack(javaItem.javaId(), count, components); ItemData.Builder builder = javaItem.translateToBedrock(itemStack, bedrockItem, session.getItemMappings()); if (bedrockItem.isBlock()) { @@ -172,10 +175,10 @@ public final class ItemTranslator { } if (bedrockItem.getJavaItem().equals(Items.PLAYER_HEAD)) { - translatePlayerHead(session, nbt, builder); + translatePlayerHead(session, components, builder); } - translateCustomItem(nbt, builder, bedrockItem); + translateCustomItem(components, builder, bedrockItem); if (components != null) { // Translate the canDestroy and canPlaceOn Java NBT @@ -198,21 +201,12 @@ public final class ItemTranslator { * Bedrock Edition does not see attribute modifiers like Java Edition does, * so we add them as lore instead. * - * @param nbt the NBT of the ItemStack + * @param modifiers the attribute modifiers of the ItemStack * @param language the locale of the player */ - private static void addAttributeLore(ItemAttributeModifiers modifiers, NbtMapBuilder builder, String language) { - CompoundTag displayTag = builder.get("display"); - if (displayTag == null) { - displayTag = new CompoundTag("display"); - } - ListTag lore = displayTag.get("Lore"); - if (lore == null) { - lore = new ListTag("Lore"); - } - + private static void addAttributeLore(ItemAttributeModifiers modifiers, BedrockItemBuilder builder, String language) { // maps each slot to the modifiers applied when in such slot - Map> slotsToModifiers = new HashMap<>(); + Map> slotsToModifiers = new HashMap<>(); for (ItemAttributeModifiers.Entry entry : modifiers.getModifiers()) { // convert the modifier tag to a lore entry String loreEntry = attributeToLore(entry.getModifier(), language); @@ -220,23 +214,22 @@ public final class ItemTranslator { continue; // invalid or failed } - StringTag loreTag = new StringTag("", loreEntry); ItemAttributeModifiers.EquipmentSlotGroup slotGroup = entry.getSlot(); if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ANY) { // modifier applies to all slots implicitly - for (String slot : ALL_SLOTS) { - slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreTag); + for (String slot : ALL_SLOTS) { // TODO SOMEONE LOOK HERE PLZ + //slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreEntry); } } else { // modifier applies to only the specified slot - slotsToModifiers.computeIfAbsent(slotGroup, s -> new ArrayList<>()).add(loreTag); + slotsToModifiers.computeIfAbsent(slotGroup, s -> new ArrayList<>()).add(loreEntry); } } // iterate through the small array, not the map, so that ordering matches Java Edition for (String slot : ALL_SLOTS) { - List modifiers = slotsToModifiers.get(slot); - if (modifiers == null || modifiers.isEmpty()) { + List modifierStrings = slotsToModifiers.get(slot); + if (modifierStrings == null || modifierStrings.isEmpty()) { continue; } @@ -246,16 +239,13 @@ public final class ItemTranslator { .color(NamedTextColor.GRAY) .append(Component.newline(), Component.translatable("item.modifiers." + slot)) .build(); - lore.add(new StringTag("", MessageTranslator.convertMessage(slotComponent, language))); + builder.getOrCreateLore().add(MessageTranslator.convertMessage(slotComponent, language)); // Then list all the modifiers when used in this slot - for (StringTag modifier : modifiers) { - lore.add(modifier); + for (String modifier : modifierStrings) { + builder.getOrCreateLore().add(modifier); } } - - displayTag.put(lore); - nbt.put(displayTag); } @Nullable @@ -294,29 +284,13 @@ public final class ItemTranslator { return MessageTranslator.convertMessage(attributeComponent, language); } - private static CompoundTag addAdvancedTooltips(CompoundTag nbt, Item item, String language) { - CompoundTag newNbt = nbt; - if (newNbt == null) { - newNbt = new CompoundTag("nbt"); - CompoundTag display = new CompoundTag("display"); - display.put(new ListTag("Lore")); - newNbt.put(display); - } - CompoundTag compoundTag = newNbt.get("display"); - if (compoundTag == null) { - compoundTag = new CompoundTag("display"); - } - ListTag listTag = compoundTag.get("Lore"); - - if (listTag == null) { - listTag = new ListTag("Lore"); - } + private static void addAdvancedTooltips(DataComponents components, BedrockItemBuilder builder, Item item, String language) { int maxDurability = item.maxDamage(); if (maxDurability != 0) { - Tag durabilityTag = newNbt.get("Damage"); - if (durabilityTag instanceof IntTag) { - int durability = maxDurability - ((IntTag) durabilityTag).getValue(); + Integer durabilityComponent = components.get(DataComponentType.DAMAGE); + if (durabilityComponent != null) { + int durability = maxDurability - durabilityComponent; if (durability != maxDurability) { Component component = Component.text() .resetStyle() @@ -325,24 +299,21 @@ public final class ItemTranslator { Component.text(durability), Component.text(maxDurability))) .build(); - listTag.add(new StringTag("", MessageTranslator.convertMessage(component, language))); + builder.getOrCreateLore().add(MessageTranslator.convertMessage(component, language)); } } } - listTag.add(new StringTag("", ChatColor.RESET + ChatColor.DARK_GRAY + item.javaIdentifier())); - if (nbt != null) { + builder.getOrCreateLore().add(ChatColor.RESET + ChatColor.DARK_GRAY + item.javaIdentifier()); + if (components != null) { Component component = Component.text() .resetStyle() .color(NamedTextColor.DARK_GRAY) - .append(Component.translatable("item.nbt_tags", - Component.text(nbt.size()))) + .append(Component.translatable("item.nbt_tags", // TODO + Component.text(components.getDataComponents().size()))) .build(); - listTag.add(new StringTag("", MessageTranslator.convertMessage(component, language))); + builder.getOrCreateLore().add(MessageTranslator.convertMessage(component, language)); } - compoundTag.put(listTag); - newNbt.put(compoundTag); - return newNbt; } /** @@ -396,13 +367,13 @@ public final class ItemTranslator { } if (mapping.getJavaItem().equals(Items.PLAYER_HEAD)) { - CustomSkull customSkull = getCustomSkull(session, itemStack.getNbt()); + CustomSkull customSkull = getCustomSkull(session, itemStack.getComponents()); if (customSkull != null) { itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customSkull.getCustomBlockData()); } } - ItemDefinition definition = CustomItemTranslator.getCustomItem(itemStack, mapping); + ItemDefinition definition = CustomItemTranslator.getCustomItem(itemStack.getComponents(), mapping); if (definition == null) { // No custom item return itemDefinition; @@ -533,65 +504,45 @@ public final class ItemTranslator { /** * Translates the display name of the item * @param session the Bedrock client's session - * @param tag the tag to translate + * @param components the components to translate * @param mapping the item entry, in case it requires translation - * - * @return the new tag to use, should the current one be null */ - public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemMapping mapping) { - return translateDisplayProperties(session, tag, mapping, 'f'); + public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping) { + return getCustomName(session, components, mapping, 'f'); } /** * @param translationColor if this item is not available on Java, the color that the new name should be. * Normally, this should just be white, but for shulker boxes this should be gray. */ - public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemMapping mapping, char translationColor) { - boolean hasCustomName = false; - if (tag != null) { - if (tag.get("display") instanceof CompoundTag display && display.get("Name") instanceof StringTag tagName) { - String name = tagName.getValue(); - - // Get the translated name and prefix it with a reset char - name = MessageTranslator.convertMessageLenient(name, session.locale()); - - // Add the new name tag - display.put(new StringTag("Name", name)); - // Indicate that a custom name is present - hasCustomName = true; - - // Add to the new root tag - tag.put(display); + public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor) { + if (components != null) { + // ItemStack#getHoverName as of 1.20.5 + Component customName = components.get(DataComponentType.CUSTOM_NAME); + if (customName == null) { + customName = components.get(DataComponentType.ITEM_NAME); + } + if (customName != null) { + // Get the translated name and prefix it with a reset char TODO test + return MessageTranslator.convertMessage(customName, session.locale()); } } - if (!hasCustomName && mapping.hasTranslation()) { + if (mapping.hasTranslation()) { // No custom name, but we need to localize the item's name - if (tag == null) { - tag = new CompoundTag(""); - } - CompoundTag display; - if (tag.get("display") instanceof CompoundTag oldDisplay) { - display = oldDisplay; - } else { - display = new CompoundTag("display"); - // Add to the new root tag - tag.put(display); - } - String translationKey = mapping.getTranslationString(); // Reset formatting since Bedrock defaults to italics - display.put(new StringTag("Name", ChatColor.RESET + ChatColor.ESCAPE + translationColor + MinecraftLocale.getLocaleString(translationKey, session.locale()))); + return ChatColor.RESET + ChatColor.ESCAPE + translationColor + MinecraftLocale.getLocaleString(translationKey, session.locale()); } - - return tag; + // No custom name + return null; } /** * Translates the custom model data of an item */ - public static void translateCustomItem(CompoundTag nbt, ItemData.Builder builder, ItemMapping mapping) { - ItemDefinition definition = CustomItemTranslator.getCustomItem(nbt, mapping); + public static void translateCustomItem(DataComponents components, ItemData.Builder builder, ItemMapping mapping) { + ItemDefinition definition = CustomItemTranslator.getCustomItem(components, mapping); if (definition != null) { builder.definition(definition); builder.blockDefinition(null); @@ -608,8 +559,12 @@ public final class ItemTranslator { builder.blockDefinition(blockDefinition); } - private static @Nullable CustomSkull getCustomSkull(GeyserSession session, CompoundTag nbt) { - if (nbt != null && nbt.contains("SkullOwner")) { + private static @Nullable CustomSkull getCustomSkull(GeyserSession session, DataComponents components) { + if (components == null) { + return null; + } + GameProfile profile = components.get(DataComponentType.PROFILE); + if (profile != null) { if (!(nbt.get("SkullOwner") instanceof CompoundTag skullOwner)) { // It's a username give up d: return null; @@ -626,8 +581,8 @@ public final class ItemTranslator { return null; } - private static void translatePlayerHead(GeyserSession session, CompoundTag nbt, ItemData.Builder builder) { - CustomSkull customSkull = getCustomSkull(session, nbt); + private static void translatePlayerHead(GeyserSession session, DataComponents components, ItemData.Builder builder) { + CustomSkull customSkull = getCustomSkull(session, components); if (customSkull != null) { CustomBlockData customBlockData = customSkull.getCustomBlockData(); ItemDefinition itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customBlockData); @@ -636,18 +591,4 @@ public final class ItemTranslator { builder.blockDefinition(blockDefinition); } } - - /** - * Checks if the NBT of a Java item stack has the given hide flag. - * - * @param hideFlags the "HideFlags", which may not be null - * @param flagMask the flag to check for, as a bit mask - * @return true if the flag is present, false if not or if the tag value is not a number - */ - private static boolean hasFlagPresent(Tag hideFlags, byte flagMask) { - if (hideFlags.getValue() instanceof Number flags) { - return (flags.byteValue() & flagMask) == flagMask; - } - return false; - } } From 909139326d3324eb6637c23f60a0f4516f09149c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 20 Apr 2024 14:55:30 -0400 Subject: [PATCH 044/897] Keep chugging away --- .../geyser/item/DyeableLeatherItem.java | 15 +++--- .../geysermc/geyser/item/type/ArmorItem.java | 25 ++++++---- .../geyser/item/type/AxolotlBucketItem.java | 14 +++--- .../geysermc/geyser/item/type/BannerItem.java | 37 +++++++------- .../geysermc/geyser/item/type/ChestItem.java | 16 ++----- .../geyser/item/type/CompassItem.java | 34 +++++++------ .../geyser/item/type/CrossbowItem.java | 35 +++++++------- .../geyser/item/type/DecoratedPotItem.java | 20 ++++---- .../geyser/item/type/DyeableArmorItem.java | 6 +-- .../item/type/DyeableHorseArmorItem.java | 6 +-- .../geyser/item/type/EnchantedBookItem.java | 4 +- .../geyser/item/type/FilledMapItem.java | 18 +++---- .../geyser/item/type/FireworkRocketItem.java | 48 +++++++++---------- .../geyser/item/type/FireworkStarItem.java | 4 +- .../geyser/item/type/FishingRodItem.java | 4 +- .../org/geysermc/geyser/item/type/Item.java | 18 ++----- .../geysermc/geyser/item/type/MapItem.java | 4 +- .../geyser/item/type/PlayerHeadItem.java | 4 +- .../geysermc/geyser/item/type/ShieldItem.java | 4 +- .../geyser/item/type/ShulkerBoxItem.java | 16 +++---- .../item/type/TropicalFishBucketItem.java | 4 +- .../geyser/item/type/WritableBookItem.java | 4 +- .../geyser/item/type/WrittenBookItem.java | 4 +- .../geyser/session/cache/LodestoneCache.java | 3 +- .../translator/item/BedrockItemBuilder.java | 35 ++++++++++++++ .../translator/item/ItemTranslator.java | 2 +- 26 files changed, 200 insertions(+), 184 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java b/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java index e0eec767f..214b9d78c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java @@ -25,20 +25,21 @@ package org.geysermc.geyser.item; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.mc.protocol.data.game.item.component.DyedItemColor; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public interface DyeableLeatherItem { - static void translateNbtToBedrock(CompoundTag tag) { - CompoundTag displayTag = tag.get("display"); - if (displayTag == null) { + static void translateComponentsToBedrock(DataComponents components, BedrockItemBuilder builder) { + DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR); + if (dyedItemColor == null) { return; } - IntTag color = displayTag.remove("color"); - if (color != null) { - tag.put(new IntTag("customColor", color.getValue())); - } + builder.putInt("customColor", dyedItemColor.getRgb()); } static void translateNbtToJava(CompoundTag tag) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index eb5233b88..ba7f05205 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -25,14 +25,18 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.ArmorTrim; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class ArmorItem extends Item { private final ArmorMaterial material; @@ -43,23 +47,26 @@ public class ArmorItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - if (tag.get("Trim") instanceof CompoundTag trim) { - StringTag material = trim.remove("material"); - StringTag pattern = trim.remove("pattern"); + ArmorTrim trim = components.get(DataComponentType.TRIM); + if (trim != null) { + // TODO material IDs + String material = trim.getMaterial().getAssetName(); + String pattern = trim.getPattern().getAssetId(); // discard custom trim patterns/materials to prevent visual glitches on bedrock - if (!material.getValue().startsWith("minecraft:") - || !pattern.getValue().startsWith("minecraft:")) { - tag.remove("Trim"); + if (!material.startsWith("minecraft:") + || !pattern.startsWith("minecraft:")) { return; } + NbtMapBuilder trimBuilder = NbtMap.builder(); // bedrock has an uppercase first letter key, and the value is not namespaced - trim.put(new StringTag("Material", stripNamespace(material.getValue()))); - trim.put(new StringTag("Pattern", stripNamespace(pattern.getValue()))); + trimBuilder.put("Material", stripNamespace(material)); + trimBuilder.put("Pattern", stripNamespace(pattern)); + builder.putCompound("Trim", trimBuilder.build()); } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java index d0aa1e901..99f649e87 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java @@ -26,12 +26,10 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class AxolotlBucketItem extends Item { public AxolotlBucketItem(String javaIdentifier, Builder builder) { @@ -39,15 +37,15 @@ public class AxolotlBucketItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); // Bedrock Edition displays the properties of the axolotl. Java does not. // To work around this, set the custom name to the Axolotl translation and it's displayed correctly - tag.put(new ByteTag("AppendCustomName", (byte) 1)); - tag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.axolotl", session.locale()))); + builder.putByte("AppendCustomName", 1); + builder.putString("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.axolotl", session.locale())); // Boilerplate required so the nametag does not appear as "Bucket of " - tag.put(new StringTag("ColorID", "")); - tag.put(new StringTag("BodyID", "")); + builder.putString("ColorID", ""); + builder.putString("BodyID", ""); } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 2a8ca9f15..549809391 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.BannerPatternLayer; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; @@ -33,16 +35,14 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import java.util.ArrayList; import java.util.List; -import static org.geysermc.erosion.util.BannerUtils.getJavaPatternTag; - public class BannerItem extends BlockItem { /** * Holds what a Java ominous banner pattern looks like. @@ -51,19 +51,20 @@ public class BannerItem extends BlockItem { * ominous banners that we set instead. This variable is used to detect Java ominous banner patterns, and apply * the correct ominous banner pattern if Bedrock pulls the item from creative. */ - public static final ListTag OMINOUS_BANNER_PATTERN; + public static final List OMINOUS_BANNER_PATTERN; static { - OMINOUS_BANNER_PATTERN = new ListTag("Patterns"); // Construct what an ominous banner is supposed to look like - OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("mr", 9)); - OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bs", 8)); - OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("cs", 7)); - OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bo", 8)); - OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("ms", 15)); - OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("hh", 8)); - OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("mc", 8)); - OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bo", 15)); + OMINOUS_BANNER_PATTERN = List.of( + new BannerPatternLayer("mr", 9), + new BannerPatternLayer("bs", 8), + new BannerPatternLayer("cs", 7), + new BannerPatternLayer("bo", 8), + new BannerPatternLayer("ms", 15), + new BannerPatternLayer("hh", 8), + new BannerPatternLayer("mc", 8), + new BannerPatternLayer("bo", 15) + ); } /** @@ -102,7 +103,7 @@ public class BannerItem extends BlockItem { * @return The Java edition format pattern nbt */ public static CompoundTag getJavaBannerPattern(NbtMap pattern) { - return getJavaPatternTag(pattern.getString("Pattern"), 15 - pattern.getInt("Color")); + return new BannerPatternLayer(pattern.getString("Pattern"), 15 - pattern.getInt("Color")); } /** @@ -122,14 +123,14 @@ public class BannerItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - CompoundTag blockEntityTag = tag.remove("BlockEntityTag"); - if (blockEntityTag != null && blockEntityTag.get("Patterns") instanceof ListTag patterns) { + List patterns = components.get(DataComponentType.BANNER_PATTERNS); + if (patterns != null) { if (patterns.equals(OMINOUS_BANNER_PATTERN)) { // Remove the current patterns and set the ominous banner type - tag.put(new IntTag("Type", 1)); + builder.putInt("Type", 1); } else { invertBannerColors(patterns); tag.put(patterns); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java index 8644ec8be..1f6ac6964 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java @@ -27,9 +27,10 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; +@Deprecated public class ChestItem extends BlockItem { public ChestItem(String javaIdentifier, Builder builder) { @@ -37,18 +38,7 @@ public class ChestItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - - // Strip the BlockEntityTag from the chests contents - // sent to the client. The client does not parse this - // or use it for anything, as this tag is fully - // server-side, so we remove it to reduce bandwidth and - // solve potential issues with very large tags. - - // There was a problem in the past where this would strip - // NBT data in creative mode, however with the new server - // authoritative inventories, this is no longer a concern. - tag.remove("BlockEntityTag"); } } 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 605d19852..8d48d1307 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 @@ -26,17 +26,16 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.protocol.data.game.item.component.LodestoneTracker; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; +import org.checkerframework.checker.nullness.qual.Nullable; 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.geyser.translator.item.BedrockItemBuilder; public class CompassItem extends Item { public CompassItem(String javaIdentifier, Builder builder) { @@ -45,36 +44,35 @@ public class CompassItem extends Item { @Override public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - if (isLodestoneCompass(itemStack.getNbt())) { + if (isLodestoneCompass(itemStack.getDataComponents())) { return super.translateToBedrock(itemStack, mappings.getLodestoneCompass(), mappings); } return super.translateToBedrock(itemStack, mapping, mappings); } @Override - public ItemMapping toBedrockDefinition(CompoundTag nbt, ItemMappings mappings) { - if (isLodestoneCompass(nbt)) { + public ItemMapping toBedrockDefinition(DataComponents components, ItemMappings mappings) { + if (isLodestoneCompass(components)) { return mappings.getLodestoneCompass(); } - return super.toBedrockDefinition(nbt, mappings); + return super.toBedrockDefinition(components, mappings); } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - Tag lodestoneTag = tag.get("LodestoneTracked"); - if (lodestoneTag instanceof ByteTag) { - int trackId = session.getLodestoneCache().store(tag); + LodestoneTracker tracker = components.get(DataComponentType.LODESTONE_TRACKER); + if (tracker != null) { + int trackId = session.getLodestoneCache().store(tracker); // Set the bedrock tracking id - will return 0 if invalid - tag.put(new IntTag("trackingHandle", trackId)); + builder.putInt("trackingHandle", trackId); } } - private boolean isLodestoneCompass(CompoundTag nbt) { - if (nbt != null) { - Tag lodestoneTag = nbt.get("LodestoneTracked"); - return lodestoneTag instanceof ByteTag; + private boolean isLodestoneCompass(@Nullable DataComponents components) { + if (components != null) { + return components.getDataComponents().containsKey(DataComponentType.LODESTONE_TRACKER); } return false; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java index c38e2f2ba..5b92ba303 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java @@ -26,44 +26,41 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.*; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.ItemTranslator; +import java.util.List; + public class CrossbowItem extends Item { public CrossbowItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - ListTag chargedProjectiles = tag.get("ChargedProjectiles"); - if (chargedProjectiles != null) { - if (!chargedProjectiles.getValue().isEmpty()) { - CompoundTag javaProjectileAsNbt = (CompoundTag) chargedProjectiles.getValue().get(0); + List chargedProjectiles = components.get(DataComponentType.CHARGED_PROJECTILES); + if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { + ItemStack javaProjectile = chargedProjectiles.get(0); - ItemMapping projectileMapping = session.getItemMappings().getMapping((String) javaProjectileAsNbt.get("id").getValue()); - if (projectileMapping == null) return; - @Nullable CompoundTag projectileTag = javaProjectileAsNbt.get("tag"); - ItemStack itemStack = new ItemStack(projectileMapping.getJavaItem().javaId(), (byte) javaProjectileAsNbt.get("Count").getValue(), projectileTag); - ItemData itemData = ItemTranslator.translateToBedrock(session, itemStack); + ItemMapping projectileMapping = session.getItemMappings().getMapping(javaProjectile.getId()); + ItemData itemData = ItemTranslator.translateToBedrock(session, javaProjectile); - CompoundTag newProjectile = new CompoundTag("chargedItem"); - newProjectile.put(new ByteTag("Count", (byte) itemData.getCount())); - newProjectile.put(new StringTag("Name", projectileMapping.getBedrockIdentifier())); + NbtMapBuilder newProjectile = BedrockItemBuilder.createItemNbt(projectileMapping, itemData.getCount(), itemData.getDamage()); - newProjectile.put(new ShortTag("Damage", (short) itemData.getDamage())); - - tag.put(newProjectile); - } + builder.putCompound("chargedItem", newProjectile.build()); } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index 74cabc3d9..792ec0f0b 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -25,12 +25,11 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class DecoratedPotItem extends BlockItem { @@ -39,14 +38,15 @@ public class DecoratedPotItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { - if (blockEntityTag.remove("sherds") instanceof ListTag sherds) { - // bedrock wants it on the root level - tag.put(sherds); - } - } + components.get(DataComponentType.POT_DECORATIONS); // TODO +// if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { +// if (blockEntityTag.remove("sherds") instanceof ListTag sherds) { +// // bedrock wants it on the root level +// tag.put(sherds); +// } +// } } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index fbe0222bc..117e70b9a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -28,11 +28,11 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.item.DyeableLeatherItem; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem { public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) { @@ -40,10 +40,10 @@ public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - DyeableLeatherItem.translateNbtToBedrock(tag); + DyeableLeatherItem.translateComponentsToBedrock(components, builder); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java index 09878e652..cb6dd869b 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java @@ -28,10 +28,10 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.DyeableLeatherItem; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class DyeableHorseArmorItem extends Item implements DyeableLeatherItem { public DyeableHorseArmorItem(String javaIdentifier, Builder builder) { @@ -39,10 +39,10 @@ public class DyeableHorseArmorItem extends Item implements DyeableLeatherItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - DyeableLeatherItem.translateNbtToBedrock(tag); + DyeableLeatherItem.translateComponentsToBedrock(components, builder); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index d3aa72cbc..3851813ae 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -30,8 +30,8 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import java.util.ArrayList; import java.util.List; @@ -42,7 +42,7 @@ public class EnchantedBookItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); List newTags = new ArrayList<>(); 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 8125ce101..78a175f8d 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 @@ -26,8 +26,8 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.registry.type.ItemMapping; @@ -41,16 +41,16 @@ public class FilledMapItem extends MapItem { @Override public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings); - CompoundTag nbt = itemStack.getNbt(); - if (nbt == null) { + DataComponents components = itemStack.getDataComponents(); + 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()); - } else if (nbt.get("display") instanceof CompoundTag display) { - // Note: damage 5 treasure map, 6 ??? - Tag mapColor = display.get("MapColor"); - if (mapColor != null && mapColor.getValue() instanceof Number color) { + } else { + Integer mapColor = components.get(DataComponentType.MAP_COLOR); + if (mapColor != null) { + // Note: damage 5 treasure map, 6 ??? // Java Edition allows any color; Bedrock only allows some. So let's take what colors we can get - switch (color.intValue()) { + switch (mapColor) { case 3830373 -> builder.damage(3); // Ocean Monument case 5393476 -> builder.damage(4); // Woodland explorer } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index b44dc08eb..d688e59f6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -25,44 +25,47 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.mc.protocol.data.game.item.component.Fireworks; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.FireworkColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.util.MathUtils; +import java.util.ArrayList; +import java.util.List; + public class FireworkRocketItem extends Item { public FireworkRocketItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - CompoundTag fireworks = tag.get("Fireworks"); + Fireworks fireworks = components.get(DataComponentType.FIREWORKS); if (fireworks == null) { return; } + NbtMapBuilder fireworksNbt = NbtMap.builder(); + fireworksNbt.putByte("Flight", (byte) fireworks.getFlightDuration()); - if (fireworks.get("Flight") != null) { - fireworks.put(new ByteTag("Flight", MathUtils.getNbtByte(fireworks.get("Flight").getValue()))); - } - - ListTag explosions = fireworks.get("Explosions"); - if (explosions == null) { + List explosions = fireworks.getExplosions(); + if (explosions.isEmpty()) { return; } - for (Tag effect : explosions.getValue()) { - CompoundTag effectData = (CompoundTag) effect; - CompoundTag newEffectData = translateExplosionToBedrock(effectData, ""); - - explosions.remove(effectData); - explosions.add(newEffectData); + List explosionNbt = new ArrayList<>(); + for (Fireworks.FireworkExplosion explosion : explosions) { + explosionNbt.add(translateExplosionToBedrock(explosion, "")); } + } @Override @@ -70,13 +73,15 @@ public class FireworkRocketItem extends Item { super.translateNbtToJava(tag, mapping); } - static CompoundTag translateExplosionToBedrock(CompoundTag explosion, String newName) { - CompoundTag newExplosionData = new CompoundTag(newName); + static NbtMap translateExplosionToBedrock(Fireworks.FireworkExplosion explosion, String newName) { + NbtMapBuilder newExplosionData = NbtMap.builder(); if (explosion.get("Type") != null) { newExplosionData.put(new ByteTag("FireworkType", MathUtils.getNbtByte(explosion.get("Type").getValue()))); } + //newExplosionData.putByte("FireworkType", explosion.get) //TODO??? + // TODO do we need length checks if (explosion.get("Colors") != null) { int[] oldColors = (int[]) explosion.get("Colors").getValue(); byte[] colors = new byte[oldColors.length]; @@ -101,15 +106,10 @@ public class FireworkRocketItem extends Item { newExplosionData.put(new ByteArrayTag("FireworkFade", colors)); } - if (explosion.get("Trail") != null) { - newExplosionData.put(new ByteTag("FireworkTrail", MathUtils.getNbtByte(explosion.get("Trail").getValue()))); - } + newExplosionData.putBoolean("FireworkTrail", explosion.isHasTrail()); + newExplosionData.putBoolean("FireworkFlicker", explosion.isHasTwinkle()); // TODO verify - if (explosion.get("Flicker") != null) { - newExplosionData.put(new ByteTag("FireworkFlicker", MathUtils.getNbtByte(explosion.get("Flicker").getValue()))); - } - - return newExplosionData; + return newExplosionData.build(); } static CompoundTag translateExplosionToJava(CompoundTag explosion, String newName) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 80a32fc44..4ae9c8b13 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -31,9 +31,9 @@ import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class FireworkStarItem extends Item { public FireworkStarItem(String javaIdentifier, Builder builder) { @@ -41,7 +41,7 @@ public class FireworkStarItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); Tag explosion = tag.remove("Explosion"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java index 0e1a4cc0e..4538689da 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java @@ -29,8 +29,8 @@ import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class FishingRodItem extends Item { public FishingRodItem(String javaIdentifier, Builder builder) { @@ -38,7 +38,7 @@ public class FishingRodItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); // Fix damage inconsistency 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 3ecf3be1b..decc60da8 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 @@ -34,10 +34,8 @@ import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Enchantment; @@ -46,6 +44,7 @@ import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.InventoryUtils; @@ -120,29 +119,20 @@ public class Item { return new ItemStack(javaId, itemData.getCount(), ItemTranslator.translateToJavaNBT("", itemData.getTag())); } - public ItemMapping toBedrockDefinition(CompoundTag nbt, ItemMappings mappings) { + public ItemMapping toBedrockDefinition(DataComponents components, ItemMappings mappings) { return mappings.getMapping(javaId); } /** * Takes components from Java Edition and map them into Bedrock. */ - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { -// // Basing off of ItemStack#getHoverName as of 1.20.5. VERIFY?? -// Component customName = components.get(DataComponentType.CUSTOM_NAME); -// if (customName == null) { -// customName = components.get(DataComponentType.ITEM_NAME); -// } -// if (customName != null) { -// -// } + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { List loreComponents = components.get(DataComponentType.LORE); if (loreComponents != null) { - List lore = new ArrayList<>(); + List lore = builder.getOrCreateLore(); for (Component loreComponent : loreComponents) { lore.add(MessageTranslator.convertMessage(loreComponent, session.locale())); } - builder.putList("Lore", NbtType.STRING, lore); } List newTags = new ArrayList<>(); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java index 64e505800..b015862c5 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java @@ -28,9 +28,9 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class MapItem extends Item { public MapItem(String javaIdentifier, Builder builder) { @@ -38,7 +38,7 @@ public class MapItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); Tag mapId = tag.remove("map"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index 6ebc728cb..dae444775 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -30,10 +30,10 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; public class PlayerHeadItem extends Item { @@ -42,7 +42,7 @@ public class PlayerHeadItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); CompoundTag displayTag; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index b3f9f57e3..30b50b436 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -31,9 +31,9 @@ import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; public class ShieldItem extends Item { public ShieldItem(String javaIdentifier, Builder builder) { @@ -41,7 +41,7 @@ public class ShieldItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index 3d5fa2444..395563fe3 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -36,6 +36,7 @@ import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.ItemTranslator; import java.util.ArrayList; @@ -47,7 +48,7 @@ public class ShulkerBoxItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); List contents = components.get(DataComponentType.CONTAINER); @@ -61,15 +62,12 @@ public class ShulkerBoxItem extends BlockItem { if (item.getId() == Items.AIR_ID) { continue; } - NbtMapBuilder boxItemNbt = NbtMap.builder(); // Final item tag to add to the list - boxItemNbt.putByte("Slot", (byte) slot); - boxItemNbt.putByte("WasPickedUp", (byte) 0); // ??? - ItemMapping boxMapping = session.getItemMappings().getMapping(item.getId()); - boxItemNbt.putString("Name", boxMapping.getBedrockIdentifier()); - boxItemNbt.putShort("Damage", (short) boxMapping.getBedrockData()); - boxItemNbt.putByte("Count", (byte) item.getAmount()); + NbtMapBuilder boxItemNbt = BedrockItemBuilder.createItemNbt(boxMapping, item.getAmount(), boxMapping.getBedrockData()); // Final item tag to add to the list + boxItemNbt.putByte("Slot", (byte) slot); + boxItemNbt.putByte("WasPickedUp", (byte) 0); // ??? TODO might not be needed + // Only the display name is what we have interest in, so just translate that if relevant DataComponents boxComponents = item.getDataComponents(); if (boxComponents != null) { @@ -85,7 +83,7 @@ public class ShulkerBoxItem extends BlockItem { itemsList.add(boxItemNbt.build()); } - builder.putList("Items", NbtType.COMPOUND, itemsList); + builder.getOrCreateNbt().putList("Items", NbtType.COMPOUND, itemsList); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index 2ce0dd071..3ece87745 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -32,10 +32,10 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.entity.type.living.animal.TropicalFishEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; import java.util.ArrayList; @@ -49,7 +49,7 @@ public class TropicalFishBucketItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); // Prevent name from appearing as "Bucket of" diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java index 46b9b80ce..68cdf99d4 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java @@ -31,9 +31,9 @@ import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; import java.util.ArrayList; @@ -45,7 +45,7 @@ public class WritableBookItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); ListTag pagesTag = tag.remove("pages"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index 46eceaa86..ae6b81f6e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -33,8 +33,8 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; import java.util.List; @@ -50,7 +50,7 @@ public class WrittenBookItem extends WritableBookItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull NbtMapBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { boolean isValid = isValidWrittenBook(tag); if (!isValid) { tag.remove("pages"); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java index f118195b9..4bd2244ab 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.session.cache; +import com.github.steveice10.mc.protocol.data.game.item.component.LodestoneTracker; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; @@ -88,7 +89,7 @@ public final class LodestoneCache { this.activeLodestones.put(itemStack, new LodestonePos(id++, x, y, z, dim)); } - public int store(CompoundTag tag) { + public int store(LodestoneTracker tracker) { CompoundTag lodestonePos = tag.get("LodestonePos"); if (lodestonePos == null) { // invalid diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java index 162d57120..83293d4ee 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java @@ -30,6 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.registry.type.ItemMapping; import java.util.ArrayList; import java.util.List; @@ -70,6 +71,28 @@ public final class BedrockItemBuilder { return builder; } + // NBT convenience methods. Returns NbtMapBuilder since that's what's used the most + + public NbtMapBuilder putByte(String name, byte value) { + return getOrCreateNbt().putByte(name, value); + } + + public NbtMapBuilder putByte(String name, int value) { + return getOrCreateNbt().putByte(name, (byte) value); + } + + public NbtMapBuilder putInt(String name, int value) { + return getOrCreateNbt().putInt(name, value); + } + + public NbtMapBuilder putString(String name, String value) { + return getOrCreateNbt().putString(name, value); + } + + public NbtMapBuilder putCompound(String name, NbtMap value) { + return getOrCreateNbt().putCompound(name, value); + } + /** * @return null if no NBT is needed on this item. */ @@ -90,4 +113,16 @@ public final class BedrockItemBuilder { } return builder.build(); } + + /** + * Creates item NBT with count, name, and damage set. + */ + public static NbtMapBuilder createItemNbt(ItemMapping mapping, int count, int damage) { + NbtMapBuilder builder = NbtMap.builder(); + builder.putByte("Count", (byte) count); + builder.putString("Name", mapping.getBedrockIdentifier()); + + builder.putShort("Damage", (short) damage); + return builder; + } } 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 b52861b35..6459aa9ec 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 @@ -141,7 +141,7 @@ public final class ItemTranslator { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); if (components != null) { - javaItem.translateComponentsToBedrock(session, components, nbtBuilder.getOrCreateNbt()); + javaItem.translateComponentsToBedrock(session, components, nbtBuilder); } String customName = getCustomName(session, components, bedrockItem); From 6d8021f155765de2cd668d24985f19f03943c15e Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Sun, 21 Apr 2024 00:12:53 +0100 Subject: [PATCH 045/897] Update the non-item parts (#4586) * Update the non-item parts * Add MaceItem * Fix registry data loading --- .../geyser/inventory/item/Enchantment.java | 5 +- .../updater/AnvilInventoryUpdater.java | 2 +- .../geysermc/geyser/item/ArmorMaterial.java | 7 +- .../java/org/geysermc/geyser/item/Items.java | 106 ++++++++++-------- .../geysermc/geyser/item/type/MaceItem.java | 39 +++++++ .../geysermc/geyser/level/JavaDimension.java | 22 ++-- .../geyser/network/netty/LocalSession.java | 2 +- .../loader/EnchantmentRegistryLoader.java | 8 +- .../registry/populator/Conversion649_630.java | 4 +- .../registry/populator/Conversion662_649.java | 24 +++- .../registry/populator/Conversion671_662.java | 25 ++++- .../geyser/session/GeyserSession.java | 5 +- .../inventory/PlayerInventoryTranslator.java | 8 +- .../translator/level/BiomeTranslator.java | 20 ++-- .../protocol/java/JavaCommandsTranslator.java | 2 +- .../protocol/java/JavaLoginTranslator.java | 8 +- .../java/JavaRegistryDataTranslator.java | 46 ++++---- .../protocol/java/JavaRespawnTranslator.java | 6 +- .../level/JavaLevelParticlesTranslator.java | 3 +- .../geysermc/geyser/util/AttributeUtils.java | 4 +- .../geysermc/geyser/util/DimensionUtils.java | 34 ++++-- .../geysermc/geyser/util/InventoryUtils.java | 8 +- .../geysermc/geyser/util/JavaCodecUtil.java | 64 ----------- gradle/libs.versions.toml | 4 +- 24 files changed, 255 insertions(+), 201 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/type/MaceItem.java delete mode 100644 core/src/main/java/org/geysermc/geyser/util/JavaCodecUtil.java diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java b/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java index 5fa2a5784..773de29b1 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java @@ -118,7 +118,7 @@ public enum Enchantment { KNOCKBACK, FIRE_ASPECT, LOOTING, - SWEEPING, + SWEEPING_EDGE, EFFICIENCY, SILK_TOUCH, UNBREAKING, @@ -136,6 +136,9 @@ public enum Enchantment { MULTISHOT, QUICK_CHARGE, PIERCING, + DENSITY, + BREACH, + WIND_BURST, MENDING, VANISHING_CURSE; 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 5adee0c20..96ef12861 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 @@ -350,7 +350,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { if (enchantment == JavaEnchantment.IMPALING) { // Multiplier is halved on Bedrock for some reason rarityMultiplier /= 2; - } else if (enchantment == JavaEnchantment.SWEEPING) { + } else if (enchantment == JavaEnchantment.SWEEPING_EDGE) { // Doesn't exist on Bedrock rarityMultiplier = 0; } diff --git a/core/src/main/java/org/geysermc/geyser/item/ArmorMaterial.java b/core/src/main/java/org/geysermc/geyser/item/ArmorMaterial.java index 315a8cd4d..348c0af8c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/ArmorMaterial.java +++ b/core/src/main/java/org/geysermc/geyser/item/ArmorMaterial.java @@ -31,12 +31,13 @@ import java.util.function.Supplier; public enum ArmorMaterial { LEATHER(() -> Items.LEATHER), - CHAIN(() -> Items.IRON_INGOT), + CHAINMAIL(() -> Items.IRON_INGOT), IRON(() -> Items.IRON_INGOT), GOLD(() -> Items.GOLD_INGOT), DIAMOND(() -> Items.DIAMOND), - TURTLE(() -> Items.SCUTE), - NETHERITE(() -> Items.NETHERITE_INGOT); + TURTLE(() -> Items.TURTLE_SCUTE), + NETHERITE(() -> Items.NETHERITE_INGOT), + ARMADILLO(() -> Items.ARMADILLO_SCUTE); private final Supplier repairIngredient; 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 2147ebb2c..42a087acf 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -123,6 +123,7 @@ public final class Items { public static final Item RAW_IRON_BLOCK = register(new BlockItem("raw_iron_block", builder())); public static final Item RAW_COPPER_BLOCK = register(new BlockItem("raw_copper_block", builder())); public static final Item RAW_GOLD_BLOCK = register(new BlockItem("raw_gold_block", builder())); + public static final Item HEAVY_CORE = register(new BlockItem("heavy_core", builder())); public static final Item AMETHYST_BLOCK = register(new BlockItem("amethyst_block", builder())); public static final Item BUDDING_AMETHYST = register(new BlockItem("budding_amethyst", builder())); public static final Item IRON_BLOCK = register(new BlockItem("iron_block", builder())); @@ -832,7 +833,9 @@ public final class Items { public static final Item STRUCTURE_BLOCK = register(new BlockItem("structure_block", builder())); public static final Item JIGSAW = register(new BlockItem("jigsaw", builder())); public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", ArmorMaterial.TURTLE, builder().stackSize(1).maxDamage(275))); - public static final Item SCUTE = register(new Item("scute", builder())); + public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder())); + public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder())); + public static final Item WOLF_ARMOR = register(new ArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder().stackSize(1).maxDamage(64))); public static final Item FLINT_AND_STEEL = register(new Item("flint_and_steel", builder().stackSize(1).maxDamage(64))); public static final Item APPLE = register(new Item("apple", builder())); public static final Item BOW = register(new Item("bow", builder().stackSize(1).maxDamage(384))); @@ -852,36 +855,36 @@ public final class Items { public static final Item GOLD_INGOT = register(new Item("gold_ingot", builder())); public static final Item NETHERITE_INGOT = register(new Item("netherite_ingot", builder())); public static final Item NETHERITE_SCRAP = register(new Item("netherite_scrap", builder())); - public static final Item WOODEN_SWORD = register(new TieredItem("wooden_sword", ToolTier.WOODEN, builder().stackSize(1).attackDamage(4).maxDamage(59))); - public static final Item WOODEN_SHOVEL = register(new TieredItem("wooden_shovel", ToolTier.WOODEN, builder().stackSize(1).attackDamage(2.5).maxDamage(59))); - public static final Item WOODEN_PICKAXE = register(new TieredItem("wooden_pickaxe", ToolTier.WOODEN, builder().stackSize(1).attackDamage(2).maxDamage(59))); - public static final Item WOODEN_AXE = register(new TieredItem("wooden_axe", ToolTier.WOODEN, builder().stackSize(1).attackDamage(7).maxDamage(59))); - public static final Item WOODEN_HOE = register(new TieredItem("wooden_hoe", ToolTier.WOODEN, builder().stackSize(1).attackDamage(1).maxDamage(59))); - public static final Item STONE_SWORD = register(new TieredItem("stone_sword", ToolTier.STONE, builder().stackSize(1).attackDamage(5).maxDamage(131))); - public static final Item STONE_SHOVEL = register(new TieredItem("stone_shovel", ToolTier.STONE, builder().stackSize(1).attackDamage(3.5).maxDamage(131))); - public static final Item STONE_PICKAXE = register(new TieredItem("stone_pickaxe", ToolTier.STONE, builder().stackSize(1).attackDamage(3).maxDamage(131))); - public static final Item STONE_AXE = register(new TieredItem("stone_axe", ToolTier.STONE, builder().stackSize(1).attackDamage(9).maxDamage(131))); - public static final Item STONE_HOE = register(new TieredItem("stone_hoe", ToolTier.STONE, builder().stackSize(1).attackDamage(1).maxDamage(131))); - public static final Item GOLDEN_SWORD = register(new TieredItem("golden_sword", ToolTier.GOLDEN, builder().stackSize(1).attackDamage(4).maxDamage(32))); - public static final Item GOLDEN_SHOVEL = register(new TieredItem("golden_shovel", ToolTier.GOLDEN, builder().stackSize(1).attackDamage(2.5).maxDamage(32))); - public static final Item GOLDEN_PICKAXE = register(new TieredItem("golden_pickaxe", ToolTier.GOLDEN, builder().stackSize(1).attackDamage(2).maxDamage(32))); - public static final Item GOLDEN_AXE = register(new TieredItem("golden_axe", ToolTier.GOLDEN, builder().stackSize(1).attackDamage(7).maxDamage(32))); - public static final Item GOLDEN_HOE = register(new TieredItem("golden_hoe", ToolTier.GOLDEN, builder().stackSize(1).attackDamage(1).maxDamage(32))); - public static final Item IRON_SWORD = register(new TieredItem("iron_sword", ToolTier.IRON, builder().stackSize(1).attackDamage(6).maxDamage(250))); - public static final Item IRON_SHOVEL = register(new TieredItem("iron_shovel", ToolTier.IRON, builder().stackSize(1).attackDamage(4.5).maxDamage(250))); - public static final Item IRON_PICKAXE = register(new TieredItem("iron_pickaxe", ToolTier.IRON, builder().stackSize(1).attackDamage(4).maxDamage(250))); - public static final Item IRON_AXE = register(new TieredItem("iron_axe", ToolTier.IRON, builder().stackSize(1).attackDamage(9).maxDamage(250))); - public static final Item IRON_HOE = register(new TieredItem("iron_hoe", ToolTier.IRON, builder().stackSize(1).attackDamage(1).maxDamage(250))); - public static final Item DIAMOND_SWORD = register(new TieredItem("diamond_sword", ToolTier.DIAMOND, builder().stackSize(1).attackDamage(7).maxDamage(1561))); - public static final Item DIAMOND_SHOVEL = register(new TieredItem("diamond_shovel", ToolTier.DIAMOND, builder().stackSize(1).attackDamage(5.5).maxDamage(1561))); - public static final Item DIAMOND_PICKAXE = register(new TieredItem("diamond_pickaxe", ToolTier.DIAMOND, builder().stackSize(1).attackDamage(5).maxDamage(1561))); - public static final Item DIAMOND_AXE = register(new TieredItem("diamond_axe", ToolTier.DIAMOND, builder().stackSize(1).attackDamage(9).maxDamage(1561))); - public static final Item DIAMOND_HOE = register(new TieredItem("diamond_hoe", ToolTier.DIAMOND, builder().stackSize(1).attackDamage(1).maxDamage(1561))); - public static final Item NETHERITE_SWORD = register(new TieredItem("netherite_sword", ToolTier.NETHERITE, builder().stackSize(1).attackDamage(8).maxDamage(2031))); - public static final Item NETHERITE_SHOVEL = register(new TieredItem("netherite_shovel", ToolTier.NETHERITE, builder().stackSize(1).attackDamage(6.5).maxDamage(2031))); - public static final Item NETHERITE_PICKAXE = register(new TieredItem("netherite_pickaxe", ToolTier.NETHERITE, builder().stackSize(1).attackDamage(6).maxDamage(2031))); - public static final Item NETHERITE_AXE = register(new TieredItem("netherite_axe", ToolTier.NETHERITE, builder().stackSize(1).attackDamage(10).maxDamage(2031))); - public static final Item NETHERITE_HOE = register(new TieredItem("netherite_hoe", ToolTier.NETHERITE, builder().stackSize(1).attackDamage(1).maxDamage(2031))); + public static final Item WOODEN_SWORD = register(new TieredItem("wooden_sword", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(4.0))); + public static final Item WOODEN_SHOVEL = register(new TieredItem("wooden_shovel", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(2.5))); + public static final Item WOODEN_PICKAXE = register(new TieredItem("wooden_pickaxe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(2.0))); + public static final Item WOODEN_AXE = register(new TieredItem("wooden_axe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(7.0))); + public static final Item WOODEN_HOE = register(new TieredItem("wooden_hoe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(1.0))); + public static final Item STONE_SWORD = register(new TieredItem("stone_sword", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(5.0))); + public static final Item STONE_SHOVEL = register(new TieredItem("stone_shovel", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(3.5))); + public static final Item STONE_PICKAXE = register(new TieredItem("stone_pickaxe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(3.0))); + public static final Item STONE_AXE = register(new TieredItem("stone_axe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(9.0))); + public static final Item STONE_HOE = register(new TieredItem("stone_hoe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(1.0))); + public static final Item GOLDEN_SWORD = register(new TieredItem("golden_sword", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(4.0))); + public static final Item GOLDEN_SHOVEL = register(new TieredItem("golden_shovel", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(2.5))); + public static final Item GOLDEN_PICKAXE = register(new TieredItem("golden_pickaxe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(2.0))); + public static final Item GOLDEN_AXE = register(new TieredItem("golden_axe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(7.0))); + public static final Item GOLDEN_HOE = register(new TieredItem("golden_hoe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(1.0))); + public static final Item IRON_SWORD = register(new TieredItem("iron_sword", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(6.0))); + public static final Item IRON_SHOVEL = register(new TieredItem("iron_shovel", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(4.5))); + public static final Item IRON_PICKAXE = register(new TieredItem("iron_pickaxe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(4.0))); + public static final Item IRON_AXE = register(new TieredItem("iron_axe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(9.0))); + public static final Item IRON_HOE = register(new TieredItem("iron_hoe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(1.0))); + public static final Item DIAMOND_SWORD = register(new TieredItem("diamond_sword", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(7.0))); + public static final Item DIAMOND_SHOVEL = register(new TieredItem("diamond_shovel", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(5.5))); + public static final Item DIAMOND_PICKAXE = register(new TieredItem("diamond_pickaxe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(5.0))); + public static final Item DIAMOND_AXE = register(new TieredItem("diamond_axe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(9.0))); + public static final Item DIAMOND_HOE = register(new TieredItem("diamond_hoe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(1.0))); + public static final Item NETHERITE_SWORD = register(new TieredItem("netherite_sword", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(8.0))); + public static final Item NETHERITE_SHOVEL = register(new TieredItem("netherite_shovel", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(6.5))); + public static final Item NETHERITE_PICKAXE = register(new TieredItem("netherite_pickaxe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(6.0))); + public static final Item NETHERITE_AXE = register(new TieredItem("netherite_axe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(10.0))); + public static final Item NETHERITE_HOE = register(new TieredItem("netherite_hoe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(1.0))); public static final Item STICK = register(new Item("stick", builder())); public static final Item BOWL = register(new Item("bowl", builder())); public static final Item MUSHROOM_STEW = register(new Item("mushroom_stew", builder().stackSize(1))); @@ -891,14 +894,14 @@ public final class Items { public static final Item WHEAT_SEEDS = register(new BlockItem("wheat_seeds", builder())); public static final Item WHEAT = register(new Item("wheat", builder())); public static final Item BREAD = register(new Item("bread", builder())); - public static final Item LEATHER_HELMET = register(new DyeableArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(55))); - public static final Item LEATHER_CHESTPLATE = register(new DyeableArmorItem("leather_chestplate", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(80))); - public static final Item LEATHER_LEGGINGS = register(new DyeableArmorItem("leather_leggings", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(75))); - public static final Item LEATHER_BOOTS = register(new DyeableArmorItem("leather_boots", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(65))); - public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", ArmorMaterial.CHAIN, builder().stackSize(1).maxDamage(165))); - public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", ArmorMaterial.CHAIN, builder().stackSize(1).maxDamage(240))); - public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", ArmorMaterial.CHAIN, builder().stackSize(1).maxDamage(225))); - public static final Item CHAINMAIL_BOOTS = register(new ArmorItem("chainmail_boots", ArmorMaterial.CHAIN, builder().stackSize(1).maxDamage(195))); + public static final Item LEATHER_HELMET = register(new ArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(55))); + public static final Item LEATHER_CHESTPLATE = register(new ArmorItem("leather_chestplate", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(80))); + public static final Item LEATHER_LEGGINGS = register(new ArmorItem("leather_leggings", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(75))); + public static final Item LEATHER_BOOTS = register(new ArmorItem("leather_boots", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(65))); + public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(165))); + public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(240))); + public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(225))); + public static final Item CHAINMAIL_BOOTS = register(new ArmorItem("chainmail_boots", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(195))); public static final Item IRON_HELMET = register(new ArmorItem("iron_helmet", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(165))); public static final Item IRON_CHESTPLATE = register(new ArmorItem("iron_chestplate", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(240))); public static final Item IRON_LEGGINGS = register(new ArmorItem("iron_leggings", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(225))); @@ -1043,11 +1046,13 @@ public final class Items { public static final Item CAULDRON = register(new BlockItem("cauldron", builder())); 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())); public static final Item ALLAY_SPAWN_EGG = register(new SpawnEggItem("allay_spawn_egg", builder())); public static final Item AXOLOTL_SPAWN_EGG = register(new SpawnEggItem("axolotl_spawn_egg", builder())); public static final Item BAT_SPAWN_EGG = register(new SpawnEggItem("bat_spawn_egg", builder())); public static final Item BEE_SPAWN_EGG = register(new SpawnEggItem("bee_spawn_egg", builder())); public static final Item BLAZE_SPAWN_EGG = register(new SpawnEggItem("blaze_spawn_egg", builder())); + public static final Item BOGGED_SPAWN_EGG = register(new SpawnEggItem("bogged_spawn_egg", builder())); public static final Item BREEZE_SPAWN_EGG = register(new SpawnEggItem("breeze_spawn_egg", builder())); public static final Item CAT_SPAWN_EGG = register(new SpawnEggItem("cat_spawn_egg", builder())); public static final Item CAMEL_SPAWN_EGG = register(new SpawnEggItem("camel_spawn_egg", builder())); @@ -1123,8 +1128,10 @@ public final class Items { 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())); 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(250))); 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("flower_pot", builder())); @@ -1155,10 +1162,10 @@ 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 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 DyeableHorseArmorItem("leather_horse_armor", builder().stackSize(1))); + 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 LEATHER_HORSE_ARMOR = register(new ArmorItem("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))); @@ -1216,7 +1223,7 @@ public final class Items { 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 DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder())); - public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).attackDamage(9).maxDamage(250))); + public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0))); public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder())); 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())); @@ -1229,6 +1236,8 @@ public final class Items { 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))); + 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 GOAT_HORN = register(new GoatHornItem("goat_horn", builder().stackSize(1))); public static final Item COMPOSTER = register(new BlockItem("composter", builder())); public static final Item BARREL = register(new ChestItem("barrel", builder())); @@ -1312,6 +1321,8 @@ public final class Items { public static final Item SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("silence_armor_trim_smithing_template", builder())); public static final Item RAISER_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("raiser_armor_trim_smithing_template", builder())); public static final Item HOST_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("host_armor_trim_smithing_template", builder())); + public static final Item FLOW_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("flow_armor_trim_smithing_template", builder())); + public static final Item BOLT_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("bolt_armor_trim_smithing_template", builder())); public static final Item ANGLER_POTTERY_SHERD = register(new Item("angler_pottery_sherd", builder())); public static final Item ARCHER_POTTERY_SHERD = register(new Item("archer_pottery_sherd", builder())); public static final Item ARMS_UP_POTTERY_SHERD = register(new Item("arms_up_pottery_sherd", builder())); @@ -1320,7 +1331,9 @@ public final class Items { public static final Item BURN_POTTERY_SHERD = register(new Item("burn_pottery_sherd", builder())); public static final Item DANGER_POTTERY_SHERD = register(new Item("danger_pottery_sherd", builder())); public static final Item EXPLORER_POTTERY_SHERD = register(new Item("explorer_pottery_sherd", builder())); + public static final Item FLOW_POTTERY_SHERD = register(new Item("flow_pottery_sherd", builder())); public static final Item FRIEND_POTTERY_SHERD = register(new Item("friend_pottery_sherd", builder())); + public static final Item GUSTER_POTTERY_SHERD = register(new Item("guster_pottery_sherd", builder())); public static final Item HEART_POTTERY_SHERD = register(new Item("heart_pottery_sherd", builder())); public static final Item HEARTBREAK_POTTERY_SHERD = register(new Item("heartbreak_pottery_sherd", builder())); public static final Item HOWL_POTTERY_SHERD = register(new Item("howl_pottery_sherd", builder())); @@ -1328,6 +1341,7 @@ public final class Items { public static final Item MOURNER_POTTERY_SHERD = register(new Item("mourner_pottery_sherd", builder())); public static final Item PLENTY_POTTERY_SHERD = register(new Item("plenty_pottery_sherd", builder())); public static final Item PRIZE_POTTERY_SHERD = register(new Item("prize_pottery_sherd", builder())); + public static final Item SCRAPE_POTTERY_SHERD = register(new Item("scrape_pottery_sherd", builder())); public static final Item SHEAF_POTTERY_SHERD = register(new Item("sheaf_pottery_sherd", builder())); public static final Item SHELTER_POTTERY_SHERD = register(new Item("shelter_pottery_sherd", builder())); public static final Item SKULL_POTTERY_SHERD = register(new Item("skull_pottery_sherd", builder())); @@ -1350,6 +1364,10 @@ public final class Items { public static final Item WAXED_OXIDIZED_COPPER_BULB = register(new BlockItem("waxed_oxidized_copper_bulb", builder())); public static final Item TRIAL_SPAWNER = register(new BlockItem("trial_spawner", builder())); 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("vault", builder())); + public static final Item OMINOUS_BOTTLE = register(new Item("ominous_bottle", builder())); + public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder())); public static final int AIR_ID = AIR.javaId(); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MaceItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MaceItem.java new file mode 100644 index 000000000..e7b9a8684 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/type/MaceItem.java @@ -0,0 +1,39 @@ +/* + * 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.item.type; + +import org.geysermc.geyser.item.Items; + +public class MaceItem extends Item { + public MaceItem(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public boolean isValidRepairItem(Item other) { + return other == Items.BREEZE_ROD; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index a3f6b55e4..6e7223da0 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -25,11 +25,12 @@ package org.geysermc.geyser.level; +import com.github.steveice10.mc.protocol.data.game.RegistryEntry; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; -import org.geysermc.geyser.util.JavaCodecUtil; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import java.util.Map; +import java.util.List; /** * Represents the information we store from the current Java dimension @@ -38,19 +39,20 @@ import java.util.Map; */ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale) { - public static void load(CompoundTag tag, Map map) { - for (CompoundTag dimension : JavaCodecUtil.iterateAsTag(tag.get("minecraft:dimension_type"))) { - CompoundTag elements = dimension.get("element"); - int minY = ((IntTag) elements.get("min_y")).getValue(); - int maxY = ((IntTag) elements.get("height")).getValue(); + public static void load(List entries, Int2ObjectMap map) { + for (int i = 0; i < entries.size(); i++) { + RegistryEntry entry = entries.get(i); + CompoundTag dimension = entry.getData(); + int minY = ((IntTag) dimension.get("min_y")).getValue(); + int maxY = ((IntTag) dimension.get("height")).getValue(); // Logical height can be ignored probably - seems to be for artificial limits like the Nether. // Set if piglins/hoglins should shake - boolean piglinSafe = ((Number) elements.get("piglin_safe").getValue()).byteValue() != (byte) 0; + boolean piglinSafe = ((Number) dimension.get("piglin_safe").getValue()).byteValue() != (byte) 0; // Load world coordinate scale for the world border - double coordinateScale = ((Number) elements.get("coordinate_scale").getValue()).doubleValue(); + double coordinateScale = ((Number) dimension.get("coordinate_scale").getValue()).doubleValue(); - map.put((String) dimension.get("name").getValue(), new JavaDimension(minY, maxY, piglinSafe, coordinateScale)); + map.put(i, new JavaDimension(minY, maxY, piglinSafe, coordinateScale)); } } } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index a2951116f..121c70f90 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -79,7 +79,7 @@ public final class LocalSession extends TcpSession { public void initChannel(@NonNull LocalChannelWithRemoteAddress channel) { channel.spoofedRemoteAddress(new InetSocketAddress(clientIp, 0)); PacketProtocol protocol = getPacketProtocol(); - protocol.newClientSession(LocalSession.this); + protocol.newClientSession(LocalSession.this, false); refreshReadTimeoutHandler(channel); refreshWriteTimeoutHandler(channel); diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java index 185eca694..8a0fb1f40 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java @@ -56,13 +56,7 @@ public class EnchantmentRegistryLoader implements RegistryLoader entry = it.next(); JavaEnchantment key = JavaEnchantment.getByJavaIdentifier(entry.getKey()); JsonNode node = entry.getValue(); - int rarityMultiplier = switch (node.get("rarity").textValue()) { - case "common" -> 1; - case "uncommon" -> 2; - case "rare" -> 4; - case "very_rare" -> 8; - default -> throw new IllegalStateException("Unexpected value: " + node.get("rarity").textValue()); - }; + int rarityMultiplier = node.get("anvil_cost").asInt(); int maxLevel = node.get("max_level").asInt(); EnumSet incompatibleEnchantments = EnumSet.noneOf(JavaEnchantment.class); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion649_630.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion649_630.java index 56de1081e..70a5e1ad9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion649_630.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion649_630.java @@ -37,9 +37,11 @@ public class Conversion649_630 { String identifer = mapping.getBedrockIdentifier(); switch (identifer) { - case "minecraft:turtle_scute" -> { return mapping.withBedrockIdentifier("minecraft:scute"); } + case "minecraft:armadillo_scute", "minecraft:turtle_scute" -> { return mapping.withBedrockIdentifier("minecraft:scute"); } + case "minecraft:armadillo_spawn_egg" -> { return mapping.withBedrockIdentifier("minecraft:rabbit_spawn_egg"); } case "minecraft:trial_spawner" -> { return mapping.withBedrockIdentifier("minecraft:mob_spawner"); } case "minecraft:trial_key" -> { return mapping.withBedrockIdentifier("minecraft:echo_shard"); } + case "minecraft:wolf_armor" -> { return mapping.withBedrockIdentifier("minecraft:leather_horse_armor"); } default -> { return mapping; } } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java index 0fe1610f2..041afdbc8 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java @@ -35,7 +35,7 @@ import java.util.stream.Stream; public class Conversion662_649 { - private static final List NEW_MISC = List.of("minecraft:grass_block", "minecraft:trial_spawner"); + private static final List NEW_MISC = List.of("minecraft:grass_block", "minecraft:vault"); private static final List NEW_WOODS = List.of("minecraft:oak_wood", "minecraft:spruce_wood", "minecraft:birch_wood", "minecraft:jungle_wood", "minecraft:acacia_wood", "minecraft:dark_oak_wood", "minecraft:stripped_oak_wood", "minecraft:stripped_spruce_wood", "minecraft:stripped_birch_wood", "minecraft:stripped_jungle_wood", "minecraft:stripped_acacia_wood", "minecraft:stripped_dark_oak_wood"); private static final List NEW_LEAVES = List.of("minecraft:oak_leaves", "minecraft:spruce_leaves", "minecraft:birch_leaves", "minecraft:jungle_leaves"); private static final List NEW_LEAVES2 = List.of("minecraft:acacia_leaves", "minecraft:dark_oak_leaves"); @@ -48,9 +48,12 @@ public class Conversion662_649 { String identifer = mapping.getBedrockIdentifier(); - if (identifer.equals("minecraft:grass_block")) { - return mapping.withBedrockIdentifier("minecraft:grass"); - } + switch (identifer) { + case "minecraft:bogged_spawn_egg" -> { return mapping.withBedrockIdentifier("minecraft:creeper_spawn_egg"); } + case "minecraft:grass_block" -> { return mapping.withBedrockIdentifier("minecraft:grass"); } + case "minecraft:vault" -> { return mapping.withBedrockIdentifier("minecraft:trial_spawner"); } + case "minecraft:wind_charge" -> { return mapping.withBedrockIdentifier("minecraft:snowball"); } + }; if (NEW_WOODS.contains(identifer)) { switch (identifer) { @@ -114,6 +117,19 @@ public class Conversion662_649 { return builder.build(); } + if (name.equals("minecraft:vault")) { + replacement = "minecraft:trial_spawner"; + + NbtMapBuilder statesBuilder = NbtMap.builder() + .putInt("trial_spawner_state", 0); + + NbtMapBuilder builder = tag.toBuilder(); + builder.putString("name", replacement); + builder.putCompound("states", statesBuilder.build()); + + return builder.build(); + } + if (NEW_WOODS.contains(name)) { replacement = "minecraft:wood"; diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java index 2c6db7567..29ab3f2e5 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.registry.populator; import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.type.GeyserMappingItem; @@ -33,11 +34,12 @@ import java.util.List; import java.util.stream.Stream; public class Conversion671_662 { + private static final List NEW_MISC = List.of("minecraft:heavy_core", "minecraft:mace", "minecraft:flow_banner_pattern", "minecraft:guster_banner_pattern", "minecraft:flow_armor_trim_smithing_template", "minecraft:bolt_armor_trim_smithing_template", "minecraft:flow_pottery_sherd", "minecraft:guster_pottery_sherd", "minecraft:scrape_pottery_sherd", "minecraft:breeze_rod"); private static final List NEW_CORAL_FANS = List.of("minecraft:tube_coral_fan", "minecraft:brain_coral_fan", "minecraft:bubble_coral_fan", "minecraft:fire_coral_fan", "minecraft:horn_coral_fan"); private static final List NEW_DEAD_CORAL_FANS = List.of("minecraft:dead_tube_coral_fan", "minecraft:dead_brain_coral_fan", "minecraft:dead_bubble_coral_fan", "minecraft:dead_fire_coral_fan", "minecraft:dead_horn_coral_fan"); private static final List NEW_FLOWERS = List.of("minecraft:poppy", "minecraft:blue_orchid", "minecraft:allium", "minecraft:azure_bluet", "minecraft:red_tulip", "minecraft:orange_tulip", "minecraft:white_tulip", "minecraft:pink_tulip", "minecraft:oxeye_daisy", "minecraft:cornflower", "minecraft:lily_of_the_valley"); private static final List NEW_SAPLINGS = List.of("minecraft:oak_sapling", "minecraft:spruce_sapling", "minecraft:birch_sapling", "minecraft:jungle_sapling", "minecraft:acacia_sapling", "minecraft:dark_oak_sapling", "minecraft:bamboo_sapling"); - private static final List NEW_BLOCKS = Stream.of(NEW_CORAL_FANS, NEW_DEAD_CORAL_FANS, NEW_FLOWERS, NEW_SAPLINGS).flatMap(List::stream).toList(); + private static final List NEW_BLOCKS = Stream.of(NEW_MISC, NEW_CORAL_FANS, NEW_DEAD_CORAL_FANS, NEW_FLOWERS, NEW_SAPLINGS).flatMap(List::stream).toList(); static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { String identifer = mapping.getBedrockIdentifier(); @@ -46,6 +48,18 @@ public class Conversion671_662 { return mapping; } + switch (identifer) { + case "minecraft:bolt_armor_trim_smithing_template" -> { return mapping.withBedrockIdentifier("minecraft:wayfinder_armor_trim_smithing_template"); } + case "minecraft:breeze_rod" -> { return mapping.withBedrockIdentifier("minecraft:blaze_rod"); } + case "minecraft:flow_armor_trim_smithing_template" -> { return mapping.withBedrockIdentifier("minecraft:spire_armor_trim_smithing_template"); } + case "minecraft:flow_banner_pattern", "minecraft:guster_banner_pattern" -> { return mapping.withBedrockIdentifier("minecraft:globe_banner_pattern"); } + case "minecraft:flow_pottery_sherd" -> { return mapping.withBedrockIdentifier("minecraft:skull_pottery_sherd"); } + case "minecraft:guster_pottery_sherd" -> { return mapping.withBedrockIdentifier("minecraft:shelter_pottery_sherd"); } + case "minecraft:scrape_pottery_sherd" -> { return mapping.withBedrockIdentifier("minecraft:heartbreak_pottery_sherd"); } + case "minecraft:heavy_core" -> { return mapping.withBedrockIdentifier("minecraft:conduit"); } + case "minecraft:mace" -> { return mapping.withBedrockIdentifier("minecraft:netherite_axe"); } + } + if (NEW_FLOWERS.contains(identifer)) { switch (identifer) { case "minecraft:poppy" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(0); } @@ -114,6 +128,15 @@ public class Conversion671_662 { String replacement; + if (name.equals("minecraft:heavy_core")) { + replacement = "minecraft:conduit"; + + NbtMapBuilder builder = tag.toBuilder(); + builder.putString("name", replacement); + + return builder.build(); + } + if (NEW_SAPLINGS.contains(name)) { replacement = "minecraft:sapling"; String saplingType = name.replaceAll("minecraft:|_sapling", "");; 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 63022636c..936fc932d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -45,6 +45,7 @@ import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundClientInformationPacket; import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; @@ -360,7 +361,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * As all entities are in the same world, this can be safely applied to all other entities. */ @Setter - private String dimension = DimensionUtils.OVERWORLD; + private int dimension = DimensionUtils.OVERWORLD; @MonotonicNonNull @Setter private JavaDimension dimensionType = null; @@ -1464,7 +1465,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Sends a command to the Java server. */ public void sendCommand(String command) { - sendDownstreamGamePacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet())); + sendDownstreamGamePacket(new ServerboundChatCommandSignedPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet())); } public void setServerRenderDistance(int renderDistance) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 429b577ce..b461c7afc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -360,7 +360,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { return rejectRequest(request); } - ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, sourceItem.getItemStack(dropAction.getCount())); + ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket((short)-1, sourceItem.getItemStack(dropAction.getCount())); session.sendDownstreamGamePacket(creativeDropPacket); sourceItem.sub(dropAction.getCount()); @@ -493,9 +493,9 @@ public class PlayerInventoryTranslator extends InventoryTranslator { dropStack = javaCreativeItem; } else { // Specify custom count - dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getNbt()); + dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getDataComponents()); } - ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, dropStack); + ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket((short)-1, dropStack); session.sendDownstreamGamePacket(creativeDropPacket); break; } @@ -516,7 +516,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { GeyserItemStack item = inventory.getItem(slot); ItemStack itemStack = item.isEmpty() ? new ItemStack(-1, 0, null) : item.getItemStack(); - ServerboundSetCreativeModeSlotPacket creativePacket = new ServerboundSetCreativeModeSlotPacket(slot, itemStack); + ServerboundSetCreativeModeSlotPacket creativePacket = new ServerboundSetCreativeModeSlotPacket((short)slot, itemStack); session.sendDownstreamGamePacket(creativePacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index 90ac1cc5e..d4288c5a7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -25,15 +25,13 @@ package org.geysermc.geyser.translator.level; +import com.github.steveice10.mc.protocol.data.game.RegistryEntry; import com.github.steveice10.mc.protocol.data.game.chunk.BitStorage; import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.GlobalPalette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.Palette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.SingletonPalette; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import it.unimi.dsi.fastutil.ints.*; import org.geysermc.geyser.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.bitarray.BitArray; @@ -41,24 +39,24 @@ import org.geysermc.geyser.level.chunk.bitarray.BitArrayVersion; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.JavaCodecUtil; import org.geysermc.geyser.util.MathUtils; +import java.util.List; + // Array index formula by https://wiki.vg/Chunk_Format public class BiomeTranslator { - public static void loadServerBiomes(GeyserSession session, CompoundTag codec) { + public static void loadServerBiomes(GeyserSession session, List entries) { Int2IntMap biomeTranslations = new Int2IntOpenHashMap(); - CompoundTag worldGen = codec.get("minecraft:worldgen/biome"); - ListTag serverBiomes = worldGen.get("value"); - session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(serverBiomes.size())); + session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(entries.size())); int greatestBiomeId = 0; - for (CompoundTag biomeTag : JavaCodecUtil.iterateAsTag(worldGen)) { - String javaIdentifier = ((StringTag) biomeTag.get("name")).getValue(); + for (int i = 0; i < entries.size(); i++) { + RegistryEntry entry = entries.get(i); + String javaIdentifier = entry.getId(); int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); - int javaId = ((IntTag) biomeTag.get("id")).getValue(); + int javaId = i; if (javaId > greatestBiomeId) { greatestBiomeId = javaId; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 0d7f45c7d..9d3351217 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -60,7 +60,7 @@ import java.util.*; public class JavaCommandsTranslator extends PacketTranslator { private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers(); - private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.keySet().toArray(new String[0]); + private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(AttributeType::getIdentifier).toList().toArray(new String[0]); private static final String[] ENUM_BOOLEAN = {"true", "false"}; private static final String[] VALID_COLORS; private static final String[] VALID_SCOREBOARD_SLOTS; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 4a15157f9..ebf99fb65 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -63,7 +63,7 @@ public class JavaLoginTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundRegistryDataPacket packet) { - Map dimensions = session.getDimensions(); - dimensions.clear(); - JavaDimension.load(packet.getRegistry(), dimensions); - - Int2ObjectMap chatTypes = session.getChatTypes(); - chatTypes.clear(); - for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { - // The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. - int id = ((IntTag) tag.get("id")).getValue(); - CompoundTag element = tag.get("element"); - CompoundTag chat = element.get("chat"); - TextDecoration textDecoration = null; - if (chat != null) { - textDecoration = new TextDecoration(chat); - } - chatTypes.put(id, textDecoration); + if (packet.getRegistry().equals("minecraft:dimension_type")) { + Int2ObjectMap dimensions = session.getDimensions(); + dimensions.clear(); + JavaDimension.load(packet.getEntries(), dimensions); } - BiomeTranslator.loadServerBiomes(session, packet.getRegistry()); + if (packet.getRegistry().equals("minecraft:chat_type")) { + Int2ObjectMap chatTypes = session.getChatTypes(); + chatTypes.clear(); + List entries = packet.getEntries(); + for (int i = 0; i < entries.size(); i++) { + // The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. + RegistryEntry entry = entries.get(i); + CompoundTag tag = entry.getData(); + CompoundTag chat = tag.get("chat"); + TextDecoration textDecoration = null; + if (chat != null) { + textDecoration = new TextDecoration(chat); + } + chatTypes.put(i, textDecoration); + } + } + + if (packet.getRegistry().equals("minecraft:worldgen/biome")) { + BiomeTranslator.loadServerBiomes(session, packet.getEntries()); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index d69077dcb..bfb590247 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -92,11 +92,11 @@ public class JavaRespawnTranslator extends PacketTranslator { - int blockState = session.getBlockMappings().getBedrockBlockId(((FallingDustParticleData) particle.getData()).getBlockState()); + int blockState = session.getBlockMappings().getBedrockBlockId(((BlockParticleData) particle.getData()).getBlockState()); return (position) -> { LevelEventPacket packet = new LevelEventPacket(); // In fact, FallingDustParticle should have data like DustParticle, diff --git a/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java b/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java index e1fe6e6f2..d79d606b4 100644 --- a/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java @@ -45,12 +45,12 @@ public class AttributeUtils { } double value = base; for (AttributeModifier modifier : attribute.getModifiers()) { - if (modifier.getOperation() == ModifierOperation.ADD_MULTIPLIED) { + if (modifier.getOperation() == ModifierOperation.ADD_MULTIPLIED_BASE) { value += base * modifier.getAmount(); } } for (AttributeModifier modifier : attribute.getModifiers()) { - if (modifier.getOperation() == ModifierOperation.MULTIPLY) { + if (modifier.getOperation() == ModifierOperation.ADD_MULTIPLIED_TOTAL) { value *= 1.0D + modifier.getAmount(); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index eaa7b5084..469accd40 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -50,19 +50,19 @@ public class DimensionUtils { /** * String reference to vanilla Java overworld dimension identifier */ - public static final String OVERWORLD = "minecraft:overworld"; + public static final int OVERWORLD = 0; /** * String reference to vanilla Java nether dimension identifier */ - public static final String NETHER = "minecraft:the_nether"; + public static final int NETHER = 3; /** * String reference to vanilla Java end dimension identifier */ - public static final String THE_END = "minecraft:the_end"; + public static final int THE_END = 2; - public static void switchDimension(GeyserSession session, String javaDimension) { + public static void switchDimension(GeyserSession session, int javaDimension) { int bedrockDimension = javaToBedrock(javaDimension); // new bedrock dimension - String previousDimension = session.getDimension(); // previous java dimension + int previousDimension = session.getDimension(); // previous java dimension Entity player = session.getPlayerEntity(); @@ -142,15 +142,15 @@ public class DimensionUtils { // we check if the player is entering the nether and apply the nether fog to fake the fact that the client // thinks they are in the end dimension. if (isCustomBedrockNetherId()) { - if (NETHER.equals(javaDimension)) { + if (NETHER == javaDimension) { session.camera().sendFog(BEDROCK_FOG_HELL); - } else if (NETHER.equals(previousDimension)) { + } else if (NETHER == previousDimension) { session.camera().removeFog(BEDROCK_FOG_HELL); } } } - public static void setBedrockDimension(GeyserSession session, String javaDimension) { + public static void setBedrockDimension(GeyserSession session, int javaDimension) { session.getChunkCache().setBedrockDimension(switch (javaDimension) { case DimensionUtils.THE_END -> BedrockDimension.THE_END; case DimensionUtils.NETHER -> DimensionUtils.isCustomBedrockNetherId() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER; @@ -174,7 +174,7 @@ public class DimensionUtils { * @param javaDimension Dimension ID to convert * @return Converted Bedrock edition dimension ID */ - public static int javaToBedrock(String javaDimension) { + public static int javaToBedrock(int javaDimension) { return switch (javaDimension) { case NETHER -> BEDROCK_NETHER_ID; case THE_END -> 2; @@ -182,6 +182,20 @@ public class DimensionUtils { }; } + /** + * Map the Java edition dimension IDs to Bedrock edition + * + * @param javaDimension Dimension ID to convert + * @return Converted Bedrock edition dimension ID + */ + public static int javaToBedrock(String javaDimension) { + return switch (javaDimension) { + case "minecraft:the_nether" -> BEDROCK_NETHER_ID; + case "minecraft:the_end" -> 2; + default -> 0; + }; + } + /** * The Nether dimension in Bedrock does not permit building above Y128 - the Bedrock above the dimension. * This workaround sets the Nether as the End dimension to ignore this limit. @@ -201,7 +215,7 @@ public class DimensionUtils { * @param newDimension the new dimension that the player will be transferred to * @return the fake dimension to transfer to */ - public static String getTemporaryDimension(String currentDimension, String newDimension) { + public static int getTemporaryDimension(int currentDimension, int newDimension) { if (isCustomBedrockNetherId()) { // Prevents rare instances of Bedrock locking up return javaToBedrock(newDimension) == 2 ? OVERWORLD : NETHER; 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 e56aea8c9..7f3a02df6 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; @@ -66,6 +67,7 @@ import org.jetbrains.annotations.Contract; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.IntFunction; @@ -77,7 +79,7 @@ public class InventoryUtils { */ public static int LAST_RECIPE_NET_ID; - public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new CompoundTag("")); + public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new DataComponents(new HashMap<>())); public static void openInventory(GeyserSession session, Inventory inventory) { session.setOpenInventory(inventory); @@ -279,7 +281,7 @@ public class InventoryUtils { if (session.getGameMode() == GameMode.CREATIVE) { int slot = findEmptyHotbarSlot(inventory); - ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket(slot, + ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket((short) slot, itemStack); if ((slot - 36) != inventory.getHeldItemSlot()) { setHotbarItem(session, slot); @@ -345,7 +347,7 @@ public class InventoryUtils { ItemMapping mapping = session.getItemMappings().getMapping(itemName); // TODO if (mapping != null) { - ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket(slot, + ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket((short)slot, new ItemStack(mapping.getJavaItem().javaId())); if ((slot - 36) != inventory.getHeldItemSlot()) { setHotbarItem(session, slot); diff --git a/core/src/main/java/org/geysermc/geyser/util/JavaCodecUtil.java b/core/src/main/java/org/geysermc/geyser/util/JavaCodecUtil.java deleted file mode 100644 index 795d45490..000000000 --- a/core/src/main/java/org/geysermc/geyser/util/JavaCodecUtil.java +++ /dev/null @@ -1,64 +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.util; - -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.Iterator; - -public final class JavaCodecUtil { - - /** - * Iterate over a Java Edition codec and return each entry as a CompoundTag - */ - public static Iterable iterateAsTag(CompoundTag tag) { - ListTag value = tag.get("value"); - Iterator originalIterator = value.iterator(); - return new Iterable<>() { - @NonNull - @Override - public Iterator iterator() { - return new Iterator<>() { - @Override - public boolean hasNext() { - return originalIterator.hasNext(); - } - - @Override - public CompoundTag next() { - return (CompoundTag) originalIterator.next(); - } - }; - } - }; - } - - private JavaCodecUtil() { - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2d32159f0..e9fadb577 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "1.20.4-2-20240116.220521-7" +mcprotocollib = "b2e93c520a" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" @@ -107,7 +107,7 @@ guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } -mcprotocollib = { group = "com.github.steveice10", name = "mcprotocollib", version.ref = "mcprotocollib" } +mcprotocollib = { group = "com.github.geysermc", name = "mcprotocollib", version.ref = "mcprotocollib" } raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } From aed7f1bed73b6eab4e7c70be597c4c15a5767db8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 20 Apr 2024 19:20:00 -0400 Subject: [PATCH 046/897] Update the item parts --- .../geyser/item/type/CompassItem.java | 8 +-- .../geyser/item/type/FilledMapItem.java | 10 ++-- .../geyser/item/type/FireworkRocketItem.java | 45 ++++++++--------- .../geyser/item/type/FireworkStarItem.java | 23 ++++----- .../geyser/item/type/FishingRodItem.java | 8 +-- .../geyser/item/type/GoatHornItem.java | 15 ++++-- .../org/geysermc/geyser/item/type/Item.java | 16 +++--- .../geysermc/geyser/item/type/MapItem.java | 15 +++--- .../geyser/item/type/PlayerHeadItem.java | 49 +++++++------------ .../geysermc/geyser/item/type/PotionItem.java | 18 +++---- .../geyser/item/type/ShulkerBoxItem.java | 2 +- .../geyser/item/type/TippedArrowItem.java | 9 ++-- .../item/type/TropicalFishBucketItem.java | 7 +-- .../geyser/item/type/WritableBookItem.java | 26 +++++----- .../geyser/item/type/WrittenBookItem.java | 41 +++++++++------- .../translator/item/BedrockItemBuilder.java | 27 ++++++++++ .../translator/item/ItemTranslator.java | 6 +-- 17 files changed, 171 insertions(+), 154 deletions(-) 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 8d48d1307..10c574d5d 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(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - if (isLodestoneCompass(itemStack.getDataComponents())) { - return super.translateToBedrock(itemStack, mappings.getLodestoneCompass(), mappings); + public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + if (isLodestoneCompass(components)) { + return super.translateToBedrock(count, components, mappings.getLodestoneCompass(), mappings); } - return super.translateToBedrock(itemStack, mapping, mappings); + return super.translateToBedrock(count, components, mapping, mappings); } @Override 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 78a175f8d..af0b84308 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 @@ -25,10 +25,8 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; @@ -39,12 +37,12 @@ public class FilledMapItem extends MapItem { } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings); - DataComponents components = itemStack.getDataComponents(); + public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + ItemData.Builder builder = super.translateToBedrock(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()); + //return builder.tag(NbtMap.builder().putInt("map", 0).build()); TODO if this is *still* broken, let's move it to translateComponentsToBedrock + return builder; } else { Integer mapColor = components.get(DataComponentType.MAP_COLOR); if (mapColor != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index d688e59f6..afb848e2d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -32,6 +32,7 @@ import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.level.FireworkColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -63,9 +64,10 @@ public class FireworkRocketItem extends Item { } List explosionNbt = new ArrayList<>(); for (Fireworks.FireworkExplosion explosion : explosions) { - explosionNbt.add(translateExplosionToBedrock(explosion, "")); + explosionNbt.add(translateExplosionToBedrock(explosion)); } - + fireworksNbt.putList("Explosions", NbtType.COMPOUND, explosionNbt); + builder.putCompound("Fireworks", fireworksNbt.build()); } @Override @@ -73,39 +75,34 @@ public class FireworkRocketItem extends Item { super.translateNbtToJava(tag, mapping); } - static NbtMap translateExplosionToBedrock(Fireworks.FireworkExplosion explosion, String newName) { + static NbtMap translateExplosionToBedrock(Fireworks.FireworkExplosion explosion) { NbtMapBuilder newExplosionData = NbtMap.builder(); - if (explosion.get("Type") != null) { - newExplosionData.put(new ByteTag("FireworkType", MathUtils.getNbtByte(explosion.get("Type").getValue()))); - } +// if (explosion.get("Type") != null) { +// newExplosionData.put(new ByteTag("FireworkType", MathUtils.getNbtByte(explosion.get("Type").getValue()))); +// } //newExplosionData.putByte("FireworkType", explosion.get) //TODO??? - // TODO do we need length checks - if (explosion.get("Colors") != null) { - int[] oldColors = (int[]) explosion.get("Colors").getValue(); - byte[] colors = new byte[oldColors.length]; + int[] oldColors = explosion.getColors(); + byte[] colors = new byte[oldColors.length]; - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaRGB(color); - } - - newExplosionData.put(new ByteArrayTag("FireworkColor", colors)); + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaRGB(color); } - if (explosion.get("FadeColors") != null) { - int[] oldColors = (int[]) explosion.get("FadeColors").getValue(); - byte[] colors = new byte[oldColors.length]; + newExplosionData.putByteArray("FireworkColor", colors); - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaRGB(color); - } + oldColors = explosion.getFadeColors(); + colors = new byte[oldColors.length]; - newExplosionData.put(new ByteArrayTag("FireworkFade", colors)); + i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaRGB(color); } + newExplosionData.putByteArray("FireworkFade", colors); + newExplosionData.putBoolean("FireworkTrail", explosion.isHasTrail()); newExplosionData.putBoolean("FireworkFlicker", explosion.isHasTwinkle()); // TODO verify diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 4ae9c8b13..505296418 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -25,12 +25,13 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.mc.protocol.data.game.item.component.Fireworks; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -44,19 +45,15 @@ public class FireworkStarItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - Tag explosion = tag.remove("Explosion"); - if (explosion instanceof CompoundTag) { - CompoundTag newExplosion = FireworkRocketItem.translateExplosionToBedrock((CompoundTag) explosion, "FireworksItem"); - tag.put(newExplosion); - Tag color = ((CompoundTag) explosion).get("Colors"); - if (color instanceof IntArrayTag) { + Fireworks.FireworkExplosion explosion = components.get(DataComponentType.FIREWORK_EXPLOSION); + if (explosion != null) { + NbtMap newExplosion = FireworkRocketItem.translateExplosionToBedrock(explosion); + builder.putCompound("FireworksItem", newExplosion); + int[] colors = explosion.getColors(); + if (colors.length != 0) { // Determine the custom color, if any. // Mostly replicates Java's own rendering code, as Java determines the final firework star color client-side // while Bedrock determines it server-side. - int[] colors = ((IntArrayTag) color).getValue(); - if (colors.length == 0) { - return; - } int finalColor; if (colors.length == 1) { finalColor = colors[0]; @@ -77,7 +74,7 @@ public class FireworkStarItem extends Item { finalColor = r << 16 | g << 8 | b; } - tag.put(new IntTag("customColor", finalColor)); + builder.putInt("customColor", finalColor); } } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java index 4538689da..743928482 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java @@ -26,8 +26,6 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -42,11 +40,7 @@ public class FishingRodItem extends Item { super.translateComponentsToBedrock(session, components, builder); // Fix damage inconsistency - Tag damage = tag.get("Damage"); - if (damage instanceof IntTag) { - int originalDurability = ((IntTag) damage).getValue(); - tag.put(new IntTag("Damage", getBedrockDamage(originalDurability))); - } + builder.getDamage().ifPresent(damage -> builder.setDamage(getBedrockDamage(damage))); } public static int getBedrockDamage(int javaDamage) { 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 60b201961..20f9782df 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 @@ -26,6 +26,9 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.mc.protocol.data.game.item.component.Instrument; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -52,10 +55,14 @@ public class GoatHornItem extends Item { } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings); - if (itemStack.getNbt() != null && itemStack.getNbt().get("instrument") instanceof StringTag instrumentTag) { - String instrument = instrumentTag.getValue(); + public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + ItemData.Builder builder = super.translateToBedrock(count, components, mapping, mappings); + if (components == null) { + return builder; + } + Instrument instrument = components.get(DataComponentType.INSTRUMENT); + // TODO registry + if (instrument != null) { // Drop the Minecraft namespace if applicable if (instrument.startsWith("minecraft:")) { instrument = instrument.substring("minecraft:".length()); 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 decc60da8..e2822ea7a 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 @@ -39,6 +39,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Enchantment; +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; @@ -93,20 +94,16 @@ public class Item { /* Translation methods to Bedrock and back */ - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - if (InventoryUtils.isEmpty(itemStack)) { + public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + if (this == Items.AIR || count <= 0) { // Return, essentially, air return ItemData.builder(); } ItemData.Builder builder = ItemData.builder() .definition(mapping.getBedrockDefinition()) .damage(mapping.getBedrockData()) - .count(itemStack.getAmount()); - if (itemStack.getDataComponents() != null) { - builder.tag(ItemTranslator.translateNbtToBedrock(itemStack.getDataComponents())); - } + .count(count); - DataComponents components = itemStack.getDataComponents(); ItemTranslator.translateCustomItem(components, builder, mapping); return builder; @@ -135,6 +132,11 @@ public class Item { } } + Integer damage = components.get(DataComponentType.DAMAGE); + if (damage != null) { + builder.setDamage(damage); + } + List newTags = new ArrayList<>(); ItemEnchantments enchantments = components.get(DataComponentType.ENCHANTMENTS); if (enchantments != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java index b015862c5..72014e15e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.*; import org.checkerframework.checker.nullness.qual.NonNull; @@ -41,14 +42,14 @@ public class MapItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - Tag mapId = tag.remove("map"); - if (mapId == null || !(mapId.getValue() instanceof Number number)) return; + Integer mapValue = components.get(DataComponentType.MAP_ID); + if (mapValue == null) { + return; + } - int mapValue = number.intValue(); - - tag.put(new LongTag("map_uuid", mapValue)); - tag.put(new IntTag("map_name_index", mapValue)); - tag.put(new ByteTag("map_display_players", (byte) 1)); + builder.putLong("map_uuid", mapValue); + builder.putInt("map_name_index", mapValue); + builder.putByte("map_display_players", (byte) 1); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index dae444775..82219d7d9 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -25,16 +25,14 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.auth.data.GameProfile; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.geyser.translator.text.MessageTranslator; public class PlayerHeadItem extends Item { public PlayerHeadItem(String javaIdentifier, Builder builder) { @@ -45,35 +43,24 @@ public class PlayerHeadItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - CompoundTag displayTag; - if (tag.get("display") instanceof CompoundTag existingDisplayTag) { - displayTag = existingDisplayTag; - } else { - displayTag = new CompoundTag("display"); - tag.put(displayTag); - } - - if (displayTag.get("Name") instanceof StringTag nameTag) { - // Custom names are always yellow and italic - displayTag.put(new StringTag("Name", ChatColor.YELLOW + ChatColor.ITALIC + MessageTranslator.convertMessageLenient(nameTag.getValue(), session.locale()))); - } else { - if (tag.contains("SkullOwner")) { - StringTag name; - Tag skullOwner = tag.get("SkullOwner"); - if (skullOwner instanceof StringTag skullName) { - name = skullName; + // TODO verify + // Also - ChatColor.YELLOW + ChatColor.ITALIC + MessageTranslator.convertMessageLenient(nameTag.getValue(), session.locale())) this code existed if a custom name was already present. + // But I think we would always overwrite that because translateDisplayProperties runs after this method. + String customName = builder.getCustomName(); + if (customName == null) { + GameProfile profile = components.get(DataComponentType.PROFILE); + if (profile != null) { + String name = profile.getName(); + if (name != null) { + // Add correct name of player skull + String displayName = ChatColor.RESET + ChatColor.YELLOW + + MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.locale()).replace("%s", name); + builder.setCustomName(displayName); } else { - if (skullOwner instanceof CompoundTag && ((CompoundTag) skullOwner).get("Name") instanceof StringTag skullName) { - name = skullName; - } else { - // No name found so default to "Player Head" - displayTag.put(new StringTag("Name", ChatColor.RESET + ChatColor.YELLOW + MinecraftLocale.getLocaleString("block.minecraft.player_head", session.locale()))); - return; - } + // No name found so default to "Player Head" + builder.setCustomName(ChatColor.RESET + ChatColor.YELLOW + + MinecraftLocale.getLocaleString("block.minecraft.player_head", session.locale())); } - // Add correct name of player skull - String displayName = ChatColor.RESET + ChatColor.YELLOW + MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.locale()).replace("%s", name.getValue()); - displayTag.put(new StringTag("Name", displayName)); } } } 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 bed2945ba..6aac28c05 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 @@ -27,9 +27,9 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -46,29 +46,27 @@ public class PotionItem extends Item { } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - if (itemStack.getDataComponents() == null) return super.translateToBedrock(itemStack, mapping, mappings); - PotionContents potionContents = itemStack.getDataComponents().get(DataComponentType.POTION_CONTENTS); + public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + if (components == null) return super.translateToBedrock(count, components, mapping, mappings); + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); if (potionContents != null) { - ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(itemStack.getDataComponents(), mapping); + ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(components, mapping); if (customItemDefinition == null) { Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); if (potion != null) { return ItemData.builder() .definition(mapping.getBedrockDefinition()) .damage(potion.getBedrockId()) - .count(itemStack.getAmount()) - .tag(ItemTranslator.translateNbtToBedrock(itemStack.getNbt())); + .count(count); } GeyserImpl.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue()); } else { return ItemData.builder() .definition(customItemDefinition) - .count(itemStack.getAmount()) - .tag(ItemTranslator.translateNbtToBedrock(itemStack.getNbt())); + .count(count); } } - return super.translateToBedrock(itemStack, mapping, mappings); + return super.translateToBedrock(count, components, mapping, mappings); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index 395563fe3..267946442 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -83,7 +83,7 @@ public class ShulkerBoxItem extends BlockItem { itemsList.add(boxItemNbt.build()); } - builder.getOrCreateNbt().putList("Items", NbtType.COMPOUND, itemsList); + builder.putList("Items", NbtType.COMPOUND, itemsList); } @Override 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 fcf562ba5..e4bad2f32 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -41,7 +41,7 @@ public class TippedArrowItem extends ArrowItem { } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { Tag potionTag = itemStack.getNbt().get("Potion"); if (potionTag instanceof StringTag) { TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByJavaIdentifier(((StringTag) potionTag).getValue()); @@ -49,11 +49,10 @@ public class TippedArrowItem extends ArrowItem { return ItemData.builder() .definition(mapping.getBedrockDefinition()) .damage(tippedArrowPotion.getBedrockId()) - .count(itemStack.getAmount()) - .tag(ItemTranslator.translateNbtToBedrock(itemStack.getNbt())); + .count(count); } GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionTag.getValue()); } - return super.translateToBedrock(itemStack, mapping, mappings); + return super.translateToBedrock(count, components, mapping, mappings); } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index 3ece87745..c0407e697 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; @@ -53,10 +54,10 @@ public class TropicalFishBucketItem extends Item { super.translateComponentsToBedrock(session, components, builder); // Prevent name from appearing as "Bucket of" - tag.put(new ByteTag("AppendCustomName", (byte) 1)); - tag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale()))); + builder.putByte("AppendCustomName", (byte) 1); + builder.putString("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale())); // Add Java's client side lore tag - Tag bucketVariantTag = tag.get("BucketVariantTag"); + components.get(DataComponentType) if (bucketVariantTag instanceof IntTag) { CompoundTag displayTag = tag.get("display"); if (displayTag == null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java index 68cdf99d4..d925d2b8a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java @@ -25,12 +25,18 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.mc.protocol.data.game.item.component.Filterable; +import com.github.steveice10.mc.protocol.data.game.item.component.WritableBookContent; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -48,22 +54,20 @@ public class WritableBookItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - ListTag pagesTag = tag.remove("pages"); - if (pagesTag == null) { + WritableBookContent bookContent = components.get(DataComponentType.WRITABLE_BOOK_CONTENT); + if (bookContent == null) { return; } - List pages = new ArrayList<>(); - for (Tag subTag : pagesTag.getValue()) { - if (!(subTag instanceof StringTag textTag)) - continue; - CompoundTag pageTag = new CompoundTag(""); - pageTag.put(new StringTag("photoname", "")); - pageTag.put(new StringTag("text", MessageTranslator.convertMessageLenient(textTag.getValue()))); - pages.add(pageTag); + List bedrockPages = new ArrayList<>(); + for (Filterable page : bookContent.getPages()) { + NbtMapBuilder pageBuilder = NbtMap.builder(); + pageBuilder.putString("photoname", ""); + pageBuilder.putString("text", MessageTranslator.convertMessageLenient(page.getRaw())); + bedrockPages.add(pageBuilder.build()); } - tag.put(new ListTag("pages", pages)); + builder.putList("pages", NbtType.COMPOUND, bedrockPages); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index ae6b81f6e..6ca52aca4 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -25,21 +25,27 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.mc.protocol.data.game.item.component.Filterable; +import com.github.steveice10.mc.protocol.data.game.item.component.WrittenBookContent; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; +import java.util.ArrayList; import java.util.List; -public class WrittenBookItem extends WritableBookItem { +public class WrittenBookItem extends Item { public static final int MAXIMUM_PAGE_EDIT_LENGTH = 1024; public static final int MAXIMUM_PAGE_LENGTH = 32768; public static final int MAXIMUM_PAGE_COUNT = 100; // Java edition limit. Bedrock edition has a limit of 50 pages. @@ -51,25 +57,24 @@ public class WrittenBookItem extends WritableBookItem { @Override public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - boolean isValid = isValidWrittenBook(tag); - if (!isValid) { - tag.remove("pages"); - } - super.translateComponentsToBedrock(session, components, builder); - if (!isValid) { - CompoundTag invalidTagPage = new CompoundTag(""); - invalidTagPage.put(new StringTag("photoname", "")); - invalidTagPage.put(new StringTag( - "text", - MessageTranslator.convertMessage( - Component.translatable("book.invalid.tag", NamedTextColor.DARK_RED), - session.locale() - ) - )); - tag.put(new ListTag("pages", List.of(invalidTagPage))); + WrittenBookContent bookContent = components.get(DataComponentType.WRITTEN_BOOK_CONTENT); + if (bookContent == null) { + return; } + List bedrockPages = new ArrayList<>(); + for (Filterable page : bookContent.getPages()) { + NbtMapBuilder pageBuilder = NbtMap.builder(); + pageBuilder.putString("photoname", ""); + pageBuilder.putString("text", MessageTranslator.convertMessage(page.getRaw())); + bedrockPages.add(pageBuilder.build()); + } + builder.putList("pages", NbtType.COMPOUND, bedrockPages); + + builder.putString("title", bookContent.getTitle().getRaw()) + .putString("author", bookContent.getAuthor()); + // TODO isResolved } private boolean isValidWrittenBook(CompoundTag tag) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java index 83293d4ee..c1f7184f2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java @@ -34,6 +34,7 @@ import org.geysermc.geyser.registry.type.ItemMapping; import java.util.ArrayList; import java.util.List; +import java.util.OptionalInt; /** * An intermediary class made to allow easy access to work-in-progress NBT, such as lore and display. @@ -44,12 +45,18 @@ public final class BedrockItemBuilder { private String customName; @Nullable private List lore; + private OptionalInt damage = OptionalInt.empty(); /** * Miscellaneous NBT that will be put into the final item. */ @Nullable private NbtMapBuilder builder; + @Nullable + public String getCustomName() { + return customName; + } + public BedrockItemBuilder setCustomName(String customName) { this.customName = customName; return this; @@ -63,6 +70,15 @@ public final class BedrockItemBuilder { return lore; } + public OptionalInt getDamage() { + return damage; + } + + public BedrockItemBuilder setDamage(int damage) { + this.damage = OptionalInt.of(damage); + return this; + } + @NonNull public NbtMapBuilder getOrCreateNbt() { if (builder == null) { @@ -85,6 +101,14 @@ public final class BedrockItemBuilder { return getOrCreateNbt().putInt(name, value); } + public NbtMapBuilder putList(String name, NbtType type, List value) { + return getOrCreateNbt().putList(name, type, value); + } + + public NbtMapBuilder putLong(String name, long value) { + return getOrCreateNbt().putLong(name, value); + } + public NbtMapBuilder putString(String name, String value) { return getOrCreateNbt().putString(name, value); } @@ -108,6 +132,9 @@ public final class BedrockItemBuilder { } getOrCreateNbt().put("display", display.build()); } + if (damage.isPresent()) { + getOrCreateNbt().putInt("Damage", damage.getAsInt()); + } if (builder == null) { return null; } 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 6459aa9ec..65ceb3497 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 @@ -161,9 +161,9 @@ public final class ItemTranslator { addAdvancedTooltips(components, nbtBuilder, javaItem, session.locale()); } - ItemStack itemStack = new ItemStack(javaItem.javaId(), count, components); - - ItemData.Builder builder = javaItem.translateToBedrock(itemStack, bedrockItem, session.getItemMappings()); + ItemData.Builder builder = javaItem.translateToBedrock(count, components, bedrockItem, session.getItemMappings()); + // Finalize the Bedrock NBT + builder.tag(nbtBuilder.build()); if (bedrockItem.isBlock()) { CustomBlockData customBlockData = BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.getOrDefault( bedrockItem.getJavaItem().javaIdentifier(), null); From 94e533ea7ce5d87e8cbcf23a3f3d8b66bc633448 Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Sun, 21 Apr 2024 01:33:07 +0100 Subject: [PATCH 047/897] Fix tags and attributes --- .../org/geysermc/geyser/entity/type/LivingEntity.java | 2 +- .../entity/type/living/animal/AxolotlEntity.java | 2 +- .../org/geysermc/geyser/session/GeyserSession.java | 2 +- .../org/geysermc/geyser/session/cache/TagCache.java | 10 +++++----- gradle/libs.versions.toml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) 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 245b99cef..b070bdfff 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 @@ -299,7 +299,7 @@ public class LivingEntity extends Entity { case GENERIC_MOVEMENT_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.MOVEMENT_SPEED)); case GENERIC_FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE)); case GENERIC_KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE)); - case HORSE_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH)); + case GENERIC_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH)); } } } 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 85b2afc14..97753f63f 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 @@ -61,7 +61,7 @@ public class AxolotlEntity extends AnimalEntity { @Override public boolean canEat(Item item) { - return session.getTagCache().isAxolotlTemptItem(item); + return session.getTagCache().isAxolotlFood(item); } @Override 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 936fc932d..8e1ed2e51 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -368,7 +368,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * All dimensions that the client could possibly connect to. */ - private final Map dimensions = new Object2ObjectOpenHashMap<>(3); + private final Int2ObjectMap dimensions = new Int2ObjectOpenHashMap<>(4); private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); 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 5acfc1f09..57000bf8b 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 @@ -58,7 +58,7 @@ public class TagCache { private IntList requiresDiamondTool; /* Items */ - private IntList axolotlTemptItems; + private IntList axolotlFood; private IntList creeperIgniters; private IntList fishes; private IntList flowers; @@ -96,7 +96,7 @@ public class TagCache { } Map itemTags = packet.getTags().get("minecraft:item"); - this.axolotlTemptItems = IntList.of(itemTags.get("minecraft:axolotl_tempt_items")); + this.axolotlFood = IntList.of(itemTags.get("minecraft:axolotl_food")); this.creeperIgniters = load(itemTags.get("minecraft:creeper_igniters")); this.fishes = IntList.of(itemTags.get("minecraft:fishes")); this.flowers = IntList.of(itemTags.get("minecraft:flowers")); @@ -133,7 +133,7 @@ public class TagCache { this.requiresIronTool = IntLists.emptyList(); this.requiresDiamondTool = IntLists.emptyList(); - this.axolotlTemptItems = IntLists.emptyList(); + this.axolotlFood = IntLists.emptyList(); this.creeperIgniters = IntLists.emptyList(); this.fishes = IntLists.emptyList(); this.flowers = IntLists.emptyList(); @@ -143,8 +143,8 @@ public class TagCache { this.snifferFood = IntLists.emptyList(); } - public boolean isAxolotlTemptItem(Item item) { - return axolotlTemptItems.contains(item.javaId()); + public boolean isAxolotlFood(Item item) { + return axolotlFood.contains(item.javaId()); } public boolean isCreeperIgniter(Item item) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e9fadb577..08c04a84a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "b2e93c520a" # Revert from jitpack after release +mcprotocollib = "897eb241b6" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 8bd2df0828a581de8019e4e08aeb46a46458296f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 20 Apr 2024 22:42:25 -0400 Subject: [PATCH 048/897] Trying to get more compiled but brain is officially fried for the day! --- .../geyser/entity/type/FireworkEntity.java | 92 ++----------------- .../entity/type/ThrownPotionEntity.java | 16 ++-- .../inventory/item/TippedArrowPotion.java | 5 + .../geysermc/geyser/item/type/ArrowItem.java | 4 +- .../geysermc/geyser/item/type/BannerItem.java | 35 +++---- .../geyser/item/type/DecoratedPotItem.java | 2 +- .../geyser/item/type/EnchantedBookItem.java | 25 ++--- .../geyser/item/type/GoatHornItem.java | 22 ++--- .../org/geysermc/geyser/item/type/Item.java | 70 +++++--------- .../geysermc/geyser/item/type/PotionItem.java | 7 +- .../geysermc/geyser/item/type/ShieldItem.java | 35 ++++--- .../geyser/item/type/TippedArrowItem.java | 13 ++- .../item/type/TropicalFishBucketItem.java | 34 +++---- .../geyser/session/cache/LodestoneCache.java | 52 ++++++----- .../inventory/LoomInventoryTranslator.java | 7 +- .../translator/item/BedrockItemBuilder.java | 5 +- .../translator/item/ItemTranslator.java | 55 +++++------ .../bedrock/BedrockBookEditTranslator.java | 12 +-- .../entity/JavaSetEquipmentTranslator.java | 20 ++-- .../geysermc/geyser/util/InventoryUtils.java | 13 +-- 20 files changed, 210 insertions(+), 314 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java index 171849ce5..04317e6d6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java @@ -27,24 +27,16 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; -import org.geysermc.floodgate.util.DeviceOs; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.level.FireworkColor; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.MathUtils; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import java.util.ArrayList; -import java.util.List; import java.util.OptionalInt; import java.util.UUID; @@ -59,80 +51,16 @@ public class FireworkEntity extends Entity { if (item == null) { return; } - CompoundTag tag = item.getNbt(); - - if (tag == null) { + DataComponents components = item.getDataComponents(); + if (components == null) { return; } - // TODO: Remove once Mojang fixes bugs with fireworks crashing clients on these specific devices. - // https://bugs.mojang.com/browse/MCPE-89115 - if (session.getClientData().getDeviceOs() == DeviceOs.XBOX - || session.getClientData().getDeviceOs() == DeviceOs.PS4) { - return; - } - - CompoundTag fireworks = tag.get("Fireworks"); - if (fireworks == null) { - // Thank you Mineplex very cool - return; - } - - NbtMapBuilder fireworksBuilder = NbtMap.builder(); - if (fireworks.get("Flight") != null) { - fireworksBuilder.putByte("Flight", MathUtils.getNbtByte(fireworks.get("Flight").getValue())); - } - - List explosions = new ArrayList<>(); - if (fireworks.get("Explosions") != null) { - for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) { - CompoundTag effectData = (CompoundTag) effect; - NbtMapBuilder effectBuilder = NbtMap.builder(); - - if (effectData.get("Type") != null) { - effectBuilder.putByte("FireworkType", MathUtils.getNbtByte(effectData.get("Type").getValue())); - } - - if (effectData.get("Colors") != null) { - int[] oldColors = (int[]) effectData.get("Colors").getValue(); - byte[] colors = new byte[oldColors.length]; - - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaRGB(color); - } - - effectBuilder.putByteArray("FireworkColor", colors); - } - - if (effectData.get("FadeColors") != null) { - int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); - byte[] colors = new byte[oldColors.length]; - - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaRGB(color); - } - - effectBuilder.putByteArray("FireworkFade", colors); - } - - if (effectData.get("Trail") != null) { - effectBuilder.putByte("FireworkTrail", MathUtils.getNbtByte(effectData.get("Trail").getValue())); - } - - if (effectData.get("Flicker") != null) { - effectBuilder.putByte("FireworkFlicker", MathUtils.getNbtByte(effectData.get("Flicker").getValue())); - } - - explosions.add(effectBuilder.build()); - } - } - - fireworksBuilder.putList("Explosions", NbtType.COMPOUND, explosions); - - NbtMapBuilder builder = NbtMap.builder(); - builder.put("Fireworks", fireworksBuilder.build()); + // TODO this looked the same, so I'm going to assume it is and (keep below comment if true) + // Translate using item methods to get firework NBT for Bedrock + BedrockItemBuilder builder = new BedrockItemBuilder(); + Items.FIREWORK_ROCKET.translateComponentsToBedrock(session, components, builder); + dirtyMetadata.put(EntityDataTypes.DISPLAY_FIREWORK, builder.build()); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java index cea371963..31428477a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java @@ -27,8 +27,9 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -58,16 +59,17 @@ public class ThrownPotionEntity extends ThrowableItemEntity { setFlag(EntityFlag.LINGERING, false); } else { // As of Java 1.19.3, the server/client doesn't seem to care of the item is actually a potion? - if (itemStack.getNbt() != null) { - Tag potionTag = itemStack.getNbt().get("Potion"); - if (potionTag instanceof StringTag) { - Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); + DataComponents components = itemStack.getDataComponents(); + if (components != null) { + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + Potion potion = Potion.VALUES[potionContents.getPotionId()]; if (potion != null) { dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, (int) potion.getBedrockId()); setFlag(EntityFlag.ENCHANTED, !NON_ENCHANTED_POTIONS.contains(potion)); } else { dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0); - GeyserImpl.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue()); + GeyserImpl.getInstance().getLogger().debug("Unknown java potion: " + potionContents.getPotionId()); } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java index 3ba0ad56f..5c33fec67 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java @@ -36,6 +36,7 @@ import java.util.Locale; */ @Getter public enum TippedArrowPotion { + WATER(-1, ArrowParticleColors.NONE), // Guessing this based off of the Potion enum. TODO merge? MUNDANE(2, ArrowParticleColors.NONE), // 3 is extended? THICK(4, ArrowParticleColors.NONE), AWKWARD(5, ArrowParticleColors.NONE), @@ -94,6 +95,10 @@ public enum TippedArrowPotion { this.javaColor = arrowParticleColor.getColor(); } + public static TippedArrowPotion of(int id) { + return VALUES[id]; + } + public static @Nullable TippedArrowPotion getByJavaIdentifier(String javaIdentifier) { for (TippedArrowPotion potion : VALUES) { if (potion.javaIdentifier.equals(javaIdentifier)) { 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 cf66b036b..16d5fd482 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 @@ -26,8 +26,6 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -48,7 +46,7 @@ public class ArrowItem extends Item { if (tippedArrowPotion != null) { itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getDataComponents()); StringTag potionTag = new StringTag("Potion", tippedArrowPotion.getJavaIdentifier()); - itemStack.getDataComponents().put(DataComponentType.POTION_CONTENTS, new PotionContents()); + //itemStack.getDataComponents().put(DataComponentType.POTION_CONTENTS, new PotionContents()); } return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 549809391..32806c3c2 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -56,14 +56,14 @@ public class BannerItem extends BlockItem { static { // Construct what an ominous banner is supposed to look like OMINOUS_BANNER_PATTERN = List.of( - new BannerPatternLayer("mr", 9), - new BannerPatternLayer("bs", 8), - new BannerPatternLayer("cs", 7), - new BannerPatternLayer("bo", 8), - new BannerPatternLayer("ms", 15), - new BannerPatternLayer("hh", 8), - new BannerPatternLayer("mc", 8), - new BannerPatternLayer("bo", 15) +// new BannerPatternLayer("mr", 9), +// new BannerPatternLayer("bs", 8), +// new BannerPatternLayer("cs", 7), +// new BannerPatternLayer("bo", 8), +// new BannerPatternLayer("ms", 15), +// new BannerPatternLayer("hh", 8), +// new BannerPatternLayer("mc", 8), +// new BannerPatternLayer("bo", 15) ); } @@ -103,7 +103,8 @@ public class BannerItem extends BlockItem { * @return The Java edition format pattern nbt */ public static CompoundTag getJavaBannerPattern(NbtMap pattern) { - return new BannerPatternLayer(pattern.getString("Pattern"), 15 - pattern.getInt("Color")); + //return new BannerPatternLayer(0/*pattern.getString("Pattern")*/, 15 - pattern.getInt("Color")); + return null; } /** @@ -128,13 +129,13 @@ public class BannerItem extends BlockItem { List patterns = components.get(DataComponentType.BANNER_PATTERNS); if (patterns != null) { - if (patterns.equals(OMINOUS_BANNER_PATTERN)) { - // Remove the current patterns and set the ominous banner type - builder.putInt("Type", 1); - } else { - invertBannerColors(patterns); - tag.put(patterns); - } +// if (patterns.equals(OMINOUS_BANNER_PATTERN)) { +// // Remove the current patterns and set the ominous banner type +// builder.putInt("Type", 1); +// } else { +// invertBannerColors(patterns); +// tag.put(patterns); +// } } } @@ -146,7 +147,7 @@ public class BannerItem extends BlockItem { // Ominous banner pattern tag.remove("Type"); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - blockEntityTag.put(OMINOUS_BANNER_PATTERN); + //blockEntityTag.put(OMINOUS_BANNER_PATTERN); tag.put(blockEntityTag); } else if (tag.get("Patterns") instanceof ListTag patterns) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index 792ec0f0b..8d9be4db2 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -41,7 +41,7 @@ public class DecoratedPotItem extends BlockItem { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - components.get(DataComponentType.POT_DECORATIONS); // TODO + components.get(DataComponentType.POT_DECORATIONS); // TODO what does this look like on Bedrock? // if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { // if (blockEntityTag.remove("sherds") instanceof ListTag sherds) { // // bedrock wants it on the root level diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index 3851813ae..095537a09 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -25,16 +25,18 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class EnchantedBookItem extends Item { public EnchantedBookItem(String javaIdentifier, Builder builder) { @@ -45,20 +47,19 @@ public class EnchantedBookItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - List newTags = new ArrayList<>(); - Tag enchantmentTag = tag.remove("StoredEnchantments"); - if (enchantmentTag instanceof ListTag listTag) { - for (Tag subTag : listTag.getValue()) { - if (!(subTag instanceof CompoundTag)) continue; - CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) subTag, tag); + List bedrockEnchants = new ArrayList<>(); + ItemEnchantments enchantments = components.get(DataComponentType.STORED_ENCHANTMENTS); + if (enchantments != null) { // TODO don't duplicate code? + for (Map.Entry enchantment : enchantments.getEnchantments().entrySet()) { + NbtMap bedrockTag = remapEnchantment(session, enchantment.getKey(), enchantment.getValue(), builder); if (bedrockTag != null) { - newTags.add(bedrockTag); + bedrockEnchants.add(bedrockTag); } } } - if (!newTags.isEmpty()) { - tag.put(new ListTag("ench", newTags)); + if (!bedrockEnchants.isEmpty()) { + builder.putList("ench", NbtType.COMPOUND, bedrockEnchants); } } } 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 20f9782df..48e75dc79 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 @@ -64,16 +64,16 @@ public class GoatHornItem extends Item { // TODO registry if (instrument != null) { // Drop the Minecraft namespace if applicable - if (instrument.startsWith("minecraft:")) { - instrument = instrument.substring("minecraft:".length()); - } - - int damage = INSTRUMENTS.indexOf(instrument); - if (damage == -1) { - damage = 0; - GeyserImpl.getInstance().getLogger().debug("Unknown goat horn instrument: " + instrumentTag.getValue()); - } - builder.damage(damage); +// if (instrument.startsWith("minecraft:")) { +// instrument = instrument.substring("minecraft:".length()); +// } +// +// int damage = INSTRUMENTS.indexOf(instrument); +// if (damage == -1) { +// damage = 0; +// GeyserImpl.getInstance().getLogger().debug("Unknown goat horn instrument: " + instrumentTag.getValue()); +// } +// builder.damage(damage); } return builder; } @@ -90,7 +90,7 @@ public class GoatHornItem extends Item { String instrument = INSTRUMENTS.get(damage); StringTag instrumentTag = new StringTag("instrument", "minecraft:" + instrument); - itemStack.getNbt().put(instrumentTag); + //itemStack.getNbt().put(instrumentTag); 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 e2822ea7a..2779768db 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 @@ -27,15 +27,15 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments; import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Enchantment; @@ -48,7 +48,6 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.InventoryUtils; import java.util.ArrayList; import java.util.List; @@ -113,7 +112,7 @@ public class Item { if (itemData.getTag() == null) { return new ItemStack(javaId, itemData.getCount(), null); } - return new ItemStack(javaId, itemData.getCount(), ItemTranslator.translateToJavaNBT("", itemData.getTag())); + return new ItemStack(javaId, itemData.getCount(), null/*ItemTranslator.translateToJavaNBT("", itemData.getTag())*/); } public ItemMapping toBedrockDefinition(DataComponents components, ItemMappings mappings) { @@ -137,23 +136,19 @@ public class Item { builder.setDamage(damage); } - List newTags = new ArrayList<>(); + List enchantNbtList = new ArrayList<>(); ItemEnchantments enchantments = components.get(DataComponentType.ENCHANTMENTS); if (enchantments != null) { - - } - if (enchantmentTag instanceof ListTag listTag) { - for (Tag subTag : listTag.getValue()) { - if (!(subTag instanceof CompoundTag)) continue; - CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) subTag, tag); - if (bedrockTag != null) { - newTags.add(bedrockTag); + for (Map.Entry enchantment : enchantments.getEnchantments().entrySet()) { + NbtMap enchantNbt = remapEnchantment(session, enchantment.getKey(), enchantment.getValue(), builder); + if (enchantNbt != null) { + enchantNbtList.add(enchantNbt); } } } - if (!newTags.isEmpty()) { - tag.put(new ListTag("ench", newTags)); + if (!enchantNbtList.isEmpty()) { + builder.putList("ench", NbtType.COMPOUND, enchantNbtList); } } @@ -220,45 +215,30 @@ public class Item { } } - protected final @Nullable NbtMap remapEnchantment(GeyserSession session, ItemEnchantments, NbtMapBuilder rootBuilder) { - - Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); + protected final @Nullable NbtMap remapEnchantment(GeyserSession session, int enchantId, int level, BedrockItemBuilder builder) { + // TODO verify + // TODO streamline Enchantment process + Enchantment.JavaEnchantment enchantment = Enchantment.JavaEnchantment.of(enchantId); + if (enchantment == Enchantment.JavaEnchantment.SWEEPING_EDGE) { + addSweeping(session, builder, level); + return null; + } if (enchantment == null) { - if (Identifier.formalize((String) javaEnchId.getValue()).equals("minecraft:sweeping")) { - Tag javaEnchLvl = tag.get("lvl"); - int sweepingLvl = javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.intValue() : 0; - - addSweeping(session, rootTag, sweepingLvl); - return null; - } - GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + javaEnchId.getValue()); + GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + enchantId); return null; } - Tag javaEnchLvl = tag.get("lvl"); - - NbtMapBuilder builder = NbtMap.builder(); - builder.putShort("id", (short) enchantment.ordinal()); - builder.putShort("lvl", ); - return builder.build(); + return NbtMap.builder() + .putShort("id", (short) Enchantment.valueOf(enchantment.name()).ordinal()) + .putShort("lvl", (short) level) + .build(); } - private void addSweeping(GeyserSession session, CompoundTag itemTag, int level) { - CompoundTag displayTag = itemTag.get("display"); - if (displayTag == null) { - displayTag = new CompoundTag("display"); - itemTag.put(displayTag); - } - ListTag loreTag = displayTag.get("Lore"); - if (loreTag == null) { - loreTag = new ListTag("Lore"); - displayTag.put(loreTag); - } - + private void addSweeping(GeyserSession session, BedrockItemBuilder builder, int level) { String sweepingTranslation = MinecraftLocale.getLocaleString("enchantment.minecraft.sweeping", session.locale()); String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale()); - loreTag.add(new StringTag("", ChatColor.RESET + ChatColor.GRAY + sweepingTranslation + " " + lvlTranslation)); + builder.getOrCreateLore().add(ChatColor.RESET + ChatColor.GRAY + sweepingTranslation + " " + lvlTranslation); } /* Translation methods end */ 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 6aac28c05..63b9240c0 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 @@ -38,7 +38,6 @@ 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.translator.item.CustomItemTranslator; -import org.geysermc.geyser.translator.item.ItemTranslator; public class PotionItem extends Item { public PotionItem(String javaIdentifier, Builder builder) { @@ -52,14 +51,14 @@ public class PotionItem extends Item { if (potionContents != null) { ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(components, mapping); if (customItemDefinition == null) { - Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); + Potion potion = Potion.VALUES[potionContents.getPotionId()]; if (potion != null) { return ItemData.builder() .definition(mapping.getBedrockDefinition()) .damage(potion.getBedrockId()) .count(count); } - GeyserImpl.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue()); + GeyserImpl.getInstance().getLogger().debug("Unknown Java potion: " + potionContents.getPotionId()); } else { return ItemData.builder() .definition(customItemDefinition) @@ -75,7 +74,7 @@ public class PotionItem extends Item { ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (potion != null) { StringTag potionTag = new StringTag("Potion", potion.getJavaIdentifier()); - itemStack.getNbt().put(potionTag); + //itemStack.getNbt().put(potionTag); } return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index 30b50b436..f495222f3 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -26,10 +26,6 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.session.GeyserSession; @@ -44,21 +40,22 @@ public class ShieldItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { - if (blockEntityTag.get("Patterns") instanceof ListTag patterns) { - for (Tag pattern : patterns) { - if (((CompoundTag) pattern).get("Color") instanceof IntTag color) { - color.setValue(15 - color.getValue()); - } - } - // Bedrock looks for patterns at the root - tag.put(patterns); - } - if (blockEntityTag.get("Base") instanceof IntTag base) { - base.setValue(15 - base.getValue()); - tag.put(base); - } - } + // TODO figure out patterns first. +// if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { +// if (blockEntityTag.get("Patterns") instanceof ListTag patterns) { +// for (Tag pattern : patterns) { +// if (((CompoundTag) pattern).get("Color") instanceof IntTag color) { +// color.setValue(15 - color.getValue()); +// } +// } +// // Bedrock looks for patterns at the root +// tag.put(patterns); +// } +// if (blockEntityTag.get("Base") instanceof IntTag base) { +// base.setValue(15 - base.getValue()); +// tag.put(base); +// } +// } } @Override 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 e4bad2f32..9074c2ec8 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 @@ -25,15 +25,14 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.TippedArrowPotion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; -import org.geysermc.geyser.translator.item.ItemTranslator; public class TippedArrowItem extends ArrowItem { public TippedArrowItem(String javaIdentifier, Builder builder) { @@ -42,16 +41,16 @@ public class TippedArrowItem extends ArrowItem { @Override public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { - Tag potionTag = itemStack.getNbt().get("Potion"); - if (potionTag instanceof StringTag) { - TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByJavaIdentifier(((StringTag) potionTag).getValue()); + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + TippedArrowPotion tippedArrowPotion = TippedArrowPotion.of(potionContents.getPotionId()); if (tippedArrowPotion != null) { return ItemData.builder() .definition(mapping.getBedrockDefinition()) .damage(tippedArrowPotion.getBedrockId()) .count(count); } - GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionTag.getValue()); + GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionContents.getPotionId()); } return super.translateToBedrock(count, components, mapping, mappings); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index c0407e697..f70e6b295 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -27,7 +27,8 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.*; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; @@ -39,7 +40,6 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; -import java.util.ArrayList; import java.util.List; public class TropicalFishBucketItem extends Item { @@ -57,24 +57,24 @@ public class TropicalFishBucketItem extends Item { builder.putByte("AppendCustomName", (byte) 1); builder.putString("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale())); // Add Java's client side lore tag - components.get(DataComponentType) - if (bucketVariantTag instanceof IntTag) { - CompoundTag displayTag = tag.get("display"); - if (displayTag == null) { - displayTag = new CompoundTag("display"); - tag.put(displayTag); + // Do you know how frequently Java NBT used to be before 1.20.5? It was a lot. And now it's just this lowly check. + CompoundTag entityTag = components.get(DataComponentType.BUCKET_ENTITY_DATA); + if (entityTag != null && !entityTag.isEmpty()) { + //TODO test + Tag bucketVariant = entityTag.get("BucketVariantTag"); + if (bucketVariant == null || !(bucketVariant.getValue() instanceof Number)) { + return; } + List lore = builder.getOrCreateLore(); - List lore = new ArrayList<>(); - - int varNumber = ((IntTag) bucketVariantTag).getValue(); + int varNumber = ((Number) bucketVariant.getValue()).intValue(); int predefinedVariantId = TropicalFishEntity.getPredefinedId(varNumber); if (predefinedVariantId != -1) { Component tooltip = Component.translatable("entity.minecraft.tropical_fish.predefined." + predefinedVariantId, LORE_STYLE); - lore.add(0, new StringTag("", MessageTranslator.convertMessage(tooltip, session.locale()))); + lore.add(0, MessageTranslator.convertMessage(tooltip, session.locale())); } else { Component typeTooltip = Component.translatable("entity.minecraft.tropical_fish.type." + TropicalFishEntity.getVariantName(varNumber), LORE_STYLE); - lore.add(0, new StringTag("", MessageTranslator.convertMessage(typeTooltip, session.locale()))); + lore.add(0, MessageTranslator.convertMessage(typeTooltip, session.locale())); byte baseColor = TropicalFishEntity.getBaseColor(varNumber); byte patternColor = TropicalFishEntity.getPatternColor(varNumber); @@ -83,14 +83,8 @@ public class TropicalFishBucketItem extends Item { colorTooltip = colorTooltip.append(Component.text(", ", LORE_STYLE)) .append(Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(patternColor), LORE_STYLE)); } - lore.add(1, new StringTag("", MessageTranslator.convertMessage(colorTooltip, session.locale()))); + lore.add(1, MessageTranslator.convertMessage(colorTooltip, session.locale())); } - - ListTag loreTag = displayTag.get("Lore"); - if (loreTag != null) { - lore.addAll(loreTag.getValue()); - } - displayTag.put(new ListTag("Lore", lore)); } } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java index 4bd2244ab..eced0e50b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java @@ -25,13 +25,14 @@ package org.geysermc.geyser.session.cache; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.LodestoneTracker; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.GeyserItemStack; import java.util.Map; @@ -54,22 +55,27 @@ public final class LodestoneCache { private int id = 1; public void cacheInventoryItem(GeyserItemStack itemStack) { - CompoundTag tag = itemStack.getNbt(); - if (tag == null) { + DataComponents components = itemStack.getComponents(); + if (components == null) { // invalid return; } - CompoundTag lodestonePos = tag.get("LodestonePos"); - if (lodestonePos == null) { - // invalid + LodestoneTracker tracker = components.get(DataComponentType.LODESTONE_TRACKER); + if (tracker == null) { return; } - // Get all info needed for tracking - int x = ((IntTag) lodestonePos.get("X")).getValue(); - int y = ((IntTag) lodestonePos.get("Y")).getValue(); - int z = ((IntTag) lodestonePos.get("Z")).getValue(); - String dim = ((StringTag) tag.get("LodestoneDimension")).getValue(); + GlobalPos position = tracker.getPos(); + + if (position == null) { + GeyserImpl.getInstance().getLogger().error("Position is null. Find out why."); + Thread.dumpStack(); + return; + } + int x = position.getX(); + int y = position.getY(); + int z = position.getZ(); + String dim = position.getDimension(); for (LodestonePos pos : this.activeLodestones.values()) { if (pos.equals(x, y, z, dim)) { @@ -90,17 +96,17 @@ public final class LodestoneCache { } public int store(LodestoneTracker tracker) { - CompoundTag lodestonePos = tag.get("LodestonePos"); - if (lodestonePos == null) { - // invalid - return 0; - } + GlobalPos position = tracker.getPos(); - // Get all info needed for tracking - int x = ((IntTag) lodestonePos.get("X")).getValue(); - int y = ((IntTag) lodestonePos.get("Y")).getValue(); - int z = ((IntTag) lodestonePos.get("Z")).getValue(); - String dim = ((StringTag) tag.get("LodestoneDimension")).getValue(); + if (position == null) { + GeyserImpl.getInstance().getLogger().error("Position is null. Find out why."); + Thread.dumpStack(); + return -1; + } + int x = position.getX(); + int y = position.getY(); + int z = position.getZ(); + String dim = position.getDimension(); for (LodestonePos pos : this.activeLodestones.values()) { if (pos.equals(x, y, z, dim)) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 0e43ba660..6c7a11ff2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; @@ -51,6 +52,7 @@ import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.session.GeyserSession; import java.util.Collections; +import java.util.HashMap; import java.util.List; public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { @@ -154,9 +156,10 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { GeyserItemStack inputCopy = inventory.getItem(0).copy(1); inputCopy.setNetId(session.getNextItemNetId()); // Add the pattern manually, for better item synchronization - if (inputCopy.getNbt() == null) { - inputCopy.setNbt(new CompoundTag("")); + if (inputCopy.getComponents() == null) { + inputCopy.setComponents(new DataComponents(new HashMap<>())); } + //TODO CompoundTag blockEntityTag = inputCopy.getNbt().get("BlockEntityTag"); CompoundTag javaBannerPattern = BannerItem.getJavaBannerPattern(pattern); diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java index c1f7184f2..52d5b7e31 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java @@ -142,13 +142,12 @@ public final class BedrockItemBuilder { } /** - * Creates item NBT with count, name, and damage set. + * Creates item NBT to nest within NBT with name, count, and damage set. */ public static NbtMapBuilder createItemNbt(ItemMapping mapping, int count, int damage) { NbtMapBuilder builder = NbtMap.builder(); - builder.putByte("Count", (byte) count); builder.putString("Name", mapping.getBedrockIdentifier()); - + builder.putByte("Count", (byte) count); builder.putShort("Damage", (short) damage); return builder; } 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 65ceb3497..c96542fc1 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 @@ -30,52 +30,42 @@ import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOperation; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.item.component.AdventureModePredicate; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.ItemAttributeModifiers; -import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.DoubleTag; -import com.github.steveice10.opennbt.tag.builtin.FloatTag; -import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; -import com.github.steveice10.opennbt.tag.builtin.LongTag; -import com.github.steveice10.opennbt.tag.builtin.ShortTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; -import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.CustomSkull; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.skin.SkinManager; -import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.InventoryUtils; import java.text.DecimalFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public final class ItemTranslator { @@ -357,7 +347,7 @@ public final class ItemTranslator { return ItemDefinition.AIR; } - ItemMapping mapping = itemStack.asItem().toBedrockDefinition(itemStack.getNbt(), session.getItemMappings()); + ItemMapping mapping = itemStack.asItem().toBedrockDefinition(itemStack.getComponents(), session.getItemMappings()); ItemDefinition itemDefinition = mapping.getBedrockDefinition(); CustomBlockData customBlockData = BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.getOrDefault( @@ -563,20 +553,21 @@ public final class ItemTranslator { if (components == null) { return null; } + //TODO GameProfile profile = components.get(DataComponentType.PROFILE); if (profile != null) { - if (!(nbt.get("SkullOwner") instanceof CompoundTag skullOwner)) { - // It's a username give up d: - return null; - } - SkinManager.GameProfileData data = SkinManager.GameProfileData.from(skullOwner); - if (data == null) { - session.getGeyser().getLogger().debug("Not sure how to handle skull head item display. " + nbt); - return null; - } - - String skinHash = data.skinUrl().substring(data.skinUrl().lastIndexOf('/') + 1); - return BlockRegistries.CUSTOM_SKULLS.get(skinHash); +// if (!(nbt.get("SkullOwner") instanceof CompoundTag skullOwner)) { +// // It's a username give up d: +// return null; +// } +// SkinManager.GameProfileData data = SkinManager.GameProfileData.from(skullOwner); +// if (data == null) { +// session.getGeyser().getLogger().debug("Not sure how to handle skull head item display. " + nbt); +// return null; +// } +// +// String skinHash = data.skinUrl().substring(data.skinUrl().lastIndexOf('/') + 1); +// return BlockRegistries.CUSTOM_SKULLS.get(skinHash); } return null; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java index ec1d62d16..ba802e42e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.translator.protocol.bedrock; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; +import com.github.steveice10.mc.protocol.data.game.item.component.WritableBookContent; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundEditBookPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; @@ -39,10 +41,7 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; +import java.util.*; @Translator(packet = BookEditPacket.class) public class BedrockBookEditTranslator extends PacketTranslator { @@ -56,8 +55,9 @@ public class BedrockBookEditTranslator extends PacketTranslator GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(); if (itemStack != null) { - CompoundTag tag = itemStack.getNbt() != null ? itemStack.getNbt() : new CompoundTag(""); - ItemStack bookItem = new ItemStack(itemStack.getJavaId(), itemStack.getAmount(), tag); + DataComponents components = itemStack.getComponents() != null ? itemStack.getComponents() : new DataComponents(new HashMap<>()); + ItemStack bookItem = new ItemStack(itemStack.getJavaId(), itemStack.getAmount(), components); + WritableBookContent List pages = tag.contains("pages") ? new LinkedList<>(((ListTag) tag.get("pages")).getValue()) : new LinkedList<>(); int page = packet.getPageNumber(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index c178f27d4..6178a51e8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -31,10 +31,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.Client import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; -import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.skin.FakeHeadProvider; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -62,14 +59,15 @@ public class JavaSetEquipmentTranslator extends PacketTranslator { ItemStack javaItem = equipment.getItem(); - if (livingEntity instanceof PlayerEntity - && javaItem != null - && javaItem.getId() == Items.PLAYER_HEAD.javaId() - && javaItem.getNbt() != null) { - FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, javaItem.getNbt().get("SkullOwner")); - } else { - FakeHeadProvider.restoreOriginalSkin(session, livingEntity); - } + // TODO +// if (livingEntity instanceof PlayerEntity +// && javaItem != null +// && javaItem.getId() == Items.PLAYER_HEAD.javaId() +// && javaItem.getNbt() != null) { +// FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, javaItem.getNbt().get("SkullOwner")); +// } else { +// FakeHeadProvider.restoreOriginalSkin(session, livingEntity); +// } livingEntity.setHelmet(item); armorUpdated = true; 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 7f3a02df6..08c2b6cdb 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -25,13 +25,12 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; @@ -43,11 +42,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerHotbarPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.Container; -import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.LecternContainer; -import org.geysermc.geyser.inventory.PlayerInventory; +import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; @@ -256,7 +251,7 @@ public class InventoryUtils { continue; } // If this is the item we're looking for - if (geyserItem.getJavaId() == itemStack.getId() && Objects.equals(geyserItem.getNbt(), itemStack.getNbt())) { + if (geyserItem.getJavaId() == itemStack.getId() && Objects.equals(geyserItem.getComponents(), itemStack.getDataComponents())) { //TODO verify setHotbarItem(session, i); // Don't check inventory if item was in hotbar return; @@ -270,7 +265,7 @@ public class InventoryUtils { continue; } // If this is the item we're looking for - if (geyserItem.getJavaId() == itemStack.getId() && Objects.equals(geyserItem.getNbt(), itemStack.getNbt())) { + if (geyserItem.getJavaId() == itemStack.getId() && Objects.equals(geyserItem.getComponents(), itemStack.getDataComponents())) { //TODO verify ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item session.sendDownstreamGamePacket(packetToSend); return; From ab8832b771deffb569a5558fa171faf587bd370e Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 21 Apr 2024 01:09:23 -0400 Subject: [PATCH 049/897] Compiles --- .../BedrockBlockPickRequestTranslator.java | 4 +- .../bedrock/BedrockBookEditTranslator.java | 52 +++++++++---------- .../player/BedrockActionTranslator.java | 2 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 59317fd7c..3781ef3c0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -69,7 +69,7 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator session.ensureInEventLoop(() -> { if (tag == null) { @@ -94,7 +94,7 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator if (itemStack != null) { DataComponents components = itemStack.getComponents() != null ? itemStack.getComponents() : new DataComponents(new HashMap<>()); ItemStack bookItem = new ItemStack(itemStack.getJavaId(), itemStack.getAmount(), components); - WritableBookContent - List pages = tag.contains("pages") ? new LinkedList<>(((ListTag) tag.get("pages")).getValue()) : new LinkedList<>(); + List pages = new LinkedList<>(); + + WritableBookContent writableBookContent = components.get(DataComponentType.WRITABLE_BOOK_CONTENT); + if (writableBookContent != null) { + for (Filterable page : writableBookContent.getPages()) { + pages.add(page.getRaw()); + } + } int page = packet.getPageNumber(); if (page < 0 || WrittenBookItem.MAXIMUM_PAGE_COUNT <= page) { @@ -69,21 +73,21 @@ public class BedrockBookEditTranslator extends PacketTranslator case ADD_PAGE: { // Add empty pages in between for (int i = pages.size(); i < page; i++) { - pages.add(i, new StringTag("", "")); + pages.add(i, ""); } - pages.add(page, new StringTag("", MessageTranslator.convertToPlainText(packet.getText()))); + pages.add(page, MessageTranslator.convertToPlainText(packet.getText())); break; } // Called whenever a page is modified case REPLACE_PAGE: { if (page < pages.size()) { - pages.set(page, new StringTag("", MessageTranslator.convertToPlainText(packet.getText()))); + pages.set(page, MessageTranslator.convertToPlainText(packet.getText())); } else { // Add empty pages in between for (int i = pages.size(); i < page; i++) { - pages.add(i, new StringTag("", "")); + pages.add(i, ""); } - pages.add(page, new StringTag("", MessageTranslator.convertToPlainText(packet.getText()))); + pages.add(page, MessageTranslator.convertToPlainText(packet.getText())); } break; } @@ -100,33 +104,29 @@ public class BedrockBookEditTranslator extends PacketTranslator } break; } - case SIGN_BOOK: { - tag.put(new StringTag("author", MessageTranslator.convertToPlainText(packet.getAuthor()))); - tag.put(new StringTag("title", MessageTranslator.convertToPlainText(packet.getTitle()))); - break; - } default: return; } // Remove empty pages at the end - while (pages.size() > 0) { - StringTag currentPage = (StringTag) pages.get(pages.size() - 1); - if (currentPage.getValue() == null || currentPage.getValue().isEmpty()) { + while (!pages.isEmpty()) { + String currentPage = pages.get(pages.size() - 1); + if (currentPage.isEmpty()) { pages.remove(pages.size() - 1); } else { break; } } - tag.put(new ListTag("pages", pages)); + + List> filterablePages = new ArrayList<>(pages.size()); + for (String raw : pages) { + filterablePages.add(new Filterable<>(raw, null)); + } + components.put(DataComponentType.WRITABLE_BOOK_CONTENT, new WritableBookContent(filterablePages)); + // Update local copy session.getPlayerInventory().setItem(36 + session.getPlayerInventory().getHeldItemSlot(), GeyserItemStack.from(bookItem), session); session.getInventoryTranslator().updateInventory(session, session.getPlayerInventory()); - List networkPages = new ArrayList<>(); - for (Tag pageTag : pages) { - networkPages.add(((StringTag) pageTag).getValue()); - } - String title; if (packet.getAction() == BookEditPacket.Action.SIGN_BOOK) { // Add title to packet so the server knows we're signing @@ -139,7 +139,7 @@ public class BedrockBookEditTranslator extends PacketTranslator title = null; } - session.getBookEditCache().setPacket(new ServerboundEditBookPacket(session.getPlayerInventory().getHeldItemSlot(), networkPages, title)); + session.getBookEditCache().setPacket(new ServerboundEditBookPacket(session.getPlayerInventory().getHeldItemSlot(), pages, title)); // There won't be any more book updates after this, so we can try sending the edit packet immediately if (packet.getAction() == BookEditPacket.Action.SIGN_BOOK) { session.getBookEditCache().checkForSend(); 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 index f5122b256..2fd9ce405 100644 --- 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 @@ -168,7 +168,7 @@ public class BedrockActionTranslator extends PacketTranslator Date: Sun, 21 Apr 2024 16:20:22 -0400 Subject: [PATCH 050/897] Tiny fixes --- .../geyser/item/type/DecoratedPotItem.java | 21 ++++++++---- .../geyser/item/type/WrittenBookItem.java | 34 ++----------------- .../inventory/InventoryTranslator.java | 15 ++++---- 3 files changed, 24 insertions(+), 46 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index 8d9be4db2..ea194522b 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -28,9 +28,14 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import java.util.ArrayList; +import java.util.List; + public class DecoratedPotItem extends BlockItem { public DecoratedPotItem(String javaIdentifier, Builder builder) { @@ -41,12 +46,14 @@ public class DecoratedPotItem extends BlockItem { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - components.get(DataComponentType.POT_DECORATIONS); // TODO what does this look like on Bedrock? -// if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { -// if (blockEntityTag.remove("sherds") instanceof ListTag sherds) { -// // bedrock wants it on the root level -// tag.put(sherds); -// } -// } + List decorations = components.get(DataComponentType.POT_DECORATIONS); // TODO maybe unbox in MCProtocolLib + if (decorations != null) { + List sherds = new ArrayList<>(decorations.size()); + for (Integer decoration : decorations) { + ItemMapping mapping = session.getItemMappings().getMapping(decoration); + sherds.add(mapping.getBedrockIdentifier()); + } + builder.putList("sherds", NbtType.STRING, sherds); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index 6ca52aca4..a6b5e73d4 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -29,10 +29,6 @@ import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentT import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.Filterable; import com.github.steveice10.mc.protocol.data.game.item.component.WrittenBookContent; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; @@ -47,7 +43,6 @@ import java.util.List; public class WrittenBookItem extends Item { public static final int MAXIMUM_PAGE_EDIT_LENGTH = 1024; - public static final int MAXIMUM_PAGE_LENGTH = 32768; public static final int MAXIMUM_PAGE_COUNT = 100; // Java edition limit. Bedrock edition has a limit of 50 pages. public static final int MAXIMUM_TITLE_LENGTH = 16; @@ -73,33 +68,8 @@ public class WrittenBookItem extends Item { builder.putList("pages", NbtType.COMPOUND, bedrockPages); builder.putString("title", bookContent.getTitle().getRaw()) - .putString("author", bookContent.getAuthor()); + .putString("author", bookContent.getAuthor()) + .putInt("generation", bookContent.getGeneration()); // TODO isResolved } - - private boolean isValidWrittenBook(CompoundTag tag) { - if (!(tag.get("title") instanceof StringTag title)) { - return false; - } - if (title.getValue().length() > (MAXIMUM_TITLE_LENGTH * 2)) { - // Java rejects books with titles more than 2x the maximum length allowed in the input box - return false; - } - - if (!(tag.get("author") instanceof StringTag)) { - return false; - } - - if (!(tag.get("pages") instanceof ListTag pages)) { - return false; - } - for (Tag pageTag : pages) { - if (pageTag instanceof StringTag page) { - if (page.getValue().length() > MAXIMUM_PAGE_LENGTH) { - return false; - } - } - } - return true; - } } 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 e6e0c6340..2d7a1ae5a 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,11 +25,11 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import org.checkerframework.checker.nullness.qual.Nullable; @@ -909,10 +909,11 @@ public abstract class InventoryTranslator { // As of 1.16.210: Bedrock needs confirmation on what the current item durability is. // If 0 is sent, then Bedrock thinks the item is not damaged int durability = 0; - if (itemStack.getNbt() != null) { - Tag damage = itemStack.getNbt().get("Damage"); - if (damage instanceof IntTag) { - durability = ItemUtils.getCorrectBedrockDurability(itemStack.asItem(), ((IntTag) damage).getValue()); + DataComponents components = itemStack.getComponents(); + if (components != null) { + Integer damage = components.get(DataComponentType.DAMAGE); + if (damage != null) { + durability = ItemUtils.getCorrectBedrockDurability(itemStack.asItem(), damage); } } From 61907b18512276bf2a3ba959caff6cd74a9d17e4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 21 Apr 2024 16:36:54 -0400 Subject: [PATCH 051/897] Little more work --- .../geyser/inventory/AnvilContainer.java | 3 +- .../geyser/inventory/GeyserItemStack.java | 25 +++++++++++++++++ .../updater/AnvilInventoryUpdater.java | 28 +++++++------------ .../translator/text/MessageTranslator.java | 10 +++++++ .../geysermc/geyser/util/InventoryUtils.java | 2 +- .../org/geysermc/geyser/util/ItemUtils.java | 17 ++++++----- 6 files changed, 56 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 9e0b83768..3c7b7e4bd 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -72,7 +73,7 @@ public class AnvilContainer extends Container { String correctRename; newName = rename; - String originalName = ItemUtils.getCustomName(getInput().getNbt()); + Component originalName = ItemUtils.getCustomName(getInput().getComponents()); String plainOriginalName = MessageTranslator.convertToPlainTextLenient(originalName, session.locale()); String plainNewName = MessageTranslator.convertToPlainText(rename); 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 7e621d3aa..a1ecc6f58 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.inventory; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import lombok.AccessLevel; @@ -87,6 +88,30 @@ public class GeyserItemStack { return isEmpty() ? null : components; } + public boolean getComponent(DataComponentType type, boolean def) { + if (components == null) { + return def; + } + + Boolean result = components.get(type); + if (result != null) { + return result; + } + return def; + } + + public int getComponent(DataComponentType type, int def) { + if (components == null) { + return def; + } + + Integer result = components.get(type); + if (result != null) { + return result; + } + return def; + } + public int getNetId() { return isEmpty() ? 0 : netId; } 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 96ef12861..9bf001f42 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.inventory.updater; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; @@ -34,6 +35,7 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import net.kyori.adventure.text.Component; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; @@ -118,7 +120,8 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // Changing the item in the input slot resets the name field on Bedrock, but // does not result in a FilterTextPacket - String originalName = MessageTranslator.convertToPlainTextLenient(ItemUtils.getCustomName(input.getNbt()), session.locale()); + // TODO test + String originalName = MessageTranslator.convertToPlainText(ItemUtils.getCustomName(input.getComponents())); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName); session.sendDownstreamGamePacket(renameItemPacket); @@ -424,38 +427,27 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } // This should really check the name field in all cases, but that requires the localized name // of the item which can change depending on NBT and Minecraft Edition - String originalName = ItemUtils.getCustomName(anvilContainer.getInput().getNbt()); + Component originalName = ItemUtils.getCustomName(anvilContainer.getInput().getComponents()); if (bedrock && originalName != null && anvilContainer.getNewName() != null) { // Check text and formatting - String legacyOriginalName = MessageTranslator.convertMessageLenient(originalName, session.locale()); + String legacyOriginalName = MessageTranslator.convertMessage(originalName, session.locale()); return !legacyOriginalName.equals(anvilContainer.getNewName()); } - return !Objects.equals(originalName, ItemUtils.getCustomName(anvilContainer.getResult().getNbt())); - } - - @SuppressWarnings("SameParameterValue") - private int getTagIntValueOr(GeyserItemStack itemStack, String tagName, int defaultValue) { - if (itemStack.getNbt() != null) { - Tag tag = itemStack.getNbt().get(tagName); - if (tag != null && tag.getValue() instanceof Number value) { - return value.intValue(); - } - } - return defaultValue; + return !Objects.equals(originalName, ItemUtils.getCustomName(anvilContainer.getResult().getComponents())); } private int getRepairCost(GeyserItemStack itemStack) { - return getTagIntValueOr(itemStack, "RepairCost", 0); + return itemStack.getComponent(DataComponentType.REPAIR_COST, 0); } private boolean hasDurability(GeyserItemStack itemStack) { if (itemStack.asItem().maxDamage() > 0) { - return getTagIntValueOr(itemStack, "Unbreakable", 0) == 0; + return itemStack.getComponent(DataComponentType.UNBREAKABLE, false); } return false; } private int getDamage(GeyserItemStack itemStack) { - return getTagIntValueOr(itemStack, "Damage", 0); + return itemStack.getComponent(DataComponentType.DAMAGE, 0); } } 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 d93123cff..ed6b9404d 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 @@ -245,6 +245,16 @@ public class MessageTranslator { return GSON_SERIALIZER.serialize(component); } + /** + * Convert legacy format message to plain text + * + * @param message Message to convert + * @return The plain text of the message + */ + public static String convertToPlainText(Component message) { + return PlainTextComponentSerializer.plainText().serialize(message); + } + /** * Convert legacy format message to plain text * 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 08c2b6cdb..2b619714e 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -180,7 +180,7 @@ public class InventoryUtils { public static boolean canStack(GeyserItemStack item1, GeyserItemStack item2) { if (item1.isEmpty() || item2.isEmpty()) return false; - return item1.getJavaId() == item2.getJavaId() && Objects.equals(item1.getNbt(), item2.getNbt()); + return item1.getJavaId() == item2.getJavaId() && Objects.equals(item1.getComponents(), item2.getComponents()); } /** diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index a116c5cf2..2138103d4 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -25,10 +25,13 @@ package org.geysermc.geyser.util; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.FishingRodItem; @@ -70,17 +73,13 @@ public class ItemUtils { } /** - * @param itemTag the NBT tag of the item + * @param components the data components of the item * @return the custom name of the item */ - public static @Nullable String getCustomName(CompoundTag itemTag) { - if (itemTag != null) { - if (itemTag.get("display") instanceof CompoundTag displayTag) { - if (displayTag.get("Name") instanceof StringTag nameTag) { - return nameTag.getValue(); - } - } + public static @Nullable Component getCustomName(DataComponents components) { + if (components == null) { + return null; } - return null; + return components.get(DataComponentType.CUSTOM_NAME); } } From 57ce5706ee6fc7f2f674a95beef293cd84dd278a Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Sun, 21 Apr 2024 21:49:56 +0100 Subject: [PATCH 052/897] Update mappings submodule --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 4f89411d5..cb2cbe9f2 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 4f89411d5bfb4e48699f635876d9c556e5c7e505 +Subproject commit cb2cbe9f262d14640f7c46885f1c8c9d23f2beaa From b73f23de0f190ae2b6942af083b9767059dc78dd Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 21 Apr 2024 22:54:54 +0200 Subject: [PATCH 053/897] remove global palette bits, fix nullable block entity tags --- .../java/org/geysermc/geyser/session/GeyserSession.java | 5 ----- .../geysermc/geyser/translator/level/BiomeTranslator.java | 4 ---- .../java/level/JavaLevelChunkWithLightTranslator.java | 8 ++++---- .../src/main/java/org/geysermc/geyser/util/MathUtils.java | 7 ------- 4 files changed, 4 insertions(+), 20 deletions(-) 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 8e1ed2e51..994879f82 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -263,11 +263,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private ItemMappings itemMappings; - /** - * Required to decode biomes correctly. - */ - @Setter - private int biomeGlobalPalette; /** * Stores the map between Java and Bedrock biome network IDs. */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index d4288c5a7..f05ed5ed1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -31,7 +31,6 @@ import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.GlobalPalette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.Palette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.SingletonPalette; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import it.unimi.dsi.fastutil.ints.*; import org.geysermc.geyser.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.bitarray.BitArray; @@ -39,7 +38,6 @@ import org.geysermc.geyser.level.chunk.bitarray.BitArrayVersion; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.MathUtils; import java.util.List; @@ -49,8 +47,6 @@ public class BiomeTranslator { public static void loadServerBiomes(GeyserSession session, List entries) { Int2IntMap biomeTranslations = new Int2IntOpenHashMap(); - session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(entries.size())); - int greatestBiomeId = 0; for (int i = 0; i < entries.size(); i++) { RegistryEntry entry = entries.get(i); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index a98ead719..e34c0d96d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -98,7 +98,6 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator Date: Sun, 21 Apr 2024 22:22:15 +0100 Subject: [PATCH 054/897] Bump mcpl to fix item deserialization --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 08c04a84a..5e2720942 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "897eb241b6" # Revert from jitpack after release +mcprotocollib = "2a7176f7ee" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From c5e02d28e6adedeffcad6c2b2d4dddc4c8602bee Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 21 Apr 2024 23:48:30 +0200 Subject: [PATCH 055/897] ensure geyser builds --- .../java/org/geysermc/geyser/inventory/AnvilContainer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 3c7b7e4bd..1c5826cdb 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import lombok.Getter; import lombok.Setter; -import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -73,7 +72,8 @@ public class AnvilContainer extends Container { String correctRename; newName = rename; - Component originalName = ItemUtils.getCustomName(getInput().getComponents()); + // TODO 1.20.5 fix properly - this name is apparently nullable?? + String originalName = MessageTranslator.convertMessage(ItemUtils.getCustomName(getInput().getComponents())); String plainOriginalName = MessageTranslator.convertToPlainTextLenient(originalName, session.locale()); String plainNewName = MessageTranslator.convertToPlainText(rename); From 8381a148fc3557534cd250ba9b0eb3871a3e49f5 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 21 Apr 2024 19:23:05 -0400 Subject: [PATCH 056/897] Fix book signing --- .../translator/protocol/bedrock/BedrockBookEditTranslator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java index 8e045a51c..4350f6a83 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java @@ -104,6 +104,9 @@ public class BedrockBookEditTranslator extends PacketTranslator } break; } + case SIGN_BOOK: { + break; + } default: return; } From dac5f69d47aa74f46c2ca0bd0a3d505879f8f20e Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Mon, 22 Apr 2024 20:56:57 +0100 Subject: [PATCH 057/897] Bump mcpl --- .../java/org/geysermc/geyser/item/type/ArmorItem.java | 11 +++++------ .../org/geysermc/geyser/item/type/GoatHornItem.java | 3 ++- gradle/libs.versions.toml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index ba7f05205..33ff6a7d8 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -52,16 +52,15 @@ public class ArmorItem extends Item { ArmorTrim trim = components.get(DataComponentType.TRIM); if (trim != null) { - // TODO material IDs - String material = trim.getMaterial().getAssetName(); - String pattern = trim.getPattern().getAssetId(); - // discard custom trim patterns/materials to prevent visual glitches on bedrock - if (!material.startsWith("minecraft:") - || !pattern.startsWith("minecraft:")) { + if (trim.getMaterial().isCustom() || trim.getPattern().isCustom()) { return; } + // TODO material IDs + String material = trim.getMaterial().getCustomValue().getAssetName(); + String pattern = trim.getPattern().getCustomValue().getAssetId(); + NbtMapBuilder trimBuilder = NbtMap.builder(); // bedrock has an uppercase first letter key, and the value is not namespaced trimBuilder.put("Material", stripNamespace(material)); 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 48e75dc79..35b7a76fc 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.type; +import com.github.steveice10.mc.protocol.data.game.Holder; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; @@ -60,7 +61,7 @@ public class GoatHornItem extends Item { if (components == null) { return builder; } - Instrument instrument = components.get(DataComponentType.INSTRUMENT); + Holder instrument = components.get(DataComponentType.INSTRUMENT); // TODO registry if (instrument != null) { // Drop the Minecraft namespace if applicable diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5e2720942..4189f8857 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "2a7176f7ee" # Revert from jitpack after release +mcprotocollib = "8bc6990525" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From c34f0f2c3b1b2f0ca024dd53899746f2cc3fbeab Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:36:03 -0400 Subject: [PATCH 058/897] Update for latest MCProtocolLib --- .../main/java/org/geysermc/geyser/item/type/ArmorItem.java | 6 +++--- gradle/libs.versions.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index 33ff6a7d8..ab936bd08 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -53,13 +53,13 @@ public class ArmorItem extends Item { ArmorTrim trim = components.get(DataComponentType.TRIM); if (trim != null) { // discard custom trim patterns/materials to prevent visual glitches on bedrock - if (trim.getMaterial().isCustom() || trim.getPattern().isCustom()) { + if (trim.material().isCustom() || trim.pattern().isCustom()) { return; } // TODO material IDs - String material = trim.getMaterial().getCustomValue().getAssetName(); - String pattern = trim.getPattern().getCustomValue().getAssetId(); + String material = trim.material().custom().assetName(); + String pattern = trim.pattern().custom().assetId(); NbtMapBuilder trimBuilder = NbtMap.builder(); // bedrock has an uppercase first letter key, and the value is not namespaced diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4189f8857..b7e692ab7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "8bc6990525" # Revert from jitpack after release +mcprotocollib = "4ee05b62" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 6a5efa3c9dc1aa7d3d29a5dd17378195104fb1d6 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 22 Apr 2024 23:36:48 +0200 Subject: [PATCH 059/897] Start on 1.20.5 mod platform support - NeoForge (temporarily) excluded Also fixes lecterns, and block break speed calculations --- .github/workflows/build-remote.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/preview.yml | 2 +- bootstrap/mod/build.gradle.kts | 3 +- .../fabric/src/main/resources/fabric.mod.json | 5 +- .../platform/mod/ModPingPassthrough.java | 5 +- .../mod/command/ModCommandSender.java | 3 +- .../mod/world/GeyserModWorldManager.java | 153 +++++------------- .../geyser.modded-conventions.gradle.kts | 10 +- build.gradle.kts | 2 +- .../inventory/LecternInventoryTranslator.java | 22 ++- .../level/JavaBlockDestructionTranslator.java | 3 +- .../org/geysermc/geyser/util/BlockUtils.java | 45 +++--- .../org/geysermc/geyser/util/ItemUtils.java | 28 ++-- settings.gradle.kts | 4 +- 15 files changed, 110 insertions(+), 179 deletions(-) diff --git a/.github/workflows/build-remote.yml b/.github/workflows/build-remote.yml index d49920785..09326d429 100644 --- a/.github/workflows/build-remote.yml +++ b/.github/workflows/build-remote.yml @@ -64,7 +64,7 @@ jobs: with: name: Geyser NeoForge path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar - if-no-files-found: error + #if-no-files-found: error // TODO 1.20.5 until neoforge updates - name: Archive artifacts (Geyser Standalone) uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 if: success() diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 284fa265a..cfb509f30 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,7 +68,7 @@ jobs: with: name: Geyser NeoForge path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar - if-no-files-found: error + #if-no-files-found: error // TODO 1.20.5 - currently no neoforge artifacts - name: Archive artifacts (Geyser Standalone) uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 if: success() diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 13712d5ef..a33c71a79 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -53,10 +53,10 @@ jobs: with: appID: ${{ secrets.RELEASE_APP_ID }} appPrivateKey: ${{ secrets.RELEASE_APP_PK }} + # neoforge:Geyser-NeoForge.jar // TODO 1.20.5 files: | bungeecord:Geyser-BungeeCord.jar fabric:Geyser-Fabric.jar - neoforge:Geyser-NeoForge.jar spigot:Geyser-Spigot.jar standalone:Geyser-Standalone.jar velocity:Geyser-Velocity.jar diff --git a/bootstrap/mod/build.gradle.kts b/bootstrap/mod/build.gradle.kts index 7651a2df2..281fd45e7 100644 --- a/bootstrap/mod/build.gradle.kts +++ b/bootstrap/mod/build.gradle.kts @@ -1,5 +1,6 @@ architectury { - common("neoforge", "fabric") + common("fabric") + //common("neoforge", "fabric") // todo 1.20.5 } loom { diff --git a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json index 6bd217433..7fb6b302c 100644 --- a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json @@ -23,9 +23,8 @@ "geyser.mixins.json" ], "depends": { - "fabricloader": ">=0.15.2", + "fabricloader": ">=0.15.10", "fabric": "*", - "minecraft": ">=1.20.4", - "fabric-permissions-api-v0": "*" + "minecraft": ">=1.20.4" } } diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java index 12d690d83..a2bbfa379 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java @@ -29,6 +29,7 @@ import lombok.AllArgsConstructor; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.minecraft.core.RegistryAccess; import net.minecraft.network.Connection; import net.minecraft.network.PacketSendListener; import net.minecraft.network.protocol.Packet; @@ -69,7 +70,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough { StatusInterceptor connection = new StatusInterceptor(); ServerStatusPacketListener statusPacketListener = new ServerStatusPacketListenerImpl(status, connection); - statusPacketListener.handleStatusRequest(new ServerboundStatusRequestPacket()); + statusPacketListener.handleStatusRequest(ServerboundStatusRequestPacket.INSTANCE); // mods like MiniMOTD (that inject into the above method) have now processed the response status = Objects.requireNonNull(connection.status, "status response"); } catch (Exception e) { @@ -79,7 +80,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough { } } - String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description()); + String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description(), RegistryAccess.EMPTY); String legacyDescription = LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(jsonDescription, Component.empty())); return new GeyserPingInfo( diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java index 17154ffd8..5bebfae93 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.platform.mod.command; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.RegistryAccess; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import org.checkerframework.checker.nullness.qual.NonNull; @@ -63,7 +64,7 @@ public class ModCommandSender implements GeyserCommandSource { public void sendMessage(net.kyori.adventure.text.Component message) { if (source.getEntity() instanceof ServerPlayer player) { String decoded = GsonComponentSerializer.gson().serialize(message); - player.displayClientMessage(Objects.requireNonNull(Component.Serializer.fromJson(decoded)), false); + player.displayClientMessage(Objects.requireNonNull(Component.Serializer.fromJson(decoded, RegistryAccess.EMPTY)), false); return; } GeyserCommandSource.super.sendMessage(message); 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 04c538632..e9d612976 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 @@ -27,37 +27,28 @@ package org.geysermc.geyser.platform.mod.world; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; -import net.minecraft.nbt.ByteArrayTag; -import net.minecraft.nbt.ByteTag; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.DoubleTag; -import net.minecraft.nbt.EndTag; -import net.minecraft.nbt.FloatTag; -import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.IntTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.LongArrayTag; -import net.minecraft.nbt.LongTag; -import net.minecraft.nbt.ShortTag; -import net.minecraft.nbt.StringTag; -import net.minecraft.nbt.Tag; -import net.minecraft.nbt.TagVisitor; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.Filterable; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.WritableBookItem; -import net.minecraft.world.item.WrittenBookItem; +import net.minecraft.world.item.component.WritableBookContent; +import net.minecraft.world.item.component.WrittenBookContent; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BannerBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.LecternBlockEntity; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; 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.cloudburstmc.nbt.NbtMap; @@ -72,10 +63,12 @@ import org.geysermc.geyser.util.BlockEntityUtils; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.concurrent.CompletableFuture; public class GeyserModWorldManager extends GeyserWorldManager { + + private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.gson(); + private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection(); private final MinecraftServer server; public GeyserModWorldManager(MinecraftServer server) { @@ -180,7 +173,7 @@ public class GeyserModWorldManager extends GeyserWorldManager { } ItemStack book = lectern.getBook(); - int pageCount = WrittenBookItem.getPageCount(book); + int pageCount = getPageCount(book); boolean hasBookPages = pageCount > 0; NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1); lecternTag.putInt("page", lectern.getPage() / 2); @@ -189,11 +182,9 @@ public class GeyserModWorldManager extends GeyserWorldManager { .putShort("Damage", (short) 0) .putString("Name", "minecraft:writable_book"); List pages = new ArrayList<>(hasBookPages ? pageCount : 1); - if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) { - ListTag listTag = book.getTag().getList("pages", 8); - - for (int i = 0; i < listTag.size(); i++) { - String page = listTag.getString(i); + if (hasBookPages) { + List bookPages = getPages(book); + for (String page : bookPages) { NbtMapBuilder pageBuilder = NbtMap.builder() .putString("photoname", "") .putString("text", page); @@ -243,9 +234,8 @@ public class GeyserModWorldManager extends GeyserWorldManager { // Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and* // the banner might have a custom name, both of which a Java client knows and caches ItemStack itemStack = banner.getItem(); - var tag = OpenNbtTagVisitor.convert("", itemStack.getOrCreateTag()); - future.complete(tag); + future.complete(null); // todo 1.20.5 return; } future.complete(null); @@ -257,95 +247,32 @@ public class GeyserModWorldManager extends GeyserWorldManager { return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid()); } - // Future considerations: option to clone; would affect arrays - private static class OpenNbtTagVisitor implements TagVisitor { - private String currentKey; - private final com.github.steveice10.opennbt.tag.builtin.CompoundTag root; - private com.github.steveice10.opennbt.tag.builtin.Tag currentTag; - - OpenNbtTagVisitor(String key) { - root = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(key); + private static int getPageCount(ItemStack itemStack) { + WrittenBookContent writtenBookContent = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT); + if (writtenBookContent != null) { + return writtenBookContent.pages().size(); + } else { + WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT); + return writableBookContent != null ? writableBookContent.pages().size() : 0; } + } - @Override - public void visitString(StringTag stringTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.StringTag(currentKey, stringTag.getAsString()); - } - - @Override - public void visitByte(ByteTag byteTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.ByteTag(currentKey, byteTag.getAsByte()); - } - - @Override - public void visitShort(ShortTag shortTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.ShortTag(currentKey, shortTag.getAsShort()); - } - - @Override - public void visitInt(IntTag intTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.IntTag(currentKey, intTag.getAsInt()); - } - - @Override - public void visitLong(LongTag longTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.LongTag(currentKey, longTag.getAsLong()); - } - - @Override - public void visitFloat(FloatTag floatTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.FloatTag(currentKey, floatTag.getAsFloat()); - } - - @Override - public void visitDouble(DoubleTag doubleTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.DoubleTag(currentKey, doubleTag.getAsDouble()); - } - - @Override - public void visitByteArray(ByteArrayTag byteArrayTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.ByteArrayTag(currentKey, byteArrayTag.getAsByteArray()); - } - - @Override - public void visitIntArray(IntArrayTag intArrayTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.IntArrayTag(currentKey, intArrayTag.getAsIntArray()); - } - - @Override - public void visitLongArray(LongArrayTag longArrayTag) { - currentTag = new com.github.steveice10.opennbt.tag.builtin.LongArrayTag(currentKey, longArrayTag.getAsLongArray()); - } - - @Override - public void visitList(ListTag listTag) { - var newList = new com.github.steveice10.opennbt.tag.builtin.ListTag(currentKey); - for (Tag tag : listTag) { - currentKey = ""; - tag.accept(this); - newList.add(currentTag); + private static List getPages(ItemStack itemStack) { + WrittenBookContent writtenBookContent = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT); + if (writtenBookContent != null) { + return writtenBookContent.pages().stream() + .map(Filterable::raw) + .map((component) -> Component.Serializer.toJson(component, RegistryAccess.EMPTY)) + .map((json -> LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty())))) + .toList(); + } else { + WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT); + if (writableBookContent == null) { + return List.of(); } - currentTag = newList; - } - - @Override - public void visitCompound(@NonNull CompoundTag compoundTag) { - currentTag = convert(currentKey, compoundTag); - } - - private static com.github.steveice10.opennbt.tag.builtin.CompoundTag convert(String name, CompoundTag compoundTag) { - OpenNbtTagVisitor visitor = new OpenNbtTagVisitor(name); - for (String key : compoundTag.getAllKeys()) { - visitor.currentKey = key; - Tag tag = Objects.requireNonNull(compoundTag.get(key)); - tag.accept(visitor); - visitor.root.put(visitor.currentTag); - } - return visitor.root; - } - - @Override - public void visitEnd(@NonNull EndTag endTag) { + return writableBookContent.pages().stream() + .map(Filterable::raw) + .toList(); } } } diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index 3d41dbbb4..c83ea2911 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -46,6 +46,12 @@ loom { silentMojangMappingsLicense() } +indra { + javaVersions { + target(21) + } +} + configurations { create("includeTransitive").isTransitive = true } @@ -104,7 +110,7 @@ afterEvaluate { } dependencies { - minecraft("com.mojang:minecraft:1.20.4") + minecraft("com.mojang:minecraft:1.20.5-rc3") mappings(loom.officialMojangMappings()) } @@ -128,6 +134,6 @@ modrinth { syncBodyFrom.set(rootProject.file("README.md").readText()) uploadFile.set(tasks.getByPath("remapModrinthJar")) - gameVersions.addAll("1.20.4") + gameVersions.addAll("1.20.5") failSilently.set(true) } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index dfdff2187..fdacd5538 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,7 +22,7 @@ val basePlatforms = setOf( val moddedPlatforms = setOf( projects.fabric, - projects.neoforge, + //projects.neoforge, // todo 1.20.5 projects.mod ).map { it.dependencyProject } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 9d0661b08..7dff2647c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -26,10 +26,11 @@ package org.geysermc.geyser.translator.inventory; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.WritableBookContent; +import com.github.steveice10.mc.protocol.data.game.item.component.WrittenBookContent; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -152,7 +153,6 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator session.setDroppingLecternBook(false); InventoryUtils.closeInventory(session, inventory.getJavaId(), false); } else if (lecternContainer.getBlockEntityTag() == null) { - CompoundTag tag = book.getNbt(); Vector3i position = lecternContainer.isUsingRealBlock() ? session.getLastInteractionBlockPosition() : inventory.getHolderPosition(); // If shouldExpectLecternHandled returns true, this is already handled for us @@ -163,10 +163,20 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator && !GameProtocol.is1_20_60orHigher(session.getUpstream().getProtocolVersion()); NbtMap blockEntityTag; - if (tag != null) { - int pagesSize = ((ListTag) tag.get("pages")).size(); + if (book.getComponents() != null) { + int pages = 0; + WrittenBookContent writtenBookComponents = book.getComponents().get(DataComponentType.WRITTEN_BOOK_CONTENT); + if (writtenBookComponents != null) { + pages = writtenBookComponents.getPages().size(); + } else { + WritableBookContent writableBookComponents = book.getComponents().get(DataComponentType.WRITABLE_BOOK_CONTENT); + if (writableBookComponents != null) { + pages = writableBookComponents.getPages().size(); + } + } + ItemData itemData = book.getItemData(session); - NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pagesSize); + NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pages); lecternTag.putCompound("book", NbtMap.builder() .putByte("Count", (byte) itemData.getCount()) .putShort("Damage", (short) 0) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockDestructionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockDestructionTranslator.java index 2a9af8fbf..2fdba716b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockDestructionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockDestructionTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockDestructionPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.geysermc.geyser.registry.BlockRegistries; @@ -43,7 +42,7 @@ public class JavaBlockDestructionTranslator extends PacketTranslator session.getTagCache().isAxeEffective(blockMapping); + case "hoe" -> session.getTagCache().isHoeEffective(blockMapping); + case "pickaxe" -> session.getTagCache().isPickaxeEffective(blockMapping); + case "shears" -> session.getTagCache().isShearsEffective(blockMapping); + case "shovel" -> session.getTagCache().isShovelEffective(blockMapping); + case "sword" -> blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID; + default -> { session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType); - return false; - } + yield false; + } + }; } private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isShearsEffective) { if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0; - if (toolType.equals("")) return 1.0; + if (toolType.isEmpty()) return 1.0; return switch (toolTier) { // https://minecraft.wiki/w/Breaking#Speed case "wooden" -> 2.0; @@ -134,7 +130,7 @@ public final class BlockUtils { return 1.0 / speed; } - public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, @Nullable CompoundTag nbtData, boolean isSessionPlayer) { + public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice boolean canHarvestWithHand = blockMapping.isCanBreakWithHand(); String toolType = ""; @@ -147,7 +143,8 @@ public final class BlockUtils { correctTool = correctTool(session, blockMapping, toolType); toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier); } - int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(nbtData, "minecraft:efficiency"); + + int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY.ordinal()); int hasteLevel = 0; int miningFatigueLevel = 0; @@ -162,7 +159,7 @@ public final class BlockUtils { boolean waterInEyes = session.getCollisionManager().isWaterInEyes(); boolean insideOfWaterWithoutAquaAffinity = waterInEyes && - ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1; + ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY.ordinal()) < 1; return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); @@ -172,12 +169,12 @@ public final class BlockUtils { PlayerInventory inventory = session.getPlayerInventory(); GeyserItemStack item = inventory.getItemInHand(); ItemMapping mapping = ItemMapping.AIR; - CompoundTag nbtData = null; + DataComponents components = null; if (item != null) { mapping = item.getMapping(session); - nbtData = item.getNbt(); + components = item.getComponents(); } - return getBreakTime(session, blockMapping, mapping, nbtData, true); + return getBreakTime(session, blockMapping, mapping, components, true); } /** diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index 2138103d4..b1591e911 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -27,10 +27,7 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.item.Items; @@ -39,24 +36,17 @@ import org.geysermc.geyser.item.type.Item; public class ItemUtils { - public static int getEnchantmentLevel(@Nullable CompoundTag itemNBTData, String enchantmentId) { - if (itemNBTData == null) { + public static int getEnchantmentLevel(@Nullable DataComponents components, int enchantmentId) { + if (components == null) { return 0; } - ListTag enchantments = itemNBTData.get("Enchantments"); - if (enchantments != null) { - for (Tag tag : enchantments) { - CompoundTag enchantment = (CompoundTag) tag; - StringTag enchantId = enchantment.get("id"); - if (enchantId.getValue().equals(enchantmentId)) { - Tag lvl = enchantment.get("lvl"); - if (lvl != null && lvl.getValue() instanceof Number number) { - return number.intValue(); - } - } - } + + ItemEnchantments enchantmentData = components.get(DataComponentType.ENCHANTMENTS); + if (enchantmentData == null) { + return 0; } - return 0; + + return enchantmentData.getEnchantments().getOrDefault(enchantmentId, 0); } /** diff --git a/settings.gradle.kts b/settings.gradle.kts index a39bfa3d2..3867d7a84 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -66,7 +66,7 @@ include(":ap") include(":api") include(":bungeecord") include(":fabric") -include(":neoforge") +//include(":neoforge") // todo 1.20.5 include(":mod") include(":spigot") include(":standalone") @@ -78,7 +78,7 @@ include(":core") // Specify project dirs project(":bungeecord").projectDir = file("bootstrap/bungeecord") project(":fabric").projectDir = file("bootstrap/mod/fabric") -project(":neoforge").projectDir = file("bootstrap/mod/neoforge") +//project(":neoforge").projectDir = file("bootstrap/mod/neoforge") // todo 1.20.5 project(":mod").projectDir = file("bootstrap/mod") project(":spigot").projectDir = file("bootstrap/spigot") project(":standalone").projectDir = file("bootstrap/standalone") From 11f79d4e2c955b35f353eb7bacd5b354a9ca9278 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 22 Apr 2024 19:40:50 -0400 Subject: [PATCH 060/897] Refactor Java registry storage; implement trim support --- .../geyser/inventory/recipe/TrimRecipe.java | 91 ++++++----- .../geysermc/geyser/item/type/ArmorItem.java | 19 +-- .../geysermc/geyser/level/JavaDimension.java | 14 ++ .../geyser/session/GeyserSession.java | 35 +--- .../geyser/session/cache/RegistryCache.java | 153 ++++++++++++++++++ .../geysermc/geyser/text/TextDecoration.java | 12 ++ .../translator/level/BiomeTranslator.java | 58 ++----- .../java/JavaRegistryDataTranslator.java | 35 +--- .../java/JavaUpdateRecipesTranslator.java | 4 +- .../translator/text/MessageTranslator.java | 2 +- .../org/geysermc/geyser/util/ChunkUtils.java | 2 +- 11 files changed, 253 insertions(+), 172 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/RegistryCache.java diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java index 584928e65..441f050a7 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java @@ -25,63 +25,68 @@ package org.geysermc.geyser.inventory.recipe; +import com.github.steveice10.mc.protocol.data.game.RegistryEntry; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescriptor; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.text.MessageTranslator; /** - * Hardcoded recipe information about armor trims until further improvements can be made. This information was scraped - * from BDS 1.19.81 with a world with the next_major_update and sniffer features enabled, using ProxyPass. + * Stores information on trim materials and patterns, including smithing armor hacks for pre-1.20. */ -public class TrimRecipe { - - // For TrimDataPacket, which BDS sends just before the CraftingDataPacket - public static final List PATTERNS; - public static final List MATERIALS; - +public final class TrimRecipe { // For CraftingDataPacket public static final String ID = "minecraft:smithing_armor_trim"; public static final ItemDescriptorWithCount BASE = tagDescriptor("minecraft:trimmable_armors"); public static final ItemDescriptorWithCount ADDITION = tagDescriptor("minecraft:trim_materials"); public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates"); - static { - List patterns = new ArrayList<>(16); - patterns.add(new TrimPattern("minecraft:ward_armor_trim_smithing_template", "ward")); - patterns.add(new TrimPattern("minecraft:sentry_armor_trim_smithing_template", "sentry")); - patterns.add(new TrimPattern("minecraft:snout_armor_trim_smithing_template", "snout")); - patterns.add(new TrimPattern("minecraft:dune_armor_trim_smithing_template", "dune")); - patterns.add(new TrimPattern("minecraft:spire_armor_trim_smithing_template", "spire")); - patterns.add(new TrimPattern("minecraft:tide_armor_trim_smithing_template", "tide")); - patterns.add(new TrimPattern("minecraft:wild_armor_trim_smithing_template", "wild")); - patterns.add(new TrimPattern("minecraft:rib_armor_trim_smithing_template", "rib")); - patterns.add(new TrimPattern("minecraft:coast_armor_trim_smithing_template", "coast")); - patterns.add(new TrimPattern("minecraft:shaper_armor_trim_smithing_template", "shaper")); - patterns.add(new TrimPattern("minecraft:eye_armor_trim_smithing_template", "eye")); - patterns.add(new TrimPattern("minecraft:vex_armor_trim_smithing_template", "vex")); - patterns.add(new TrimPattern("minecraft:silence_armor_trim_smithing_template", "silence")); - patterns.add(new TrimPattern("minecraft:wayfinder_armor_trim_smithing_template", "wayfinder")); - patterns.add(new TrimPattern("minecraft:raiser_armor_trim_smithing_template", "raiser")); - patterns.add(new TrimPattern("minecraft:host_armor_trim_smithing_template", "host")); - PATTERNS = Collections.unmodifiableList(patterns); + public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) { + String key = stripNamespace(entry.getId()); - List materials = new ArrayList<>(10); - materials.add(new TrimMaterial("quartz", "§h", "minecraft:quartz")); - materials.add(new TrimMaterial("iron", "§i", "minecraft:iron_ingot")); - materials.add(new TrimMaterial("netherite", "§j", "minecraft:netherite_ingot")); - materials.add(new TrimMaterial("redstone", "§m", "minecraft:redstone")); - materials.add(new TrimMaterial("copper", "§n", "minecraft:copper_ingot")); - materials.add(new TrimMaterial("gold", "§p", "minecraft:gold_ingot")); - materials.add(new TrimMaterial("emerald", "§q", "minecraft:emerald")); - materials.add(new TrimMaterial("diamond", "§s", "minecraft:diamond")); - materials.add(new TrimMaterial("lapis", "§t", "minecraft:lapis_lazuli")); - materials.add(new TrimMaterial("amethyst", "§u", "minecraft:amethyst_shard")); - MATERIALS = Collections.unmodifiableList(materials); + // Color is used when hovering over the item + // Find the nearest legacy color from the RGB Java gives us to work with + // Also yes this is a COMPLETE hack but it works ok!!!!! + StringTag colorTag = ((CompoundTag) entry.getData().get("description")).get("color"); + TextColor color = TextColor.fromHexString(colorTag.getValue()); + String legacy = MessageTranslator.convertMessage(Component.space().color(color)); + + String itemIdentifier = ((StringTag) entry.getData().get("ingredient")).getValue(); + ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier); + if (itemMapping == null) { + // This should never happen so not sure what to do here. + itemMapping = ItemMapping.AIR; + } + // Just pick out the resulting color code, without RESET in front. + return new TrimMaterial(key, legacy.substring(2).trim(), itemMapping.getBedrockIdentifier()); + } + + public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) { + String key = stripNamespace(entry.getId()); + + String itemIdentifier = ((StringTag) entry.getData().get("template_item")).getValue(); + ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier); + if (itemMapping == null) { + // This should never happen so not sure what to do here. + itemMapping = ItemMapping.AIR; + } + return new TrimPattern(itemMapping.getBedrockIdentifier(), key); + } + + // TODO find a good place for a stripNamespace util method + private static String stripNamespace(String identifier) { + int i = identifier.indexOf(':'); + if (i >= 0) { + return identifier.substring(i + 1); + } + return identifier; } private TrimRecipe() { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index ab936bd08..773b850c0 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -33,6 +33,8 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; +import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -57,14 +59,13 @@ public class ArmorItem extends Item { return; } - // TODO material IDs - String material = trim.material().custom().assetName(); - String pattern = trim.pattern().custom().assetId(); + TrimMaterial material = session.getRegistryCache().trimMaterials().get(trim.material().id()); + TrimPattern pattern = session.getRegistryCache().trimPatterns().get(trim.pattern().id()); NbtMapBuilder trimBuilder = NbtMap.builder(); // bedrock has an uppercase first letter key, and the value is not namespaced - trimBuilder.put("Material", stripNamespace(material)); - trimBuilder.put("Pattern", stripNamespace(pattern)); + trimBuilder.put("Material", material.getMaterialId()); + trimBuilder.put("Pattern", pattern.getPatternId()); builder.putCompound("Trim", trimBuilder.build()); } } @@ -86,12 +87,4 @@ public class ArmorItem extends Item { public boolean isValidRepairItem(Item other) { return material.getRepairIngredient() == other; } - - private static String stripNamespace(String identifier) { - int i = identifier.indexOf(':'); - if (i >= 0) { - return identifier.substring(i + 1); - } - return identifier; - } } diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 6e7223da0..4babc3af0 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -55,4 +55,18 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double world map.put(i, new JavaDimension(minY, maxY, piglinSafe, coordinateScale)); } } + + public static JavaDimension read(RegistryEntry entry) { + CompoundTag dimension = entry.getData(); + int minY = ((IntTag) dimension.get("min_y")).getValue(); + int maxY = ((IntTag) dimension.get("height")).getValue(); + // Logical height can be ignored probably - seems to be for artificial limits like the Nether. + + // Set if piglins/hoglins should shake + boolean piglinSafe = ((Number) dimension.get("piglin_safe").getValue()).byteValue() != (byte) 0; + // Load world coordinate scale for the world border + double coordinateScale = ((Number) dimension.get("coordinate_scale").getValue()).doubleValue(); + + return new JavaDimension(minY, maxY, piglinSafe, coordinateScale); + } } 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 994879f82..9ae1f6f49 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -44,7 +44,6 @@ import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundClientInformationPacket; import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; @@ -54,11 +53,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.Session; -import com.github.steveice10.packetlib.event.session.ConnectedEvent; -import com.github.steveice10.packetlib.event.session.DisconnectedEvent; -import com.github.steveice10.packetlib.event.session.PacketErrorEvent; -import com.github.steveice10.packetlib.event.session.PacketSendingEvent; -import com.github.steveice10.packetlib.event.session.SessionAdapter; +import com.github.steveice10.packetlib.event.session.*; import com.github.steveice10.packetlib.packet.Packet; import com.github.steveice10.packetlib.tcp.TcpClientSession; import com.github.steveice10.packetlib.tcp.TcpSession; @@ -66,8 +61,6 @@ import io.netty.channel.Channel; import io.netty.channel.EventLoop; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -146,7 +139,6 @@ import org.geysermc.geyser.session.cache.*; import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; -import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.ChunkUtils; @@ -158,16 +150,7 @@ import java.net.ConnectException; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledFuture; @@ -214,6 +197,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final LodestoneCache lodestoneCache; private final PistonCache pistonCache; private final PreferencesCache preferencesCache; + private final RegistryCache registryCache; private final SkullCache skullCache; private final StructureBlockCache structureBlockCache; private final TagCache tagCache; @@ -263,12 +247,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private ItemMappings itemMappings; - /** - * Stores the map between Java and Bedrock biome network IDs. - */ - @Setter - private int[] biomeTranslations = null; - /** * A map of Vector3i positions to Java entities. * Used for translating Bedrock block actions to Java entity actions. @@ -360,12 +338,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @MonotonicNonNull @Setter private JavaDimension dimensionType = null; - /** - * All dimensions that the client could possibly connect to. - */ - private final Int2ObjectMap dimensions = new Int2ObjectOpenHashMap<>(4); - - private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); @Setter private int breakingBlock; @@ -619,6 +591,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { 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(); 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 new file mode 100644 index 000000000..44a5469b8 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/RegistryCache.java @@ -0,0 +1,153 @@ +/* + * 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.session.cache; + +import com.github.steveice10.mc.protocol.data.game.RegistryEntry; +import com.github.steveice10.mc.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; +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 lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.Accessors; +import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; +import org.cloudburstmc.protocol.bedrock.data.TrimPattern; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.inventory.recipe.TrimRecipe; +import org.geysermc.geyser.level.JavaDimension; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.TextDecoration; +import org.geysermc.geyser.translator.level.BiomeTranslator; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.ToIntFunction; + +/** + * Stores any information sent via Java registries. May not contain all data in a given registry - we'll strip what's + * unneeded. + * + * Crafted as of 1.20.5 for easy "add new registry" in the future. + */ +@Accessors(fluent = true) +@Getter +public final class RegistryCache { + private static final Map>> REGISTRIES = new HashMap<>(); + + static { + register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry)); + register("dimension_type", cache -> cache.dimensions, ($, entry) -> JavaDimension.read(entry)); + register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); + register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); + register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); + } + + @Getter(AccessLevel.NONE) + private final GeyserSession session; + + /** + * Java -> Bedrock biome network IDs. + */ + private int[] biomeTranslations; + private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); + /** + * All dimensions that the client could possibly connect to. + */ + private final Int2ObjectMap dimensions = new Int2ObjectOpenHashMap<>(4); + private final Int2ObjectMap trimMaterials = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap trimPatterns = new Int2ObjectOpenHashMap<>(); + + public RegistryCache(GeyserSession session) { + this.session = session; + } + + /** + * Loads a registry in, if we are tracking it. + */ + public void load(ClientboundRegistryDataPacket packet) { + var reader = REGISTRIES.get(packet.getRegistry()); + if (reader != null) { + reader.accept(this, packet.getEntries()); + } else { + GeyserImpl.getInstance().getLogger().debug("Ignoring registry of type " + packet.getRegistry()); + } + } + + /** + * @param registry the Java registry resource location, without the "minecraft:" prefix. + * @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(String registry, Function> localCacheFunction, BiFunction reader) { + REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> { + Int2ObjectMap localCache = localCacheFunction.apply(registryCache); + // Clear each local cache every time a new registry entry is given to us + localCache.clear(); + for (int i = 0; i < entries.size(); i++) { + RegistryEntry entry = entries.get(i); + // This is what Geyser wants to keep as a value for this registry. + T cacheEntry = reader.apply(registryCache.session, entry); + localCache.put(i, cacheEntry); + } + // Trim registry down to needed size + if (localCache instanceof Int2ObjectOpenHashMap hashMap) { + hashMap.trim(); + } + }); + } + + /** + * @param localCacheFunction the int array to set the final values to. + */ + private static void register(String registry, BiConsumer localCacheFunction, ToIntFunction reader) { + REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> { + Int2IntMap temp = new Int2IntOpenHashMap(); + int greatestId = 0; + for (int i = 0; i < entries.size(); i++) { + RegistryEntry entry = entries.get(i); + // This is what Geyser wants to keep as a value for this registry. + int cacheEntry = reader.applyAsInt(entry); + temp.put(i, cacheEntry); + if (i > greatestId) { + // Maximum registry ID, so far. Make sure the final array is at least this large. + greatestId = i; + } + } + + int[] array = new int[greatestId + 1]; + for (Int2IntMap.Entry entry : temp.int2IntEntrySet()) { + array[entry.getIntKey()] = entry.getIntValue(); + } + localCacheFunction.accept(registryCache, array); + }); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java index 121e1b2b9..bad55a5ca 100644 --- a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.text; +import com.github.steveice10.mc.protocol.data.game.RegistryEntry; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; @@ -87,6 +88,17 @@ public final class TextDecoration { '}'; } + public static TextDecoration readChatType(RegistryEntry entry) { + // Note: The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. + CompoundTag tag = entry.getData(); + CompoundTag chat = tag.get("chat"); + TextDecoration textDecoration = null; + if (chat != null) { + textDecoration = new TextDecoration(chat); + } + return textDecoration; + } + public enum Parameter { CONTENT, SENDER, diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index f05ed5ed1..fce928bdb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -31,7 +31,9 @@ import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.GlobalPalette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.Palette; import com.github.steveice10.mc.protocol.data.game.chunk.palette.SingletonPalette; -import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.IntLists; import org.geysermc.geyser.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.bitarray.BitArray; import org.geysermc.geyser.level.chunk.bitarray.BitArrayVersion; @@ -39,58 +41,20 @@ import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; -import java.util.List; - // Array index formula by https://wiki.vg/Chunk_Format public class BiomeTranslator { - public static void loadServerBiomes(GeyserSession session, List entries) { - Int2IntMap biomeTranslations = new Int2IntOpenHashMap(); - - int greatestBiomeId = 0; - for (int i = 0; i < entries.size(); i++) { - RegistryEntry entry = entries.get(i); - String javaIdentifier = entry.getId(); - int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); - int javaId = i; - if (javaId > greatestBiomeId) { - greatestBiomeId = javaId; - } - - // TODO - the category tag no longer exists - find a better replacement option -// if (bedrockId == -1) { -// // There is no matching Bedrock variation for this biome; let's set the closest match based on biome category -// String category = ((StringTag) ((CompoundTag) biomeTag.get("element")).get("category")).getValue(); -// String replacementBiome = switch (category) { -// case "extreme_hills" -> "minecraft:mountains"; -// case "icy" -> "minecraft:ice_spikes"; -// case "mesa" -> "minecraft:badlands"; -// case "mushroom" -> "minecraft:mushroom_fields"; -// case "nether" -> "minecraft:nether_wastes"; -// default -> "minecraft:ocean"; // Typically ID 0 so a good default -// case "taiga", "jungle", "plains", "savanna", "the_end", "beach", "ocean", "desert", "river", "swamp" -> "minecraft:" + category; -// }; -// bedrockId = Registries.BIOME_IDENTIFIERS.get().getInt(replacementBiome); -// } - - // When we see the Java ID, we should instead apply the Bedrock ID - biomeTranslations.put(javaId, bedrockId); - - if (javaId == 0) { - // Matches Java behavior when it sees an invalid biome - it just replaces it with ID 0 - biomeTranslations.defaultReturnValue(bedrockId); - } - } - - int[] biomes = new int[greatestBiomeId + 1]; - for (Int2IntMap.Entry entry : biomeTranslations.int2IntEntrySet()) { - biomes[entry.getIntKey()] = entry.getIntValue(); - } - session.setBiomeTranslations(biomes); + public static int loadServerBiome(RegistryEntry entry) { + String javaIdentifier = entry.getId(); + return Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); +// if (javaId == 0) { +// // Matches Java behavior when it sees an invalid biome - it just replaces it with ID 0 +// biomeTranslations.defaultReturnValue(bedrockId); +// } } public static BlockStorage toNewBedrockBiome(GeyserSession session, DataPalette biomeData) { - int[] biomeTranslations = session.getBiomeTranslations(); + int[] biomeTranslations = session.getRegistryCache().biomeTranslations(); // As of 1.17.10: the client expects the same format as a chunk but filled with biomes // As of 1.18 this is the same as Java Edition diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java index 5d9bbff7d..ddb9c76b7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java @@ -25,49 +25,16 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.RegistryEntry; import com.github.steveice10.mc.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.TextDecoration; -import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import java.util.List; - @Translator(packet = ClientboundRegistryDataPacket.class) public class JavaRegistryDataTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundRegistryDataPacket packet) { - if (packet.getRegistry().equals("minecraft:dimension_type")) { - Int2ObjectMap dimensions = session.getDimensions(); - dimensions.clear(); - JavaDimension.load(packet.getEntries(), dimensions); - } - - if (packet.getRegistry().equals("minecraft:chat_type")) { - Int2ObjectMap chatTypes = session.getChatTypes(); - chatTypes.clear(); - List entries = packet.getEntries(); - for (int i = 0; i < entries.size(); i++) { - // The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. - RegistryEntry entry = entries.get(i); - CompoundTag tag = entry.getData(); - CompoundTag chat = tag.get("chat"); - TextDecoration textDecoration = null; - if (chat != null) { - textDecoration = new TextDecoration(chat); - } - chatTypes.put(i, textDecoration); - } - } - - if (packet.getRegistry().equals("minecraft:worldgen/biome")) { - BiomeTranslator.loadServerBiomes(session, packet.getEntries()); - } + session.getRegistryCache().load(packet); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index aca02feab..20b223248 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -269,8 +269,8 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Date: Mon, 22 Apr 2024 22:49:46 -0400 Subject: [PATCH 061/897] Banners --- .../geyser/inventory/item/BannerPattern.java | 104 +++++++++++++ .../geyser/inventory/item/DyeColor.java | 75 +++++++++ .../geysermc/geyser/item/type/BannerItem.java | 145 ++++++++++++------ .../geyser/session/cache/RegistryCache.java | 4 + .../inventory/LoomInventoryTranslator.java | 27 +--- .../entity/BannerBlockEntityTranslator.java | 4 +- .../bedrock/BedrockBookEditTranslator.java | 1 + 7 files changed, 295 insertions(+), 65 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java create mode 100644 core/src/main/java/org/geysermc/geyser/inventory/item/DyeColor.java diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java new file mode 100644 index 000000000..442690d7d --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java @@ -0,0 +1,104 @@ +/* + * 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.inventory.item; + +import lombok.Getter; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Locale; + +@Getter +public enum BannerPattern { + BASE("b"), + SQUARE_BOTTOM_LEFT("bl"), + SQUARE_BOTTOM_RIGHT("br"), + SQUARE_TOP_LEFT("tl"), + SQUARE_TOP_RIGHT("tr"), + STRIPE_BOTTOM("bs"), + STRIPE_TOP("ts"), + STRIPE_LEFT("ls"), + STRIPE_RIGHT("rs"), + STRIPE_CENTER("cs"), + STRIPE_MIDDLE("ms"), + STRIPE_DOWNRIGHT("drs"), + STRIPE_DOWNLEFT("dls"), + SMALL_STRIPES("ss"), + CROSS("cr"), + STRAIGHT_CROSS("sc"), + TRIANGLE_BOTTOM("bt"), + TRIANGLE_TOP("tt"), + TRIANGLES_BOTTOM("bts"), + TRIANGLES_TOP("tts"), + DIAGONAL_LEFT("ld"), + DIAGONAL_UP_RIGHT("rd"), + DIAGONAL_UP_LEFT("lud"), + DIAGONAL_RIGHT("rud"), + CIRCLE("mc"), + RHOMBUS("mr"), + HALF_VERTICAL("vh"), + HALF_HORIZONTAL("hh"), + HALF_VERTICAL_RIGHT("vhr"), + HALF_HORIZONTAL_BOTTOM("hhb"), + BORDER("bo"), + CURLY_BORDER("cbo"), + GRADIENT("gra"), + GRADIENT_UP("gru"), + BRICKS("bri"), + GLOBE("glb"), + CREEPER("cre"), + SKULL("sku"), + FLOWER("flo"), + MOJANG("moj"), + PIGLIN("pig"); + + private static final BannerPattern[] VALUES = values(); + + private final String javaIdentifier; + private final String bedrockIdentifier; + + BannerPattern(String bedrockIdentifier) { + this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT); + this.bedrockIdentifier = bedrockIdentifier; + } + + public static @Nullable BannerPattern getByJavaIdentifier(String javaIdentifier) { + for (BannerPattern bannerPattern : VALUES) { + if (bannerPattern.javaIdentifier.equals(javaIdentifier)) { + return bannerPattern; + } + } + return null; + } + + public static @Nullable BannerPattern getByBedrockIdentifier(String bedrockIdentifier) { + for (BannerPattern bannerPattern : VALUES) { + if (bannerPattern.bedrockIdentifier.equals(bedrockIdentifier)) { + return bannerPattern; + } + } + return null; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/DyeColor.java b/core/src/main/java/org/geysermc/geyser/inventory/item/DyeColor.java new file mode 100644 index 000000000..e2649a343 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/DyeColor.java @@ -0,0 +1,75 @@ +/* + * 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.inventory.item; + +import lombok.Getter; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Locale; + +@Getter +public enum DyeColor { + WHITE, + ORANGE, + MAGENTA, + LIGHT_BLUE, + YELLOW, + LIME, + PINK, + GRAY, + LIGHT_GRAY, + CYAN, + PURPLE, + BLUE, + BROWN, + GREEN, + RED, + BLACK; + + private static final DyeColor[] VALUES = values(); + + private final String javaIdentifier; + + DyeColor() { + this.javaIdentifier = this.name().toLowerCase(Locale.ROOT); + } + + public static @Nullable DyeColor getById(int id) { + if (id >= 0 && id < VALUES.length) { + return VALUES[id]; + } + return null; + } + + public static @Nullable DyeColor getByJavaIdentifier(String javaIdentifier) { + for (DyeColor dyeColor : VALUES) { + if (dyeColor.javaIdentifier.equals(javaIdentifier)) { + return dyeColor; + } + } + return null; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 32806c3c2..0d8050dec 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -28,14 +28,14 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.item.component.BannerPatternLayer; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.opennbt.tag.builtin.*; +import it.unimi.dsi.fastutil.Pair; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.inventory.item.BannerPattern; +import org.geysermc.geyser.inventory.item.DyeColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -51,20 +51,48 @@ public class BannerItem extends BlockItem { * ominous banners that we set instead. This variable is used to detect Java ominous banner patterns, and apply * the correct ominous banner pattern if Bedrock pulls the item from creative. */ - public static final List OMINOUS_BANNER_PATTERN; + private static final List> OMINOUS_BANNER_PATTERN; + private static final ListTag OMINOUS_BANNER_PATTERN_BLOCK; static { // Construct what an ominous banner is supposed to look like OMINOUS_BANNER_PATTERN = List.of( -// new BannerPatternLayer("mr", 9), -// new BannerPatternLayer("bs", 8), -// new BannerPatternLayer("cs", 7), -// new BannerPatternLayer("bo", 8), -// new BannerPatternLayer("ms", 15), -// new BannerPatternLayer("hh", 8), -// new BannerPatternLayer("mc", 8), -// new BannerPatternLayer("bo", 15) + Pair.of(BannerPattern.RHOMBUS, DyeColor.CYAN), + Pair.of(BannerPattern.STRIPE_BOTTOM, DyeColor.LIGHT_GRAY), + Pair.of(BannerPattern.STRIPE_CENTER, DyeColor.GRAY), + Pair.of(BannerPattern.BORDER, DyeColor.LIGHT_GRAY), + Pair.of(BannerPattern.STRIPE_MIDDLE, DyeColor.BLACK), + Pair.of(BannerPattern.HALF_HORIZONTAL, DyeColor.LIGHT_GRAY), + Pair.of(BannerPattern.CIRCLE, DyeColor.LIGHT_GRAY), + Pair.of(BannerPattern.BORDER, DyeColor.BLACK) ); + + OMINOUS_BANNER_PATTERN_BLOCK = new ListTag("patterns"); + for (Pair pair : OMINOUS_BANNER_PATTERN) { + OMINOUS_BANNER_PATTERN_BLOCK.add(getJavaBannerPatternTag(pair.left(), pair.right())); + } + } + + public static boolean isOminous(GeyserSession session, List patternLayers) { + if (OMINOUS_BANNER_PATTERN.size() != patternLayers.size()) { + return false; + } + for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) { + BannerPatternLayer patternLayer = patternLayers.get(i); + Pair pair = OMINOUS_BANNER_PATTERN.get(i); + if (!patternLayer.getPattern().isId() || patternLayer.getColorId() != pair.right().ordinal()) { + return false; + } + BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(patternLayer.getPattern().id()); + if (bannerPattern != pair.left()) { + return false; + } + } + return true; + } + + public static boolean isOminous(ListTag blockEntityPatterns) { + return OMINOUS_BANNER_PATTERN_BLOCK.equals(blockEntityPatterns); } /** @@ -76,7 +104,10 @@ public class BannerItem extends BlockItem { public static NbtList convertBannerPattern(ListTag patterns) { List tagsList = new ArrayList<>(); for (Tag patternTag : patterns.getValue()) { - tagsList.add(getBedrockBannerPattern((CompoundTag) patternTag)); + NbtMap bedrockBannerPattern = getBedrockBannerPattern((CompoundTag) patternTag); + if (bedrockBannerPattern != null) { + tagsList.add(bedrockBannerPattern); + } } return new NbtList<>(NbtType.COMPOUND, tagsList); @@ -88,35 +119,41 @@ public class BannerItem extends BlockItem { * @param pattern Java edition pattern nbt * @return The Bedrock edition format pattern nbt */ - @NonNull private static NbtMap getBedrockBannerPattern(CompoundTag pattern) { + BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier((String) pattern.get("pattern").getValue()); + DyeColor dyeColor = DyeColor.getByJavaIdentifier((String) pattern.get("color").getValue()); + if (bannerPattern == null || dyeColor == null) { + return null; + } + return NbtMap.builder() - .putInt("Color", 15 - (int) pattern.get("Color").getValue()) - .putString("Pattern", (String) pattern.get("Pattern").getValue()) + .putString("Pattern", bannerPattern.getBedrockIdentifier()) + .putInt("Color", 15 - dyeColor.ordinal()) .build(); } + public static CompoundTag getJavaBannerPatternTag(BannerPattern bannerPattern, DyeColor dyeColor) { + CompoundTag tag = new CompoundTag(""); + tag.put(new StringTag("pattern", bannerPattern.getJavaIdentifier())); + tag.put(new StringTag("color", dyeColor.getJavaIdentifier())); + return tag; + } + /** * Convert the Bedrock edition banner pattern nbt to Java edition * * @param pattern Bedrock edition pattern nbt - * @return The Java edition format pattern nbt + * @return The Java edition format pattern layer */ - public static CompoundTag getJavaBannerPattern(NbtMap pattern) { - //return new BannerPatternLayer(0/*pattern.getString("Pattern")*/, 15 - pattern.getInt("Color")); - return null; - } - - /** - * Convert a list of patterns from Java nbt to Bedrock nbt, or vice versa (we just need to invert the color) - * - * @param patterns The patterns to convert - */ - private void invertBannerColors(ListTag patterns) { - for (Tag patternTag : patterns.getValue()) { - IntTag color = ((CompoundTag) patternTag).get("Color"); - color.setValue(15 - color.getValue()); + public static BannerPatternLayer getJavaBannerPattern(GeyserSession session, NbtMap pattern) { + return null; // TODO + /*Int2ObjectBiMap registry = session.getRegistryCache().bannerPatterns(); + BannerPattern bannerPattern = BannerPattern.getByBedrockIdentifier(pattern.getString("Pattern")); + DyeColor dyeColor = DyeColor.getById(15 - pattern.getInt("Color")); + if (bannerPattern != null && dyeColor != null && registry.containsValue(bannerPattern)) { + return new BannerPatternLayer(Holder.ofId(registry.get(bannerPattern)), dyeColor.ordinal()); } + return null;*/ } public BannerItem(String javaIdentifier, Builder builder) { @@ -129,31 +166,51 @@ public class BannerItem extends BlockItem { List patterns = components.get(DataComponentType.BANNER_PATTERNS); if (patterns != null) { -// if (patterns.equals(OMINOUS_BANNER_PATTERN)) { -// // Remove the current patterns and set the ominous banner type -// builder.putInt("Type", 1); -// } else { -// invertBannerColors(patterns); -// tag.put(patterns); -// } + if (isOminous(session, patterns)) { + // Remove the current patterns and set the ominous banner type + builder.putInt("Type", 1); + } else { + List patternList = new ArrayList<>(patterns.size()); + for (BannerPatternLayer patternLayer : patterns) { + patternLayer.getPattern().ifId(holder -> { + BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(holder.id()); + if (bannerPattern != null) { + NbtMap tag = NbtMap.builder() + .putString("Pattern", bannerPattern.getBedrockIdentifier()) + .putInt("Color", 15 - patternLayer.getColorId()) + .build(); + patternList.add(tag); + } + }); + } + builder.putList("Patterns", NbtType.COMPOUND, patternList); + } } } @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { + public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { // TODO super.translateNbtToJava(tag, mapping); if (tag.get("Type") instanceof IntTag type && type.getValue() == 1) { // Ominous banner pattern tag.remove("Type"); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - //blockEntityTag.put(OMINOUS_BANNER_PATTERN); + blockEntityTag.put(OMINOUS_BANNER_PATTERN_BLOCK); tag.put(blockEntityTag); - } else if (tag.get("Patterns") instanceof ListTag patterns) { + } else if (tag.get("Patterns") instanceof ListTag patterns && patterns.getElementType() == CompoundTag.class) { CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - invertBannerColors(patterns); - blockEntityTag.put(patterns); + + ListTag javaPatterns = new ListTag("patterns"); + for (Tag pattern : patterns.getValue()) { + BannerPattern bannerPattern = BannerPattern.getByBedrockIdentifier((String) ((CompoundTag) pattern).get("Pattern").getValue()); + DyeColor dyeColor = DyeColor.getById((int) ((CompoundTag) pattern).get("Color").getValue()); + if (bannerPattern != null && dyeColor != null) { + javaPatterns.add(getJavaBannerPatternTag(bannerPattern, dyeColor)); + } + } + blockEntityTag.put(javaPatterns); tag.put(blockEntityTag); tag.remove("Patterns"); // Remove the old Bedrock patterns list 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 44a5469b8..6f69574ed 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 @@ -37,6 +37,7 @@ import lombok.experimental.Accessors; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; @@ -68,6 +69,7 @@ public final class RegistryCache { register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); + register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); } @Getter(AccessLevel.NONE) @@ -85,6 +87,8 @@ public final class RegistryCache { private final Int2ObjectMap trimMaterials = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap trimPatterns = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap bannerPatterns = new Int2ObjectOpenHashMap<>(); + public RegistryCache(GeyserSession session) { this.session = session; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 6c7a11ff2..636a7982a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.translator.inventory; +import com.github.steveice10.mc.protocol.data.game.item.component.BannerPatternLayer; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.cloudburstmc.nbt.NbtMap; @@ -51,7 +51,7 @@ import org.geysermc.geyser.item.type.BannerItem; import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.session.GeyserSession; -import java.util.Collections; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -159,23 +159,12 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { if (inputCopy.getComponents() == null) { inputCopy.setComponents(new DataComponents(new HashMap<>())); } - //TODO - CompoundTag blockEntityTag = inputCopy.getNbt().get("BlockEntityTag"); - CompoundTag javaBannerPattern = BannerItem.getJavaBannerPattern(pattern); - if (blockEntityTag != null) { - ListTag patternsList = blockEntityTag.get("Patterns"); - if (patternsList != null) { - patternsList.add(javaBannerPattern); - } else { - patternsList = new ListTag("Patterns", Collections.singletonList(javaBannerPattern)); - blockEntityTag.put(patternsList); - } - } else { - blockEntityTag = new CompoundTag("BlockEntityTag"); - ListTag patternsList = new ListTag("Patterns", Collections.singletonList(javaBannerPattern)); - blockEntityTag.put(patternsList); - inputCopy.getNbt().put(blockEntityTag); + BannerPatternLayer bannerPatternLayer = BannerItem.getJavaBannerPattern(session, pattern); // TODO + if (bannerPatternLayer != null) { + List patternsList = inputCopy.getComponents().getOrDefault(DataComponentType.BANNER_PATTERNS, new ArrayList<>()); + patternsList.add(bannerPatternLayer); + inputCopy.getComponents().put(DataComponentType.BANNER_PATTERNS, patternsList); } // Set the new item as the output diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java index f23433bbe..e0e0130c5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java @@ -46,8 +46,8 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement return; } - if (tag.get("Patterns") instanceof ListTag patterns) { - if (patterns.equals(BannerItem.OMINOUS_BANNER_PATTERN)) { + if (tag.get("patterns") instanceof ListTag patterns) { + if (BannerItem.isOminous(patterns)) { // This is an ominous banner; don't try to translate the raw patterns (it doesn't translate correctly) // and tell the Bedrock client that this is an ominous banner builder.putInt("Type", 1); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java index 4350f6a83..10024c02f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java @@ -105,6 +105,7 @@ public class BedrockBookEditTranslator extends PacketTranslator break; } case SIGN_BOOK: { + // As of JE 1.20.5, client no longer adds title and author on its own break; } default: From 1bdbcab4e8fc8a8373b13cdf962eb17e7fccaa02 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 23 Apr 2024 00:44:20 -0400 Subject: [PATCH 062/897] Wolf variants --- .../geyser/entity/EntityDefinitions.java | 1 + .../living/animal/tameable/WolfEntity.java | 41 +++++++++++++++++++ .../geysermc/geyser/item/type/BannerItem.java | 3 +- .../geyser/session/cache/RegistryCache.java | 3 ++ 4 files changed, 47 insertions(+), 1 deletion(-) 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 e9d49fbd8..6b243212d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -971,6 +971,7 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataType.INT, WolfEntity::setCollarColor) .addTranslator(MetadataType.INT, WolfEntity::setWolfAngerTime) + .addTranslator(MetadataType.WOLF_VARIANT, WolfEntity::setWolfVariant) .build(); // As of 1.18 these don't track entity data at all 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 c75247fdf..ee7281772 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 @@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEnti import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -43,6 +44,7 @@ import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import java.util.Collections; +import java.util.Locale; import java.util.Set; import java.util.UUID; @@ -102,6 +104,15 @@ public class WolfEntity extends TameableEntity { dirtyMetadata.put(EntityDataTypes.COLOR, time != 0 ? (byte) 0 : collarColor); } + // 1.20.5+ + public void setWolfVariant(IntEntityMetadata entityMetadata) { + WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().get(entityMetadata.getPrimitiveValue()); + if (wolfVariant == null) { + wolfVariant = WolfVariant.PALE; + } + dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal()); + } + @Override public boolean canEat(Item item) { // Cannot be a baby to eat these foods @@ -147,4 +158,34 @@ public class WolfEntity extends TameableEntity { return InteractionResult.PASS; } } + + // Ordered by bedrock id + public enum WolfVariant { + PALE, + ASHEN, + BLACK, + CHESTNUT, + RUSTY, + SNOWY, + SPOTTED, + STRIPED, + WOODS; + + private static final WolfVariant[] VALUES = values(); + + private final String javaIdentifier; + + WolfVariant() { + this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT); + } + + public static @Nullable WolfVariant getByJavaIdentifier(String javaIdentifier) { + for (WolfVariant wolfVariant : VALUES) { + if (wolfVariant.javaIdentifier.equals(javaIdentifier)) { + return wolfVariant; + } + } + return null; + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 0d8050dec..fe378d4c6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -80,7 +80,8 @@ public class BannerItem extends BlockItem { for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) { BannerPatternLayer patternLayer = patternLayers.get(i); Pair pair = OMINOUS_BANNER_PATTERN.get(i); - if (!patternLayer.getPattern().isId() || patternLayer.getColorId() != pair.right().ordinal()) { + if (patternLayer.getColorId() != pair.right().ordinal() || + !patternLayer.getPattern().isId()) { return false; } BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(patternLayer.getPattern().id()); 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 6f69574ed..d5293c5c3 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 @@ -37,6 +37,7 @@ import lombok.experimental.Accessors; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; 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.recipe.TrimRecipe; import org.geysermc.geyser.level.JavaDimension; @@ -70,6 +71,7 @@ public final class RegistryCache { register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); + register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId())); } @Getter(AccessLevel.NONE) @@ -88,6 +90,7 @@ public final class RegistryCache { private final Int2ObjectMap trimPatterns = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap bannerPatterns = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap wolfVariants = new Int2ObjectOpenHashMap<>(); public RegistryCache(GeyserSession session) { this.session = session; From 3f499e3ec05592510a9cdeca0e642478a435cf17 Mon Sep 17 00:00:00 2001 From: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 23 Apr 2024 03:09:42 -0700 Subject: [PATCH 063/897] Start on custom skulls Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .../geyser/skin/FakeHeadProvider.java | 86 ++++++++++++------- .../inventory/InventoryTranslator.java | 2 +- .../inventory/PlayerInventoryTranslator.java | 4 +- .../translator/item/ItemTranslator.java | 36 +++++--- .../entity/SkullBlockEntityTranslator.java | 1 + .../entity/JavaSetEquipmentTranslator.java | 20 +++-- .../JavaLevelChunkWithLightTranslator.java | 1 + 7 files changed, 96 insertions(+), 54 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index c7bd235b2..2d6345bfa 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java @@ -25,9 +25,13 @@ package org.geysermc.geyser.skin; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.github.steveice10.mc.auth.data.GameProfile; +import com.github.steveice10.mc.auth.data.GameProfile.Texture; +import com.github.steveice10.mc.auth.data.GameProfile.TextureModel; +import com.github.steveice10.mc.auth.data.GameProfile.TextureType; +import com.github.steveice10.mc.auth.exception.property.PropertyException; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -39,11 +43,13 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.skin.SkinManager.GameProfileData; import org.geysermc.geyser.text.GeyserLocale; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; +import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -95,38 +101,60 @@ public class FakeHeadProvider { } }); - public static void setHead(GeyserSession session, PlayerEntity entity, Tag skullOwner) { - if (skullOwner == null) { + public static void setHead(GeyserSession session, PlayerEntity entity, DataComponents components) { + GameProfile profile = components.get(DataComponentType.PROFILE); + + if (profile == null) { return; } - if (skullOwner instanceof CompoundTag profileTag) { - SkinManager.GameProfileData gameProfileData = SkinManager.GameProfileData.from(profileTag); - if (gameProfileData == null) { + + Map textures = null; + try { + textures = profile.getTextures(false); + } catch (PropertyException e) { + session.getGeyser().getLogger().debug("Failed to get textures from GameProfile: " + e); + } + + if (textures == null || textures.isEmpty()) { + loadHead(session, entity, profile.getName()); + return; + } + + Texture skinTexture = textures.get(TextureType.SKIN); + + if (skinTexture == null) { + return; + } + + Texture capeTexture = textures.get(TextureType.CAPE); + String capeUrl = capeTexture != null ? capeTexture.getURL() : null; + + boolean isAlex = skinTexture.getModel() == TextureModel.SLIM; + + loadHead(session, entity, new GameProfileData(skinTexture.getURL(), capeUrl, isAlex)); + } + + public static void loadHead(GeyserSession session, PlayerEntity entity, String owner) { + if (owner == null || owner.isEmpty()) { + return; + } + + CompletableFuture completableFuture = SkinProvider.requestTexturesFromUsername(owner); + completableFuture.whenCompleteAsync((encodedJson, throwable) -> { + if (throwable != null) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), throwable); return; } - loadHead(session, entity, gameProfileData); - } else if (skullOwner instanceof StringTag ownerTag) { - String owner = ownerTag.getValue(); - if (owner.isEmpty()) { - return; - } - CompletableFuture completableFuture = SkinProvider.requestTexturesFromUsername(owner); - completableFuture.whenCompleteAsync((encodedJson, throwable) -> { - if (throwable != null) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), throwable); + try { + SkinManager.GameProfileData gameProfileData = SkinManager.GameProfileData.loadFromJson(encodedJson); + if (gameProfileData == null) { return; } - try { - SkinManager.GameProfileData gameProfileData = SkinManager.GameProfileData.loadFromJson(encodedJson); - if (gameProfileData == null) { - return; - } - loadHead(session, entity, gameProfileData); - } catch (IOException e) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid(), e.getMessage())); - } - }); - } + loadHead(session, entity, gameProfileData); + } catch (IOException e) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid(), e.getMessage())); + } + }); } public static void loadHead(GeyserSession session, PlayerEntity entity, SkinManager.GameProfileData gameProfileData) { 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 2d7a1ae5a..4a3e31b30 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 @@ -225,7 +225,7 @@ public abstract class InventoryTranslator { GeyserItemStack javaItem = inventory.getItem(sourceSlot); if (javaItem.asItem() == Items.PLAYER_HEAD && javaItem.getNbt() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getNbt().get("SkullOwner")); + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents()); } } else if (sourceSlot == 5) { //we are probably removing the head, so restore the original skin diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index b461c7afc..36d10aa54 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -100,7 +100,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (i == 5 && item.asItem() == Items.PLAYER_HEAD && item.getNbt() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getNbt().get("SkullOwner")); + FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponents()); } } armorContentPacket.setContents(Arrays.asList(contents)); @@ -144,7 +144,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { // Check for custom skull if (javaItem.asItem() == Items.PLAYER_HEAD && javaItem.getNbt() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getNbt().get("SkullOwner")); + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents()); } else { FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity()); } 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 c96542fc1..a8e9e1c52 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 @@ -26,6 +26,9 @@ package org.geysermc.geyser.translator.item; import com.github.steveice10.mc.auth.data.GameProfile; +import com.github.steveice10.mc.auth.data.GameProfile.Texture; +import com.github.steveice10.mc.auth.data.GameProfile.TextureType; +import com.github.steveice10.mc.auth.exception.property.PropertyException; import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOperation; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; @@ -553,21 +556,28 @@ public final class ItemTranslator { if (components == null) { return null; } - //TODO + GameProfile profile = components.get(DataComponentType.PROFILE); if (profile != null) { -// if (!(nbt.get("SkullOwner") instanceof CompoundTag skullOwner)) { -// // It's a username give up d: -// return null; -// } -// SkinManager.GameProfileData data = SkinManager.GameProfileData.from(skullOwner); -// if (data == null) { -// session.getGeyser().getLogger().debug("Not sure how to handle skull head item display. " + nbt); -// return null; -// } -// -// String skinHash = data.skinUrl().substring(data.skinUrl().lastIndexOf('/') + 1); -// return BlockRegistries.CUSTOM_SKULLS.get(skinHash); + Map textures = null; + try { + textures = profile.getTextures(false); + } catch (PropertyException e) { + session.getGeyser().getLogger().debug("Failed to get textures from GameProfile: " + e); + } + + if (textures == null || textures.isEmpty()) { + return null; + } + + Texture skinTexture = textures.get(TextureType.SKIN); + + if (skinTexture == null) { + return null; + } + + String skinHash = skinTexture.getURL().substring(skinTexture.getURL().lastIndexOf('/') + 1); + return BlockRegistries.CUSTOM_SKULLS.get(skinHash); } return null; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index 9ac9126db..e9aceece5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -101,6 +101,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements } public static @Nullable BlockDefinition translateSkull(GeyserSession session, CompoundTag tag, Vector3i blockPosition, int blockState) { + // TODO: The tag layout follows new format (profille, etc...) CompoundTag owner = tag.get("SkullOwner"); if (owner == null) { session.getSkullCache().removeSkull(blockPosition); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index 6178a51e8..b0168a4ce 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -31,7 +31,10 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.Client import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.skin.FakeHeadProvider; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -59,15 +62,14 @@ public class JavaSetEquipmentTranslator extends PacketTranslator { ItemStack javaItem = equipment.getItem(); - // TODO -// if (livingEntity instanceof PlayerEntity -// && javaItem != null -// && javaItem.getId() == Items.PLAYER_HEAD.javaId() -// && javaItem.getNbt() != null) { -// FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, javaItem.getNbt().get("SkullOwner")); -// } else { -// FakeHeadProvider.restoreOriginalSkin(session, livingEntity); -// } + if (livingEntity instanceof PlayerEntity + && javaItem != null + && javaItem.getId() == Items.PLAYER_HEAD.javaId() + && javaItem.getDataComponents() != null) { + FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, javaItem.getDataComponents()); + } else { + FakeHeadProvider.restoreOriginalSkin(session, livingEntity); + } livingEntity.setHelmet(item); armorUpdated = true; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index e34c0d96d..fc1d0316c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -425,6 +425,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator Date: Tue, 23 Apr 2024 06:13:19 -0400 Subject: [PATCH 064/897] Fix horse inventory --- .../inventory/JavaHorseScreenOpenTranslator.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java index 58deaa0e9..33cfeaf31 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java @@ -112,19 +112,23 @@ public class JavaHorseScreenOpenTranslator extends PacketTranslator slots = new ArrayList<>(); + // Since 1.20.5, the armor slot is not included in the container size, + // but everything is still indexed the same. + int slotCount = packet.getNumberOfSlots() + 1; + InventoryTranslator inventoryTranslator; if (entity instanceof LlamaEntity) { - inventoryTranslator = new LlamaInventoryTranslator(packet.getNumberOfSlots()); + inventoryTranslator = new LlamaInventoryTranslator(slotCount); slots.add(CARPET_SLOT); } else if (entity instanceof ChestedHorseEntity) { - inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots()); + inventoryTranslator = new DonkeyInventoryTranslator(slotCount); slots.add(SADDLE_SLOT); } else if (entity instanceof CamelEntity) { // The camel has an invisible armor slot and needs special handling, same as the donkey - inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots()); + inventoryTranslator = new DonkeyInventoryTranslator(slotCount); slots.add(SADDLE_SLOT); } else { - inventoryTranslator = new HorseInventoryTranslator(packet.getNumberOfSlots()); + inventoryTranslator = new HorseInventoryTranslator(slotCount); slots.add(SADDLE_SLOT); slots.add(ARMOR_SLOT); } @@ -136,6 +140,6 @@ public class JavaHorseScreenOpenTranslator extends PacketTranslator Date: Tue, 23 Apr 2024 17:57:03 +0200 Subject: [PATCH 065/897] init: pick item component change --- .../mod/world/GeyserModWorldManager.java | 50 +++++++++++++++++-- .../manager/GeyserSpigotWorldManager.java | 9 ++-- .../erosion/GeyserboundPacketHandlerImpl.java | 15 ++++-- .../geyser/level/GeyserWorldManager.java | 14 ++++-- .../geysermc/geyser/level/WorldManager.java | 4 +- .../BedrockBlockPickRequestTranslator.java | 27 +++------- gradle/libs.versions.toml | 2 +- 7 files changed, 79 insertions(+), 42 deletions(-) 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 e9d612976..b9fbd6cdc 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 @@ -25,7 +25,10 @@ package org.geysermc.geyser.platform.mod.world; +import com.github.steveice10.mc.protocol.data.game.Holder; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.item.component.BannerPatternLayer; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; @@ -43,6 +46,7 @@ import net.minecraft.world.item.component.WrittenBookContent; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BannerBlockEntity; +import net.minecraft.world.level.block.entity.BannerPatternLayers; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.LecternBlockEntity; import net.minecraft.world.level.chunk.ChunkAccess; @@ -62,6 +66,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -217,8 +222,8 @@ public class GeyserModWorldManager extends GeyserWorldManager { @NonNull @Override - public CompletableFuture getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) { - CompletableFuture future = new CompletableFuture<>(); + public CompletableFuture getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { + CompletableFuture future = new CompletableFuture<>(); server.execute(() -> { ServerPlayer player = getPlayer(session); if (player == null) { @@ -235,7 +240,22 @@ public class GeyserModWorldManager extends GeyserWorldManager { // the banner might have a custom name, both of which a Java client knows and caches ItemStack itemStack = banner.getItem(); - future.complete(null); // todo 1.20.5 + com.github.steveice10.mc.protocol.data.game.item.component.DataComponents components = + new com.github.steveice10.mc.protocol.data.game.item.component.DataComponents(new HashMap<>()); + + components.put(DataComponentType.DAMAGE, itemStack.getDamageValue()); + + Component customName = itemStack.getComponents().get(DataComponents.CUSTOM_NAME); + if (customName != null) { + components.put(DataComponentType.CUSTOM_NAME, toKyoriComponent(customName)); + } + + BannerPatternLayers pattern = itemStack.get(DataComponents.BANNER_PATTERNS); + if (pattern != null) { + components.put(DataComponentType.BANNER_PATTERNS, toPatternList(pattern)); + } + + future.complete(components); return; } future.complete(null); @@ -262,8 +282,7 @@ public class GeyserModWorldManager extends GeyserWorldManager { if (writtenBookContent != null) { return writtenBookContent.pages().stream() .map(Filterable::raw) - .map((component) -> Component.Serializer.toJson(component, RegistryAccess.EMPTY)) - .map((json -> LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty())))) + .map(GeyserModWorldManager::fromComponent) .toList(); } else { WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT); @@ -275,4 +294,25 @@ public class GeyserModWorldManager extends GeyserWorldManager { .toList(); } } + + private static String fromComponent(Component component) { + String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY); + return LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty())); + } + + private static net.kyori.adventure.text.Component toKyoriComponent(Component component) { + String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY); + return GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty()); + } + + private static List toPatternList(BannerPatternLayers patternLayers) { + return patternLayers.layers().stream() + .map(layer -> { + BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern( + layer.pattern().value().assetId().toString(), layer.pattern().value().translationKey() + ); + return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId()); + }) + .toList(); + } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 42f0d17f4..07a9d489a 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -26,8 +26,8 @@ package org.geysermc.geyser.platform.spigot.world.manager; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -39,7 +39,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.geysermc.erosion.bukkit.BukkitLecterns; import org.geysermc.erosion.bukkit.BukkitUtils; -import org.geysermc.erosion.bukkit.PickBlockUtils; import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.GameRule; @@ -205,8 +204,8 @@ public class GeyserSpigotWorldManager extends WorldManager { } @Override - public @NonNull CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) { - CompletableFuture<@Nullable CompoundTag> future = new CompletableFuture<>(); + public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { + CompletableFuture<@Nullable DataComponents> future = new CompletableFuture<>(); Player bukkitPlayer; if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { future.complete(null); @@ -215,7 +214,7 @@ public class GeyserSpigotWorldManager extends WorldManager { Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); // Paper 1.19.3 complains about async access otherwise. // java.lang.IllegalStateException: Tile is null, asynchronous access? - SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block); + SchedulerUtils.runTask(this.plugin, () -> future.complete(/*PickBlockUtils.pickBlock(block)*/ null), block); // TODO fix erosion once clear how to handle this return future; } diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index 3ae458f63..57147fc49 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.erosion; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import io.netty.channel.Channel; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; @@ -43,7 +43,14 @@ import org.geysermc.erosion.packet.ErosionPacketHandler; import org.geysermc.erosion.packet.ErosionPacketSender; import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket; import org.geysermc.erosion.packet.backendbound.BackendboundPacket; -import org.geysermc.erosion.packet.geyserbound.*; +import org.geysermc.erosion.packet.geyserbound.GeyserboundBatchBlockIdPacket; +import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockEntityPacket; +import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockIdPacket; +import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockLookupFailPacket; +import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockPlacePacket; +import org.geysermc.erosion.packet.geyserbound.GeyserboundHandshakePacket; +import org.geysermc.erosion.packet.geyserbound.GeyserboundPickBlockPacket; +import org.geysermc.erosion.packet.geyserbound.GeyserboundPistonEventPacket; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.network.GameProtocol; @@ -64,7 +71,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke @Setter private CompletableFuture pendingBatchLookup = null; @Setter - private CompletableFuture pickBlockLookup = null; + private CompletableFuture pickBlockLookup = null; private final AtomicInteger nextTransactionId = new AtomicInteger(1); @@ -140,7 +147,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke @Override public void handlePickBlock(GeyserboundPickBlockPacket packet) { if (this.pickBlockLookup != null) { - this.pickBlockLookup.complete(packet.getTag()); + //this.pickBlockLookup.complete(packet.getTag()); // TODO 1.20.5 } } diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 44c3b94b3..9a9eac2df 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -26,8 +26,8 @@ package org.geysermc.geyser.level; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -36,7 +36,11 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.erosion.packet.backendbound.*; +import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockEntityPacket; +import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockRequestPacket; +import org.geysermc.erosion.packet.backendbound.BackendboundBlockEntityPacket; +import org.geysermc.erosion.packet.backendbound.BackendboundBlockRequestPacket; +import org.geysermc.erosion.packet.backendbound.BackendboundPickBlockPacket; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.session.GeyserSession; @@ -174,12 +178,12 @@ public class GeyserWorldManager extends WorldManager { @NonNull @Override - public CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) { + public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { var erosionHandler = session.getErosionHandler().getAsActive(); if (erosionHandler == null) { - return super.getPickItemNbt(session, x, y, z, addNbtData); + return super.getPickItemComponents(session, x, y, z, addNbtData); } - CompletableFuture future = new CompletableFuture<>(); + CompletableFuture future = new CompletableFuture<>(); erosionHandler.setPickBlockLookup(future); erosionHandler.sendPacket(new BackendboundPickBlockPacket(Vector3i.from(x, y, z))); return future; diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index be7e2c139..aa0b43b80 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -26,9 +26,9 @@ package org.geysermc.geyser.level; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; @@ -220,7 +220,7 @@ public abstract class WorldManager { * @return expected NBT for this item. */ @NonNull - public CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) { + public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addExtraData) { return CompletableFuture.completedFuture(null); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 3781ef3c0..f4116ec0c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -26,9 +26,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket; import org.geysermc.geyser.entity.EntityDefinitions; @@ -68,33 +65,23 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator session.ensureInEventLoop(() -> { - if (tag == null) { + boolean addExtraData = packet.isAddUserData() && blockMapping.isBlockEntity(); // Holding down CTRL + if (BlockStateValues.getBannerColor(blockToPick) != -1 || addExtraData) { //TODO + session.getGeyser().getWorldManager().getPickItemComponents(session, vector.getX(), vector.getY(), vector.getZ(), addExtraData) + .whenComplete((components, ex) -> session.ensureInEventLoop(() -> { + if (components == null) { pickItem(session, blockMapping); return; } - if (addNbtData) { - ListTag lore = new ListTag("Lore"); - lore.add(new StringTag("", "\"(+NBT)\"")); - CompoundTag display = tag.get("display"); - if (display == null) { - display = new CompoundTag("display"); - tag.put(display); - } - display.put(lore); - } // I don't really like this... I'd rather get an ID from the block mapping I think ItemMapping mapping = session.getItemMappings().getMapping(blockMapping.getPickItem()); - ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), 1, tag); + ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), 1, components); InventoryUtils.findOrCreateItem(session, itemStack); })); return; - }*/ + } pickItem(session, blockMapping); } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b7e692ab7..f2e068c22 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "4ee05b62" # Revert from jitpack after release +mcprotocollib = "7026b600" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From b81408820b7308c6fa8a6bb218ff3627d4f70b93 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 23 Apr 2024 12:33:06 -0400 Subject: [PATCH 066/897] Refactor TagCache to be extensible Previously, for any new tag, we would have to add a field, add the line to load it, add the line to clear it, and make a method for that tag. Now, you just add an enum. --- .../entity/type/living/DolphinEntity.java | 5 +- .../type/living/animal/AxolotlEntity.java | 3 +- .../entity/type/living/animal/BeeEntity.java | 3 +- .../entity/type/living/animal/FoxEntity.java | 3 +- .../type/living/animal/MooshroomEntity.java | 4 +- .../type/living/animal/SnifferEntity.java | 3 +- .../type/living/monster/CreeperEntity.java | 5 +- .../type/living/monster/PiglinEntity.java | 3 +- .../geyser/session/cache/RegistryCache.java | 3 +- .../geyser/session/cache/TagCache.java | 188 +++++------------- .../geyser/session/cache/tags/BlockTag.java | 48 +++++ .../geyser/session/cache/tags/ItemTag.java | 47 +++++ .../translator/level/BiomeTranslator.java | 4 - .../org/geysermc/geyser/util/BlockUtils.java | 19 +- 14 files changed, 177 insertions(+), 161 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/tags/BlockTag.java create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/tags/ItemTag.java 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 f0348bcaf..a43bb666f 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 @@ -31,6 +31,7 @@ import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -49,7 +50,7 @@ public class DolphinEntity extends WaterEntity { @NonNull @Override protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { - if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) { + if (!itemInHand.isEmpty() && session.getTagCache().is(ItemTag.FISHES, itemInHand)) { return InteractiveTag.FEED; } return super.testMobInteraction(hand, itemInHand); @@ -58,7 +59,7 @@ public class DolphinEntity extends WaterEntity { @NonNull @Override protected InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { - if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) { + if (!itemInHand.isEmpty() && session.getTagCache().is(ItemTag.FISHES, itemInHand)) { // Feed return InteractionResult.SUCCESS; } 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 97753f63f..c4f95e546 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 @@ -36,6 +36,7 @@ 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.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; @@ -61,7 +62,7 @@ public class AxolotlEntity extends AnimalEntity { @Override public boolean canEat(Item item) { - return session.getTagCache().isAxolotlFood(item); + return session.getTagCache().is(ItemTag.AXOLOTL_FOOD, item); } @Override 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 e05b44cf0..7f1a88d7b 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 @@ -35,6 +35,7 @@ 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 java.util.UUID; @@ -67,6 +68,6 @@ public class BeeEntity extends AnimalEntity { @Override public boolean canEat(Item item) { - return session.getTagCache().isFlower(item); + return session.getTagCache().is(ItemTag.FLOWERS, item); } } 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 98c73cbce..200505f14 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 @@ -33,6 +33,7 @@ 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 java.util.UUID; @@ -56,6 +57,6 @@ public class FoxEntity extends AnimalEntity { @Override public boolean canEat(Item item) { - return session.getTagCache().isFoxFood(item); + return session.getTagCache().is(ItemTag.FOX_FOOD, item); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 1c347bf31..8673eb18e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -33,8 +33,8 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.item.type.FlowerItem; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -77,7 +77,7 @@ public class MooshroomEntity extends AnimalEntity { } else if (!isBaby && isAlive() && itemInHand.asItem() == Items.SHEARS) { // Shear items return InteractionResult.SUCCESS; - } else if (isBrown && session.getTagCache().isSmallFlower(itemInHand) && itemInHand.asItem() instanceof FlowerItem) { + } else if (isBrown && session.getTagCache().is(ItemTag.SMALL_FLOWERS, itemInHand)) { // ? return InteractionResult.SUCCESS; } 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 a97756e39..0e6fffbc0 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 @@ -39,6 +39,7 @@ 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 java.util.UUID; @@ -72,7 +73,7 @@ public class SnifferEntity extends AnimalEntity implements Tickable { @Override public boolean canEat(Item item) { - return session.getTagCache().isSnifferFood(item); + return session.getTagCache().is(ItemTag.SNIFFER_FOOD, item); } public void setSnifferState(ObjectEntityMetadata entityMetadata) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java index 33ea4e544..f134c31b3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java @@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -65,7 +66,7 @@ public class CreeperEntity extends MonsterEntity { @NonNull @Override protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { - if (session.getTagCache().isCreeperIgniter(itemInHand.asItem())) { + if (session.getTagCache().is(ItemTag.CREEPER_IGNITERS, itemInHand)) { return InteractiveTag.IGNITE_CREEPER; } else { return super.testMobInteraction(hand, itemInHand); @@ -75,7 +76,7 @@ public class CreeperEntity extends MonsterEntity { @NonNull @Override protected InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { - if (session.getTagCache().isCreeperIgniter(itemInHand.asItem())) { + if (session.getTagCache().is(ItemTag.CREEPER_IGNITERS, itemInHand)) { // Ignite creeper - as of 1.19.3 session.playSoundEvent(SoundEvent.IGNITE, position); return InteractionResult.SUCCESS; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java index 450c546ec..696982a33 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java @@ -35,6 +35,7 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -65,7 +66,7 @@ public class PiglinEntity extends BasePiglinEntity { @Override public void updateOffHand(GeyserSession session) { // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates - setFlag(EntityFlag.ADMIRING, session.getTagCache().shouldPiglinAdmire(session.getItemMappings().getMapping(this.offHand).getJavaItem())); + setFlag(EntityFlag.ADMIRING, session.getTagCache().is(ItemTag.PIGLIN_LOVED, session.getItemMappings().getMapping(this.offHand).getJavaItem())); super.updateBedrockMetadata(); super.updateOffHand(session); 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 d5293c5c3..d6d5ae292 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 @@ -57,7 +57,7 @@ import java.util.function.ToIntFunction; * Stores any information sent via Java registries. May not contain all data in a given registry - we'll strip what's * unneeded. * - * Crafted as of 1.20.5 for easy "add new registry" in the future. + * Crafted as of 1.20.5 for easy "add new registry" functionality in the future. */ @Accessors(fluent = true) @Getter @@ -118,6 +118,7 @@ public final class RegistryCache { REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> { Int2ObjectMap localCache = localCacheFunction.apply(registryCache); // Clear each local cache every time a new registry entry is given to us + // (e.g. proxy server switches) localCache.clear(); for (int i = 0; i < entries.size(); i++) { RegistryEntry entry = entries.get(i); 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 57000bf8b..b2f43f180 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 @@ -27,64 +27,45 @@ package org.geysermc.geyser.session.cache; import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import it.unimi.dsi.fastutil.ints.IntList; -import it.unimi.dsi.fastutil.ints.IntLists; -import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.BlockTag; +import org.geysermc.geyser.session.cache.tags.ItemTag; import javax.annotation.ParametersAreNonnullByDefault; +import java.util.EnumMap; +import java.util.HashMap; import java.util.Map; /** * Manages information sent from the {@link ClientboundUpdateTagsPacket}. If that packet is not sent, all lists here * will remain empty, matching Java Edition behavior. + * + * This system is designed for easy extensibility - just add an enum to {@link BlockTag} or {@link ItemTag}. */ @ParametersAreNonnullByDefault -public class TagCache { - /* Blocks */ - private IntList leaves; - private IntList wool; +public final class TagCache { + // Put these here so the enums can load without a static map + public static final Map ALL_BLOCK_TAGS = new HashMap<>(); + public static final Map ALL_ITEM_TAGS = new HashMap<>(); - private IntList axeEffective; - private IntList hoeEffective; - private IntList pickaxeEffective; - private IntList shovelEffective; - - private IntList requiresStoneTool; - private IntList requiresIronTool; - private IntList requiresDiamondTool; - - /* Items */ - private IntList axolotlFood; - private IntList creeperIgniters; - private IntList fishes; - private IntList flowers; - private IntList foxFood; - private IntList piglinLoved; - private IntList smallFlowers; - private IntList snifferFood; - - public TagCache() { - // Ensure all lists are non-null - clear(); - } + private final Map blocks = new EnumMap<>(BlockTag.class); + private final Map items = new EnumMap<>(ItemTag.class); public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) { Map blockTags = packet.getTags().get("minecraft:block"); - this.leaves = IntList.of(blockTags.get("minecraft:leaves")); - this.wool = IntList.of(blockTags.get("minecraft:wool")); - - this.axeEffective = IntList.of(blockTags.get("minecraft:mineable/axe")); - this.hoeEffective = IntList.of(blockTags.get("minecraft:mineable/hoe")); - this.pickaxeEffective = IntList.of(blockTags.get("minecraft:mineable/pickaxe")); - this.shovelEffective = IntList.of(blockTags.get("minecraft:mineable/shovel")); - - this.requiresStoneTool = IntList.of(blockTags.get("minecraft:needs_stone_tool")); - this.requiresIronTool = IntList.of(blockTags.get("minecraft:needs_iron_tool")); - this.requiresDiamondTool = IntList.of(blockTags.get("minecraft:needs_diamond_tool")); + this.blocks.clear(); + ALL_BLOCK_TAGS.forEach((location, tag) -> { + int[] values = blockTags.get(location); + if (values != null) { + this.blocks.put(tag, IntList.of(values)); + } else { + session.getGeyser().getLogger().debug("Block tag not found from server: " + location); + } + }); // Hack btw GeyserLogger logger = session.getGeyser().getLogger(); @@ -96,14 +77,15 @@ public class TagCache { } Map itemTags = packet.getTags().get("minecraft:item"); - this.axolotlFood = IntList.of(itemTags.get("minecraft:axolotl_food")); - this.creeperIgniters = load(itemTags.get("minecraft:creeper_igniters")); - this.fishes = IntList.of(itemTags.get("minecraft:fishes")); - this.flowers = IntList.of(itemTags.get("minecraft:flowers")); - this.foxFood = IntList.of(itemTags.get("minecraft:fox_food")); - this.piglinLoved = IntList.of(itemTags.get("minecraft:piglin_loved")); - this.smallFlowers = IntList.of(itemTags.get("minecraft:small_flowers")); - this.snifferFood = load(itemTags.get("minecraft:sniffer_food")); + this.items.clear(); + ALL_ITEM_TAGS.forEach((location, tag) -> { + int[] values = itemTags.get(location); + if (values != null) { + this.items.put(tag, IntList.of(values)); + } else { + session.getGeyser().getLogger().debug("Item tag not found from server: " + location); + } + }); // Hack btw boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1; @@ -113,98 +95,32 @@ public class TagCache { } } - private IntList load(int @Nullable[] tags) { - if (tags == null) { - return IntLists.EMPTY_LIST; + /** + * @return true if the block tag is present and contains this block mapping's Java ID. + */ + public boolean is(BlockTag tag, BlockMapping mapping) { + IntList values = this.blocks.get(tag); + if (values != null) { + return values.contains(mapping.getJavaBlockId()); } - return IntList.of(tags); + return false; } - public void clear() { - this.leaves = IntLists.emptyList(); - this.wool = IntLists.emptyList(); - - this.axeEffective = IntLists.emptyList(); - this.hoeEffective = IntLists.emptyList(); - this.pickaxeEffective = IntLists.emptyList(); - this.shovelEffective = IntLists.emptyList(); - - this.requiresStoneTool = IntLists.emptyList(); - this.requiresIronTool = IntLists.emptyList(); - this.requiresDiamondTool = IntLists.emptyList(); - - this.axolotlFood = IntLists.emptyList(); - this.creeperIgniters = IntLists.emptyList(); - this.fishes = IntLists.emptyList(); - this.flowers = IntLists.emptyList(); - this.foxFood = IntLists.emptyList(); - this.piglinLoved = IntLists.emptyList(); - this.smallFlowers = IntLists.emptyList(); - this.snifferFood = IntLists.emptyList(); + /** + * @return true if the item tag is present and contains this item stack's Java ID. + */ + public boolean is(ItemTag tag, GeyserItemStack itemStack) { + return is(tag, itemStack.asItem()); } - public boolean isAxolotlFood(Item item) { - return axolotlFood.contains(item.javaId()); - } - - public boolean isCreeperIgniter(Item item) { - return creeperIgniters.contains(item.javaId()); - } - - public boolean isFish(GeyserItemStack itemStack) { - return fishes.contains(itemStack.getJavaId()); - } - - public boolean isFlower(Item item) { - return flowers.contains(item.javaId()); - } - - public boolean isFoxFood(Item item) { - return foxFood.contains(item.javaId()); - } - - public boolean shouldPiglinAdmire(Item item) { - return piglinLoved.contains(item.javaId()); - } - - public boolean isSmallFlower(GeyserItemStack itemStack) { - return smallFlowers.contains(itemStack.getJavaId()); - } - - public boolean isSnifferFood(Item item) { - return snifferFood.contains(item.javaId()); - } - - public boolean isAxeEffective(BlockMapping blockMapping) { - return axeEffective.contains(blockMapping.getJavaBlockId()); - } - - public boolean isHoeEffective(BlockMapping blockMapping) { - return hoeEffective.contains(blockMapping.getJavaBlockId()); - } - - public boolean isPickaxeEffective(BlockMapping blockMapping) { - return pickaxeEffective.contains(blockMapping.getJavaBlockId()); - } - - public boolean isShovelEffective(BlockMapping blockMapping) { - return shovelEffective.contains(blockMapping.getJavaBlockId()); - } - - public boolean isShearsEffective(BlockMapping blockMapping) { - int javaBlockId = blockMapping.getJavaBlockId(); - return leaves.contains(javaBlockId) || wool.contains(javaBlockId); - } - - public boolean requiresStoneTool(BlockMapping blockMapping) { - return requiresStoneTool.contains(blockMapping.getJavaBlockId()); - } - - public boolean requiresIronTool(BlockMapping blockMapping) { - return requiresIronTool.contains(blockMapping.getJavaBlockId()); - } - - public boolean requiresDiamondTool(BlockMapping blockMapping) { - return requiresDiamondTool.contains(blockMapping.getJavaBlockId()); + /** + * @return true if the item tag is present and contains this item's Java ID. + */ + public boolean is(ItemTag tag, Item item) { + IntList values = this.items.get(tag); + if (values != null) { + return values.contains(item.javaId()); + } + return false; } } 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 new file mode 100644 index 000000000..7017ad55c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/BlockTag.java @@ -0,0 +1,48 @@ +/* + * 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.session.cache.tags; + +import org.geysermc.geyser.session.cache.TagCache; + +public enum BlockTag { + LEAVES("leaves"), + WOOL("wool"), + AXE_EFFECTIVE("mineable/axe"), + HOE_EFFECTIVE("mineable/hoe"), + PICKAXE_EFFECTIVE("mineable/pickaxe"), + SHOVEL_EFFECTIVE("mineable/shovel"), + NEEDS_STONE_TOOL("needs_stone_tool"), + NEEDS_IRON_TOOL("needs_iron_tool"), + NEEDS_DIAMOND_TOOL("needs_diamond_tool"); + + BlockTag(String identifier) { + register(identifier, this); + } + + private static void register(String name, BlockTag tag) { + TagCache.ALL_BLOCK_TAGS.put("minecraft:" + name, tag); + } +} 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 new file mode 100644 index 000000000..df9a423ed --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/ItemTag.java @@ -0,0 +1,47 @@ +/* + * 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.session.cache.tags; + +import org.geysermc.geyser.session.cache.TagCache; + +public enum ItemTag { + AXOLOTL_FOOD("axolotl_food"), + CREEPER_IGNITERS("creeper_igniters"), + FISHES("fishes"), + FLOWERS("flowers"), + FOX_FOOD("fox_food"), + PIGLIN_LOVED("piglin_loved"), + SMALL_FLOWERS("small_flowers"), + SNIFFER_FOOD("sniffer_food"); + + ItemTag(String identifier) { + register(identifier, this); + } + + private static void register(String name, ItemTag tag) { + TagCache.ALL_ITEM_TAGS.put("minecraft:" + name, tag); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index fce928bdb..450c786f2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -47,10 +47,6 @@ public class BiomeTranslator { public static int loadServerBiome(RegistryEntry entry) { String javaIdentifier = entry.getId(); return Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); -// if (javaId == 0) { -// // Matches Java behavior when it sees an invalid biome - it just replaces it with ID 0 -// biomeTranslations.defaultReturnValue(bedrockId); -// } } public static BlockStorage toNewBedrockBiome(GeyserSession session, DataPalette biomeData) { 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 da98f45c7..8392f9fcd 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -36,17 +36,18 @@ import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.BlockTag; import org.geysermc.geyser.translator.collision.BlockCollision; public final class BlockUtils { private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) { return switch (itemToolType) { - case "axe" -> session.getTagCache().isAxeEffective(blockMapping); - case "hoe" -> session.getTagCache().isHoeEffective(blockMapping); - case "pickaxe" -> session.getTagCache().isPickaxeEffective(blockMapping); - case "shears" -> session.getTagCache().isShearsEffective(blockMapping); - case "shovel" -> session.getTagCache().isShovelEffective(blockMapping); + case "axe" -> session.getTagCache().is(BlockTag.AXE_EFFECTIVE, blockMapping); + case "hoe" -> session.getTagCache().is(BlockTag.HOE_EFFECTIVE, blockMapping); + case "pickaxe" -> session.getTagCache().is(BlockTag.PICKAXE_EFFECTIVE, blockMapping); + case "shears" -> session.getTagCache().is(BlockTag.LEAVES, blockMapping) || session.getTagCache().is(BlockTag.WOOL, blockMapping); + case "shovel" -> session.getTagCache().is(BlockTag.SHOVEL_EFFECTIVE, blockMapping); case "sword" -> blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID; default -> { session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType); @@ -79,15 +80,15 @@ public final class BlockUtils { switch (toolTier) { // Use intentional fall-throughs to check each tier with this block default: - if (session.getTagCache().requiresStoneTool(blockMapping)) { + if (session.getTagCache().is(BlockTag.NEEDS_STONE_TOOL, blockMapping)) { return false; } case "stone": - if (session.getTagCache().requiresIronTool(blockMapping)) { + if (session.getTagCache().is(BlockTag.NEEDS_IRON_TOOL, blockMapping)) { return false; } case "iron": - if (session.getTagCache().requiresDiamondTool(blockMapping)) { + if (session.getTagCache().is(BlockTag.NEEDS_DIAMOND_TOOL, blockMapping)) { return false; } } @@ -131,7 +132,7 @@ public final class BlockUtils { } public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { - boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice + boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, blockMapping) || session.getTagCache().is(BlockTag.WOOL, blockMapping); //TODO called twice boolean canHarvestWithHand = blockMapping.isCanBreakWithHand(); String toolType = ""; String toolTier = ""; From d105dadf62a79d6f81e6829f1919545dce745c4a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 23 Apr 2024 12:36:39 -0400 Subject: [PATCH 067/897] Update for release. STILL NOT READY YET THOUGH --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f2e068c22..bbb6045f5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "7026b600" # Revert from jitpack after release +mcprotocollib = "3c81cc80" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From abea0131e41e62fe76f750f8e7a1e08a73b32eb2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:08:26 -0400 Subject: [PATCH 068/897] Fix llama carpets --- .../geyser/entity/EntityDefinitions.java | 1 - .../type/living/animal/horse/LlamaEntity.java | 27 ------------------- .../populator/ItemRegistryPopulator.java | 10 ------- .../geyser/registry/type/ItemMappings.java | 1 - .../entity/JavaSetEquipmentTranslator.java | 3 ++- 5 files changed, 2 insertions(+), 40 deletions(-) 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 6b243212d..d825daa8a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -938,7 +938,6 @@ public final class EntityDefinitions { .type(EntityType.LLAMA) .height(1.87f).width(0.9f) .addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.STRENGTH, entityMetadata.getValue())) - .addTranslator(MetadataType.INT, LlamaEntity::setCarpetedColor) .addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.VARIANT, entityMetadata.getValue())) .build(); TRADER_LLAMA = EntityDefinition.inherited(TraderLlamaEntity::new, LLAMA) 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 a32d7b1b5..7fcada504 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 @@ -25,11 +25,8 @@ package org.geysermc.geyser.entity.type.living.animal.horse; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; -import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; -import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; @@ -45,30 +42,6 @@ public class LlamaEntity extends ChestedHorseEntity { dirtyMetadata.put(EntityDataTypes.CONTAINER_STRENGTH_MODIFIER, 3); // Presumably 3 slots for every 1 strength } - /** - * Color equipped on the llama - */ - public void setCarpetedColor(IntEntityMetadata entityMetadata) { - // Bedrock treats llama decoration as armor - MobArmorEquipmentPacket equipmentPacket = new MobArmorEquipmentPacket(); - equipmentPacket.setRuntimeEntityId(geyserId); - // -1 means no armor - int carpetIndex = entityMetadata.getPrimitiveValue(); - if (carpetIndex > -1 && carpetIndex <= 15) { - // The damage value is the dye color that Java sends us, for pre-1.16.220 - // The item is always going to be a carpet - equipmentPacket.setChestplate(session.getItemMappings().getCarpets().get(carpetIndex)); - } else { - equipmentPacket.setChestplate(ItemData.AIR); - } - // Required to fill out the rest of the equipment or Bedrock ignores it, including above else statement if removing armor - equipmentPacket.setBoots(ItemData.AIR); - equipmentPacket.setHelmet(ItemData.AIR); - equipmentPacket.setLeggings(ItemData.AIR); - - session.sendUpstreamPacket(equipmentPacket); - } - @Override public boolean canEat(Item item) { return item == Items.WHEAT || item == Items.HAY_BLOCK; diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 5b64da7a1..d3a4bed84 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -159,7 +159,6 @@ public class ItemRegistryPopulator { Object2ObjectMap customBlockItemDefinitions = new Object2ObjectOpenHashMap<>(); List buckets = new ObjectArrayList<>(); - List carpets = new ObjectArrayList<>(); List mappings = new ObjectArrayList<>(); // Temporary mapping to create stored items @@ -458,14 +457,6 @@ public class ItemRegistryPopulator { if (javaItem.javaIdentifier().contains("bucket") && !javaItem.javaIdentifier().contains("milk")) { buckets.add(definition); - } else if (javaItem.javaIdentifier().contains("_carpet") && !javaItem.javaIdentifier().contains("moss")) { - // This should be the numerical order Java sends as an integer value for llamas - carpets.add(ItemData.builder() - .definition(definition) - .damage(mapping.getBedrockData()) - .count(1) - .blockDefinition(mapping.getBedrockBlockDefinition()) - .build()); } else if (javaItem.javaIdentifier().startsWith("minecraft:music_disc_")) { // The Java record level event uses the item ID as the "key" to play the record Registries.RECORDS.register(javaItem.javaId(), SoundEvent.valueOf("RECORD_" + @@ -589,7 +580,6 @@ public class ItemRegistryPopulator { .storedItems(new StoredItemMappings(javaItemToMapping)) .javaOnlyItems(javaOnlyItems) .buckets(buckets) - .carpets(carpets) .componentItemData(componentItemData) .lodestoneCompass(lodestoneEntry) .customIdMappings(customIdMappings) diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index 33908a7e7..5df969111 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -69,7 +69,6 @@ public class ItemMappings implements DefinitionRegistry { List buckets; List boats; - List carpets; List componentItemData; Int2ObjectMap customIdMappings; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index b0168a4ce..7c93725e0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -74,7 +74,8 @@ public class JavaSetEquipmentTranslator extends PacketTranslator { + case CHESTPLATE, BODY -> { + // BODY is sent for llamas with a carpet equipped, as of 1.20.5 livingEntity.setChestplate(item); armorUpdated = true; } From c54624fb2632dd5dc60626eb55ea830b3818836c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:14:18 -0400 Subject: [PATCH 069/897] Fix some cases of empty tags being needed --- .../level/block/entity/BlockEntityTranslator.java | 8 ++++++-- .../level/JavaLevelChunkWithLightTranslator.java | 12 ++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java index 7566e0d90..053e2c8f3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java @@ -43,12 +43,16 @@ public abstract class BlockEntityTranslator { public abstract void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState); public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, CompoundTag tag, int blockState) { - NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(type), x, y, z); + NbtMapBuilder tagBuilder = getConstantBedrockTag(type, x, y, z); translateTag(tagBuilder, tag, blockState); return tagBuilder.build(); } - protected NbtMapBuilder getConstantBedrockTag(String bedrockId, int x, int y, int z) { + public static NbtMapBuilder getConstantBedrockTag(BlockEntityType type, int x, int y, int z) { + return getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(type), x, y, z); + } + + public static NbtMapBuilder getConstantBedrockTag(String bedrockId, int x, int y, int z) { return NbtMap.builder() .putInt("x", x) .putInt("y", y) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index fc1d0316c..1e6534130 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -393,10 +393,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator Date: Tue, 23 Apr 2024 23:04:38 +0200 Subject: [PATCH 070/897] target 1.20.5 release, build neoforge again --- .github/workflows/build-remote.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/preview.yml | 2 +- README.md | 2 +- bootstrap/mod/build.gradle.kts | 3 +-- bootstrap/mod/fabric/src/main/resources/fabric.mod.json | 2 +- .../mod/neoforge/src/main/resources/META-INF/mods.toml | 4 ++-- .../src/main/kotlin/geyser.modded-conventions.gradle.kts | 4 ++-- build.gradle.kts | 2 +- gradle/libs.versions.toml | 8 ++++---- settings.gradle.kts | 4 ++-- 11 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build-remote.yml b/.github/workflows/build-remote.yml index 09326d429..d49920785 100644 --- a/.github/workflows/build-remote.yml +++ b/.github/workflows/build-remote.yml @@ -64,7 +64,7 @@ jobs: with: name: Geyser NeoForge path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar - #if-no-files-found: error // TODO 1.20.5 until neoforge updates + if-no-files-found: error - name: Archive artifacts (Geyser Standalone) uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 if: success() diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfb509f30..284fa265a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,7 +68,7 @@ jobs: with: name: Geyser NeoForge path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar - #if-no-files-found: error // TODO 1.20.5 - currently no neoforge artifacts + if-no-files-found: error - name: Archive artifacts (Geyser Standalone) uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 if: success() diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index a33c71a79..13712d5ef 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -53,10 +53,10 @@ jobs: with: appID: ${{ secrets.RELEASE_APP_ID }} appPrivateKey: ${{ secrets.RELEASE_APP_PK }} - # neoforge:Geyser-NeoForge.jar // TODO 1.20.5 files: | bungeecord:Geyser-BungeeCord.jar fabric:Geyser-Fabric.jar + neoforge:Geyser-NeoForge.jar spigot:Geyser-Spigot.jar standalone:Geyser-Standalone.jar velocity:Geyser-Velocity.jar diff --git a/README.md b/README.md index e17c9d2bb..314876d60 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80 and Minecraft Java 1.20.4 +### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80 and Minecraft Java 1.20.5 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/bootstrap/mod/build.gradle.kts b/bootstrap/mod/build.gradle.kts index 281fd45e7..7651a2df2 100644 --- a/bootstrap/mod/build.gradle.kts +++ b/bootstrap/mod/build.gradle.kts @@ -1,6 +1,5 @@ architectury { - common("fabric") - //common("neoforge", "fabric") // todo 1.20.5 + common("neoforge", "fabric") } loom { diff --git a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json index 7fb6b302c..93f48b73c 100644 --- a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json @@ -25,6 +25,6 @@ "depends": { "fabricloader": ">=0.15.10", "fabric": "*", - "minecraft": ">=1.20.4" + "minecraft": ">=1.20.5" } } diff --git a/bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml b/bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml index 2f9e9b12e..1110568e8 100644 --- a/bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml +++ b/bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml @@ -14,12 +14,12 @@ config = "geyser.mixins.json" [[dependencies.geyser_neoforge]] modId="neoforge" type="required" - versionRange="[20.4.48-beta,)" + versionRange="[20.5.0-beta,)" ordering="NONE" side="BOTH" [[dependencies.geyser_neoforge]] modId="minecraft" type="required" - versionRange="[1.20,1.21)" + versionRange="[1.20.4,1.21)" ordering="NONE" side="BOTH" \ No newline at end of file diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index c83ea2911..afea247a7 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -39,7 +39,7 @@ provided("io.netty", "netty-resolver-dns-native-macos") provided("org.ow2.asm", "asm") architectury { - minecraft = "1.20.4" + minecraft = "1.20.5" } loom { @@ -110,7 +110,7 @@ afterEvaluate { } dependencies { - minecraft("com.mojang:minecraft:1.20.5-rc3") + minecraft("com.mojang:minecraft:1.20.5") mappings(loom.officialMojangMappings()) } diff --git a/build.gradle.kts b/build.gradle.kts index fdacd5538..dfdff2187 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,7 +22,7 @@ val basePlatforms = setOf( val moddedPlatforms = setOf( projects.fabric, - //projects.neoforge, // todo 1.20.5 + projects.neoforge, projects.mod ).map { it.dependencyProject } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bbb6045f5..2b6df11a6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,11 +30,11 @@ commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.1.1" viaproxy = "3.2.0-SNAPSHOT" -fabric-minecraft = "1.20.4" -fabric-loader = "0.15.2" -fabric-api = "0.91.2+1.20.4" +fabric-minecraft = "1.20.5" +fabric-loader = "0.15.10" +fabric-api = "0.97.6+1.20.5" fabric-permissions = "0.2-SNAPSHOT" -neoforge-minecraft = "20.4.48-beta" +neoforge-minecraft = "20.5.0-beta" mixin = "0.8.5" # plugin versions diff --git a/settings.gradle.kts b/settings.gradle.kts index 3867d7a84..a39bfa3d2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -66,7 +66,7 @@ include(":ap") include(":api") include(":bungeecord") include(":fabric") -//include(":neoforge") // todo 1.20.5 +include(":neoforge") include(":mod") include(":spigot") include(":standalone") @@ -78,7 +78,7 @@ include(":core") // Specify project dirs project(":bungeecord").projectDir = file("bootstrap/bungeecord") project(":fabric").projectDir = file("bootstrap/mod/fabric") -//project(":neoforge").projectDir = file("bootstrap/mod/neoforge") // todo 1.20.5 +project(":neoforge").projectDir = file("bootstrap/mod/neoforge") project(":mod").projectDir = file("bootstrap/mod") project(":spigot").projectDir = file("bootstrap/spigot") project(":standalone").projectDir = file("bootstrap/standalone") From bbaffb2ab38a825c0ab4ec7a360bf0ac831fa773 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 23 Apr 2024 19:12:20 -0400 Subject: [PATCH 071/897] Wolf interactions --- .../living/animal/tameable/WolfEntity.java | 25 ++++++++++++++----- .../geysermc/geyser/util/InteractiveTag.java | 5 +++- 2 files changed, 23 insertions(+), 7 deletions(-) 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 ee7281772..ff130aeff 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 @@ -133,16 +133,29 @@ public class WolfEntity extends TameableEntity { if (itemInHand.asItem() == Items.BONE && !getFlag(EntityFlag.TAMED)) { // Bone and untamed - can tame return InteractiveTag.TAME; - } else { - if (itemInHand.asItem() instanceof DyeItem item) { + } + if (getFlag(EntityFlag.TAMED) && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { + if (itemInHand.asItem() instanceof DyeItem dyeItem) { // If this fails, as of Java Edition 1.18.1, you cannot toggle sit/stand - if (item.dyeColor() != this.collarColor) { + if (dyeItem.dyeColor() != this.collarColor) { return InteractiveTag.DYE; + } else { + return super.testMobInteraction(hand, itemInHand); } - } else if (getFlag(EntityFlag.TAMED) && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { - // Tamed and owned by player - can sit/stand - return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; } + if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.chestplate.isValid() && !getFlag(EntityFlag.BABY)) { + return InteractiveTag.EQUIP_WOLF_ARMOR; + } + if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid()) { // TODO: check curse of binding + return InteractiveTag.REMOVE_WOLF_ARMOR; + } + if (Items.WOLF_ARMOR.isValidRepairItem(itemInHand.asItem()) && getFlag(EntityFlag.SITTING) && + this.chestplate.isValid() && this.chestplate.getTag() != null && + this.chestplate.getTag().getInt("Damage") > 0) { + return InteractiveTag.REPAIR_WOLF_ARMOR; + } + // Tamed and owned by player - can sit/stand + return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; } return super.testMobInteraction(hand, itemInHand); } diff --git a/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java b/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java index 9607ac61e..168c861f5 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java +++ b/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java @@ -70,7 +70,10 @@ public enum InteractiveTag { READ, WAKE_VILLAGER("wakevillager"), BARTER, - GIVE_ITEM_TO_ALLAY("allay"); + GIVE_ITEM_TO_ALLAY("allay"), + EQUIP_WOLF_ARMOR("equipwolfarmor"), + REMOVE_WOLF_ARMOR("removewolfarmor"), + REPAIR_WOLF_ARMOR("repairwolfarmor"); /** * The full string that should be passed on to the client. From a1534e45350f8787f49c8d07aacdfa683b65dbb4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 23 Apr 2024 20:11:32 -0400 Subject: [PATCH 072/897] Basic Armadillo structure --- .../geyser/entity/EntityDefinitions.java | 6 +++ .../type/living/animal/ArmadilloEntity.java | 38 +++++++++++++++++++ .../geyser/registry/type/ItemMappings.java | 4 +- 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java 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 d825daa8a..9563e6d37 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -53,6 +53,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator; public final class EntityDefinitions { 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; @@ -770,6 +771,11 @@ public final class EntityDefinitions { // Extends ageable { + ARMADILLO = EntityDefinition.inherited(ArmadilloEntity::new, ageableEntityBase) + .type(EntityType.ARMADILLO) + .height(0.65f).width(0.7f) + .addTranslator(null) + .build(); AXOLOTL = EntityDefinition.inherited(AxolotlEntity::new, ageableEntityBase) .type(EntityType.AXOLOTL) .height(0.42f).width(0.7f) 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 new file mode 100644 index 000000000..d89b4e3f7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java @@ -0,0 +1,38 @@ +/* + * 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.entity.type.living.animal; + +import org.cloudburstmc.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.UUID; + +public class ArmadilloEntity extends AnimalEntity { + public ArmadilloEntity(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/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index 5df969111..199481cbc 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -98,9 +98,9 @@ public class ItemMappings implements DefinitionRegistry { return javaId >= 0 && javaId < this.items.length ? this.items[javaId] : ItemMapping.AIR; } - @Nullable + @NonNull public ItemMapping getMapping(Item javaItem) { - return getMapping(javaItem.javaIdentifier()); + return getMapping(javaItem.javaId()); } /** From 9490a091b576155b8d60a9216a6d0192153143a3 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 23 Apr 2024 20:43:46 -0400 Subject: [PATCH 073/897] Calculate horse inventory size --- .../geysermc/geyser/entity/EntityDefinitions.java | 2 +- .../type/living/animal/horse/LlamaEntity.java | 13 +++++++++++++ .../inventory/JavaHorseScreenOpenTranslator.java | 14 ++++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) 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 9563e6d37..f454bef88 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -943,7 +943,7 @@ public final class EntityDefinitions { LLAMA = EntityDefinition.inherited(LlamaEntity::new, chestedHorseEntityBase) .type(EntityType.LLAMA) .height(1.87f).width(0.9f) - .addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.STRENGTH, entityMetadata.getValue())) + .addTranslator(MetadataType.INT, LlamaEntity::setStrength) .addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.VARIANT, entityMetadata.getValue())) .build(); TRADER_LLAMA = EntityDefinition.inherited(TraderLlamaEntity::new, LLAMA) 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 7fcada504..29da2e0dc 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 @@ -25,16 +25,24 @@ package org.geysermc.geyser.entity.type.living.animal.horse; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import lombok.Getter; 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.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.MathUtils; import java.util.UUID; public class LlamaEntity extends ChestedHorseEntity { + /** + * Used to calculate inventory size + */ + @Getter + private int strength = 1; public LlamaEntity(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); @@ -42,6 +50,11 @@ public class LlamaEntity extends ChestedHorseEntity { dirtyMetadata.put(EntityDataTypes.CONTAINER_STRENGTH_MODIFIER, 3); // Presumably 3 slots for every 1 strength } + public void setStrength(IntEntityMetadata entityMetadata) { + strength = MathUtils.constrain(entityMetadata.getPrimitiveValue(), 1, 5); + this.dirtyMetadata.put(EntityDataTypes.STRENGTH, strength); + } + @Override public boolean canEat(Item item) { return item == Items.WHEAT || item == Items.HAY_BLOCK; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java index 33cfeaf31..d2abcb5e3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java @@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.Cli import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.packet.UpdateEquipPacket; import org.geysermc.geyser.entity.type.Entity; @@ -114,16 +115,25 @@ public class JavaHorseScreenOpenTranslator extends PacketTranslator Date: Wed, 24 Apr 2024 16:39:35 -0400 Subject: [PATCH 074/897] Move MCProtocolLib to dev - package ID change --- .../mod/world/GeyserModWorldManager.java | 18 +++--- .../platform/spigot/GeyserSpigotInjector.java | 2 +- .../platform/spigot/PaperAdventure.java | 2 +- .../spigot/world/GeyserPistonListener.java | 2 +- .../manager/GeyserSpigotWorldManager.java | 6 +- .../java/org/geysermc/geyser/GeyserImpl.java | 2 +- .../command/defaults/StatisticsCommand.java | 4 +- .../geyser/dump/BootstrapDumpInfo.java | 2 +- .../org/geysermc/geyser/dump/DumpInfo.java | 7 +-- .../geyser/entity/EntityDefinition.java | 6 +- .../geyser/entity/EntityDefinitions.java | 8 +-- .../entity/type/AbstractArrowEntity.java | 4 +- .../entity/type/AreaEffectCloudEntity.java | 6 +- .../geyser/entity/type/BoatEntity.java | 9 ++- .../geyser/entity/type/ChestBoatEntity.java | 2 +- .../type/CommandBlockMinecartEntity.java | 2 +- .../type/DefaultBlockMinecartEntity.java | 4 +- .../entity/type/EnderCrystalEntity.java | 2 +- .../geysermc/geyser/entity/type/Entity.java | 27 +++------ .../entity/type/FallingBlockEntity.java | 2 +- .../geyser/entity/type/FireworkEntity.java | 6 +- .../geyser/entity/type/FishingHookEntity.java | 4 +- .../entity/type/FurnaceMinecartEntity.java | 4 +- .../geyser/entity/type/InteractionEntity.java | 8 +-- .../geyser/entity/type/ItemEntity.java | 4 +- .../geyser/entity/type/ItemFrameEntity.java | 14 ++--- .../geyser/entity/type/LeashKnotEntity.java | 2 +- .../geyser/entity/type/LivingEntity.java | 16 ++--- .../geyser/entity/type/MinecartEntity.java | 6 +- .../geyser/entity/type/PaintingEntity.java | 6 +- .../geyser/entity/type/TNTEntity.java | 2 +- .../geyser/entity/type/TextDisplayEntity.java | 4 +- .../geyser/entity/type/ThrowableEntity.java | 2 +- .../entity/type/ThrowableItemEntity.java | 4 +- .../entity/type/ThrownPotionEntity.java | 10 ++-- .../geyser/entity/type/TippedArrowEntity.java | 2 +- .../geyser/entity/type/WitherSkullEntity.java | 2 +- .../type/living/AbstractFishEntity.java | 2 +- .../entity/type/living/AgeableEntity.java | 2 +- .../entity/type/living/AllayEntity.java | 4 +- .../entity/type/living/ArmorStandEntity.java | 8 +-- .../geyser/entity/type/living/BatEntity.java | 2 +- .../entity/type/living/DolphinEntity.java | 2 +- .../entity/type/living/IronGolemEntity.java | 2 +- .../geyser/entity/type/living/MobEntity.java | 4 +- .../entity/type/living/SlimeEntity.java | 2 +- .../entity/type/living/SnowGolemEntity.java | 4 +- .../entity/type/living/TadpoleEntity.java | 2 +- .../type/living/animal/AnimalEntity.java | 2 +- .../type/living/animal/AxolotlEntity.java | 6 +- .../entity/type/living/animal/BeeEntity.java | 4 +- .../entity/type/living/animal/CowEntity.java | 2 +- .../entity/type/living/animal/FoxEntity.java | 4 +- .../entity/type/living/animal/FrogEntity.java | 6 +- .../entity/type/living/animal/GoatEntity.java | 6 +- .../type/living/animal/HoglinEntity.java | 2 +- .../type/living/animal/MooshroomEntity.java | 4 +- .../type/living/animal/OcelotEntity.java | 2 +- .../type/living/animal/PandaEntity.java | 6 +- .../entity/type/living/animal/PigEntity.java | 2 +- .../type/living/animal/PufferFishEntity.java | 2 +- .../type/living/animal/RabbitEntity.java | 2 +- .../type/living/animal/SheepEntity.java | 4 +- .../type/living/animal/SnifferEntity.java | 6 +- .../type/living/animal/StriderEntity.java | 4 +- .../living/animal/TropicalFishEntity.java | 4 +- .../type/living/animal/TurtleEntity.java | 2 +- .../animal/horse/AbstractHorseEntity.java | 4 +- .../type/living/animal/horse/CamelEntity.java | 6 +- .../type/living/animal/horse/HorseEntity.java | 2 +- .../type/living/animal/horse/LlamaEntity.java | 2 +- .../animal/horse/SkeletonHorseEntity.java | 2 +- .../animal/horse/ZombieHorseEntity.java | 2 +- .../living/animal/tameable/CatEntity.java | 8 +-- .../living/animal/tameable/ParrotEntity.java | 2 +- .../animal/tameable/TameableEntity.java | 6 +- .../living/animal/tameable/WolfEntity.java | 6 +- .../merchant/AbstractMerchantEntity.java | 2 +- .../type/living/merchant/VillagerEntity.java | 4 +- .../monster/AbstractSkeletonEntity.java | 2 +- .../type/living/monster/BasePiglinEntity.java | 2 +- .../type/living/monster/BlazeEntity.java | 2 +- .../type/living/monster/CreeperEntity.java | 6 +- .../living/monster/EnderDragonEntity.java | 10 +--- .../type/living/monster/EndermanEntity.java | 4 +- .../type/living/monster/GhastEntity.java | 2 +- .../type/living/monster/GuardianEntity.java | 2 +- .../type/living/monster/PhantomEntity.java | 2 +- .../type/living/monster/PiglinEntity.java | 4 +- .../type/living/monster/ShulkerEntity.java | 6 +- .../type/living/monster/SkeletonEntity.java | 2 +- .../type/living/monster/SpiderEntity.java | 2 +- .../entity/type/living/monster/VexEntity.java | 2 +- .../type/living/monster/WardenEntity.java | 4 +- .../type/living/monster/WitherEntity.java | 2 +- .../type/living/monster/ZoglinEntity.java | 2 +- .../type/living/monster/ZombieEntity.java | 2 +- .../living/monster/ZombieVillagerEntity.java | 8 +-- .../raid/SpellcasterIllagerEntity.java | 2 +- .../living/monster/raid/VindicatorEntity.java | 2 +- .../entity/type/player/PlayerEntity.java | 31 +++++----- .../type/player/SessionPlayerEntity.java | 14 ++--- .../entity/type/player/SkullPlayerEntity.java | 2 +- .../erosion/GeyserboundPacketHandlerImpl.java | 4 +- .../geyser/impl/camera/GeyserCameraData.java | 13 +---- .../geyser/impl/camera/GeyserCameraFade.java | 2 +- .../geyser/inventory/AnvilContainer.java | 4 +- .../geyser/inventory/BeaconContainer.java | 2 +- .../inventory/CartographyContainer.java | 2 +- .../geysermc/geyser/inventory/Container.java | 2 +- .../geyser/inventory/CrafterContainer.java | 2 +- .../geyser/inventory/EnchantingContainer.java | 2 +- .../geyser/inventory/Generic3X3Container.java | 2 +- .../geyser/inventory/GeyserItemStack.java | 6 +- .../geysermc/geyser/inventory/Inventory.java | 6 +- .../geyser/inventory/LecternContainer.java | 2 +- .../geyser/inventory/MerchantContainer.java | 6 +- .../geyser/inventory/PlayerInventory.java | 2 +- .../inventory/StonecutterContainer.java | 2 +- .../geyser/inventory/click/Click.java | 2 +- .../geyser/inventory/click/ClickPlan.java | 10 ++-- .../geyser/inventory/recipe/GeyserRecipe.java | 2 +- .../inventory/recipe/GeyserShapedRecipe.java | 6 +- .../recipe/GeyserShapelessRecipe.java | 6 +- .../recipe/GeyserStonecutterData.java | 2 +- .../geyser/inventory/recipe/TrimRecipe.java | 2 +- .../updater/AnvilInventoryUpdater.java | 6 +- .../geyser/item/DyeableLeatherItem.java | 6 +- .../geysermc/geyser/item/type/ArmorItem.java | 6 +- .../geysermc/geyser/item/type/ArrowItem.java | 2 +- .../geyser/item/type/AxolotlBucketItem.java | 2 +- .../geysermc/geyser/item/type/BannerItem.java | 6 +- .../geysermc/geyser/item/type/ChestItem.java | 2 +- .../geyser/item/type/CompassItem.java | 8 +-- .../geyser/item/type/CrossbowItem.java | 6 +- .../geyser/item/type/DecoratedPotItem.java | 4 +- .../geyser/item/type/DyeableArmorItem.java | 2 +- .../item/type/DyeableHorseArmorItem.java | 2 +- .../geyser/item/type/EnchantedBookItem.java | 6 +- .../geyser/item/type/FilledMapItem.java | 4 +- .../geyser/item/type/FireworkRocketItem.java | 10 ++-- .../geyser/item/type/FireworkStarItem.java | 6 +- .../geyser/item/type/FishingRodItem.java | 2 +- .../geyser/item/type/GoatHornItem.java | 10 ++-- .../org/geysermc/geyser/item/type/Item.java | 10 ++-- .../geysermc/geyser/item/type/MapItem.java | 7 ++- .../geyser/item/type/PlayerHeadItem.java | 4 +- .../geysermc/geyser/item/type/PotionItem.java | 8 +-- .../geysermc/geyser/item/type/ShieldItem.java | 2 +- .../geyser/item/type/ShulkerBoxItem.java | 6 +- .../geyser/item/type/TippedArrowItem.java | 6 +- .../item/type/TropicalFishBucketItem.java | 4 +- .../geyser/item/type/WritableBookItem.java | 8 +-- .../geyser/item/type/WrittenBookItem.java | 8 +-- .../geysermc/geyser/level/BedrockMapIcon.java | 2 +- .../geyser/level/GeyserAdvancement.java | 6 +- .../geyser/level/GeyserWorldManager.java | 12 ++-- .../geysermc/geyser/level/JavaDimension.java | 2 +- .../geysermc/geyser/level/PaintingType.java | 2 +- .../geysermc/geyser/level/WorldManager.java | 8 +-- .../block/GeyserCustomBlockComponents.java | 13 +---- .../geyser/level/chunk/GeyserChunk.java | 2 +- .../geyser/level/physics/BoundingBox.java | 2 +- .../level/physics/CollisionManager.java | 4 +- .../geyser/level/physics/Direction.java | 18 +++--- .../geysermc/geyser/network/GameProtocol.java | 4 +- .../geyser/network/netty/LocalSession.java | 14 ++--- .../geyser/pack/SkullResourcePackManager.java | 4 +- .../ping/GeyserLegacyPingPassthrough.java | 4 +- .../geyser/ping/IGeyserPingPassthrough.java | 1 + .../registry/PacketTranslatorRegistry.java | 8 +-- .../geysermc/geyser/registry/Registries.java | 12 ++-- .../loader/BlockEntityRegistryLoader.java | 2 +- .../loader/ParticleTypesRegistryLoader.java | 2 +- .../loader/SoundEventsRegistryLoader.java | 8 +-- .../mappings/versions/MappingsReader_v1.java | 2 +- .../populator/PacketRegistryPopulator.java | 2 +- .../populator/RecipeRegistryPopulator.java | 6 +- .../geyser/registry/type/ItemMappings.java | 2 +- .../geysermc/geyser/scoreboard/Objective.java | 6 +- .../org/geysermc/geyser/scoreboard/Score.java | 4 +- .../geyser/scoreboard/Scoreboard.java | 7 +-- .../org/geysermc/geyser/scoreboard/Team.java | 4 +- .../geyser/session/DownstreamSession.java | 6 +- .../geyser/session/GeyserSession.java | 58 +++++++++---------- .../session/cache/AdvancementsCache.java | 4 +- .../geyser/session/cache/BookEditCache.java | 2 +- .../geyser/session/cache/ChunkCache.java | 2 +- .../session/cache/EntityEffectCache.java | 2 +- .../geyser/session/cache/LodestoneCache.java | 8 +-- .../geyser/session/cache/RegistryCache.java | 4 +- .../geyser/session/cache/TagCache.java | 2 +- .../geyser/session/cache/TeleportCache.java | 2 +- .../geyser/session/cache/WorldCache.java | 2 +- .../geyser/skin/FakeHeadProvider.java | 4 +- .../geysermc/geyser/text/ChatTypeEntry.java | 4 +- .../geysermc/geyser/text/MinecraftLocale.java | 4 +- .../geysermc/geyser/text/TextDecoration.java | 2 +- .../translator/collision/BlockCollision.java | 4 +- .../entity/EntityMetadataTranslator.java | 4 +- .../inventory/AnvilInventoryTranslator.java | 2 +- .../inventory/BaseInventoryTranslator.java | 8 +-- .../inventory/BeaconInventoryTranslator.java | 4 +- .../CartographyInventoryTranslator.java | 2 +- .../inventory/CrafterInventoryTranslator.java | 8 +-- .../EnchantingInventoryTranslator.java | 4 +- .../Generic3X3InventoryTranslator.java | 2 +- .../inventory/InventoryTranslator.java | 10 ++-- .../inventory/LecternInventoryTranslator.java | 18 +++--- .../inventory/LoomInventoryTranslator.java | 8 +-- .../MerchantInventoryTranslator.java | 4 +- .../inventory/OldSmithingTableTranslator.java | 6 +- .../inventory/PlayerInventoryTranslator.java | 15 ++--- .../inventory/ShulkerInventoryTranslator.java | 2 +- .../StonecutterInventoryTranslator.java | 6 +- .../translator/item/CustomItemTranslator.java | 4 +- .../translator/item/ItemTranslator.java | 14 ++--- .../translator/level/BiomeTranslator.java | 12 ++-- .../entity/BannerBlockEntityTranslator.java | 2 +- .../entity/BeaconBlockEntityTranslator.java | 2 +- .../entity/BedBlockEntityTranslator.java | 2 +- .../level/block/entity/BlockEntity.java | 2 +- .../block/entity/BlockEntityTranslator.java | 2 +- .../BrushableBlockEntityTranslator.java | 2 +- .../entity/CampfireBlockEntityTranslator.java | 2 +- .../CommandBlockBlockEntityTranslator.java | 2 +- .../DecoratedPotBlockEntityTranslator.java | 2 +- .../DoubleChestBlockEntityTranslator.java | 2 +- .../EndGatewayBlockEntityTranslator.java | 6 +- .../HangingSignBlockEntityTranslator.java | 2 +- .../JigsawBlockBlockEntityTranslator.java | 2 +- .../level/block/entity/PistonBlockEntity.java | 2 +- .../ShulkerBoxBlockEntityTranslator.java | 2 +- .../entity/SignBlockEntityTranslator.java | 2 +- .../entity/SkullBlockEntityTranslator.java | 2 +- .../entity/SpawnerBlockEntityTranslator.java | 2 +- .../StructureBlockBlockEntityTranslator.java | 2 +- .../TrialSpawnerBlockEntityTranslator.java | 2 +- .../level/event/LevelEventTranslator.java | 2 +- .../level/event/PlaySoundEventTranslator.java | 2 +- .../event/SoundEventEventTranslator.java | 2 +- .../event/SoundLevelEventTranslator.java | 2 +- .../bedrock/BedrockAnimateTranslator.java | 6 +- .../BedrockBlockEntityDataTranslator.java | 4 +- .../BedrockBlockPickRequestTranslator.java | 2 +- .../bedrock/BedrockBookEditTranslator.java | 12 ++-- .../BedrockCommandBlockUpdateTranslator.java | 6 +- .../BedrockContainerCloseTranslator.java | 2 +- ...BedrockInventoryTransactionTranslator.java | 22 +++---- .../BedrockItemFrameDropItemTranslator.java | 6 +- .../BedrockLecternUpdateTranslator.java | 10 ++-- .../BedrockMobEquipmentTranslator.java | 6 +- .../BedrockMoveEntityAbsoluteTranslator.java | 2 +- .../BedrockNetworkStackLatencyTranslator.java | 2 +- .../bedrock/BedrockPlayerInputTranslator.java | 4 +- .../BedrockRequestAbilityTranslator.java | 4 +- .../bedrock/BedrockRespawnTranslator.java | 4 +- .../bedrock/BedrockShowCreditsTranslator.java | 4 +- ...BedrockStructureBlockUpdateTranslator.java | 4 +- ...tructureTemplateDataRequestTranslator.java | 4 +- ...ockToggleCrafterSlotRequestTranslator.java | 2 +- .../entity/BedrockEntityEventTranslator.java | 2 +- .../player/BedrockActionTranslator.java | 10 +--- .../player/BedrockInteractTranslator.java | 12 ++-- .../player/BedrockMovePlayerTranslator.java | 8 +-- .../player/BedrockRiderJumpTranslator.java | 4 +- .../BedrockSetDefaultGameTypeTranslator.java | 2 +- .../BedrockSetDifficultyTranslator.java | 2 +- .../BedrockSetPlayerGameTypeTranslator.java | 2 +- ...ckSetPlayerInventoryOptionsTranslator.java | 6 +- .../BedrockLevelSoundEventTranslator.java | 8 +-- .../java/JavaAwardStatsTranslator.java | 2 +- .../java/JavaBossEventTranslator.java | 2 +- .../java/JavaChangeDifficultyTranslator.java | 2 +- .../JavaClientboundRecipesTranslator.java | 2 +- ...JavaClientboundResourcePackPushPacket.java | 6 +- .../protocol/java/JavaCommandsTranslator.java | 10 ++-- .../java/JavaCustomPayloadTranslator.java | 8 +-- .../java/JavaCustomQueryTranslator.java | 4 +- .../java/JavaDisconnectTranslator.java | 2 +- .../java/JavaDisguisedChatTranslator.java | 2 +- .../java/JavaGameProfileTranslator.java | 4 +- .../java/JavaKeepAliveTranslator.java | 2 +- .../java/JavaLoginDisconnectTranslator.java | 2 +- .../protocol/java/JavaLoginTranslator.java | 6 +- .../protocol/java/JavaPingTranslator.java | 4 +- .../java/JavaPlayerChatTranslator.java | 2 +- .../java/JavaRegistryDataTranslator.java | 2 +- .../protocol/java/JavaRespawnTranslator.java | 4 +- .../JavaSelectAdvancementsTabTranslator.java | 2 +- .../java/JavaSystemChatTranslator.java | 2 +- .../JavaUpdateAdvancementsTranslator.java | 4 +- .../java/JavaUpdateRecipesTranslator.java | 24 ++++---- .../java/JavaUpdateTagsTranslator.java | 2 +- .../java/entity/JavaAnimateTranslator.java | 4 +- .../entity/JavaDamageEventTranslator.java | 2 +- .../entity/JavaEntityEventTranslator.java | 2 +- .../JavaMoveEntityPosRotTranslator.java | 2 +- .../entity/JavaMoveEntityPosTranslator.java | 2 +- .../entity/JavaMoveEntityRotTranslator.java | 2 +- .../entity/JavaMoveVehicleTranslator.java | 2 +- .../entity/JavaRemoveEntitiesTranslator.java | 2 +- .../entity/JavaRemoveMobEffectTranslator.java | 2 +- .../java/entity/JavaRotateHeadTranslator.java | 2 +- .../entity/JavaSetEntityDataTranslator.java | 4 +- .../entity/JavaSetEntityLinkTranslator.java | 2 +- .../entity/JavaSetEntityMotionTranslator.java | 2 +- .../entity/JavaSetEquipmentTranslator.java | 6 +- .../entity/JavaSetPassengersTranslator.java | 2 +- .../entity/JavaSoundEntityTranslator.java | 2 +- .../entity/JavaTakeItemEntityTranslator.java | 2 +- .../entity/JavaTeleportEntityTranslator.java | 2 +- .../JavaUpdateAttributesTranslator.java | 2 +- .../entity/JavaUpdateMobEffectTranslator.java | 2 +- .../player/JavaBlockChangedAckTranslator.java | 2 +- .../player/JavaPlayerAbilitiesTranslator.java | 2 +- .../JavaPlayerCombatKillTranslator.java | 2 +- .../JavaPlayerInfoRemoveTranslator.java | 2 +- .../JavaPlayerInfoUpdateTranslator.java | 6 +- .../player/JavaPlayerLookAtTranslator.java | 2 +- .../player/JavaPlayerPositionTranslator.java | 8 +-- .../player/JavaSetCarriedItemTranslator.java | 2 +- .../player/JavaSetExperienceTranslator.java | 2 +- .../player/JavaSetHealthTranslator.java | 2 +- .../entity/spawn/JavaAddEntityTranslator.java | 14 ++--- .../spawn/JavaAddExperienceOrbTranslator.java | 2 +- .../JavaContainerCloseTranslator.java | 2 +- .../JavaContainerSetContentTranslator.java | 2 +- .../JavaContainerSetDataTranslator.java | 2 +- .../JavaContainerSetSlotTranslator.java | 6 +- .../JavaHorseScreenOpenTranslator.java | 2 +- .../JavaMerchantOffersTranslator.java | 6 +- .../inventory/JavaOpenBookTranslator.java | 6 +- .../inventory/JavaOpenScreenTranslator.java | 6 +- .../level/JavaBlockDestructionTranslator.java | 2 +- .../level/JavaBlockEntityDataTranslator.java | 6 +- .../java/level/JavaBlockEventTranslator.java | 4 +- .../java/level/JavaBlockUpdateTranslator.java | 2 +- .../JavaChunkBatchFinishedTranslator.java | 4 +- .../java/level/JavaCooldownTranslator.java | 2 +- .../java/level/JavaExplodeTranslator.java | 2 +- .../level/JavaForgetLevelChunkTranslator.java | 2 +- .../java/level/JavaGameEventTranslator.java | 16 ++--- .../JavaLevelChunkWithLightTranslator.java | 29 ++++------ .../java/level/JavaLevelEventTranslator.java | 6 +- .../level/JavaLevelParticlesTranslator.java | 18 +++--- .../java/level/JavaMapItemDataTranslator.java | 6 +- .../level/JavaOpenSignEditorTranslator.java | 2 +- .../JavaSectionBlocksUpdateTranslator.java | 4 +- .../JavaSetChunkCacheCenterTranslator.java | 2 +- .../JavaSetChunkCacheRadiusTranslator.java | 2 +- ...JavaSetDefaultSpawnPositionTranslator.java | 2 +- .../java/level/JavaSetTimeTranslator.java | 2 +- .../java/level/JavaSoundTranslator.java | 2 +- .../java/level/JavaStopSoundTranslator.java | 2 +- .../JavaInitializeBorderTranslator.java | 2 +- .../border/JavaSetBorderCenterTranslator.java | 2 +- .../JavaSetBorderLerpSizeTranslator.java | 2 +- .../border/JavaSetBorderSizeTranslator.java | 2 +- .../JavaSetBorderWarningDelayTranslator.java | 2 +- ...avaSetBorderWarningDistanceTranslator.java | 2 +- .../java/scoreboard/JavaResetScorePacket.java | 4 +- .../JavaSetDisplayObjectiveTranslator.java | 2 +- .../JavaSetObjectiveTranslator.java | 6 +- .../JavaSetPlayerTeamTranslator.java | 8 +-- .../scoreboard/JavaSetScoreTranslator.java | 4 +- .../java/title/JavaClearTitlesTranslator.java | 2 +- .../title/JavaSetActionBarTextTranslator.java | 2 +- .../title/JavaSetSubtitleTextTranslator.java | 2 +- .../title/JavaSetTitleTextTranslator.java | 2 +- .../JavaSetTitlesAnimationTranslator.java | 2 +- .../BlockSoundInteractionTranslator.java | 2 +- .../translator/text/MessageTranslator.java | 4 +- .../geysermc/geyser/util/AttributeUtils.java | 6 +- .../geyser/util/BlockEntityUtils.java | 2 +- .../org/geysermc/geyser/util/BlockUtils.java | 4 +- .../geysermc/geyser/util/CooldownUtils.java | 2 +- .../geysermc/geyser/util/DimensionUtils.java | 8 +-- .../org/geysermc/geyser/util/EntityUtils.java | 8 +-- .../geysermc/geyser/util/InventoryUtils.java | 12 ++-- .../org/geysermc/geyser/util/ItemUtils.java | 6 +- .../geyser/util/PluginMessageUtils.java | 2 +- .../org/geysermc/geyser/util/SoundUtils.java | 2 +- .../geyser/util/StatisticFormatters.java | 2 +- .../geysermc/geyser/util/StatisticsUtils.java | 2 +- .../geyser/util/StructureBlockUtils.java | 24 ++++---- .../chat/MessageTranslatorTest.java | 2 +- .../loader/ResourcePackLoaderTest.java | 4 +- gradle/libs.versions.toml | 2 +- 389 files changed, 869 insertions(+), 956 deletions(-) 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 b9fbd6cdc..656305690 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 @@ -25,11 +25,11 @@ package org.geysermc.geyser.platform.mod.world; -import com.github.steveice10.mc.protocol.data.game.Holder; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.item.component.BannerPatternLayer; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.SharedConstants; @@ -222,8 +222,8 @@ public class GeyserModWorldManager extends GeyserWorldManager { @NonNull @Override - public CompletableFuture getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { - CompletableFuture future = new CompletableFuture<>(); + public CompletableFuture getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { + CompletableFuture future = new CompletableFuture<>(); server.execute(() -> { ServerPlayer player = getPlayer(session); if (player == null) { @@ -240,8 +240,8 @@ public class GeyserModWorldManager extends GeyserWorldManager { // the banner might have a custom name, both of which a Java client knows and caches ItemStack itemStack = banner.getItem(); - com.github.steveice10.mc.protocol.data.game.item.component.DataComponents components = - new com.github.steveice10.mc.protocol.data.game.item.component.DataComponents(new HashMap<>()); + org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents components = + new org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents(new HashMap<>()); components.put(DataComponentType.DAMAGE, itemStack.getDamageValue()); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index ad31131bd..43ecf7154 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.platform.spigot; -import com.github.steveice10.mc.protocol.MinecraftProtocol; +import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java index 9e0b14b11..fa7555ac6 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.platform.spigot; -import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer; +import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer; import net.kyori.adventure.text.Component; import org.bukkit.command.CommandSender; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java index 01b0be9f2..61c0d5fe8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.platform.spigot.world; -import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import org.cloudburstmc.math.vector.Vector3i; import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 07a9d489a..8a0e0b70d 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.platform.spigot.world.manager; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 8b54f5298..5c4313f09 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -29,7 +29,6 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.steveice10.packetlib.tcp.TcpSession; import io.netty.channel.epoll.Epoll; import io.netty.util.NettyRuntime; import io.netty.util.concurrent.DefaultThreadFactory; @@ -86,6 +85,7 @@ import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.*; +import org.geysermc.mcprotocollib.network.tcp.TcpSession; import java.io.File; import java.io.FileWriter; diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java index 1ff12dea3..5952ea00d 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.command.defaults; -import com.github.steveice10.mc.protocol.data.game.ClientCommand; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.ClientCommand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; public class StatisticsCommand extends GeyserCommand { diff --git a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java index 6a56c536a..7851fadfd 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java @@ -27,8 +27,8 @@ package org.geysermc.geyser.dump; import lombok.AllArgsConstructor; import lombok.Getter; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.text.AsteriskSerializer; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index e54bbc1eb..6989dc10a 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -56,12 +56,7 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; +import java.util.*; import java.util.stream.Collectors; @Getter diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java index 8b430d559..f0e221bad 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.entity; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import lombok.Setter; import lombok.experimental.Accessors; 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 f454bef88..328dd4bbf 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.entity; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.type.*; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java index 6828d1020..1cc746d7a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java index 84dfae468..4b8eea061 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.level.particle.Particle; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -35,6 +32,9 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; import java.util.UUID; 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 e3420abeb..d9a64ccc6 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 @@ -25,22 +25,21 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import lombok.Getter; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; -import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; 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 java.util.UUID; -import java.util.concurrent.TimeUnit; public class BoatEntity extends Entity implements Tickable { 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 675e9517d..479b4d80d 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 @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; 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.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java index 9c7a28f6e..2d0835286 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java index 63b5ff2ab..fd6f17eb8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java index 86436f82b..932864bf7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; 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 306c244b3..f1d6bfb98 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,13 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -42,12 +35,7 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; -import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; -import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket; -import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket; -import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; +import org.cloudburstmc.protocol.bedrock.packet.*; import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.GeyserDirtyMetadata; @@ -57,12 +45,15 @@ import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +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.data.game.entity.type.EntityType; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; @Getter @Setter diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java index e6d3a5783..4fcec7a63 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; 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.EntityDefinitions; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java index 04317e6d6..f0739abb3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; @@ -36,6 +33,9 @@ import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.OptionalInt; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java index 0de11c382..f4c0cea36 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java @@ -25,11 +25,10 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import lombok.Getter; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; -import lombok.Getter; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.PlayerEntity; @@ -38,6 +37,7 @@ import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java index a7a117fff..ef584c4fd 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java index 0917465d4..4e7a805b4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java @@ -25,16 +25,16 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java index 226ad7df8..ead717b34 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; @@ -38,6 +36,8 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.UUID; import java.util.concurrent.CompletableFuture; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java index 453125945..f38e727c0 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java @@ -25,12 +25,7 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; +import lombok.Getter; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; @@ -39,12 +34,17 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; -import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; +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.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java index 3f0d2ee68..af739297c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; 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 b070bdfff..5823ba3b2 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,14 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import lombok.AccessLevel; @@ -57,6 +49,14 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.InteractionResult; +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.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.*; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java index ecf67052b..9096d8bd6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; @@ -35,6 +32,9 @@ import org.geysermc.geyser.entity.EntityDefinitions; 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 java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java index 4e5fe9d59..f5145c11f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.AddPaintingPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.PaintingType; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; import java.util.UUID; @@ -49,7 +49,7 @@ public class PaintingEntity extends Entity { // Wait until we get the metadata needed } - public void setPaintingType(ObjectEntityMetadata entityMetadata) { + public void setPaintingType(ObjectEntityMetadata entityMetadata) { PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue()); AddPaintingPacket addPaintingPacket = new AddPaintingPacket(); addPaintingPacket.setUniqueEntityId(geyserId); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java index 98c2edd00..dca36cda0 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java index 0b6160401..28f38f919 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java @@ -25,14 +25,14 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import net.kyori.adventure.text.Component; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.Optional; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java index 47884e60a..25bbdbd3c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -34,6 +33,7 @@ import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java index 3c080345e..55334010f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java index 31428477a..bfe429f33 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java @@ -25,11 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -39,6 +34,11 @@ import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +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.item.component.PotionContents; import java.util.EnumSet; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java index 856c4cc66..be4133028 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.item.TippedArrowPotion; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java index 637ca4139..8427a8e10 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java index 9cc3a006e..6ecfa4978 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -34,6 +33,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java index 6e2e7a407..5b1d682ce 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; 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.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java index 48d633e5d..01a42e527 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -36,6 +34,8 @@ import org.geysermc.geyser.item.Items; 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.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index 9c56568c8..c64f2f218 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import lombok.Getter; import net.kyori.adventure.text.Component; import org.cloudburstmc.math.vector.Vector3f; @@ -43,6 +39,10 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.Optional; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java index 644054e72..bdfc20c88 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.UUID; 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 a43bb666f..6182a27f4 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; @@ -34,6 +33,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java index 7afa4b436..58a349cc9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -35,6 +34,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java index 0ac81c957..95145ae60 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; @@ -40,6 +38,8 @@ import org.geysermc.geyser.item.type.SpawnEggItem; 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.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java index 1d2eb95bc..50095fe3f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java index 7f0699415..50aa7b90e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -36,6 +34,8 @@ import org.geysermc.geyser.item.Items; 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.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java index 7094c431e..4fdaa1059 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; @@ -34,6 +33,7 @@ import org.geysermc.geyser.item.Items; 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.player.Hand; import java.util.UUID; 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 7278709ce..bf23a5418 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; @@ -38,6 +37,7 @@ 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.player.Hand; import java.util.UUID; 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 c4f95e546..37cd5f1e6 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 @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -39,6 +36,9 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; +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 java.util.UUID; 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 7f1a88d7b..d6aa9615d 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 @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; @@ -36,6 +34,8 @@ 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.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; 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 cdcf534a3..d542cb46f 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; @@ -36,6 +35,7 @@ import org.geysermc.geyser.item.Items; 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.player.Hand; import java.util.UUID; 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 200505f14..18e346b98 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 @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -34,6 +32,8 @@ 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.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; 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 039ef5bf9..ed21a9609 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 @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -36,6 +33,9 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +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; import java.util.OptionalInt; import java.util.UUID; 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 9ed94f96f..7cbbd4433 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 @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; @@ -38,6 +35,9 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; 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; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; 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 154c2f688..29d1839c7 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 @@ -25,13 +25,13 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; 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.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 8673eb18e..55c3c406f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -37,6 +35,8 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; 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 c115ebcdc..8a3dd6c72 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -36,6 +35,7 @@ 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.player.Hand; import java.util.UUID; 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 d2ef36932..df72fdc63 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 @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; @@ -42,6 +39,9 @@ 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.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; 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 2bc02cd55..4dbf3064a 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -37,6 +36,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java index d0d119593..6f0063474 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.AbstractFishEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; 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 1efa87ec8..09db7257b 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -33,6 +32,7 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; 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 13059244a..e87186bf6 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 @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -38,6 +36,8 @@ import org.geysermc.geyser.item.type.DyeItem; 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.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; 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 0e6fffbc0..35b2b4183 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 @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.SnifferState; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; @@ -40,6 +37,9 @@ 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.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; import java.util.UUID; 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 39a55fa1e..dcdd40199 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 @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -39,6 +37,8 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.EntityUtils; 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.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java index b18e55a48..b6751bc3f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java @@ -25,14 +25,14 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.ints.IntList; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; -import it.unimi.dsi.fastutil.ints.IntList; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.AbstractFishEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.List; import java.util.UUID; 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 870ded193..1d0aec75f 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 @@ -25,13 +25,13 @@ package org.geysermc.geyser.entity.type.living.animal; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; 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.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; 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 faa495487..76416c146 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 @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.horse; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -44,6 +42,8 @@ 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.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.Set; import java.util.UUID; 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 8106b096d..00144617a 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 @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.horse; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; @@ -38,6 +35,9 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java index dfa6ef30a..b8a9a8f28 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.animal.horse; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; 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 29da2e0dc..346b6da9b 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.horse; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import lombok.Getter; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -34,6 +33,7 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java index 7080f9f75..d74913c31 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.horse; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; @@ -33,6 +32,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; 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.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java index 3275712fc..9e77daebc 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.horse; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; @@ -33,6 +32,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; 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.player.Hand; import java.util.UUID; 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 93cb92c7d..fc5978c2b 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 @@ -25,10 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -40,6 +36,10 @@ 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.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; 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 4c4b6a222..18feec979 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -36,6 +35,7 @@ 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.player.Hand; import java.util.Set; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java index 5fc8c459d..4a1cd70e9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java @@ -25,16 +25,16 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import lombok.Getter; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.Optional; import java.util.UUID; 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 ff130aeff..29c3526fe 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 @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; @@ -42,6 +39,9 @@ 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.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.Collections; import java.util.Locale; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java index c7b29130f..64e35e52e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.merchant; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -37,6 +36,7 @@ import org.geysermc.geyser.item.Items; 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.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java index 9b0f50050..3c2160a2b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.merchant; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData; import lombok.Getter; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; @@ -38,6 +36,8 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData; import java.util.Optional; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java index 04b3bba1b..3fbdda245 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java index 5f2647b7a..09bd28cd0 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java index 43d78f468..5b26d7bd1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java index f134c31b3..5f54d2942 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; @@ -38,6 +35,9 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; 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 java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java index 8c00d065a..0162d498e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java @@ -25,23 +25,19 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import lombok.Data; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; -import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; -import org.cloudburstmc.protocol.bedrock.packet.SpawnParticleEffectPacket; +import org.cloudburstmc.protocol.bedrock.packet.*; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.living.MobEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.Optional; import java.util.Random; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java index 5b8e23f8b..586ba5cd9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; @@ -35,6 +33,8 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java index f7b9d17b8..984aab642 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.FlyingEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java index 92e50d207..40793522e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java index 915e34e79..cb4b7a8cf 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.FlyingEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java index 696982a33..db2a3ecc3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -38,6 +36,8 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; 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.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java index 27dd45f40..aecb4a915 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; 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.entity.type.living.GolemEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java index da11b2759..a6343e256 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java index 03e234911..4a4527cef 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java index 56a0975ae..840f5b3b4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java index 7a0c5e040..2341b8c32 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -36,6 +34,8 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java index 3abb7f122..19c1a457b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java index 6e40573ba..efbb7753c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; 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.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java index af6a30a10..11354fbf8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; 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.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java index 32e45507a..6e03e4f98 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -40,6 +36,10 @@ import org.geysermc.geyser.item.Items; 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.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java index f083437ae..8d4b3c44e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.entity.type.living.monster.raid; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; 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.entity.EntityDefinitions; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java index ad99dda50..04a58addd 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.monster.raid; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import java.util.UUID; 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 b957a0243..1ca387259 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,18 +25,6 @@ package org.geysermc.geyser.entity.type.player; -import com.github.steveice10.mc.protocol.codec.NbtComponentSerializer; -import com.github.steveice10.mc.protocol.data.game.chat.numbers.BlankFormat; -import com.github.steveice10.mc.protocol.data.game.chat.numbers.FixedFormat; -import com.github.steveice10.mc.protocol.data.game.chat.numbers.NumberFormat; -import com.github.steveice10.mc.protocol.data.game.chat.numbers.StyledFormat; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; -import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import lombok.Getter; @@ -47,18 +35,13 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.Ability; import org.cloudburstmc.protocol.bedrock.data.AbilityLayer; -import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.PlayerPermission; import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; -import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; -import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; -import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; -import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; -import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; +import org.cloudburstmc.protocol.bedrock.packet.*; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; @@ -73,6 +56,18 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.mcprotocollib.protocol.codec.NbtComponentSerializer; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.BlankFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.FixedFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.StyledFormat; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import java.util.Collections; import java.util.List; 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 89aa540d8..e10adb134 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 @@ -25,13 +25,6 @@ package org.geysermc.geyser.entity.type.player; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import org.checkerframework.checker.nullness.qual.Nullable; @@ -45,6 +38,13 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.DimensionUtils; +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.GlobalPos; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import java.util.Collections; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java index 939e4721d..89f9c37d6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity.type.player; +import lombok.Getter; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.GameType; @@ -33,7 +34,6 @@ import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; -import lombok.Getter; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index 57147fc49..a62f9ec49 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.erosion; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import io.netty.channel.Channel; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java index 28c881eba..2a93c89e3 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java @@ -38,19 +38,10 @@ import org.cloudburstmc.protocol.bedrock.data.camera.CameraSetInstruction; import org.cloudburstmc.protocol.bedrock.packet.CameraInstructionPacket; import org.cloudburstmc.protocol.bedrock.packet.CameraShakePacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerFogPacket; -import org.geysermc.geyser.api.bedrock.camera.CameraEaseType; -import org.geysermc.geyser.api.bedrock.camera.CameraData; -import org.geysermc.geyser.api.bedrock.camera.CameraFade; -import org.geysermc.geyser.api.bedrock.camera.CameraPerspective; -import org.geysermc.geyser.api.bedrock.camera.CameraPosition; -import org.geysermc.geyser.api.bedrock.camera.CameraShake; +import org.geysermc.geyser.api.bedrock.camera.*; import org.geysermc.geyser.session.GeyserSession; -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; +import java.util.*; public class GeyserCameraData implements CameraData { diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraFade.java b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraFade.java index 648e70c81..f69504545 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraFade.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraFade.java @@ -29,7 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.common.value.qual.IntRange; import org.geysermc.geyser.api.bedrock.camera.CameraFade; -import java.awt.Color; +import java.awt.*; import java.util.Objects; public record GeyserCameraFade( diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 1c5826cdb..e6332bc41 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java index 7644ada73..1b59772fa 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import lombok.Getter; import lombok.Setter; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java index 72f1088c3..ace3f93ad 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; public class CartographyContainer extends Container { public CartographyContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Container.java index 79fa67da1..209aeb24f 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Container.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Container.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java index bcacd3587..41452bed6 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.GeyserImpl; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java index ac55aae60..08397ab44 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData; import lombok.Getter; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java index 6518dce7c..65e47d877 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import lombok.Getter; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.Generic3X3InventoryTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; public class Generic3X3Container extends Container { /** 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 a1ecc6f58..f75c1fdd9 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import lombok.AccessLevel; import lombok.Data; @@ -42,6 +39,9 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; 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; @Data public class GeyserItemStack { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index b78bbe1b3..4e8257ff8 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -25,20 +25,20 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.Tag; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.math.vector.Vector3i; import lombok.Getter; import lombok.Setter; import lombok.ToString; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.jetbrains.annotations.Range; import java.util.Arrays; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java index 7ac2fed99..389611c67 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; @@ -33,6 +32,7 @@ import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.java.inventory.JavaOpenBookTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; public class LecternContainer extends Container { @Getter @Setter diff --git a/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java index 105b5ca5b..0bfa6d1a7 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java @@ -25,14 +25,14 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.data.game.inventory.VillagerTrade; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket; import lombok.Getter; import lombok.Setter; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket; public class MerchantContainer extends Container { @Getter @Setter diff --git a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java index bda09a4ed..9bef4b08e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.jetbrains.annotations.Range; public class PlayerInventory extends Inventory { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java index f99a0c71e..269a4fb7d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java b/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java index d7068920e..6897786c1 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory.click; -import com.github.steveice10.mc.protocol.data.game.inventory.*; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.*; import lombok.AllArgsConstructor; @AllArgsConstructor diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index a118670af..53b02ef88 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.inventory.click; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerActionType; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.data.game.inventory.MoveToHotbarAction; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerActionType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.MoveToHotbarAction; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; import it.unimi.dsi.fastutil.ints.*; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; 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 641d5ad94..9d98e9fb3 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 @@ -26,7 +26,7 @@ package org.geysermc.geyser.inventory.recipe; /** - * A more compact version of {@link com.github.steveice10.mc.protocol.data.game.recipe.Recipe}. + * A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}. */ public interface GeyserRecipe { /** 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 d420170f4..ac9fa3ab4 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,10 +25,10 @@ package org.geysermc.geyser.inventory.recipe; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; 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; public record GeyserShapedRecipe(int width, int height, Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe { 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 e6eabea2d..388831d4c 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,9 +25,9 @@ package org.geysermc.geyser.inventory.recipe; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; +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; public record GeyserShapelessRecipe(Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java index ce044e745..7bd21ecfa 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory.recipe; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.checkerframework.checker.nullness.qual.Nullable; /** diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java index 441f050a7..860ccfd89 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.inventory.recipe; -import com.github.steveice10.mc.protocol.data.game.RegistryEntry; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import net.kyori.adventure.text.Component; 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 9bf001f42..d6324ba23 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 @@ -25,9 +25,9 @@ package org.geysermc.geyser.inventory.updater; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; +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.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; diff --git a/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java b/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java index 214b9d78c..e884ecec5 100644 --- a/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.item; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.DyedItemColor; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +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.DyedItemColor; public interface DyeableLeatherItem { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index 773b850c0..fb9f35629 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.ArmorTrim; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; @@ -39,6 +36,9 @@ import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.ArmorTrim; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class ArmorItem extends Item { private final ArmorMaterial material; 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 16d5fd482..f3c832a31 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -33,6 +32,7 @@ import org.geysermc.geyser.inventory.item.TippedArrowPotion; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; public class ArrowItem extends Item { public ArrowItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java index 99f649e87..8895d45a8 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class AxolotlBucketItem extends Item { public AxolotlBucketItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index fe378d4c6..29a98e598 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.BannerPatternLayer; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.*; import it.unimi.dsi.fastutil.Pair; import org.checkerframework.checker.nullness.qual.NonNull; @@ -39,6 +36,9 @@ import org.geysermc.geyser.inventory.item.DyeColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java index 1f6ac6964..09718ba66 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @Deprecated public class ChestItem extends BlockItem { 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 10c574d5d..aa34f76ba 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 @@ -25,10 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.LodestoneTracker; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -36,6 +32,10 @@ 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.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.item.component.LodestoneTracker; public class CompassItem extends Item { public CompassItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java index 5b92ba303..9a10c701c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; @@ -39,6 +36,9 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; 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 java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index ea194522b..2631bf9be 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index 117e70b9a..e57470607 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.ArmorMaterial; @@ -33,6 +32,7 @@ import org.geysermc.geyser.item.DyeableLeatherItem; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem { public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java index cb6dd869b..881598648 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.DyeableLeatherItem; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class DyeableHorseArmorItem extends Item implements DyeableLeatherItem { public DyeableHorseArmorItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index 095537a09..952967475 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -25,14 +25,14 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +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.ItemEnchantments; import java.util.ArrayList; import java.util.List; 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 af0b84308..70a04b863 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 @@ -25,11 +25,11 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; 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.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class FilledMapItem extends MapItem { public FilledMapItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index afb848e2d..e5656b494 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -25,10 +25,9 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.Fireworks; -import com.github.steveice10.opennbt.tag.builtin.*; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -38,6 +37,9 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.util.MathUtils; +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.Fireworks; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 505296418..ab6b7f300 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.Fireworks; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; @@ -35,6 +32,9 @@ import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +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.Fireworks; public class FireworkStarItem extends Item { public FireworkStarItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java index 743928482..32b1d5df5 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class FishingRodItem extends Item { public FishingRodItem(String javaIdentifier, Builder builder) { 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 35b7a76fc..0ff78676c 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 @@ -25,17 +25,17 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.Holder; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.Instrument; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +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.item.component.Instrument; import java.util.List; 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 2779768db..64e2dcbc6 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 @@ -25,11 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.Identifier; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments; import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; @@ -48,6 +43,11 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.Identifier; +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.item.component.ItemEnchantments; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java index 72014e15e..f6492a169 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java @@ -25,13 +25,14 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.opennbt.tag.builtin.*; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class MapItem extends Item { public MapItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index 82219d7d9..0cdbe70f1 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -26,13 +26,13 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class PlayerHeadItem extends Item { public PlayerHeadItem(String javaIdentifier, Builder builder) { 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 63b9240c0..13d7ccd5e 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 @@ -25,10 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -38,6 +34,10 @@ 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.translator.item.CustomItemTranslator; +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.item.component.PotionContents; public class PotionItem extends Item { public PotionItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index f495222f3..001fa74b6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class ShieldItem extends Item { public ShieldItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index 267946442..4108d0fa0 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; @@ -38,6 +35,9 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; 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 java.util.ArrayList; import java.util.List; 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 9074c2ec8..85291886e 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 @@ -25,14 +25,14 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.PotionContents; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.TippedArrowPotion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +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; public class TippedArrowItem extends ArrowItem { public TippedArrowItem(String javaIdentifier, Builder builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index f70e6b295..8c00cb049 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.Component; @@ -39,6 +37,8 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java index d925d2b8a..097a5e65b 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.Filterable; -import com.github.steveice10.mc.protocol.data.game.item.component.WritableBookContent; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; @@ -41,6 +37,10 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; +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.Filterable; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBookContent; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index a6b5e73d4..a11c4f583 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.Filterable; -import com.github.steveice10.mc.protocol.data.game.item.component.WrittenBookContent; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; @@ -37,6 +33,10 @@ import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; +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.Filterable; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java b/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java index 120e40f17..c55a74cd2 100644 --- a/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java +++ b/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.level; -import com.github.steveice10.mc.protocol.data.game.level.map.MapIconType; import lombok.Getter; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.mcprotocollib.protocol.data.game.level.map.MapIconType; public enum BedrockMapIcon { ICON_WHITE_ARROW(MapIconType.WHITE_ARROW, 0), diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java index f51e7b2ab..7d48b90af 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.level; -import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; -import com.github.steveice10.mc.protocol.data.game.advancement.Advancement.DisplayData; -import com.github.steveice10.mc.protocol.data.game.advancement.Advancement.DisplayData.AdvancementType; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.cache.AdvancementsCache; import org.geysermc.geyser.text.ChatColor; +import org.geysermc.mcprotocollib.protocol.data.game.advancement.Advancement; +import org.geysermc.mcprotocollib.protocol.data.game.advancement.Advancement.DisplayData; +import org.geysermc.mcprotocollib.protocol.data.game.advancement.Advancement.DisplayData.AdvancementType; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 9a9eac2df..08611a5e1 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.level; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -36,15 +33,14 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockEntityPacket; -import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockRequestPacket; -import org.geysermc.erosion.packet.backendbound.BackendboundBlockEntityPacket; -import org.geysermc.erosion.packet.backendbound.BackendboundBlockRequestPacket; -import org.geysermc.erosion.packet.backendbound.BackendboundPickBlockPacket; +import org.geysermc.erosion.packet.backendbound.*; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import java.util.List; import java.util.concurrent.CompletableFuture; diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 4babc3af0..27b2430bd 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.level; -import com.github.steveice10.mc.protocol.data.game.RegistryEntry; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java index 5c0cbf643..643fd735d 100644 --- a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java +++ b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java @@ -75,7 +75,7 @@ public enum PaintingType { return KEBAB; } - public static PaintingType getByPaintingType(com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType paintingType) { + public static PaintingType getByPaintingType(org.geysermc.mcprotocollib.protocol.data.game.entity.type.PaintingType paintingType) { return getByName(paintingType.name()); } } diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index aa0b43b80..a1b16a1d5 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.level; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; -import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; +import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import java.util.List; import java.util.Locale; diff --git a/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockComponents.java b/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockComponents.java index dfcb548ee..979d3bc7d 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockComponents.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockComponents.java @@ -32,18 +32,9 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Value; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.api.block.custom.component.BoxComponent; -import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents; -import org.geysermc.geyser.api.block.custom.component.GeometryComponent; -import org.geysermc.geyser.api.block.custom.component.MaterialInstance; -import org.geysermc.geyser.api.block.custom.component.PlacementConditions; -import org.geysermc.geyser.api.block.custom.component.TransformationComponent; +import org.geysermc.geyser.api.block.custom.component.*; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Objects; +import java.util.*; @Value public class GeyserCustomBlockComponents implements CustomBlockComponents { diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunk.java b/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunk.java index ca8c4db1d..c76c1994b 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunk.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunk.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.level.chunk; -import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; /** * Acts as a lightweight chunk class that doesn't store biomes, heightmaps or block entities. diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java b/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java index 8343babd0..b1a93d8ee 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.level.physics; -import org.cloudburstmc.math.vector.Vector3d; import lombok.AllArgsConstructor; import lombok.Data; import lombok.SneakyThrows; +import org.cloudburstmc.math.vector.Vector3d; @Data @AllArgsConstructor 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 2c3da3c41..ce89689eb 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 @@ -25,6 +25,8 @@ package org.geysermc.geyser.level.physics; +import lombok.Getter; +import lombok.Setter; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector3d; @@ -32,8 +34,6 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; -import lombok.Getter; -import lombok.Setter; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.Entity; diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java b/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java index 09ff89800..f14a46999 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java @@ -30,12 +30,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; public enum Direction { - DOWN(1, Vector3i.from(0, -1, 0), Axis.Y, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.DOWN), - UP(0, Vector3i.UNIT_Y, Axis.Y, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.UP), - NORTH(3, Vector3i.from(0, 0, -1), Axis.Z, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.NORTH), - SOUTH(2, Vector3i.UNIT_Z, Axis.Z, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.SOUTH), - WEST(5, Vector3i.from(-1, 0, 0), Axis.X, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.WEST), - EAST(4, Vector3i.UNIT_X, Axis.X, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.EAST); + DOWN(1, Vector3i.from(0, -1, 0), Axis.Y, org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction.DOWN), + UP(0, Vector3i.UNIT_Y, Axis.Y, org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction.UP), + NORTH(3, Vector3i.from(0, 0, -1), Axis.Z, org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction.NORTH), + SOUTH(2, Vector3i.UNIT_Z, Axis.Z, org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction.SOUTH), + WEST(5, Vector3i.from(-1, 0, 0), Axis.X, org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction.WEST), + EAST(4, Vector3i.UNIT_X, Axis.X, org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction.EAST); public static final Direction[] VALUES = values(); @@ -44,9 +44,9 @@ public enum Direction { private final Vector3i unitVector; @Getter private final Axis axis; - private final com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue; + private final org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction pistonValue; - Direction(int reversedId, Vector3i unitVector, Axis axis, com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue) { + Direction(int reversedId, Vector3i unitVector, Axis axis, org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction pistonValue) { this.reversedId = reversedId; this.unitVector = unitVector; this.axis = axis; @@ -65,7 +65,7 @@ public enum Direction { return axis == Axis.X || axis == Axis.Z; } - public static @NonNull Direction fromPistonValue(com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue) { + public static @NonNull Direction fromPistonValue(org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction pistonValue) { for (Direction direction : VALUES) { if (direction.pistonValue == pistonValue) { return direction; diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index b5fc4440c..cf80e8c6e 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.network; -import com.github.steveice10.mc.protocol.codec.MinecraftCodec; -import com.github.steveice10.mc.protocol.codec.PacketCodec; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; @@ -36,6 +34,8 @@ import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; +import org.geysermc.mcprotocollib.protocol.codec.PacketCodec; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 121c70f90..19b0b423f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -25,19 +25,19 @@ package org.geysermc.geyser.network.netty; -import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper; -import com.github.steveice10.packetlib.BuiltinFlags; -import com.github.steveice10.packetlib.codec.PacketCodecHelper; -import com.github.steveice10.packetlib.packet.PacketProtocol; -import com.github.steveice10.packetlib.tcp.TcpPacketCodec; -import com.github.steveice10.packetlib.tcp.TcpPacketSizer; -import com.github.steveice10.packetlib.tcp.TcpSession; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.*; import io.netty.channel.unix.PreferredDirectByteBufAllocator; import io.netty.handler.codec.haproxy.*; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.mcprotocollib.network.BuiltinFlags; +import org.geysermc.mcprotocollib.network.codec.PacketCodecHelper; +import org.geysermc.mcprotocollib.network.packet.PacketProtocol; +import org.geysermc.mcprotocollib.network.tcp.TcpPacketCodec; +import org.geysermc.mcprotocollib.network.tcp.TcpPacketSizer; +import org.geysermc.mcprotocollib.network.tcp.TcpSession; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; import java.net.Inet4Address; import java.net.InetSocketAddress; diff --git a/core/src/main/java/org/geysermc/geyser/pack/SkullResourcePackManager.java b/core/src/main/java/org/geysermc/geyser/pack/SkullResourcePackManager.java index f6c5140d8..f0faa4244 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/SkullResourcePackManager.java +++ b/core/src/main/java/org/geysermc/geyser/pack/SkullResourcePackManager.java @@ -48,7 +48,9 @@ import java.nio.file.StandardOpenOption; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.List; -import java.util.*; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; import java.util.function.UnaryOperator; import java.util.stream.Stream; import java.util.zip.ZipEntry; diff --git a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java index 6bbca11ca..320334ee5 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java +++ b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java @@ -27,11 +27,11 @@ package org.geysermc.geyser.ping; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.nbt.util.VarInts; import io.netty.handler.codec.haproxy.HAProxyCommand; import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol; import io.netty.util.NetUtil; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.util.VarInts; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.network.GameProtocol; diff --git a/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java b/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java index 318035e32..69ac974cc 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java +++ b/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.ping; import org.checkerframework.checker.nullness.qual.Nullable; + import java.net.InetSocketAddress; /** diff --git a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java index e37f8aa64..9a5b43816 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.registry; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundTabListPacket; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchStartPacket; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTabListPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchStartPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket; import io.netty.channel.EventLoop; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.loader.RegistryLoaders; 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 9b5ed8ae6..f19898016 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.registry; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.mc.protocol.data.game.level.event.LevelEvent; -import com.github.steveice10.mc.protocol.data.game.level.particle.ParticleType; -import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; -import com.github.steveice10.packetlib.packet.Packet; +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 org.geysermc.mcprotocollib.network.packet.Packet; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/BlockEntityRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/BlockEntityRegistryLoader.java index f47273827..a813ee458 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/BlockEntityRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/BlockEntityRegistryLoader.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.registry.loader; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.geyser.translator.level.block.entity.BlockEntity; diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java index 677806b3f..a09d6d6d3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.registry.loader; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.data.game.level.particle.ParticleType; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.LevelEventType; diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundEventsRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundEventsRegistryLoader.java index c0600b878..4e3fbe40a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundEventsRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundEventsRegistryLoader.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.registry.loader; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.data.game.level.event.LevelEvent; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEvent; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.cloudburstmc.protocol.bedrock.data.LevelEventType; import org.geysermc.geyser.GeyserImpl; @@ -58,20 +58,20 @@ public class SoundEventsRegistryLoader extends EffectRegistryLoader { - javaEffect = com.github.steveice10.mc.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); + javaEffect = org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); LevelEventType levelEventType = org.cloudburstmc.protocol.bedrock.data.LevelEvent.valueOf(node.get("name").asText()); int data = node.has("data") ? node.get("data").intValue() : 0; transformer = new SoundLevelEventTranslator(levelEventType, data); } case "soundEvent" -> { - javaEffect = com.github.steveice10.mc.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); + javaEffect = org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); org.cloudburstmc.protocol.bedrock.data.SoundEvent soundEvent = org.cloudburstmc.protocol.bedrock.data.SoundEvent.valueOf(node.get("name").asText()); String identifier = node.has("identifier") ? node.get("identifier").asText() : ""; int extraData = node.has("extraData") ? node.get("extraData").intValue() : -1; transformer = new SoundEventEventTranslator(soundEvent, identifier, extraData); } case "playSound" -> { - javaEffect = com.github.steveice10.mc.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); + javaEffect = org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEventType.valueOf(entry.getKey()); String name = node.get("name").asText(); float volume = node.has("volume") ? node.get("volume").floatValue() : 1.0f; boolean pitchSub = node.has("pitch_sub") && node.get("pitch_sub").booleanValue(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java index e8901a550..d32d5bc09 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.registry.mappings.versions; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.github.steveice10.mc.protocol.data.game.Identifier; +import org.geysermc.mcprotocollib.protocol.data.game.Identifier; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java index d055f7b28..9be00732c 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.registry.populator; -import com.github.steveice10.packetlib.packet.Packet; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.FileUtils; +import org.geysermc.mcprotocollib.network.packet.Packet; public class PacketRegistryPopulator { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java index 34e855212..928ab8df9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java @@ -26,9 +26,9 @@ package org.geysermc.geyser.registry.populator; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; +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.RecipeType; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index 199481cbc..f3cfa3f0f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.registry.type; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Builder; diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java index c00c69660..6c1389ef5 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.scoreboard; -import com.github.steveice10.mc.protocol.data.game.chat.numbers.NumberFormat; -import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; -import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import lombok.Getter; import lombok.Setter; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import java.util.Map; import java.util.Objects; diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java index ec17818c4..9a26b7f77 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.scoreboard; -import com.github.steveice10.mc.protocol.data.game.chat.numbers.FixedFormat; -import com.github.steveice10.mc.protocol.data.game.chat.numbers.NumberFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.FixedFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; import net.kyori.adventure.text.Component; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import lombok.Getter; diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java index dfd74a79e..acce86f4d 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.scoreboard; -import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import org.checkerframework.checker.nullness.qual.Nullable; @@ -40,6 +39,7 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; import org.jetbrains.annotations.Contract; import java.util.*; @@ -48,10 +48,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.util.stream.Collectors; -import static org.geysermc.geyser.scoreboard.UpdateType.ADD; -import static org.geysermc.geyser.scoreboard.UpdateType.NOTHING; -import static org.geysermc.geyser.scoreboard.UpdateType.REMOVE; -import static org.geysermc.geyser.scoreboard.UpdateType.UPDATE; +import static org.geysermc.geyser.scoreboard.UpdateType.*; public final class Scoreboard { private static final boolean SHOW_SCOREBOARD_LOGS = Boolean.parseBoolean(System.getProperty("Geyser.ShowScoreboardLogs", "true")); diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java index 9164fec1d..cdf2e247e 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.scoreboard; -import com.github.steveice10.mc.protocol.data.game.scoreboard.NameTagVisibility; -import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.AccessLevel; import lombok.Getter; diff --git a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java index 40b685783..8845cdbea 100644 --- a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.session; -import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper; -import com.github.steveice10.packetlib.packet.Packet; -import com.github.steveice10.packetlib.tcp.TcpSession; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.mcprotocollib.network.packet.Packet; +import org.geysermc.mcprotocollib.network.tcp.TcpSession; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; @Getter @RequiredArgsConstructor 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 9ae1f6f49..82717050f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -28,35 +28,35 @@ package org.geysermc.geyser.session; import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.auth.service.MsaAuthenticationService; -import com.github.steveice10.mc.protocol.MinecraftConstants; -import com.github.steveice10.mc.protocol.MinecraftProtocol; -import com.github.steveice10.mc.protocol.data.ProtocolState; -import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.data.game.entity.player.HandPreference; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; -import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility; -import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; -import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic; -import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; -import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundClientInformationPacket; -import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; -import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; -import com.github.steveice10.packetlib.BuiltinFlags; -import com.github.steveice10.packetlib.Session; -import com.github.steveice10.packetlib.event.session.*; -import com.github.steveice10.packetlib.packet.Packet; -import com.github.steveice10.packetlib.tcp.TcpClientSession; -import com.github.steveice10.packetlib.tcp.TcpSession; +import org.geysermc.mcprotocollib.protocol.MinecraftConstants; +import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; +import org.geysermc.mcprotocollib.protocol.data.ProtocolState; +import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +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.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.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.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.player.ServerboundPlayerAbilitiesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; +import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; +import org.geysermc.mcprotocollib.network.BuiltinFlags; +import org.geysermc.mcprotocollib.network.Session; +import org.geysermc.mcprotocollib.network.event.session.*; +import org.geysermc.mcprotocollib.network.packet.Packet; +import org.geysermc.mcprotocollib.network.tcp.TcpClientSession; +import org.geysermc.mcprotocollib.network.tcp.TcpSession; import io.netty.channel.Channel; import io.netty.channel.EventLoop; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java index 3bc661c16..da3c83ed4 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSeenAdvancementsPacket; +import org.geysermc.mcprotocollib.protocol.data.game.advancement.Advancement; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSeenAdvancementsPacket; import lombok.Getter; import lombok.Setter; import org.geysermc.cumulus.form.SimpleForm; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java index 6a9025bc0..90f22afd6 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundEditBookPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundEditBookPacket; import lombok.Setter; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java index d2c1415a3..e3a9cba89 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import lombok.Getter; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java index a7693e516..a9679f6ef 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.data.game.entity.Effect; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import lombok.Getter; import java.util.EnumSet; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java index eced0e50b..f9515dbb4 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.LodestoneTracker; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos; +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.LodestoneTracker; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.checkerframework.checker.nullness.qual.Nullable; 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 d6d5ae292..7ad2afec7 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 @@ -25,8 +25,6 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.data.game.RegistryEntry; -import com.github.steveice10.mc.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -44,6 +42,8 @@ import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; +import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; import java.util.HashMap; import java.util.List; 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 b2f43f180..38ac32214 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import it.unimi.dsi.fastutil.ints.IntList; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; 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 8d243d3fa..80139a988 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 @@ -33,7 +33,7 @@ import lombok.RequiredArgsConstructor; * Represents a teleport ID and corresponding coordinates that need to be confirmed.
* * The vanilla Java client, after getting a - * {@link com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket}, + * {@link org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket}, * adjusts the player's positions and immediately sends a teleport back. However, we want to acknowledge that the * Bedrock player actually moves close to that point, so we store the teleport until we get a movement packet from * Bedrock that the teleport was successful. 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 6be57670c..c84126608 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -37,6 +36,7 @@ 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.setting.Difficulty; import java.util.Iterator; diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index 2d6345bfa..d2a45b614 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java @@ -30,8 +30,6 @@ import com.github.steveice10.mc.auth.data.GameProfile.Texture; import com.github.steveice10.mc.auth.data.GameProfile.TextureModel; import com.github.steveice10.mc.auth.data.GameProfile.TextureType; import com.github.steveice10.mc.auth.exception.property.PropertyException; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -45,6 +43,8 @@ import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinManager.GameProfileData; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.awt.*; import java.awt.image.BufferedImage; diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java index 500f44d0b..f139b0bba 100644 --- a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.text; -import com.github.steveice10.mc.protocol.data.game.chat.BuiltinChatType; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.packet.TextPacket; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.geysermc.mcprotocollib.protocol.data.game.chat.BuiltinChatType; public record ChatTypeEntry(TextPacket.@NonNull Type bedrockChatType, @Nullable TextDecoration textDecoration) { private static final ChatTypeEntry CHAT = new ChatTypeEntry(TextPacket.Type.CHAT, null); diff --git a/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java b/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java index 692a05110..94d8b254f 100644 --- a/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java @@ -32,7 +32,9 @@ import org.geysermc.geyser.util.AssetUtils; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.WebUtils; -import java.io.*; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java index bad55a5ca..a85153d13 100644 --- a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.text; -import com.github.steveice10.mc.protocol.data.game.RegistryEntry; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import java.util.EnumSet; import java.util.Locale; diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java index e82b994c7..a2615deb1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.translator.collision; -import org.cloudburstmc.math.vector.Vector3d; -import org.cloudburstmc.math.vector.Vector3i; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.cloudburstmc.math.vector.Vector3d; +import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.CollisionManager; diff --git a/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java index dd53e4c5b..194194501 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.entity; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.geyser.entity.type.Entity; import java.util.function.BiConsumer; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java index 31a0b7b11..2da51a0eb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; @@ -39,6 +38,7 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.updater.AnvilInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import java.util.Objects; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java index 0f8fa4ca7..f70bad9ea 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java @@ -25,15 +25,11 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; -import org.geysermc.geyser.inventory.BedrockContainerSlot; -import org.geysermc.geyser.inventory.Container; -import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.PlayerInventory; -import org.geysermc.geyser.inventory.SlotType; +import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; public abstract class BaseInventoryTranslator extends InventoryTranslator { public BaseInventoryTranslator(int size) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java index 00323ce83..9aeeff007 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetBeaconPacket; import it.unimi.dsi.fastutil.ints.IntSets; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; @@ -47,6 +45,8 @@ import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetBeaconPacket; import java.util.OptionalInt; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java index 95f227ed7..a115bd953 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; public class CartographyInventoryTranslator extends AbstractBlockInventoryTranslator { public CartographyInventoryTranslator() { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java index 97398a207..2a2f5beb5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java @@ -25,19 +25,15 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; -import org.geysermc.geyser.inventory.BedrockContainerSlot; -import org.geysermc.geyser.inventory.CrafterContainer; -import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.PlayerInventory; -import org.geysermc.geyser.inventory.SlotType; +import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.updater.CrafterInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; /** * Translates the Crafter. Most important thing to know about this class is that diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java index 0085a7550..8fee2a391 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import it.unimi.dsi.fastutil.ints.IntSets; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData; @@ -41,6 +39,8 @@ import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import java.util.Arrays; import java.util.Locale; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java index 369a80282..2a80161c0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.geysermc.geyser.inventory.BedrockContainerSlot; @@ -34,6 +33,7 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; /** * Droppers and dispensers 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 4a3e31b30..0914aeba8 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,11 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import org.checkerframework.checker.nullness.qual.Nullable; @@ -59,6 +54,11 @@ import org.geysermc.geyser.translator.inventory.furnace.FurnaceInventoryTranslat import org.geysermc.geyser.translator.inventory.furnace.SmokerInventoryTranslator; 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 java.util.*; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 7dff2647c..f3bbc9b87 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -25,12 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.WritableBookContent; -import com.github.steveice10.mc.protocol.data.game.item.component.WrittenBookContent; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -38,16 +32,18 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.Container; -import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.LecternContainer; -import org.geysermc.geyser.inventory.PlayerInventory; +import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBookContent; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import java.util.Collections; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 636a7982a..e8571c8fb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.item.component.BannerPatternLayer; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.cloudburstmc.nbt.NbtMap; @@ -50,6 +46,10 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.item.type.BannerItem; import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; +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.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import java.util.ArrayList; import java.util.HashMap; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java index c4f958ba1..7a7646503 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSelectTradePacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; @@ -44,6 +42,8 @@ import org.geysermc.geyser.inventory.updater.InventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSelectTradePacket; import java.util.concurrent.TimeUnit; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java index 5f08f1b8a..201c900d6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java @@ -31,11 +31,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; 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.DropAction; -import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction; -import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.PlaceAction; -import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.SwapAction; -import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.TakeAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.*; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.inventory.BedrockContainerSlot; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 36d10aa54..142651eb4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -37,12 +33,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; 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.CraftCreativeAction; -import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.DestroyAction; -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.request.action.*; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse; import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; @@ -55,6 +46,10 @@ import org.geysermc.geyser.skin.FakeHeadProvider; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import java.util.Arrays; import java.util.Collections; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java index b8bb2bee4..543f519c9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -39,6 +38,7 @@ import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator { public ShulkerInventoryTranslator() { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java index d3d15680a..54f2f447b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.translator.inventory; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; @@ -39,6 +36,9 @@ import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator { public StonecutterInventoryTranslator() { diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java index 8a541fb9b..91eee3895 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.item; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.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.DataComponentType; import it.unimi.dsi.fastutil.Pair; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; 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 a8e9e1c52..24362f800 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 @@ -29,13 +29,13 @@ import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.data.GameProfile.Texture; import com.github.steveice10.mc.auth.data.GameProfile.TextureType; import com.github.steveice10.mc.auth.exception.property.PropertyException; -import com.github.steveice10.mc.protocol.data.game.Identifier; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOperation; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.AdventureModePredicate; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.ItemAttributeModifiers; +import org.geysermc.mcprotocollib.protocol.data.game.Identifier; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.AdventureModePredicate; +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.ItemAttributeModifiers; import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index 450c786f2..d70f53e2c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.level; -import com.github.steveice10.mc.protocol.data.game.RegistryEntry; -import com.github.steveice10.mc.protocol.data.game.chunk.BitStorage; -import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette; -import com.github.steveice10.mc.protocol.data.game.chunk.palette.GlobalPalette; -import com.github.steveice10.mc.protocol.data.game.chunk.palette.Palette; -import com.github.steveice10.mc.protocol.data.game.chunk.palette.SingletonPalette; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.BitStorage; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.GlobalPalette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.Palette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.SingletonPalette; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntLists; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java index e0e0130c5..bc08dd93b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java index 12b050236..0db362949 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.nbt.NbtMapBuilder; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java index 58d36af56..1c46edf0a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntity.java index 3e320029b..e6ce287c1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntity.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java index 053e2c8f3..5f6487a24 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMap; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java index 9a2b9d8e1..d2777d372 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java index 5a15ebbb7..390615b9e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; @@ -34,6 +33,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.CAMPFIRE) public class CampfireBlockEntityTranslator extends BlockEntityTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java index 36345394b..31a7dbc69 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.*; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java index 1774d9c76..3ab61c489 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index 567d3a5e1..141520ed9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -33,6 +32,7 @@ import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.DoubleChestValue; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; /** * Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockOnlyBlockEntity diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java index da992d0ad..633992431 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java @@ -25,16 +25,16 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.LongTag; import com.github.steveice10.opennbt.tag.builtin.Tag; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import java.util.LinkedHashMap; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/HangingSignBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/HangingSignBlockEntityTranslator.java index ea11dcf48..3c09c0499 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/HangingSignBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/HangingSignBlockEntityTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import org.geysermc.geyser.util.SignUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.HANGING_SIGN) public class HangingSignBlockEntityTranslator extends SignBlockEntityTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java index c8dcbc008..34c051a34 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.JIGSAW) public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index 634b7c6f1..78e71000a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java index bbe6a0725..529ed731e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.translator.inventory.ShulkerInventoryTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.SHULKER_BOX) public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java index 238b136ff..38a4f59c5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index e9aceece5..61c922528 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index f2b0f5a78..5611bf90c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java index a24d010b7..40b10de40 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java index a6a99d868..da013cf3c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.TRIAL_SPAWNER) public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/event/LevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/event/LevelEventTranslator.java index 03c40c796..311ae0acf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/event/LevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/event/LevelEventTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.event; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import org.geysermc.geyser.session.GeyserSession; /** diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/event/PlaySoundEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/event/PlaySoundEventTranslator.java index 22d5c953d..774060a4c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/event/PlaySoundEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/event/PlaySoundEventTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.event; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundEventEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundEventEventTranslator.java index d1695303d..d7a58fe48 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundEventEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundEventEventTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.event; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundLevelEventTranslator.java index 67d43e6a8..e5b20493b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundLevelEventTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.level.event; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEventType; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; 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 33fbaed30..79e013246 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,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; +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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java index 239bf9616..b5e923ee6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetJigsawBlockPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetJigsawBlockPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index f4116ec0c..35c46ffd2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket; import org.geysermc.geyser.entity.EntityDefinitions; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java index 10024c02f..456b6507f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.Filterable; -import com.github.steveice10.mc.protocol.data.game.item.component.WritableBookContent; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundEditBookPacket; +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.item.component.Filterable; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBookContent; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundEditBookPacket; import org.cloudburstmc.protocol.bedrock.packet.BookEditPacket; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.WrittenBookItem; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandBlockUpdateTranslator.java index b9561518e..401ece6ca 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandBlockUpdateTranslator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.level.block.CommandBlockMode; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCommandBlockPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCommandMinecartPacket; import org.cloudburstmc.protocol.bedrock.packet.CommandBlockUpdatePacket; 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.level.block.CommandBlockMode; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCommandBlockPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCommandMinecartPacket; @Translator(packet = CommandBlockUpdatePacket.class) public class BedrockCommandBlockUpdateTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java index e2552802f..d675a07e9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.MerchantContainer; 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 8d005e515..c4a00e41f 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 @@ -25,14 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.*; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import org.cloudburstmc.math.vector.Vector3d; @@ -73,11 +65,15 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator; 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.BlockUtils; -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.*; +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.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.*; import java.util.List; import java.util.concurrent.TimeUnit; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java index 4a5145ead..dff4631b0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; import org.cloudburstmc.protocol.bedrock.packet.ItemFrameDropItemPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; 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.data.game.entity.player.InteractAction; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; /** * Pre-1.16.210: used for both survival and creative item frame item removal diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java index 6bac96206..e6d3d4dce 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; +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.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; import org.cloudburstmc.protocol.bedrock.packet.LecternUpdatePacket; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.LecternContainer; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java index f5086e29a..030c6580f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSetCarriedItemPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSetCarriedItemPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket; import org.geysermc.geyser.inventory.GeyserItemStack; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java index 8a8749e34..f8f31d67f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.geysermc.geyser.entity.EntityDefinitions; @@ -34,6 +33,7 @@ import org.geysermc.geyser.entity.type.Entity; 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.serverbound.level.ServerboundMoveVehiclePacket; /** * Sent by the client when moving a horse or boat. diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockNetworkStackLatencyTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockNetworkStackLatencyTranslator.java index 412a97e3a..6ca0f3500 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockNetworkStackLatencyTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockNetworkStackLatencyTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundKeepAlivePacket; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; @@ -33,6 +32,7 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType; 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.common.serverbound.ServerboundKeepAlivePacket; import java.util.Collections; import java.util.concurrent.TimeUnit; 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 index 1737364ff..beb724ffb 100644 --- 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 @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundPlayerInputPacket; +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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java index be2b1f28a..d0c29c6a9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; import org.cloudburstmc.protocol.bedrock.data.Ability; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.RequestAbilityPacket; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java index 7c4798f80..878f00443 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.ClientCommand; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; +import org.geysermc.mcprotocollib.protocol.data.game.ClientCommand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; import org.cloudburstmc.protocol.bedrock.packet.RespawnPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java index 3314975ef..06f680ca6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.ClientCommand; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; +import org.geysermc.mcprotocollib.protocol.data.game.ClientCommand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; import org.cloudburstmc.protocol.bedrock.packet.ShowCreditsPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureBlockUpdateTranslator.java index 84b7ffdd2..1434a6d99 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureBlockUpdateTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockAction; -import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockMode; import org.cloudburstmc.protocol.bedrock.data.structure.StructureBlockType; import org.cloudburstmc.protocol.bedrock.data.structure.StructureEditorData; import org.cloudburstmc.protocol.bedrock.packet.StructureBlockUpdatePacket; @@ -34,6 +32,8 @@ 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.StructureBlockUtils; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.UpdateStructureBlockAction; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.UpdateStructureBlockMode; @Translator(packet = StructureBlockUpdatePacket.class) public class BedrockStructureBlockUpdateTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java index 947946f36..026d257ab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockStructureTemplateDataRequestTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockAction; -import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockMode; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.structure.StructureSettings; import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateRequestOperation; @@ -35,6 +33,8 @@ 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.StructureBlockUtils; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.UpdateStructureBlockAction; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.UpdateStructureBlockMode; /** * Packet used in Bedrock to load structure size into the structure block GUI. It is sent every time the GUI is opened. diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockToggleCrafterSlotRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockToggleCrafterSlotRequestTranslator.java index 5c494cd88..980e8ac00 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockToggleCrafterSlotRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockToggleCrafterSlotRequestTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerSlotStateChangedPacket; import org.cloudburstmc.protocol.bedrock.packet.ToggleCrafterSlotRequestPacket; import org.geysermc.geyser.inventory.CrafterContainer; 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.serverbound.inventory.ServerboundContainerSlotStateChangedPacket; @Translator(packet = ToggleCrafterSlotRequestPacket.class) public class BedrockToggleCrafterSlotRequestTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java index 17a80aa39..6b7510d8b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSelectTradePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSelectTradePacket; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.MerchantContainer; 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 index 2fd9ce405..887ea3c09 100644 --- 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 @@ -25,13 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.*; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; @@ -57,6 +50,9 @@ 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.*; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.*; @Translator(packet = PlayerActionPacket.class) public class BedrockActionTranslator extends PacketTranslator { 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 a45690ab1..20c1b055d 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,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; +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; 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/BedrockMovePlayerTranslator.java index d81c0abab..cae12170d 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/BedrockMovePlayerTranslator.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerRotPacket; -import com.github.steveice10.packetlib.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.network.packet.Packet; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; 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/bedrock/entity/player/BedrockRiderJumpTranslator.java index f7ac81219..76b95103e 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/bedrock/entity/player/BedrockRiderJumpTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; +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.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java index df28f7ca7..aa815fab7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import org.cloudburstmc.protocol.bedrock.packet.SetDefaultGameTypePacket; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; 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.EntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; @Translator(packet = SetDefaultGameTypePacket.class) public class BedrockSetDefaultGameTypeTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java index b996a96b1..176f00b8f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; +import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import org.cloudburstmc.protocol.bedrock.packet.SetDifficultyPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java index 2d8d420f8..f00156268 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; 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.EntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; /** * In vanilla Bedrock, if you have operator status, this sets the player's gamemode without confirmation from the server. diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerInventoryOptionsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerInventoryOptionsTranslator.java index 0f07d84da..7e23c2e4c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerInventoryOptionsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerInventoryOptionsTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.inventory.CraftingBookStateType; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRecipeBookChangeSettingsPacket; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.CraftingBookStateType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRecipeBookChangeSettingsPacket; import org.cloudburstmc.protocol.bedrock.data.inventory.InventoryTabLeft; import org.cloudburstmc.protocol.bedrock.data.inventory.InventoryTabRight; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerInventoryOptionsPacket; 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 ec8a18edb..822d8f6ba 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 @@ -25,10 +25,10 @@ package org.geysermc.geyser.translator.protocol.bedrock.world; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; +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.packet.ingame.serverbound.player.ServerboundSwingPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaAwardStatsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaAwardStatsTranslator.java index 4f4c2e549..4f0f1f587 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaAwardStatsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaAwardStatsTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundAwardStatsPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundAwardStatsPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaBossEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaBossEventTranslator.java index 30d6aa017..c1e0b9a3a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaBossEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaBossEventTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundBossEventPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundBossEventPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.BossBar; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaChangeDifficultyTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaChangeDifficultyTranslator.java index 970c49e23..996dc9d84 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaChangeDifficultyTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaChangeDifficultyTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundChangeDifficultyPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundChangeDifficultyPacket; import org.cloudburstmc.protocol.bedrock.packet.SetDifficultyPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; 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/JavaClientboundRecipesTranslator.java index 3fe5abff8..9eb69183d 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/JavaClientboundRecipesTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRecipePacket; +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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePackPushPacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePackPushPacket.java index b84c7a55b..9e7306ab1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePackPushPacket.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePackPushPacket.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.ResourcePackStatus; -import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundResourcePackPushPacket; -import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundResourcePackPacket; +import org.geysermc.mcprotocollib.protocol.data.game.ResourcePackStatus; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundResourcePackPushPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundResourcePackPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 9d3351217..706997402 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.command.CommandNode; -import com.github.steveice10.mc.protocol.data.game.command.CommandParser; -import com.github.steveice10.mc.protocol.data.game.command.properties.ResourceProperties; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCommandsPacket; +import org.geysermc.mcprotocollib.protocol.data.game.command.CommandNode; +import org.geysermc.mcprotocollib.protocol.data.game.command.CommandParser; +import org.geysermc.mcprotocollib.protocol.data.game.command.properties.ResourceProperties; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCommandsPacket; import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java index 2a7202b0c..f8a21f904 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java @@ -25,13 +25,11 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundCustomPayloadPacket; -import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import com.google.common.base.Charsets; -import org.cloudburstmc.protocol.bedrock.packet.TransferPacket; -import org.cloudburstmc.protocol.bedrock.packet.UnknownPacket; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import org.cloudburstmc.protocol.bedrock.packet.TransferPacket; +import org.cloudburstmc.protocol.bedrock.packet.UnknownPacket; import org.geysermc.cumulus.Forms; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormType; @@ -45,6 +43,8 @@ import org.geysermc.geyser.GeyserLogger; 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.common.clientbound.ClientboundCustomPayloadPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import java.nio.charset.StandardCharsets; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomQueryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomQueryTranslator.java index 6096af12d..1e448c48e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomQueryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomQueryTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundCustomQueryPacket; -import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; +import org.geysermc.mcprotocollib.protocol.packet.login.clientbound.ClientboundCustomQueryPacket; +import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java index 8bf5ae4ba..2eb08fb92 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundDisconnectPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundDisconnectPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisguisedChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisguisedChatTranslator.java index 2ad45fe52..67bdb6f9a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisguisedChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisguisedChatTranslator.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDisguisedChatPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundDisguisedChatPacket; @Translator(packet = ClientboundDisguisedChatPacket.class) public class JavaDisguisedChatTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java index 12f96360b..96bab0bfa 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java @@ -26,8 +26,6 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; -import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundGameProfilePacket; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; @@ -35,6 +33,8 @@ import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.PluginMessageUtils; +import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; +import org.geysermc.mcprotocollib.protocol.packet.login.clientbound.ClientboundGameProfilePacket; /** * ClientboundGameProfilePacket triggers protocol change LOGIN -> CONFIGURATION diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java index da8358da2..399c23080 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundKeepAlivePacket; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundKeepAlivePacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java index c0be2c624..e92ae1bbd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundLoginDisconnectPacket; +import org.geysermc.mcprotocollib.protocol.packet.login.clientbound.ClientboundLoginDisconnectPacket; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TranslatableComponent; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index ebf99fb65..fe4401dca 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo; -import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; +import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameRuleData; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPingTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPingTranslator.java index c966f3abb..fa7175003 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPingTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPingTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundPingPacket; -import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundPongPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundPingPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundPongPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java index e06182b8d..f8d392dd5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerChatPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerChatPacket; import net.kyori.adventure.text.Component; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java index ddb9c76b7..6af94001e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; +import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index bfb590247..fe0868253 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRespawnPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; @@ -40,6 +38,8 @@ import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRespawnPacket; @Translator(packet = ClientboundRespawnPacket.class) public class JavaRespawnTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectAdvancementsTabTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectAdvancementsTabTranslator.java index e33863244..04c018472 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectAdvancementsTabTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectAdvancementsTabTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundSelectAdvancementsTabPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundSelectAdvancementsTabPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.AdvancementsCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java index e400773c8..0a0f2832c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundSystemChatPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundSystemChatPacket; import net.kyori.adventure.text.TranslatableComponent; import org.cloudburstmc.protocol.bedrock.packet.TextPacket; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateAdvancementsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateAdvancementsTranslator.java index a7efdbefa..8bf520da0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateAdvancementsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateAdvancementsTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateAdvancementsPacket; +import org.geysermc.mcprotocollib.protocol.data.game.advancement.Advancement; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateAdvancementsPacket; import org.cloudburstmc.protocol.bedrock.packet.ToastRequestPacket; import org.geysermc.geyser.level.GeyserAdvancement; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 20b223248..0db62f21d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -25,15 +25,6 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; -import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; -import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingTransformRecipeData; -import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; @@ -48,11 +39,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescri import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket; 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.inventory.recipe.GeyserStonecutterData; -import org.geysermc.geyser.inventory.recipe.TrimRecipe; +import org.geysermc.geyser.inventory.recipe.*; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -60,6 +47,15 @@ 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.Recipe; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapedRecipeData; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapelessRecipeData; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.SmithingTransformRecipeData; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.StoneCuttingRecipeData; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; import java.util.*; import java.util.stream.Collectors; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateTagsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateTagsTranslator.java index ae59cf0f8..4df73b4c2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateTagsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateTagsTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAnimateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAnimateTranslator.java index 1aa147314..8bd4bad10 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAnimateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAnimateTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.data.game.entity.player.Animation; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundAnimatePacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.AnimateEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; @@ -36,6 +34,8 @@ 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.DimensionUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Animation; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundAnimatePacket; import java.util.Optional; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java index 19a6e25c0..9d491f92c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundDamageEventPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundDamageEventPacket; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.geyser.entity.type.Entity; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index 4b1483bbf..fbabd4afa 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityPosRotTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityPosRotTranslator.java index 2ad1503a8..31d46f096 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityPosRotTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityPosRotTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityPosRotPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityPosRotPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityPosTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityPosTranslator.java index cbb3cecc2..638828a2b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityPosTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityPosTranslator.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityPosPacket; import org.geysermc.geyser.entity.type.Entity; 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.ClientboundMoveEntityPosPacket; @Translator(packet = ClientboundMoveEntityPosPacket.class) public class JavaMoveEntityPosTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityRotTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityRotTranslator.java index 75d4c6189..b48b801f3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityRotTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveEntityRotTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityRotPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundMoveEntityRotPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveVehicleTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveVehicleTranslator.java index bdb159633..111b72c4f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveVehicleTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveVehicleTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundMoveVehiclePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundMoveVehiclePacket; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveEntitiesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveEntitiesTranslator.java index 776cfb4d7..0148b1e05 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveEntitiesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveEntitiesTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundRemoveEntitiesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRemoveEntitiesPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveMobEffectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveMobEffectTranslator.java index 52b771caa..dafa5aec1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveMobEffectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRemoveMobEffectTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundRemoveMobEffectPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRemoveMobEffectPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEffectPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRotateHeadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRotateHeadTranslator.java index 65e529792..dc03a76e9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRotateHeadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaRotateHeadTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundRotateHeadPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRotateHeadPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityDataTranslator.java index 54c14f7f0..2dc780c66 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityDataTranslator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityDataPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Entity; 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.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityDataPacket; @Translator(packet = ClientboundSetEntityDataPacket.class) public class JavaSetEntityDataTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityLinkTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityLinkTranslator.java index 720f03779..d595e928f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityLinkTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityLinkTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityLinkPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityLinkPacket; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityMotionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityMotionTranslator.java index 62e1d200e..6bbc59e8b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityMotionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityMotionTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityMotionPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityMotionPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; import org.geysermc.geyser.entity.type.Entity; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index 7c93725e0..cc71cca0a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Equipment; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundSetEquipmentPacket; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Equipment; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEquipmentPacket; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java index 14d6127ad..9895a248c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundSetPassengersPacket; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; @@ -35,6 +34,7 @@ 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.EntityUtils; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetPassengersPacket; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java index 68f310db4..d6e70b3f3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundSoundEntityPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundSoundEntityPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTakeItemEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTakeItemEntityTranslator.java index cc2b4b030..7722459d4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTakeItemEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTakeItemEntityTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundTakeItemEntityPacket; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.TakeItemEntityPacket; @@ -34,6 +33,7 @@ import org.geysermc.geyser.entity.type.ExpOrbEntity; 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.ClientboundTakeItemEntityPacket; /** * This packet is called whenever a player picks up an item. 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 9925bf432..8b3a06d7c 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,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundTeleportEntityPacket; +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.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateAttributesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateAttributesTranslator.java index a42f2d5dd..31c9c7df3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateAttributesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateAttributesTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundUpdateAttributesPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; 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.ClientboundUpdateAttributesPacket; @Translator(packet = ClientboundUpdateAttributesPacket.class) public class JavaUpdateAttributesTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java index e56a272ab..7638df8be 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundUpdateMobEffectPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundUpdateMobEffectPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEffectPacket; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java index 523d0fdc4..c48c040a2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundBlockChangedAckPacket; 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.ClientboundBlockChangedAckPacket; @Translator(packet = ClientboundBlockChangedAckPacket.class) public class JavaBlockChangedAckTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java index 783f4e824..6f41603a4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerAbilitiesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerAbilitiesPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerCombatKillTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerCombatKillTranslator.java index 4b0cafed3..6f719b762 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerCombatKillTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerCombatKillTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerCombatKillPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerCombatKillPacket; import org.cloudburstmc.protocol.bedrock.packet.DeathInfoPacket; import net.kyori.adventure.text.Component; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoRemoveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoRemoveTranslator.java index f5c4b1398..60a245111 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoRemoveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoRemoveTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoRemovePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoRemovePacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java index 3debb7f5f..f5ea4c08d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java @@ -26,9 +26,6 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.protocol.data.game.PlayerListEntry; -import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; @@ -38,6 +35,9 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry; +import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntryAction; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java index 7814a6719..b1413542b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerLookAtPacket; import org.cloudburstmc.math.vector.Vector3f; 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.MathUtils; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerLookAtPacket; @Translator(packet = ClientboundPlayerLookAtPacket.class) public class JavaPlayerLookAtTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java index f2c566a23..413833acf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.player.PositionElement; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PositionElement; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; 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/JavaSetCarriedItemTranslator.java index 97a9e0aae..e590b5658 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/JavaSetCarriedItemTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundSetCarriedItemPacket; +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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetExperienceTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetExperienceTranslator.java index 80dd08eaa..3e3550415 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetExperienceTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetExperienceTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundSetExperiencePacket; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; @@ -33,6 +32,7 @@ import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; 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.ClientboundSetExperiencePacket; import java.util.Arrays; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetHealthTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetHealthTranslator.java index decf910ca..1f8992e54 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetHealthTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetHealthTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundSetHealthPacket; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.packet.RespawnPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; @@ -34,6 +33,7 @@ import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; 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.ClientboundSetHealthPacket; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java index e058594c3..572d233d0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.translator.protocol.java.entity.spawn; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.entity.object.FallingBlockData; -import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData; -import com.github.steveice10.mc.protocol.data.game.entity.object.WardenData; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.FallingBlockData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ProjectileData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.WardenData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinition; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java index 2d5e8fb08..8f37eb4d4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity.spawn; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ExpOrbEntity; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerCloseTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerCloseTranslator.java index 9f687f046..c5786d9aa 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerCloseTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerCloseTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundContainerClosePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerClosePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java index 2f8204871..44bd7171f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetContentPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetContentPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetDataTranslator.java index 923b10a26..0b8d8c5ab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetDataTranslator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetDataPacket; import org.geysermc.geyser.inventory.Inventory; 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.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetDataPacket; @Translator(packet = ClientboundContainerSetDataPacket.class) public class JavaContainerSetDataTranslator extends PacketTranslator { 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 594c99291..4372b5ea5 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 @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetSlotPacket; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetSlotPacket; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java index d2abcb5e3..23b79ba67 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaHorseScreenOpenTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundHorseScreenOpenPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundHorseScreenOpenPacket; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java index 68d2bcab3..970061436 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.inventory.VillagerTrade; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java index 24b964b7c..539cce06d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundOpenBookPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.LecternContainer; @@ -38,6 +35,9 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator; 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.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundOpenBookPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import java.util.Objects; 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 1d0b4bf63..31894339c 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 @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundOpenScreenPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundOpenScreenPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import net.kyori.adventure.text.Component; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.network.GameProtocol; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockDestructionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockDestructionTranslator.java index 2fdba716b..1b23066cc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockDestructionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockDestructionTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockDestructionPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockDestructionPacket; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.geysermc.geyser.registry.BlockRegistries; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java index 325bae593..ca746f79b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockEntityDataPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.math.vector.Vector3i; @@ -46,6 +43,9 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.StructureBlockUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEntityDataPacket; @Translator(packet = ClientboundBlockEntityDataPacket.class) public class JavaBlockEntityDataTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java index 28fd2401b..8f6c69a29 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.block.value.*; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java index 4ccc2b4d4..ac8bd8eb0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockUpdatePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockUpdatePacket; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaChunkBatchFinishedTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaChunkBatchFinishedTranslator.java index 115222c6c..c93ebd530 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaChunkBatchFinishedTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaChunkBatchFinishedTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchFinishedPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundChunkBatchReceivedPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchFinishedPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundChunkBatchReceivedPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; 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 4249be6fc..8e07a7d89 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,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCooldownPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCooldownPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerStartItemCooldownPacket; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java index c5dba39ae..7b6d4e264 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java index 4cc0af6e7..b0abe0f59 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundForgetLevelChunkPacket; import org.cloudburstmc.math.vector.Vector3i; 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.ChunkUtils; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundForgetLevelChunkPacket; import java.util.ArrayList; import java.util.Iterator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java index f2d60fe34..3aa343cf5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java @@ -25,14 +25,14 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.ClientCommand; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.level.notify.EnterCreditsValue; -import com.github.steveice10.mc.protocol.data.game.level.notify.RainStrengthValue; -import com.github.steveice10.mc.protocol.data.game.level.notify.RespawnScreenValue; -import com.github.steveice10.mc.protocol.data.game.level.notify.ThunderStrengthValue; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundGameEventPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; +import org.geysermc.mcprotocollib.protocol.data.game.ClientCommand; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.level.notify.EnterCreditsValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.notify.RainStrengthValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.notify.RespawnScreenValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.notify.ThunderStrengthValue; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundGameEventPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameRuleData; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index 1e6534130..4fd581d84 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -25,26 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.chunk.BitStorage; -import com.github.steveice10.mc.protocol.data.game.chunk.ChunkSection; -import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette; -import com.github.steveice10.mc.protocol.data.game.chunk.palette.GlobalPalette; -import com.github.steveice10.mc.protocol.data.game.chunk.palette.Palette; -import com.github.steveice10.mc.protocol.data.game.chunk.palette.SingletonPalette; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelChunkWithLightPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntImmutableList; -import it.unimi.dsi.fastutil.ints.IntList; -import it.unimi.dsi.fastutil.ints.IntLists; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NBTOutputStream; @@ -73,15 +59,22 @@ import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.BitStorage; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.ChunkSection; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.GlobalPalette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.Palette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.SingletonPalette; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelChunkWithLightPacket; import java.io.IOException; import java.util.BitSet; import java.util.List; import java.util.Map; -import static org.geysermc.geyser.util.ChunkUtils.EMPTY_BLOCK_STORAGE; -import static org.geysermc.geyser.util.ChunkUtils.EMPTY_CHUNK_SECTION_SIZE; -import static org.geysermc.geyser.util.ChunkUtils.indexYZXtoXZY; +import static org.geysermc.geyser.util.ChunkUtils.*; @Translator(packet = ClientboundLevelChunkWithLightPacket.class) public class JavaLevelChunkWithLightTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index 843f3d514..cb8a8e60f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.level.event.*; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.*; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java index 7d9b81d29..bedddbc6e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.level.particle.BlockParticleData; -import com.github.steveice10.mc.protocol.data.game.level.particle.DustParticleData; -import com.github.steveice10.mc.protocol.data.game.level.particle.ItemParticleData; -import com.github.steveice10.mc.protocol.data.game.level.particle.Particle; -import com.github.steveice10.mc.protocol.data.game.level.particle.VibrationParticleData; -import com.github.steveice10.mc.protocol.data.game.level.particle.positionsource.BlockPositionSource; -import com.github.steveice10.mc.protocol.data.game.level.particle.positionsource.EntityPositionSource; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelParticlesPacket; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.BlockParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.DustParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ItemParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.VibrationParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.BlockPositionSource; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.EntityPositionSource; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelParticlesPacket; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.math.vector.Vector3f; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java index 01b0f324f..1591b4952 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.map.MapData; -import com.github.steveice10.mc.protocol.data.game.level.map.MapIcon; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundMapItemDataPacket; +import org.geysermc.mcprotocollib.protocol.data.game.level.map.MapData; +import org.geysermc.mcprotocollib.protocol.data.game.level.map.MapIcon; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundMapItemDataPacket; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.MapDecoration; import org.cloudburstmc.protocol.bedrock.data.MapTrackedObject; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaOpenSignEditorTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaOpenSignEditorTranslator.java index d044ac034..99a32c0c1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaOpenSignEditorTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaOpenSignEditorTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundOpenSignEditorPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundOpenSignEditorPacket; import org.cloudburstmc.protocol.bedrock.packet.OpenSignPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSectionBlocksUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSectionBlocksUpdateTranslator.java index abc9a6c21..a52bb33b0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSectionBlocksUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSectionBlocksUpdateTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockChangeEntry; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSectionBlocksUpdatePacket; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockChangeEntry; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundSectionBlocksUpdatePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetChunkCacheCenterTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetChunkCacheCenterTranslator.java index baec29d47..e75b6c022 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetChunkCacheCenterTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetChunkCacheCenterTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSetChunkCacheCenterPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundSetChunkCacheCenterPacket; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetChunkCacheRadiusTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetChunkCacheRadiusTranslator.java index 3a0a77cc0..59402325c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetChunkCacheRadiusTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetChunkCacheRadiusTranslator.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSetChunkCacheRadiusPacket; 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.level.ClientboundSetChunkCacheRadiusPacket; @Translator(packet = ClientboundSetChunkCacheRadiusPacket.class) public class JavaSetChunkCacheRadiusTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetDefaultSpawnPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetDefaultSpawnPositionTranslator.java index 9662fdd81..da751419e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetDefaultSpawnPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetDefaultSpawnPositionTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSetDefaultSpawnPositionPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundSetDefaultSpawnPositionPacket; import org.cloudburstmc.protocol.bedrock.packet.SetSpawnPositionPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; 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 b86b4247c..1e398ad9b 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSetTimePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundSetTimePacket; import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java index ceb2d989d..ad07d8537 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSoundPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundSoundPacket; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java index 7320b7637..99e076ad2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundStopSoundPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundStopSoundPacket; import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaInitializeBorderTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaInitializeBorderTranslator.java index 857997170..9f1f5b434 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaInitializeBorderTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaInitializeBorderTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.level.border; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.border.ClientboundInitializeBorderPacket; import org.cloudburstmc.math.vector.Vector2d; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldBorder; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.border.ClientboundInitializeBorderPacket; @Translator(packet = ClientboundInitializeBorderPacket.class) public class JavaInitializeBorderTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderCenterTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderCenterTranslator.java index ebcef08a7..28f7a6faa 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderCenterTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderCenterTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level.border; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderCenterPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderCenterPacket; import org.cloudburstmc.math.vector.Vector2d; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldBorder; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderLerpSizeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderLerpSizeTranslator.java index a41c90f04..b676523c9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderLerpSizeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderLerpSizeTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level.border; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderLerpSizePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderLerpSizePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldBorder; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderSizeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderSizeTranslator.java index 51cd17278..deec4b7a2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderSizeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderSizeTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level.border; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderSizePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderSizePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldBorder; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDelayTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDelayTranslator.java index 912ca9a09..e92ab34ad 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDelayTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDelayTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level.border; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderWarningDelayPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderWarningDelayPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldBorder; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDistanceTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDistanceTranslator.java index 14badb565..4d862163e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDistanceTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDistanceTranslator.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.translator.protocol.java.level.border; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderWarningDistancePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldBorder; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.border.ClientboundSetBorderWarningDistancePacket; @Translator(packet = ClientboundSetBorderWarningDistancePacket.class) public class JavaSetBorderWarningDistanceTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java index 01b4fddea..e8d307c90 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.scoreboard.ClientboundResetScorePacket; import org.geysermc.geyser.scoreboard.Objective; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; @@ -34,6 +32,8 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundResetScorePacket; @Translator(packet = ClientboundResetScorePacket.class) public class JavaResetScorePacket extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java index 74f063e44..4ce971cdf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java index 75f7d38f2..85d93c0b5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import com.github.steveice10.mc.protocol.data.game.scoreboard.ObjectiveAction; -import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.entity.type.player.PlayerEntity; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java index f942b6f09..999edcc8c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import com.github.steveice10.mc.protocol.data.game.scoreboard.NameTagVisibility; -import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamAction; -import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.scoreboard.Scoreboard; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java index 6bffee3d3..d1645b496 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaClearTitlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaClearTitlesTranslator.java index 968845e92..8601ec7e9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaClearTitlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaClearTitlesTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.title; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.title.ClientboundClearTitlesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.title.ClientboundClearTitlesPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetActionBarTextTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetActionBarTextTranslator.java index c2dfc85ff..5e3ba834b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetActionBarTextTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetActionBarTextTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.title; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.title.ClientboundSetActionBarTextPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.title.ClientboundSetActionBarTextPacket; @Translator(packet = ClientboundSetActionBarTextPacket.class) public class JavaSetActionBarTextTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetSubtitleTextTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetSubtitleTextTranslator.java index ba0407dcb..44d0a1e63 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetSubtitleTextTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetSubtitleTextTranslator.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.title; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.title.ClientboundSetSubtitleTextPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.title.ClientboundSetSubtitleTextPacket; @Translator(packet = ClientboundSetSubtitleTextPacket.class) public class JavaSetSubtitleTextTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetTitleTextTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetTitleTextTranslator.java index 1aa789ad4..d0ac15a73 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetTitleTextTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetTitleTextTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.title; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.title.ClientboundSetTitleTextPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.title.ClientboundSetTitleTextPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import net.kyori.adventure.text.Component; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetTitlesAnimationTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetTitlesAnimationTranslator.java index 4299a0596..4bc5ba0c5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetTitlesAnimationTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaSetTitlesAnimationTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.title; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.title.ClientboundSetTitlesAnimationPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.title.ClientboundSetTitlesAnimationPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/BlockSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/BlockSoundInteractionTranslator.java index ef6be0e9d..ead619b68 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/BlockSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/BlockSoundInteractionTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.sound; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; 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 604e34945..612b9c38b 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 @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.text; -import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer; -import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; +import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.ScoreComponent; import net.kyori.adventure.text.TranslatableComponent; diff --git a/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java b/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java index d79d606b4..af2faab94 100644 --- a/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeModifier; -import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOperation; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeModifier; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; public class AttributeUtils { /** diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java index 31a2ddee9..ec7f45c8d 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; @@ -35,6 +34,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.FlowerPotBlockEntityTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import java.util.List; import java.util.Locale; 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 8392f9fcd..0fc7a39e7 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -38,6 +37,7 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.BlockTag; import org.geysermc.geyser.translator.collision.BlockCollision; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public final class BlockUtils { @@ -181,7 +181,7 @@ public final class BlockUtils { /** * Given a position, return the position if a block were located on the specified block face. * @param blockPos the block position - * @param face the face of the block - see {@link com.github.steveice10.mc.protocol.data.game.entity.object.Direction} + * @param face the face of the block - see {@link org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction} * @return the block position with the block face accounted for */ public static Vector3i getBlockPosition(Vector3i blockPos, int face) { diff --git a/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java b/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java index 60838686f..c020e96b2 100644 --- a/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.util; -import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import lombok.Getter; +import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PreferencesCache; import org.geysermc.geyser.text.ChatColor; diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index 469accd40..54e1cc34a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -25,18 +25,14 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.entity.Effect; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.PlayerActionType; -import org.cloudburstmc.protocol.bedrock.packet.ChangeDimensionPacket; -import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; -import org.cloudburstmc.protocol.bedrock.packet.MobEffectPacket; -import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; -import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket; +import org.cloudburstmc.protocol.bedrock.packet.*; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import java.util.Set; 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 f040fd0ba..d11c1f9e4 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.entity.Effect; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -41,6 +37,10 @@ import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.entity.type.living.animal.horse.CamelEntity; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; +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; 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 2b619714e..63644d5fc 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -25,12 +25,6 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.item.ItemStack; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; @@ -58,6 +52,12 @@ import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; import org.geysermc.geyser.translator.inventory.chest.DoubleChestInventoryTranslator; +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.packet.ingame.serverbound.inventory.ServerboundPickItemPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import org.jetbrains.annotations.Contract; import java.util.Arrays; diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index b1591e911..1b47c3a00 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -25,14 +25,14 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; -import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; -import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.FishingRodItem; import org.geysermc.geyser.item.type.Item; +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.ItemEnchantments; public class ItemUtils { diff --git a/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java b/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java index f6b91388f..09543baca 100644 --- a/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import com.google.common.base.Charsets; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import java.nio.ByteBuffer; 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 4c5f6b68f..85f8fc704 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.level.sound.Sound; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; @@ -39,6 +38,7 @@ import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.SoundMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; import java.util.Locale; diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java b/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java index d46a759fe..589bac043 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.statistic.StatisticFormat; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.StatisticFormat; import java.text.DecimalFormat; import java.text.NumberFormat; diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index aa174497b..96328bcdd 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.statistic.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.cumulus.util.FormImage; @@ -35,6 +34,7 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.*; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java b/core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java index 9b3cfb53f..c1ccf9d5b 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StructureBlockUtils.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockAction; -import com.github.steveice10.mc.protocol.data.game.inventory.UpdateStructureBlockMode; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetStructureBlockPacket; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; @@ -39,6 +36,9 @@ import org.cloudburstmc.protocol.bedrock.data.structure.StructureSettings; import org.cloudburstmc.protocol.bedrock.data.structure.StructureTemplateResponseType; import org.cloudburstmc.protocol.bedrock.packet.StructureTemplateDataResponsePacket; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.UpdateStructureBlockAction; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.UpdateStructureBlockMode; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetStructureBlockPacket; public class StructureBlockUtils { @@ -124,17 +124,17 @@ public class StructureBlockUtils { public static void sendJavaStructurePacket(GeyserSession session, Vector3i blockPosition, Vector3i size, UpdateStructureBlockMode mode, UpdateStructureBlockAction action, StructureSettings settings, boolean boundingBoxVisible, String structureName) { - com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror mirror = switch (settings.getMirror()) { - case X -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.FRONT_BACK; - case Z -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.LEFT_RIGHT; - default -> com.github.steveice10.mc.protocol.data.game.level.block.StructureMirror.NONE; + org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureMirror mirror = switch (settings.getMirror()) { + case X -> org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureMirror.FRONT_BACK; + case Z -> org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureMirror.LEFT_RIGHT; + default -> org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureMirror.NONE; }; - com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation rotation = switch (settings.getRotation()) { - case ROTATE_90 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.CLOCKWISE_90; - case ROTATE_180 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.CLOCKWISE_180; - case ROTATE_270 -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.COUNTERCLOCKWISE_90; - default -> com.github.steveice10.mc.protocol.data.game.level.block.StructureRotation.NONE; + org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureRotation rotation = switch (settings.getRotation()) { + case ROTATE_90 -> org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureRotation.CLOCKWISE_90; + case ROTATE_180 -> org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureRotation.CLOCKWISE_180; + case ROTATE_270 -> org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureRotation.COUNTERCLOCKWISE_90; + default -> org.geysermc.mcprotocollib.protocol.data.game.level.block.StructureRotation.NONE; }; Vector3i offset = settings.getOffset(); diff --git a/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java b/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java index 5e5c3af7a..85d7ffa9a 100644 --- a/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java +++ b/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.network.translators.chat; -import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/core/src/test/java/org/geysermc/geyser/registry/loader/ResourcePackLoaderTest.java b/core/src/test/java/org/geysermc/geyser/registry/loader/ResourcePackLoaderTest.java index b66fd0811..ce2fd2a6f 100644 --- a/core/src/test/java/org/geysermc/geyser/registry/loader/ResourcePackLoaderTest.java +++ b/core/src/test/java/org/geysermc/geyser/registry/loader/ResourcePackLoaderTest.java @@ -34,9 +34,7 @@ import java.nio.file.Path; import java.nio.file.PathMatcher; import java.util.Objects; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class ResourcePackLoaderTest { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2b6df11a6..3cb136683 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "3c81cc80" # Revert from jitpack after release +mcprotocollib = "1ca8808" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 9d540fe672e6f0887a58695ef870e3c2e8fe8eff Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:41:02 -0400 Subject: [PATCH 075/897] Shulker box NPE fix --- .../main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index 4108d0fa0..2f2f45c5b 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -59,7 +59,7 @@ public class ShulkerBoxItem extends BlockItem { List itemsList = new ArrayList<>(); for (int slot = 0; slot < contents.size(); slot++) { ItemStack item = contents.get(slot); - if (item.getId() == Items.AIR_ID) { + if (item == null || item.getId() == Items.AIR_ID) { continue; } ItemMapping boxMapping = session.getItemMappings().getMapping(item.getId()); From 652f6af7849d05ecbe6d3028eff77646b68d6301 Mon Sep 17 00:00:00 2001 From: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:13:07 -0700 Subject: [PATCH 076/897] Fix custom skulls 1.20.5 Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .../entity/SkullBlockEntityTranslator.java | 32 +++++++++---------- .../level/JavaBlockEntityDataTranslator.java | 2 +- .../JavaLevelChunkWithLightTranslator.java | 3 +- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index 61c922528..38a056bd0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -66,8 +66,8 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements } } - private static UUID getUUID(CompoundTag owner) { - if (owner.get("Id") instanceof IntArrayTag uuidTag && uuidTag.length() == 4) { + private static UUID getUUID(CompoundTag profile) { + if (profile.get("id") instanceof IntArrayTag uuidTag && uuidTag.length() == 4) { int[] uuidAsArray = uuidTag.getValue(); // thank u viaversion return new UUID((long) uuidAsArray[0] << 32 | ((long) uuidAsArray[1] & 0xFFFFFFFFL), @@ -75,46 +75,44 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements } // Convert username to an offline UUID String username = null; - if (owner.get("Name") instanceof StringTag nameTag) { + if (profile.get("name") instanceof StringTag nameTag) { username = nameTag.getValue().toLowerCase(Locale.ROOT); } return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)); } - private static CompletableFuture getTextures(CompoundTag owner, UUID uuid) { - CompoundTag properties = owner.get("Properties"); + private static CompletableFuture getTextures(CompoundTag profile, UUID uuid) { + ListTag properties = profile.get("properties"); if (properties == null) { if (uuid != null && uuid.version() == 4) { String uuidString = uuid.toString().replace("-", ""); return SkinProvider.requestTexturesFromUUID(uuidString); - } else if (owner.get("Name") instanceof StringTag nameTag) { + } else if (profile.get("name") instanceof StringTag nameTag) { // Fall back to username if UUID was missing or was an offline mode UUID return SkinProvider.requestTexturesFromUsername(nameTag.getValue()); } return CompletableFuture.completedFuture(null); } - ListTag textures = properties.get("textures"); - LinkedHashMap tag1 = (LinkedHashMap) textures.get(0).getValue(); - StringTag texture = (StringTag) tag1.get("Value"); + LinkedHashMap tag1 = (LinkedHashMap) properties.get(0).getValue(); + StringTag texture = (StringTag) tag1.get("value"); return CompletableFuture.completedFuture(texture.getValue()); } public static @Nullable BlockDefinition translateSkull(GeyserSession session, CompoundTag tag, Vector3i blockPosition, int blockState) { - // TODO: The tag layout follows new format (profille, etc...) - CompoundTag owner = tag.get("SkullOwner"); - if (owner == null) { + CompoundTag profile = tag.get("profile"); + if (profile == null) { session.getSkullCache().removeSkull(blockPosition); return null; } - UUID uuid = getUUID(owner); + UUID uuid = getUUID(profile); - CompletableFuture texturesFuture = getTextures(owner, uuid); + CompletableFuture texturesFuture = getTextures(profile, uuid); if (texturesFuture.isDone()) { try { String texture = texturesFuture.get(); if (texture == null) { - session.getGeyser().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition + " " + tag); + session.getGeyser().getLogger().debug("Custom skull with invalid profile tag: " + blockPosition + " " + tag); return null; } SkullCache.Skull skull = session.getSkullCache().putSkull(blockPosition, uuid, texture, blockState); @@ -128,10 +126,10 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements return null; } - // SkullOwner contained a username, so we have to wait for it to be retrieved + // profile contained a username, so we have to wait for it to be retrieved texturesFuture.whenComplete((texturesProperty, throwable) -> { if (texturesProperty == null) { - session.getGeyser().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition + " " + tag); + session.getGeyser().getLogger().debug("Custom skull with invalid profile tag: " + blockPosition + " " + tag); return; } if (session.getEventLoop().inEventLoop()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java index ca746f79b..82b51dfdd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java @@ -71,7 +71,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator> 4) - (bedrockDimension.minY() >> 4); From 99e6a2981da27a9ec8f09c04cfc8e73a296e4263 Mon Sep 17 00:00:00 2001 From: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Date: Thu, 25 Apr 2024 01:33:18 -0700 Subject: [PATCH 077/897] Entity properties Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .../geyser/entity/EntityDefinition.java | 19 +- .../geyser/entity/EntityDefinitions.java | 15 +- .../properties/GeyserEntityProperties.java | 165 ++++++++++++++++++ .../GeyserEntityPropertyManager.java | 98 +++++++++++ .../properties/type/BooleanProperty.java | 44 +++++ .../entity/properties/type/EnumProperty.java | 61 +++++++ .../entity/properties/type/FloatProperty.java | 50 ++++++ .../entity/properties/type/IntProperty.java | 50 ++++++ .../entity/properties/type/PropertyType.java | 32 ++++ .../geysermc/geyser/entity/type/Entity.java | 22 +++ .../type/living/animal/ArmadilloEntity.java | 18 +- .../entity/type/living/animal/BeeEntity.java | 3 +- .../geysermc/geyser/registry/Registries.java | 5 + .../geyser/session/GeyserSession.java | 12 ++ 14 files changed, 587 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityPropertyManager.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/properties/type/BooleanProperty.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/properties/type/FloatProperty.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/properties/type/IntProperty.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/properties/type/PropertyType.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java index f0e221bad..31aa7cc73 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java @@ -33,6 +33,7 @@ import lombok.Setter; import lombok.experimental.Accessors; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.factory.EntityFactory; +import org.geysermc.geyser.entity.properties.GeyserEntityProperties; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.entity.EntityMetadataTranslator; @@ -49,10 +50,10 @@ import java.util.function.BiConsumer; * @param the entity type this definition represents */ public record EntityDefinition(EntityFactory factory, EntityType entityType, String identifier, - float width, float height, float offset, List> translators) { + float width, float height, float offset, GeyserEntityProperties registeredProperties, List> translators) { public static Builder inherited(EntityFactory factory, EntityDefinition parent) { - return new Builder<>(factory, parent.entityType, parent.identifier, parent.width, parent.height, parent.offset, new ObjectArrayList<>(parent.translators)); + return new Builder<>(factory, parent.entityType, parent.identifier, parent.width, parent.height, parent.offset, parent.registeredProperties, new ObjectArrayList<>(parent.translators)); } public static Builder builder(EntityFactory factory) { @@ -87,6 +88,7 @@ public record EntityDefinition(EntityFactory factory, Entit private float width; private float height; private float offset = 0.00001f; + private GeyserEntityProperties registeredProperties; private final List> translators; private Builder(EntityFactory factory) { @@ -94,13 +96,14 @@ public record EntityDefinition(EntityFactory factory, Entit translators = new ObjectArrayList<>(); } - public Builder(EntityFactory factory, EntityType type, String identifier, float width, float height, float offset, List> translators) { + public Builder(EntityFactory factory, EntityType type, String identifier, float width, float height, float offset, GeyserEntityProperties registeredProperties, List> translators) { this.factory = factory; this.type = type; this.identifier = identifier; this.width = width; this.height = height; this.offset = offset; + this.registeredProperties = registeredProperties; this.translators = translators; } @@ -127,6 +130,11 @@ public record EntityDefinition(EntityFactory factory, Entit return this; } + public Builder properties(GeyserEntityProperties registeredProperties) { + this.registeredProperties = registeredProperties; + return this; + } + public >> Builder addTranslator(MetadataType type, BiConsumer translateFunction) { translators.add(new EntityMetadataTranslator<>(type, translateFunction)); return this; @@ -149,10 +157,13 @@ public record EntityDefinition(EntityFactory factory, Entit if (identifier == null && type != null) { identifier = "minecraft:" + type.name().toLowerCase(Locale.ROOT); } - EntityDefinition definition = new EntityDefinition<>(factory, type, identifier, width, height, offset, translators); + EntityDefinition definition = new EntityDefinition<>(factory, type, identifier, width, height, offset, registeredProperties, translators); if (register && definition.entityType() != null) { Registries.ENTITY_DEFINITIONS.get().putIfAbsent(definition.entityType(), definition); Registries.JAVA_ENTITY_IDENTIFIERS.get().putIfAbsent("minecraft:" + type.name().toLowerCase(Locale.ROOT), definition); + if (definition.registeredProperties() != null) { + Registries.BEDROCK_ENTITY_PROPERTIES.get().add(definition.registeredProperties().toNbtMap(identifier)); + } } return definition; } 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 328dd4bbf..317892676 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -31,6 +31,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatE import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.geyser.entity.properties.GeyserEntityProperties; import org.geysermc.geyser.entity.type.*; import org.geysermc.geyser.entity.type.living.*; import org.geysermc.geyser.entity.type.living.animal.*; @@ -774,7 +775,16 @@ public final class EntityDefinitions { ARMADILLO = EntityDefinition.inherited(ArmadilloEntity::new, ageableEntityBase) .type(EntityType.ARMADILLO) .height(0.65f).width(0.7f) - .addTranslator(null) + .properties(new GeyserEntityProperties.Builder() + .addEnum( + "minecraft:armadillo_state", + "unrolled", + "rolled_up", + "rolled_up_peeking", + "rolled_up_relaxing", + "rolled_up_unrolling") + .build()) + .addTranslator(MetadataType.ARMADILLO_STATE, ArmadilloEntity::setArmadilloState) .build(); AXOLOTL = EntityDefinition.inherited(AxolotlEntity::new, ageableEntityBase) .type(EntityType.AXOLOTL) @@ -786,6 +796,9 @@ public final class EntityDefinitions { BEE = EntityDefinition.inherited(BeeEntity::new, ageableEntityBase) .type(EntityType.BEE) .heightAndWidth(0.6f) + .properties(new GeyserEntityProperties.Builder() + .addBoolean("minecraft:has_nectar") + .build()) .addTranslator(MetadataType.BYTE, BeeEntity::setBeeFlags) .addTranslator(MetadataType.INT, BeeEntity::setAngerTime) .build(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java new file mode 100644 index 000000000..1729b0583 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java @@ -0,0 +1,165 @@ +/* + * 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.entity.properties; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.entity.properties.type.BooleanProperty; +import org.geysermc.geyser.entity.properties.type.EnumProperty; +import org.geysermc.geyser.entity.properties.type.FloatProperty; +import org.geysermc.geyser.entity.properties.type.IntProperty; +import org.geysermc.geyser.entity.properties.type.PropertyType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@EqualsAndHashCode +@ToString +public class GeyserEntityProperties { + private final ObjectArrayList properties; + private final Object2IntMap propertyIndices; + + private GeyserEntityProperties(ObjectArrayList properties, + Object2IntMap propertyIndices) { + this.properties = properties; + this.propertyIndices = propertyIndices; + } + + public NbtMap toNbtMap(String entityType) { + NbtMapBuilder mapBuilder = NbtMap.builder(); + List nbtProperties = new ArrayList<>(); + + for (PropertyType property : properties) { + nbtProperties.add(property.nbtMap()); + } + mapBuilder.putList("properties", NbtType.COMPOUND, nbtProperties); + + return mapBuilder.putString("type", entityType).build(); + } + + public @NonNull List getProperties() { + return properties; + } + + public int getPropertyIndex(String name) { + return propertyIndices.getOrDefault(name, -1); + } + + public static class Builder { + private final ObjectArrayList properties = new ObjectArrayList<>(); + private final Object2IntMap propertyIndices = new Object2IntOpenHashMap<>(); + + public Builder addInt(@NonNull String name, int min, int max) { + if (propertyIndices.containsKey(name)) { + throw new IllegalArgumentException( + "Property with name " + name + " already exists on builder!"); + } + PropertyType property = new IntProperty(name, min, max); + this.properties.add(property); + propertyIndices.put(name, properties.size() - 1); + return this; + } + + public Builder addInt(@NonNull String name) { + if (propertyIndices.containsKey(name)) { + throw new IllegalArgumentException( + "Property with name " + name + " already exists on builder!"); + } + PropertyType property = new IntProperty(name, Integer.MIN_VALUE, Integer.MAX_VALUE); + this.properties.add(property); + propertyIndices.put(name, properties.size() - 1); + return this; + } + + public Builder addFloat(@NonNull String name, float min, float max) { + if (propertyIndices.containsKey(name)) { + throw new IllegalArgumentException( + "Property with name " + name + " already exists on builder!"); + } + PropertyType property = new FloatProperty(name, min, max); + this.properties.add(property); + propertyIndices.put(name, properties.size() - 1); + return this; + } + + public Builder addFloat(@NonNull String name) { + if (propertyIndices.containsKey(name)) { + throw new IllegalArgumentException( + "Property with name " + name + " already exists on builder!"); + } + PropertyType property = new FloatProperty(name, Float.MIN_NORMAL, Float.MAX_VALUE); + this.properties.add(property); + propertyIndices.put(name, properties.size() - 1); + return this; + } + + public Builder addBoolean(@NonNull String name) { + if (propertyIndices.containsKey(name)) { + throw new IllegalArgumentException( + "Property with name " + name + " already exists on builder!"); + } + PropertyType property = new BooleanProperty(name); + this.properties.add(property); + propertyIndices.put(name, properties.size() - 1); + return this; + } + + public Builder addEnum(@NonNull String name, List values) { + if (propertyIndices.containsKey(name)) { + throw new IllegalArgumentException( + "Property with name " + name + " already exists on builder!"); + } + PropertyType property = new EnumProperty(name, values); + this.properties.add(property); + propertyIndices.put(name, properties.size() - 1); + return this; + } + + public Builder addEnum(@NonNull String name, String... values) { + if (propertyIndices.containsKey(name)) { + throw new IllegalArgumentException( + "Property with name " + name + " already exists on builder!"); + } + List valuesList = Arrays.asList(values); // Convert array to list + PropertyType property = new EnumProperty(name, valuesList); + this.properties.add(property); + propertyIndices.put(name, properties.size() - 1); + return this; + } + + public GeyserEntityProperties build() { + return new GeyserEntityProperties(properties, propertyIndices); + } + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityPropertyManager.java b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityPropertyManager.java new file mode 100644 index 000000000..29026b172 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityPropertyManager.java @@ -0,0 +1,98 @@ +/* + * 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.entity.properties; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.cloudburstmc.protocol.bedrock.data.entity.FloatEntityProperty; +import org.cloudburstmc.protocol.bedrock.data.entity.IntEntityProperty; +import org.geysermc.geyser.entity.properties.type.EnumProperty; +import org.geysermc.geyser.entity.properties.type.PropertyType; + +import java.util.List; + +public class GeyserEntityPropertyManager { + + private final GeyserEntityProperties properties; + + private final ObjectArrayList intEntityProperties = new ObjectArrayList<>(); + private final ObjectArrayList floatEntityProperties = new ObjectArrayList<>(); + + public GeyserEntityPropertyManager(GeyserEntityProperties properties) { + this.properties = properties; + } + + public void add(String propertyName, int value) { + int index = properties.getPropertyIndex(propertyName); + intEntityProperties.add(new IntEntityProperty(index, value)); + } + + public void add(String propertyName, boolean value) { + int index = properties.getPropertyIndex(propertyName); + intEntityProperties.add(new IntEntityProperty(index, value ? 1 : 0)); + } + + public void add(String propertyName, String value) { + int index = properties.getPropertyIndex(propertyName); + PropertyType property = properties.getProperties().get(index); + int enumIndex = ((EnumProperty) property).getIndex(value); + intEntityProperties.add(new IntEntityProperty(index, enumIndex)); + } + + public void add(String propertyName, float value) { + int index = properties.getPropertyIndex(propertyName); + floatEntityProperties.add(new FloatEntityProperty(index, value)); + } + + public boolean hasFloatProperties() { + return !this.floatEntityProperties.isEmpty(); + } + + public boolean hasIntProperties() { + return !this.intEntityProperties.isEmpty(); + } + + public boolean hasProperties() { + return hasFloatProperties() || hasIntProperties(); + } + + public ObjectArrayList intProperties() { + return this.intEntityProperties; + } + + public void applyIntProperties(List properties) { + properties.addAll(intEntityProperties); + intEntityProperties.clear(); + } + + public ObjectArrayList floatProperties() { + return this.floatEntityProperties; + } + + public void applyFloatProperties(List properties) { + properties.addAll(floatEntityProperties); + floatEntityProperties.clear(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/BooleanProperty.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/BooleanProperty.java new file mode 100644 index 000000000..6fc64ad4b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/BooleanProperty.java @@ -0,0 +1,44 @@ +/* + * 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.entity.properties.type; + +import org.cloudburstmc.nbt.NbtMap; + +public class BooleanProperty implements PropertyType { + private final String name; + + public BooleanProperty(String name) { + this.name = name; + } + + @Override + public NbtMap nbtMap() { + return NbtMap.builder() + .putString("name", name) + .putInt("type", 2) + .build(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java new file mode 100644 index 000000000..9bc45f560 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java @@ -0,0 +1,61 @@ +/* + * 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.entity.properties.type; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; + +import java.util.List; + +public class EnumProperty implements PropertyType { + private final String name; + private final List values; + private final Object2IntMap valueIndexMap; + + public EnumProperty(String name, List values) { + this.name = name; + this.values = values; + this.valueIndexMap = new Object2IntOpenHashMap<>(values.size()); + for (int i = 0; i < values.size(); i++) { + valueIndexMap.put(values.get(i), i); + } + } + + @Override + public NbtMap nbtMap() { + return NbtMap.builder() + .putString("name", name) + .putList("values", NbtType.STRING, values) + .putInt("type", 3) + .build(); + } + + public int getIndex(String value) { + return valueIndexMap.getOrDefault(value, -1); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/FloatProperty.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/FloatProperty.java new file mode 100644 index 000000000..8b808ebc3 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/FloatProperty.java @@ -0,0 +1,50 @@ +/* + * 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.entity.properties.type; + +import org.cloudburstmc.nbt.NbtMap; + +public class FloatProperty implements PropertyType { + private final String name; + private final float max; + private final float min; + + public FloatProperty(String name, float min, float max) { + this.name = name; + this.max = max; + this.min = min; + } + + @Override + public NbtMap nbtMap() { + return NbtMap.builder() + .putString("name", name) + .putFloat("max", max) + .putFloat("min", min) + .putInt("type", 1) + .build(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/IntProperty.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/IntProperty.java new file mode 100644 index 000000000..9e38db7c7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/IntProperty.java @@ -0,0 +1,50 @@ +/* + * 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.entity.properties.type; + +import org.cloudburstmc.nbt.NbtMap; + +public class IntProperty implements PropertyType { + private final String name; + private final int max; + private final int min; + + public IntProperty(String name, int min, int max) { + this.name = name; + this.max = max; + this.min = min; + } + + @Override + public NbtMap nbtMap() { + return NbtMap.builder() + .putString("name", name) + .putInt("max", max) + .putInt("min", min) + .putInt("type", 0) + .build(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/PropertyType.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/PropertyType.java new file mode 100644 index 000000000..a64d7246a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/PropertyType.java @@ -0,0 +1,32 @@ +/* + * 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.entity.properties.type; + +import org.cloudburstmc.nbt.NbtMap; + +public interface PropertyType { + NbtMap nbtMap(); +} \ No newline at end of file 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 f1d6bfb98..fecd72f67 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 @@ -39,6 +39,7 @@ import org.cloudburstmc.protocol.bedrock.packet.*; import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.GeyserDirtyMetadata; +import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.EntityUtils; @@ -117,6 +118,8 @@ public class Entity implements GeyserEntity { @Setter(AccessLevel.PROTECTED) // For players private boolean flagsDirty = false; + protected final GeyserEntityPropertyManager propertyManager; + public Entity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { this.session = session; @@ -131,6 +134,8 @@ public class Entity implements GeyserEntity { this.valid = false; + this.propertyManager = new GeyserEntityPropertyManager(definition.registeredProperties()); + setPosition(position); setAirSupply(getMaxAir()); @@ -348,6 +353,23 @@ public class Entity implements GeyserEntity { } } + /** + * Sends the Bedrock entity properties to the client + */ + public void updateBedrockEntityProperties() { + if (!valid) { + return; + } + + if (propertyManager.hasProperties()) { + SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); + entityDataPacket.setRuntimeEntityId(geyserId); + propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties()); + propertyManager.applyFloatProperties(entityDataPacket.getProperties().getFloatProperties()); + session.sendUpstreamPacket(entityDataPacket); + } + } + public void setFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire 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 d89b4e3f7..205c8cbd9 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,11 +28,27 @@ package org.geysermc.geyser.entity.type.living.animal; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.ArmadilloState; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import java.util.UUID; public class ArmadilloEntity extends AnimalEntity { - public ArmadilloEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ArmadilloEntity(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); } + + // TODO: This is completely wrong; probably need to store the previous IDLE/ROLLING/SCARED state and check for transitions (pain) + public void setArmadilloState(ObjectEntityMetadata entityMetadata) { + ArmadilloState armadilloState = entityMetadata.getValue(); + + switch (armadilloState) { + case IDLE -> propertyManager.add("minecraft:armadillo_state", "unrolled"); + case ROLLING -> propertyManager.add("minecraft:armadillo_state", "rolled_up"); + case SCARED -> propertyManager.add("minecraft:armadillo_state", "rolled_up_peeking"); + } + + updateBedrockEntityProperties(); + } } 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 d6aa9615d..28ebad473 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 @@ -58,7 +58,8 @@ public class BeeEntity extends AnimalEntity { // If the bee has stung dirtyMetadata.put(EntityDataTypes.MARK_VARIANT, (xd & 0x04) == 0x04 ? 1 : 0); // If the bee has nectar or not - setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08); + propertyManager.add("minecraft:has_nectar", (xd & 0x08) == 0x08); + updateBedrockEntityProperties(); } public void setAngerTime(IntEntityMetadata entityMetadata) { 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 f19898016..54d013140 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -112,6 +112,11 @@ public final class Registries { */ public static final SimpleMappedRegistry> ENTITY_DEFINITIONS = SimpleMappedRegistry.create(RegistryLoaders.empty(() -> new EnumMap<>(EntityType.class))); + /** + * A registry holding a list of all the known entity properties to be sent to the client after start game. + */ + public static final SimpleRegistry> BEDROCK_ENTITY_PROPERTIES = SimpleRegistry.create(RegistryLoaders.empty(HashSet::new)); + /** * A map containing all Java entity identifiers and their respective Geyser definitions */ 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 82717050f..175d9eac2 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -638,6 +638,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public void connect() { startGame(); sentSpawnPacket = true; + syncEntityProperties(); // Set the hardcoded shield ID to the ID we just defined in StartGamePacket // upstream.getSession().getHardcodedBlockingId().set(this.itemMappings.getStoredItems().shield().getBedrockId()); @@ -1562,9 +1563,20 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setRewindHistorySize(0); startGamePacket.setServerAuthoritativeBlockBreaking(false); + // Entity properties for older versions + startGamePacket.getExperiments().add(new ExperimentData("upcoming_creator_features", true)); + upstream.sendPacket(startGamePacket); } + private void syncEntityProperties() { + for (NbtMap nbtMap : Registries.BEDROCK_ENTITY_PROPERTIES.get()) { + SyncEntityPropertyPacket syncEntityPropertyPacket = new SyncEntityPropertyPacket(); + syncEntityPropertyPacket.setData(nbtMap); + upstream.sendPacket(syncEntityPropertyPacket); + } + } + /** * @return the next Bedrock item network ID to use for a new item */ From 16cb76f52338293f0599c682c1a3674d125a832b Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 25 Apr 2024 17:38:03 +0200 Subject: [PATCH 078/897] neoforge 1.20.5 boots --- .../main/resources/META-INF/{mods.toml => neoforge.mods.toml} | 2 +- build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename bootstrap/mod/neoforge/src/main/resources/META-INF/{mods.toml => neoforge.mods.toml} (94%) diff --git a/bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml similarity index 94% rename from bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml rename to bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml index 1110568e8..ff2823aa2 100644 --- a/bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml +++ b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -20,6 +20,6 @@ config = "geyser.mixins.json" [[dependencies.geyser_neoforge]] modId="minecraft" type="required" - versionRange="[1.20.4,1.21)" + versionRange="[1.20.5,1.21)" ordering="NONE" side="BOTH" \ No newline at end of file diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 3d41a3dd6..950c0184b 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -23,7 +23,7 @@ indra { tasks { processResources { // Spigot, BungeeCord, Velocity, Fabric, ViaProxy, NeoForge - filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/mods.toml")) { + filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/neoforge.mods.toml")) { expand( "id" to "geyser", "name" to "Geyser", From 8e3a3ea45337d44bec2b3af8dbfaa615c9a01a7a Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Fri, 26 Apr 2024 01:00:14 +0200 Subject: [PATCH 079/897] implement curse of binding check for wolf armor removal --- .../geyser/entity/type/LivingEntity.java | 38 +++++++++++++++++-- .../entity/type/living/ArmorStandEntity.java | 17 +++++---- .../living/animal/tameable/WolfEntity.java | 15 +++++++- .../type/living/monster/PiglinEntity.java | 2 +- .../living/monster/raid/PillagerEntity.java | 2 +- .../translator/item/ItemTranslator.java | 8 ++-- .../entity/JavaEntityEventTranslator.java | 7 +--- .../entity/JavaSetEquipmentTranslator.java | 22 +++++------ .../org/geysermc/geyser/util/BlockUtils.java | 4 +- .../org/geysermc/geyser/util/ItemUtils.java | 5 ++- 10 files changed, 81 insertions(+), 39 deletions(-) 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 5823ba3b2..b1e97a0d6 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 @@ -47,6 +47,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute; @@ -57,6 +58,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEn import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; 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.data.game.item.ItemStack; import java.util.*; @@ -69,7 +71,7 @@ public class LivingEntity extends Entity { protected ItemData leggings = ItemData.AIR; protected ItemData boots = ItemData.AIR; protected ItemData hand = ItemData.AIR; - protected ItemData offHand = ItemData.AIR; + protected ItemData offhand = ItemData.AIR; @Getter(value = AccessLevel.NONE) protected float health = 1f; // The default value in Java Edition before any entity metadata is sent @@ -85,6 +87,36 @@ public class LivingEntity extends Entity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + public void setHelmet(ItemStack stack) { + this.helmet = ItemTranslator.translateToBedrock(session, stack); + } + + public void setChestplate(ItemStack stack) { + this.chestplate = ItemTranslator.translateToBedrock(session, stack); + } + + public void setLeggings(ItemStack stack) { + this.leggings = ItemTranslator.translateToBedrock(session, stack); + } + + public void setBoots(ItemStack stack) { + this.boots = ItemTranslator.translateToBedrock(session, stack); + } + + public void setHand(ItemStack stack) { + this.hand = ItemTranslator.translateToBedrock(session, stack); + } + + public void setOffhand(ItemStack stack) { + this.offhand = ItemTranslator.translateToBedrock(session, stack); + } + + public void switchHands() { + ItemData offhand = this.offhand; + this.offhand = this.hand; + this.hand = offhand; + } + @Override protected void initializeMetadata() { super.initializeMetadata(); @@ -135,7 +167,7 @@ public class LivingEntity extends Entity { protected boolean hasShield(boolean offhand) { ItemMapping shieldMapping = session.getItemMappings().getStoredItems().shield(); if (offhand) { - return offHand.getDefinition().equals(shieldMapping.getBedrockDefinition()); + return this.offhand.getDefinition().equals(shieldMapping.getBedrockDefinition()); } else { return hand.getDefinition().equals(shieldMapping.getBedrockDefinition()); } @@ -247,7 +279,7 @@ public class LivingEntity extends Entity { MobEquipmentPacket offHandPacket = new MobEquipmentPacket(); offHandPacket.setRuntimeEntityId(geyserId); - offHandPacket.setItem(offHand); + offHandPacket.setItem(offhand); offHandPacket.setHotbarSlot(-1); offHandPacket.setInventorySlot(0); offHandPacket.setContainerId(ContainerId.OFFHAND); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index c64f2f218..fce51e741 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -43,6 +43,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetad import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.Optional; import java.util.UUID; @@ -257,38 +258,38 @@ public class ArmorStandEntity extends LivingEntity { } @Override - public void setHelmet(ItemData helmet) { + public void setHelmet(ItemStack helmet) { super.setHelmet(helmet); updateSecondEntityStatus(true); } @Override - public void setChestplate(ItemData chestplate) { + public void setChestplate(ItemStack chestplate) { super.setChestplate(chestplate); updateSecondEntityStatus(true); } @Override - public void setLeggings(ItemData leggings) { + public void setLeggings(ItemStack leggings) { super.setLeggings(leggings); updateSecondEntityStatus(true); } @Override - public void setBoots(ItemData boots) { + public void setBoots(ItemStack boots) { super.setBoots(boots); updateSecondEntityStatus(true); } @Override - public void setHand(ItemData hand) { + public void setHand(ItemStack hand) { super.setHand(hand); updateSecondEntityStatus(true); } @Override - public void setOffHand(ItemData offHand) { - super.setOffHand(offHand); + public void setOffhand(ItemStack offHand) { + super.setOffhand(offHand); updateSecondEntityStatus(true); } @@ -324,7 +325,7 @@ public class ArmorStandEntity extends LivingEntity { } boolean isNametagEmpty = nametag.isEmpty(); if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR) - || !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offHand.equals(ItemData.AIR))) { + || !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offhand.equals(ItemData.AIR))) { // Reset scale of the proper armor stand this.dirtyMetadata.put(EntityDataTypes.SCALE, getScale()); // Set the proper armor stand to invisible to show armor 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 29c3526fe..833d0e175 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 @@ -33,15 +33,19 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.item.Enchantment; 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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.geyser.util.ItemUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; +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.item.ItemStack; import java.util.Collections; import java.util.Locale; @@ -60,6 +64,8 @@ public class WolfEntity extends TameableEntity { private byte collarColor = 14; // Red - default + private boolean isCurseOfBinding = false; + public WolfEntity(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); } @@ -119,6 +125,12 @@ public class WolfEntity extends TameableEntity { return WOLF_FOODS.contains(item) && !isBaby(); } + @Override + public void setChestplate(ItemStack stack) { + super.setChestplate(stack); + isCurseOfBinding = ItemUtils.getEnchantmentLevel(stack.getDataComponents(), Enchantment.JavaEnchantment.BINDING_CURSE) > 0; + } + @Override protected boolean canBeLeashed() { return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed(); @@ -146,7 +158,8 @@ public class WolfEntity extends TameableEntity { if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.chestplate.isValid() && !getFlag(EntityFlag.BABY)) { return InteractiveTag.EQUIP_WOLF_ARMOR; } - if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid()) { // TODO: check curse of binding + if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid() + && (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) { return InteractiveTag.REMOVE_WOLF_ARMOR; } if (Items.WOLF_ARMOR.isValidRepairItem(itemInHand.asItem()) && getFlag(EntityFlag.SITTING) && diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java index db2a3ecc3..9c43ab23a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java @@ -66,7 +66,7 @@ public class PiglinEntity extends BasePiglinEntity { @Override public void updateOffHand(GeyserSession session) { // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates - setFlag(EntityFlag.ADMIRING, session.getTagCache().is(ItemTag.PIGLIN_LOVED, session.getItemMappings().getMapping(this.offHand).getJavaItem())); + setFlag(EntityFlag.ADMIRING, session.getTagCache().is(ItemTag.PIGLIN_LOVED, session.getItemMappings().getMapping(this.offhand).getJavaItem())); super.updateBedrockMetadata(); super.updateOffHand(session); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java index d2f8377d3..1d2d9115b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java @@ -59,7 +59,7 @@ public class PillagerEntity extends AbstractIllagerEntity { protected void checkForCrossbow() { ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow(); boolean hasCrossbow = this.hand.getDefinition() == crossbow.getBedrockDefinition() - || this.offHand.getDefinition() == crossbow.getBedrockDefinition(); + || this.offhand.getDefinition() == crossbow.getBedrockDefinition(); setFlag(EntityFlag.USING_ITEM, hasCrossbow); setFlag(EntityFlag.CHARGED, hasCrossbow); 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 24362f800..a744c4822 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 @@ -360,7 +360,7 @@ public final class ItemTranslator { } if (mapping.getJavaItem().equals(Items.PLAYER_HEAD)) { - CustomSkull customSkull = getCustomSkull(session, itemStack.getComponents()); + CustomSkull customSkull = getCustomSkull(itemStack.getComponents()); if (customSkull != null) { itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customSkull.getCustomBlockData()); } @@ -552,7 +552,7 @@ public final class ItemTranslator { builder.blockDefinition(blockDefinition); } - private static @Nullable CustomSkull getCustomSkull(GeyserSession session, DataComponents components) { + private static @Nullable CustomSkull getCustomSkull(DataComponents components) { if (components == null) { return null; } @@ -563,7 +563,7 @@ public final class ItemTranslator { try { textures = profile.getTextures(false); } catch (PropertyException e) { - session.getGeyser().getLogger().debug("Failed to get textures from GameProfile: " + e); + GeyserImpl.getInstance().getLogger().debug("Failed to get textures from GameProfile: " + e); } if (textures == null || textures.isEmpty()) { @@ -583,7 +583,7 @@ public final class ItemTranslator { } private static void translatePlayerHead(GeyserSession session, DataComponents components, ItemData.Builder builder) { - CustomSkull customSkull = getCustomSkull(session, components); + CustomSkull customSkull = getCustomSkull(components); if (customSkull != null) { CustomBlockData customBlockData = customSkull.getCustomBlockData(); ItemDefinition itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customBlockData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index fbabd4afa..db9874af4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -25,12 +25,10 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; -import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; @@ -46,6 +44,7 @@ import org.geysermc.geyser.entity.type.living.monster.WardenEntity; 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.ClientboundEntityEventPacket; import java.util.concurrent.ThreadLocalRandom; @@ -223,9 +222,7 @@ public class JavaEntityEventTranslator extends PacketTranslator { @@ -58,7 +56,7 @@ public class JavaSetEquipmentTranslator extends PacketTranslator { ItemStack javaItem = equipment.getItem(); @@ -71,28 +69,28 @@ public class JavaSetEquipmentTranslator extends PacketTranslator { // BODY is sent for llamas with a carpet equipped, as of 1.20.5 - livingEntity.setChestplate(item); + livingEntity.setChestplate(stack); armorUpdated = true; } case LEGGINGS -> { - livingEntity.setLeggings(item); + livingEntity.setLeggings(stack); armorUpdated = true; } case BOOTS -> { - livingEntity.setBoots(item); + livingEntity.setBoots(stack); armorUpdated = true; } case MAIN_HAND -> { - livingEntity.setHand(item); + livingEntity.setHand(stack); mainHandUpdated = true; } case OFF_HAND -> { - livingEntity.setOffHand(item); + livingEntity.setOffhand(stack); offHandUpdated = true; } } 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 0fc7a39e7..70102c2b0 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -145,7 +145,7 @@ public final class BlockUtils { toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier); } - int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY.ordinal()); + int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY); int hasteLevel = 0; int miningFatigueLevel = 0; @@ -160,7 +160,7 @@ public final class BlockUtils { boolean waterInEyes = session.getCollisionManager().isWaterInEyes(); boolean insideOfWaterWithoutAquaAffinity = waterInEyes && - ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY.ordinal()) < 1; + ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY) < 1; return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index 1b47c3a00..c9d9903d4 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.util; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.FishingRodItem; import org.geysermc.geyser.item.type.Item; @@ -36,7 +37,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantm public class ItemUtils { - public static int getEnchantmentLevel(@Nullable DataComponents components, int enchantmentId) { + public static int getEnchantmentLevel(@Nullable DataComponents components, Enchantment.JavaEnchantment enchantment) { if (components == null) { return 0; } @@ -46,7 +47,7 @@ public class ItemUtils { return 0; } - return enchantmentData.getEnchantments().getOrDefault(enchantmentId, 0); + return enchantmentData.getEnchantments().getOrDefault(enchantment.ordinal(), 0); } /** From 3656395ce11b028ae3c1c5b8fbe4f783664b846d Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 25 Apr 2024 21:03:17 -0400 Subject: [PATCH 080/897] Armadillo states --- .../entity/properties/type/EnumProperty.java | 2 +- .../type/living/animal/ArmadilloEntity.java | 25 ++++++++++++++++--- .../entity/JavaEntityEventTranslator.java | 6 +++++ gradle/libs.versions.toml | 2 +- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java index 9bc45f560..05e12ba61 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java @@ -50,7 +50,7 @@ public class EnumProperty implements PropertyType { public NbtMap nbtMap() { return NbtMap.builder() .putString("name", name) - .putList("values", NbtType.STRING, values) + .putList("enum", NbtType.STRING, values) .putInt("type", 3) .build(); } 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 205c8cbd9..51fe09383 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 @@ -32,23 +32,42 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.ArmadilloSt import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import java.util.UUID; +import java.util.concurrent.TimeUnit; public class ArmadilloEntity extends AnimalEntity { + private ArmadilloState armadilloState = ArmadilloState.IDLE; + public ArmadilloEntity(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); } - // TODO: This is completely wrong; probably need to store the previous IDLE/ROLLING/SCARED state and check for transitions (pain) public void setArmadilloState(ObjectEntityMetadata entityMetadata) { - ArmadilloState armadilloState = entityMetadata.getValue(); + armadilloState = entityMetadata.getValue(); switch (armadilloState) { case IDLE -> propertyManager.add("minecraft:armadillo_state", "unrolled"); case ROLLING -> propertyManager.add("minecraft:armadillo_state", "rolled_up"); - case SCARED -> propertyManager.add("minecraft:armadillo_state", "rolled_up_peeking"); + case SCARED -> propertyManager.add("minecraft:armadillo_state", "rolled_up_relaxing"); + case UNROLLING -> propertyManager.add("minecraft:armadillo_state", "rolled_up_unrolling"); } updateBedrockEntityProperties(); } + + public void onPeeking() { + // Technically we should wait if not currently scared + if (armadilloState == ArmadilloState.SCARED) { + propertyManager.add("minecraft:armadillo_state", "rolled_up_peeking"); + updateBedrockEntityProperties(); + + // Needed for consecutive peeks + session.scheduleInEventLoop(() -> { + if (armadilloState == ArmadilloState.SCARED) { + propertyManager.add("minecraft:armadillo_state", "rolled_up_relaxing"); + updateBedrockEntityProperties(); + } + }, 250, TimeUnit.MILLISECONDS); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index db9874af4..e119d39ce 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -40,6 +40,7 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.EvokerFangsEntity; import org.geysermc.geyser.entity.type.FishingHookEntity; import org.geysermc.geyser.entity.type.LivingEntity; +import org.geysermc.geyser.entity.type.living.animal.ArmadilloEntity; import org.geysermc.geyser.entity.type.living.monster.WardenEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -257,6 +258,11 @@ public class JavaEntityEventTranslator extends PacketTranslator Date: Fri, 26 Apr 2024 14:50:48 +0200 Subject: [PATCH 081/897] idea: deal with cookies and transfer --- .../api/event/bedrock/SessionLoginEvent.java | 43 ++++++++++- .../api/event/java/ServerTransferEvent.java | 71 +++++++++++++++++++ .../platform/spigot/GeyserSpigotInjector.java | 3 +- .../geyser/item/type/WrittenBookItem.java | 1 - .../geyser/network/netty/LocalSession.java | 7 +- .../geyser/session/GeyserSession.java | 11 ++- .../player/JavaCookieRequestTranslator.java | 42 +++++++++++ .../player/JavaStoreCookieTranslator.java | 37 ++++++++++ .../player/JavaTransferPacketTranslator.java | 43 +++++++++++ 9 files changed, 251 insertions(+), 7 deletions(-) create mode 100644 api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaCookieRequestTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java index c3c8198c1..522562d11 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java @@ -32,6 +32,9 @@ import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.connection.ConnectionEvent; import org.geysermc.geyser.api.network.RemoteServer; +import java.util.Map; +import java.util.Objects; + /** * Called when a session has logged in, and is about to connect to a remote java server. * This event is cancellable, and can be used to prevent the player from connecting to the remote server. @@ -40,10 +43,16 @@ public final class SessionLoginEvent extends ConnectionEvent implements Cancella private RemoteServer remoteServer; private boolean cancelled; private String disconnectReason; + private Map cookies; + private boolean transferring; - public SessionLoginEvent(@NonNull GeyserConnection connection, @NonNull RemoteServer remoteServer) { + public SessionLoginEvent(@NonNull GeyserConnection connection, + @NonNull RemoteServer remoteServer, + @NonNull Map cookies) { super(connection); this.remoteServer = remoteServer; + this.cookies = cookies; + this.transferring = false; } /** @@ -106,4 +115,36 @@ public final class SessionLoginEvent extends ConnectionEvent implements Cancella public void remoteServer(@NonNull RemoteServer remoteServer) { this.remoteServer = remoteServer; } + + /** + * Sets a map of cookies from a possible previous session. The Java server can send and request these + * to store information on the client across server transfers. + */ + public void cookies(@NonNull Map cookies) { + Objects.requireNonNull(cookies); + this.cookies = cookies; + } + + /** + * Gets a map of the sessions cookies, if set. + * @return the connections cookies + */ + public @NonNull Map cookies() { + return cookies; + } + + /** + * Determines the connection intent of the connection + */ + public void transferring(boolean transferring) { + this.transferring = transferring; + } + + /** + * Gets whether this login attempt to the Java server + * has the transfer intent + */ + public boolean transferring() { + return this.transferring; + } } diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java new file mode 100644 index 000000000..afdf596c2 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java @@ -0,0 +1,71 @@ +/* + * 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.api.event.java; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.event.connection.ConnectionEvent; + +import java.util.Map; + +public class ServerTransferEvent extends ConnectionEvent { + + private final String host; + private final int port; + private final Map cookies; + + public ServerTransferEvent(@NonNull GeyserConnection connection, String host, int port, Map cookies) { + super(connection); + this.host = host; + this.port = port; + this.cookies = cookies; + } + + /** + * The host that the Java server requests a transfer to. + * @return the host + */ + public String host() { + return this.host; + } + + /** + * The port that the Java server requests a transfer to. + * @return the port + */ + public int port() { + return this.port; + } + + /** + * Gets a map of the sessions current cookies. + * @return the connections cookies + */ + public @NonNull Map cookies() { + return cookies; + } + +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index 43ecf7154..6aa5d563f 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -175,8 +175,9 @@ public class GeyserSpigotInjector extends GeyserInjector { MinecraftProtocol protocol = new MinecraftProtocol(); LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().address(), bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress, - InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper()); + InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper(), false); session.connect(); + session.disconnect(""); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index a11c4f583..4a2028fc7 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -70,6 +70,5 @@ public class WrittenBookItem extends Item { builder.putString("title", bookContent.getTitle().getRaw()) .putString("author", bookContent.getAuthor()) .putInt("generation", bookContent.getGeneration()); - // TODO isResolved } } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 19b0b423f..b5598d063 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -54,11 +54,14 @@ public final class LocalSession extends TcpSession { private final String clientIp; private final PacketCodecHelper codecHelper; - public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, MinecraftCodecHelper codecHelper) { + private final boolean transferring; + + public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, MinecraftCodecHelper codecHelper, boolean transferring) { super(host, port, protocol); this.targetAddress = targetAddress; this.clientIp = clientIp; this.codecHelper = codecHelper; + this.transferring = transferring; } @Override @@ -79,7 +82,7 @@ public final class LocalSession extends TcpSession { public void initChannel(@NonNull LocalChannelWithRemoteAddress channel) { channel.spoofedRemoteAddress(new InetSocketAddress(clientIp, 0)); PacketProtocol protocol = getPacketProtocol(); - protocol.newClientSession(LocalSession.this, false); + protocol.newClientSession(LocalSession.this, transferring); refreshReadTimeoutHandler(channel); refreshWriteTimeoutHandler(channel); 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 175d9eac2..869999357 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -569,6 +569,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private @Nullable ItemData currentBook = null; + /** + * Stores cookies sent by the Java server. + */ + @Setter @Getter + private Map cookies = new Object2ObjectOpenHashMap<>(); + private final GeyserCameraData cameraData; private final GeyserEntityData entityData; @@ -853,7 +859,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * After getting whatever credentials needed, we attempt to join the Java server. */ private void connectDownstream() { - SessionLoginEvent loginEvent = new SessionLoginEvent(this, remoteServer); + SessionLoginEvent loginEvent = new SessionLoginEvent(this, remoteServer, new Object2ObjectOpenHashMap<>()); GeyserImpl.getInstance().eventBus().fire(loginEvent); if (loginEvent.isCancelled()) { String disconnectReason = loginEvent.disconnectReason() == null ? @@ -862,6 +868,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return; } + this.cookies = loginEvent.cookies(); this.remoteServer = loginEvent.remoteServer(); boolean floodgate = this.remoteServer.authType() == AuthType.FLOODGATE; @@ -873,7 +880,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // We're going to connect through the JVM and not through TCP downstream = new LocalSession(this.remoteServer.address(), this.remoteServer.port(), geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), - this.protocol, this.protocol.createHelper()); + this.protocol, this.protocol.createHelper(), loginEvent.transferring()); this.downstream = new DownstreamSession(downstream); } else { downstream = new TcpClientSession(this.remoteServer.address(), this.remoteServer.port(), this.protocol); 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 new file mode 100644 index 000000000..06f020423 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaCookieRequestTranslator.java @@ -0,0 +1,42 @@ +/* + * 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.java.entity.player; + +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundCookieRequestPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ServerboundCookieResponsePacket; + +public class JavaCookieRequestTranslator extends PacketTranslator { + @Override + public void translate(GeyserSession session, ClientboundCookieRequestPacket packet) { + ServerboundCookieResponsePacket responsePacket = new ServerboundCookieResponsePacket( + packet.getKey(), + session.getCookies().get(packet.getKey()) + ); + session.sendDownstreamPacket(responsePacket); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java new file mode 100644 index 000000000..499dfda8d --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java @@ -0,0 +1,37 @@ +/* + * 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.java.entity.player; + +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundStoreCookiePacket; + +public class JavaStoreCookieTranslator extends PacketTranslator { + @Override + public void translate(GeyserSession session, ClientboundStoreCookiePacket packet) { + session.getCookies().put(packet.getKey(), packet.getPayload()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java new file mode 100644 index 000000000..1e9bd1537 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java @@ -0,0 +1,43 @@ +/* + * 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.java.entity.player; + +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.event.java.ServerTransferEvent; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundTransferPacket; + +public class JavaTransferPacketTranslator extends PacketTranslator { + @Override + public void translate(GeyserSession session, ClientboundTransferPacket packet) { + GeyserImpl.getInstance().eventBus().fire(new ServerTransferEvent( + session, + packet.getHost(), + packet.getPort(), + session.getCookies())); + } +} From f67c131b8d06f938a10f9eb0f52a6f4ab2b1423a Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Fri, 26 Apr 2024 15:36:26 +0200 Subject: [PATCH 082/897] Forcibly disconnect players even if no server target was set in the JavaTransferEvent --- .../api/event/java/ServerTransferEvent.java | 52 +++++++++++++++++++ .../player/JavaCookieRequestTranslator.java | 2 + .../player/JavaStoreCookieTranslator.java | 2 + .../player/JavaTransferPacketTranslator.java | 15 +++++- 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java index afdf596c2..b3b580ec3 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java @@ -26,15 +26,22 @@ package org.geysermc.geyser.api.event.java; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.common.value.qual.IntRange; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.connection.ConnectionEvent; import java.util.Map; +/** + * Fired when the Java server sends a transfer request to a different Java server. + * Geyser Extensions can listen to this event and set a target server ip/port for Bedrock players to be transferred to. + */ public class ServerTransferEvent extends ConnectionEvent { private final String host; private final int port; + private String bedrockHost; + private int bedrockPort; private final Map cookies; public ServerTransferEvent(@NonNull GeyserConnection connection, String host, int port, Map cookies) { @@ -42,10 +49,13 @@ public class ServerTransferEvent extends ConnectionEvent { this.host = host; this.port = port; this.cookies = cookies; + this.bedrockHost = null; + this.bedrockPort = -1; } /** * The host that the Java server requests a transfer to. + * * @return the host */ public String host() { @@ -54,14 +64,56 @@ public class ServerTransferEvent extends ConnectionEvent { /** * The port that the Java server requests a transfer to. + * * @return the port */ public int port() { return this.port; } + /** + * The host that the Bedrock player should try and connect to. + * If this is not set, the Bedrock player will just be disconnected. + * + * @return the host where the Bedrock client will be transferred to, or null if not set. + */ + public String bedrockHost() { + return this.bedrockHost; + } + + /** + * The port that the Bedrock player should try and connect to. + * If this is not set, the Bedrock player will just be disconnected. + * + * @return the port where the Bedrock client will be transferred to, or -1 if not set. + */ + public int bedrockPort() { + return this.bedrockPort; + } + + /** + * Sets the host for the Bedrock player to be transferred to + */ + public void bedrockHost(@NonNull String host) { + if (host == null || host.isBlank()) { + throw new IllegalArgumentException("Server address cannot be null or blank"); + } + this.bedrockHost = host; + } + + /** + * Sets the port for the Bedrock player to be transferred to + */ + public void bedrockPort(@IntRange(from = 0, to = 65535) int port) { + if (port < 0 || port > 65535) { + throw new IllegalArgumentException("Server port must be between 0 and 65535, was " + port); + } + this.bedrockPort = port; + } + /** * Gets a map of the sessions current cookies. + * * @return the connections cookies */ public @NonNull Map cookies() { 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 06f020423..5266ebabd 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 @@ -27,9 +27,11 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; 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.common.clientbound.ClientboundCookieRequestPacket; import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ServerboundCookieResponsePacket; +@Translator(packet = ClientboundCookieRequestPacket.class) public class JavaCookieRequestTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundCookieRequestPacket packet) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java index 499dfda8d..19237b646 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java @@ -27,8 +27,10 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; 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.common.clientbound.ClientboundStoreCookiePacket; +@Translator(packet = ClientboundStoreCookiePacket.class) public class JavaStoreCookieTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundStoreCookiePacket packet) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java index 1e9bd1537..86fd70677 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java @@ -28,16 +28,27 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.java.ServerTransferEvent; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundTransferPacket; +@Translator(packet = ClientboundTransferPacket.class) public class JavaTransferPacketTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundTransferPacket packet) { - GeyserImpl.getInstance().eventBus().fire(new ServerTransferEvent( + ServerTransferEvent event = new ServerTransferEvent( session, packet.getHost(), packet.getPort(), - session.getCookies())); + session.getCookies()); + + GeyserImpl.getInstance().eventBus().fire(event); + + if (event.bedrockHost() != null && !event.bedrockHost().isBlank() && event.bedrockPort() != -1) { + session.transfer(event.bedrockHost(), event.bedrockPort()); + } else { + session.disconnect(MinecraftLocale.getLocaleString("disconnect.transfer", session.locale())); + } } } From 5015a2ef895a2f51a1bc3d08c824d98025d3e8ff Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Fri, 26 Apr 2024 15:41:05 +0200 Subject: [PATCH 083/897] bump project version to 2.3.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index a7c0bf93d..dd61d2556 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.2.3-SNAPSHOT +version=2.3.0-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From a57e7b54dc93ad23c82c1c3c4233678b5f16dffe Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Apr 2024 16:36:47 +0200 Subject: [PATCH 084/897] Update ViaVersion api usage to be compatible with ViaVersion 4.10 (#4606) --- .../world/manager/GeyserSpigotLegacyNativeWorldManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java index 021db5ec1..d3d492553 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java @@ -58,7 +58,7 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl int newBlockId = oldBlockId; // protocolList should *not* be null; we checked for that before initializing this class for (int i = protocolList.size() - 1; i >= 0; i--) { - MappingData mappingData = protocolList.get(i).getProtocol().getMappingData(); + MappingData mappingData = protocolList.get(i).protocol().getMappingData(); if (mappingData != null) { newBlockId = mappingData.getNewBlockStateId(newBlockId); } From 42a9ba617bb11c7da5073eb7c3c8ec60a3102984 Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Fri, 26 Apr 2024 20:06:37 +0200 Subject: [PATCH 085/897] Update ViaProxy platform (#4607) * Update ViaProxy API usage * Don't reference ViaProxy API in dummy application --- .../viaproxy/GeyserViaProxyConfiguration.java | 4 ++-- .../platform/viaproxy/GeyserViaProxyDumpInfo.java | 5 ++--- .../geyser/platform/viaproxy/GeyserViaProxyMain.java | 3 +-- .../platform/viaproxy/GeyserViaProxyPlugin.java | 11 +++++------ bootstrap/viaproxy/src/main/resources/viaproxy.yml | 2 +- gradle/libs.versions.toml | 2 +- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java index ad249eb3b..bf9d6816c 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.platform.viaproxy; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import net.raphimc.vialegacy.api.LegacyProtocolVersion; -import net.raphimc.viaproxy.cli.options.Options; +import net.raphimc.viaproxy.ViaProxy; import org.geysermc.geyser.configuration.GeyserJacksonConfiguration; import java.io.File; @@ -43,7 +43,7 @@ public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration { @Override public int getPingPassthroughInterval() { int interval = super.getPingPassthroughInterval(); - if (interval < 15 && Options.PROTOCOL_VERSION != null && Options.PROTOCOL_VERSION.olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) { + if (interval < 15 && ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) { // <= 1.6.4 servers sometimes block incoming connections from an IP address if too many connections are made interval = 15; } diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java index 08f3d5371..0bfc9d022 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.platform.viaproxy; import lombok.Getter; import net.raphimc.viaproxy.ViaProxy; -import net.raphimc.viaproxy.cli.options.Options; import net.raphimc.viaproxy.plugins.ViaProxyPlugin; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.text.AsteriskSerializer; @@ -49,8 +48,8 @@ public class GeyserViaProxyDumpInfo extends BootstrapDumpInfo { public GeyserViaProxyDumpInfo() { this.platformVersion = ViaProxy.VERSION; - this.onlineMode = Options.ONLINE_MODE; - if (Options.BIND_ADDRESS instanceof InetSocketAddress inetSocketAddress) { + this.onlineMode = ViaProxy.getConfig().isProxyOnlineMode(); + if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress inetSocketAddress) { this.serverIP = inetSocketAddress.getHostString(); this.serverPort = inetSocketAddress.getPort(); } else { diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java index 675c92534..582a97d78 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.platform.viaproxy; -import net.raphimc.viaproxy.plugins.PluginManager; import org.geysermc.geyser.GeyserMain; public class GeyserViaProxyMain extends GeyserMain { @@ -39,7 +38,7 @@ public class GeyserViaProxyMain extends GeyserMain { } public String getPluginFolder() { - return PluginManager.PLUGINS_DIR.getName(); + return "plugins"; } } diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java index 47745df7d..30404e705 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.platform.viaproxy; import net.lenni0451.lambdaevents.EventHandler; import net.raphimc.vialegacy.api.LegacyProtocolVersion; import net.raphimc.viaproxy.ViaProxy; -import net.raphimc.viaproxy.cli.options.Options; import net.raphimc.viaproxy.plugins.PluginManager; import net.raphimc.viaproxy.plugins.ViaProxyPlugin; import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent; @@ -137,7 +136,7 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst GeyserImpl.start(); - if (Options.PROTOCOL_VERSION != null && Options.PROTOCOL_VERSION.newerThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) { + if (ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().newerThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) { // Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser); } @@ -186,19 +185,19 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst @NotNull @Override public String getServerBindAddress() { - if (Options.BIND_ADDRESS instanceof InetSocketAddress socketAddress) { + if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) { return socketAddress.getHostString(); } else { - throw new IllegalStateException("Unsupported bind address type: " + Options.BIND_ADDRESS.getClass().getName()); + throw new IllegalStateException("Unsupported bind address type: " + ViaProxy.getConfig().getBindAddress().getClass().getName()); } } @Override public int getServerPort() { - if (Options.BIND_ADDRESS instanceof InetSocketAddress socketAddress) { + if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) { return socketAddress.getPort(); } else { - throw new IllegalStateException("Unsupported bind address type: " + Options.BIND_ADDRESS.getClass().getName()); + throw new IllegalStateException("Unsupported bind address type: " + ViaProxy.getConfig().getBindAddress().getClass().getName()); } } diff --git a/bootstrap/viaproxy/src/main/resources/viaproxy.yml b/bootstrap/viaproxy/src/main/resources/viaproxy.yml index f42cda77b..66fbdb932 100644 --- a/bootstrap/viaproxy/src/main/resources/viaproxy.yml +++ b/bootstrap/viaproxy/src/main/resources/viaproxy.yml @@ -2,4 +2,4 @@ name: "${name}-ViaProxy" version: "${version}" author: "${author}" main: "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyPlugin" -min-version: "3.2.0" +min-version: "3.2.1" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2d32159f0..b051e8852 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ adapters = "1.11-SNAPSHOT" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.1.1" -viaproxy = "3.2.0-SNAPSHOT" +viaproxy = "3.2.1" fabric-minecraft = "1.20.4" fabric-loader = "0.15.2" fabric-api = "0.91.2+1.20.4" From 2fa7585db3538ebb386edb861abf792f1f35489c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Apr 2024 21:44:59 -0400 Subject: [PATCH 086/897] Switch to Cloudburst NBT only --- .../java/org/geysermc/geyser/GeyserImpl.java | 3 +- .../geyser/entity/type/LivingEntity.java | 7 +- .../entity/type/player/PlayerEntity.java | 18 +- .../geyser/inventory/GeyserItemStack.java | 43 +++-- .../geysermc/geyser/inventory/Inventory.java | 13 +- .../geyser/inventory/item/Potion.java | 6 + .../geyser/inventory/recipe/TrimRecipe.java | 12 +- .../updater/AnvilInventoryUpdater.java | 60 +++---- .../geyser/item/DyeableLeatherItem.java | 15 -- .../geysermc/geyser/item/type/ArmorItem.java | 16 -- .../geysermc/geyser/item/type/ArrowItem.java | 16 +- .../geysermc/geyser/item/type/BannerItem.java | 58 +++---- .../geyser/item/type/CompassItem.java | 4 +- .../geyser/item/type/CrossbowItem.java | 22 --- .../geyser/item/type/DyeableArmorItem.java | 9 - .../item/type/DyeableHorseArmorItem.java | 9 - .../geyser/item/type/EnchantedBookItem.java | 30 ++++ .../geyser/item/type/FireworkRocketItem.java | 69 ++++---- .../geyser/item/type/FireworkStarItem.java | 19 +-- .../geyser/item/type/GoatHornItem.java | 17 +- .../org/geysermc/geyser/item/type/Item.java | 117 +++++++------ .../geysermc/geyser/item/type/MapItem.java | 14 -- .../geysermc/geyser/item/type/PotionItem.java | 10 +- .../geyser/item/type/ShulkerBoxItem.java | 9 - .../item/type/TropicalFishBucketItem.java | 19 +-- .../geyser/item/type/WritableBookItem.java | 25 --- .../geyser/item/type/WrittenBookItem.java | 3 +- .../geysermc/geyser/level/JavaDimension.java | 33 +--- .../geyser/session/cache/LodestoneCache.java | 18 +- .../org/geysermc/geyser/skin/SkinManager.java | 22 +-- .../geysermc/geyser/text/TextDecoration.java | 33 ++-- .../inventory/InventoryTranslator.java | 2 +- .../inventory/PlayerInventoryTranslator.java | 4 +- .../inventory/ShulkerInventoryTranslator.java | 2 +- .../translator/item/ItemTranslator.java | 156 ++---------------- .../entity/BannerBlockEntityTranslator.java | 27 +-- .../entity/BeaconBlockEntityTranslator.java | 15 +- .../entity/BedBlockEntityTranslator.java | 9 +- .../block/entity/BlockEntityTranslator.java | 15 +- .../BrushableBlockEntityTranslator.java | 29 ++-- .../entity/CampfireBlockEntityTranslator.java | 34 ++-- .../CommandBlockBlockEntityTranslator.java | 33 ++-- .../DecoratedPotBlockEntityTranslator.java | 21 +-- .../DoubleChestBlockEntityTranslator.java | 18 +- .../entity/EmptyBlockEntityTranslator.java | 5 +- .../EndGatewayBlockEntityTranslator.java | 34 +--- .../JigsawBlockBlockEntityTranslator.java | 23 ++- .../ShulkerBoxBlockEntityTranslator.java | 7 +- .../entity/SignBlockEntityTranslator.java | 37 ++--- .../entity/SkullBlockEntityTranslator.java | 66 ++++---- .../entity/SpawnerBlockEntityTranslator.java | 64 ++++--- .../StructureBlockBlockEntityTranslator.java | 69 ++++---- .../TrialSpawnerBlockEntityTranslator.java | 11 +- .../level/JavaBlockEntityDataTranslator.java | 27 ++- .../JavaLevelChunkWithLightTranslator.java | 5 +- .../BlockSoundInteractionTranslator.java | 31 +--- .../translator/text/MessageTranslator.java | 18 +- gradle/libs.versions.toml | 2 +- 58 files changed, 586 insertions(+), 927 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 5c4313f09..d5635acf9 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -45,7 +45,6 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.geysermc.api.Geyser; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; -import org.geysermc.erosion.packet.Packets; import org.geysermc.floodgate.crypto.AesCipher; import org.geysermc.floodgate.crypto.AesKeyProducer; import org.geysermc.floodgate.crypto.Base64Topping; @@ -384,7 +383,7 @@ public class GeyserImpl implements GeyserApi { this.newsHandler = new NewsHandler(BRANCH, this.buildNumber()); - Packets.initGeyser(); + //Packets.initGeyser(); if (Epoll.isAvailable()) { this.erosionUnixListener = new UnixSocketClientListener(); 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 5823ba3b2..baaf91f59 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,8 +25,6 @@ package org.geysermc.geyser.entity.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -57,6 +55,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEn import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; 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.data.game.item.component.DataComponentType; import java.util.*; @@ -194,9 +193,9 @@ public class LivingEntity extends Entity { /** * Checks to see if a nametag interaction would go through. */ + // Implementation note for 1.20.5: this code was moved to the NameTag item. protected final InteractionResult checkInteractWithNameTag(GeyserItemStack itemStack) { - CompoundTag nbt = itemStack.getNbt(); - if (nbt != null && nbt.get("display") instanceof CompoundTag displayTag && displayTag.get("Name") instanceof StringTag) { + if (itemStack.getComponent(DataComponentType.CUSTOM_NAME) != null) { // The mob shall be named return InteractionResult.SUCCESS; } 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 1ca387259..25040063e 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,14 +25,14 @@ package org.geysermc.geyser.entity.type.player; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import lombok.Getter; import lombok.Setter; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.Ability; import org.cloudburstmc.protocol.bedrock.data.AbilityLayer; import org.cloudburstmc.protocol.bedrock.data.GameType; @@ -298,11 +298,11 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { dirtyMetadata.put(EntityDataTypes.MARK_VARIANT, ~entityMetadata.getPrimitiveValue() & 0xff); } - public void setLeftParrot(EntityMetadata entityMetadata) { + public void setLeftParrot(EntityMetadata entityMetadata) { setParrot(entityMetadata.getValue(), true); } - public void setRightParrot(EntityMetadata entityMetadata) { + public void setRightParrot(EntityMetadata entityMetadata) { setParrot(entityMetadata.getValue(), false); } @@ -310,7 +310,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { * Sets the parrot occupying the shoulder. Bedrock Edition requires a full entity whereas Java Edition just * spawns it from the NBT data provided */ - protected void setParrot(CompoundTag tag, boolean isLeft) { + protected void setParrot(NbtMap tag, boolean isLeft) { if (tag != null && !tag.isEmpty()) { if ((isLeft && leftParrot != null) || (!isLeft && rightParrot != null)) { // No need to update a parrot's data when it already exists @@ -320,7 +320,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { ParrotEntity parrot = new ParrotEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(), null, EntityDefinitions.PARROT, position, motion, getYaw(), getPitch(), getHeadYaw()); parrot.spawnEntity(); - parrot.getDirtyMetadata().put(EntityDataTypes.VARIANT, (Integer) tag.get("Variant").getValue()); + parrot.getDirtyMetadata().put(EntityDataTypes.VARIANT, (Integer) tag.get("Variant")); // Different position whether the parrot is left or right float offset = isLeft ? 0.4f : -0.4f; parrot.getDirtyMetadata().put(EntityDataTypes.SEAT_OFFSET, Vector3f.from(offset, -0.22, -0.1)); @@ -437,11 +437,11 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { } else if (numberFormat instanceof FixedFormat fixedFormat) { numberString = MessageTranslator.convertMessage(fixedFormat.getValue()); } else if (numberFormat instanceof StyledFormat styledFormat) { - CompoundTag styledAmount = styledFormat.getStyle().clone(); - styledAmount.put(new StringTag("text", String.valueOf(amount))); + NbtMapBuilder styledAmount = styledFormat.getStyle().toBuilder(); + styledAmount.putString("text", String.valueOf(amount)); numberString = MessageTranslator.convertJsonMessage( - NbtComponentSerializer.tagComponentToJson(styledAmount).toString()); + NbtComponentSerializer.tagComponentToJson(styledAmount.build()).toString(), session.locale()); } else { numberString = String.valueOf(amount); } 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 f75c1fdd9..fa62769fe 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -25,11 +25,7 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import lombok.AccessLevel; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.Getter; +import lombok.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -43,6 +39,8 @@ 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 java.util.HashMap; + @Data public class GeyserItemStack { public static final GeyserItemStack EMPTY = new GeyserItemStack(Items.AIR_ID, 0, null); @@ -52,7 +50,7 @@ public class GeyserItemStack { private DataComponents components; private int netId; - @Getter(AccessLevel.NONE) + @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) @EqualsAndHashCode.Exclude private Item item; @@ -67,6 +65,14 @@ public class GeyserItemStack { this.netId = netId; } + public static @NonNull GeyserItemStack of(int javaId, int amount) { + return of(javaId, amount, null); + } + + public static @NonNull GeyserItemStack of(int javaId, int amount, DataComponents components) { + return new GeyserItemStack(javaId, amount, components); + } + public static @NonNull GeyserItemStack from(@Nullable ItemStack itemStack) { return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponents()); } @@ -79,16 +85,27 @@ public class GeyserItemStack { return isEmpty() ? 0 : amount; } - public @Nullable CompoundTag getNbt() { - Thread.dumpStack(); - return null; - } - public @Nullable DataComponents getComponents() { return isEmpty() ? null : components; } - public boolean getComponent(DataComponentType type, boolean def) { + @NonNull + public DataComponents getOrCreateComponents() { + if (components == null) { + return components = new DataComponents(new HashMap<>()); + } + return components; + } + + @Nullable + public T getComponent(@NonNull DataComponentType type) { + if (components == null) { + return null; + } + return components.get(type); + } + + public boolean getComponent(@NonNull DataComponentType type, boolean def) { if (components == null) { return def; } @@ -100,7 +117,7 @@ public class GeyserItemStack { return def; } - public int getComponent(DataComponentType type, int def) { + public int getComponent(@NonNull DataComponentType type, int def) { if (components == null) { return def; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index 4e8257ff8..09d04f17c 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.inventory; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -39,6 +36,7 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.jetbrains.annotations.Range; import java.util.Arrays; @@ -137,12 +135,9 @@ public abstract class Inventory { // Lodestone caching if (newItem.asItem() == Items.COMPASS) { - CompoundTag nbt = newItem.getNbt(); - if (nbt != null) { - Tag lodestoneTag = nbt.get("LodestoneTracked"); - if (lodestoneTag instanceof ByteTag) { - session.getLodestoneCache().cacheInventoryItem(newItem); - } + var tracker = newItem.getComponent(DataComponentType.LODESTONE_TRACKER); + if (tracker != null) { + session.getLodestoneCache().cacheInventoryItem(newItem, tracker); } } } 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 7ce0ee278..79b9565fb 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 @@ -25,8 +25,10 @@ package org.geysermc.geyser.inventory.item; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import lombok.Getter; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; import java.util.Locale; @@ -85,6 +87,10 @@ public enum Potion { this.bedrockId = (short) bedrockId; } + public PotionContents toComponent() { + return new PotionContents(this.ordinal(), -1, Int2ObjectMaps.emptyMap()); + } + public static @Nullable Potion getByJavaIdentifier(String javaIdentifier) { for (Potion potion : VALUES) { if (potion.javaIdentifier.equals(javaIdentifier)) { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java index 860ccfd89..37eb905a4 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.inventory.recipe; -import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; @@ -37,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescri import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; /** * Stores information on trim materials and patterns, including smithing armor hacks for pre-1.20. @@ -54,11 +52,11 @@ public final class TrimRecipe { // Color is used when hovering over the item // Find the nearest legacy color from the RGB Java gives us to work with // Also yes this is a COMPLETE hack but it works ok!!!!! - StringTag colorTag = ((CompoundTag) entry.getData().get("description")).get("color"); - TextColor color = TextColor.fromHexString(colorTag.getValue()); + String colorTag = entry.getData().getCompound("description").getString("color"); + TextColor color = TextColor.fromHexString(colorTag); String legacy = MessageTranslator.convertMessage(Component.space().color(color)); - String itemIdentifier = ((StringTag) entry.getData().get("ingredient")).getValue(); + String itemIdentifier = entry.getData().getString("ingredient"); ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier); if (itemMapping == null) { // This should never happen so not sure what to do here. @@ -71,7 +69,7 @@ public final class TrimRecipe { public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) { String key = stripNamespace(entry.getId()); - String itemIdentifier = ((StringTag) entry.getData().get("template_item")).getValue(); + String itemIdentifier = entry.getData().getString("template_item"); ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier); if (itemMapping == null) { // This should never happen so not sure what to do here. 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 d6324ba23..1021a5fb9 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 @@ -25,13 +25,6 @@ package org.geysermc.geyser.inventory.updater; -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.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -53,7 +46,12 @@ import org.geysermc.geyser.session.GeyserSession; 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.ItemEnchantments; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; +import java.util.Map; import java.util.Objects; public class AnvilInventoryUpdater extends InventoryUpdater { @@ -310,9 +308,9 @@ public class AnvilInventoryUpdater extends InventoryUpdater { */ private int calcMergeEnchantmentCost(GeyserSession session, GeyserItemStack input, GeyserItemStack material, boolean bedrock) { boolean hasCompatible = false; - Object2IntMap combinedEnchantments = getEnchantments(input, bedrock); + Object2IntMap combinedEnchantments = getEnchantments(input); int cost = 0; - for (Object2IntMap.Entry entry : getEnchantments(material, bedrock).object2IntEntrySet()) { + for (Object2IntMap.Entry entry : getEnchantments(material).object2IntEntrySet()) { JavaEnchantment enchantment = entry.getKey(); EnchantmentData data = Registries.ENCHANTMENTS.get(enchantment); if (data == null) { @@ -371,42 +369,26 @@ public class AnvilInventoryUpdater extends InventoryUpdater { return cost; } - private Object2IntMap getEnchantments(GeyserItemStack itemStack, boolean bedrock) { - if (itemStack.getNbt() == null) { - return Object2IntMaps.emptyMap(); - } - Object2IntMap enchantments = new Object2IntOpenHashMap<>(); - Tag enchantmentTag; + private Object2IntMap getEnchantments(GeyserItemStack itemStack) { + ItemEnchantments enchantmentComponent; if (isEnchantedBook(itemStack)) { - enchantmentTag = itemStack.getNbt().get("StoredEnchantments"); + enchantmentComponent = itemStack.getComponent(DataComponentType.STORED_ENCHANTMENTS); } else { - enchantmentTag = itemStack.getNbt().get("Enchantments"); + enchantmentComponent = itemStack.getComponent(DataComponentType.ENCHANTMENTS); } - if (enchantmentTag instanceof ListTag listTag) { - for (Tag tag : listTag.getValue()) { - if (tag instanceof CompoundTag enchantTag) { - if (enchantTag.get("id") instanceof StringTag javaEnchId) { - JavaEnchantment enchantment = JavaEnchantment.getByJavaIdentifier(javaEnchId.getValue()); - if (enchantment == null) { - GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + javaEnchId.getValue()); - continue; - } - - Tag javaEnchLvl = enchantTag.get("lvl"); - if (javaEnchLvl == null || !(javaEnchLvl.getValue() instanceof Number number)) - continue; - - // Handle duplicate enchantments - if (bedrock) { - enchantments.putIfAbsent(enchantment, number.intValue()); - } else { - enchantments.mergeInt(enchantment, number.intValue(), Math::max); - } - } + if (enchantmentComponent != null) { + Object2IntMap enchantments = new Object2IntOpenHashMap<>(); + for (Map.Entry entry : enchantmentComponent.getEnchantments().entrySet()) { + JavaEnchantment enchantment = JavaEnchantment.of(entry.getKey()); + if (enchantment == null) { + GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + entry.getKey()); + continue; } + enchantments.put(enchantment, entry.getValue().intValue()); } + return enchantments; } - return enchantments; + return Object2IntMaps.emptyMap(); } private boolean isEnchantedBook(GeyserItemStack itemStack) { diff --git a/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java b/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java index e884ecec5..eabdbee87 100644 --- a/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.item; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -41,17 +39,4 @@ public interface DyeableLeatherItem { } builder.putInt("customColor", dyedItemColor.getRgb()); } - - static void translateNbtToJava(CompoundTag tag) { - IntTag color = tag.get("customColor"); - if (color == null) { - return; - } - CompoundTag displayTag = tag.get("display"); - if (displayTag == null) { - displayTag = new CompoundTag("display"); - } - displayTag.put(color); - tag.remove("customColor"); - } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index fb9f35629..76f951c66 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -25,15 +25,12 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.item.ArmorMaterial; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ArmorTrim; @@ -70,19 +67,6 @@ public class ArmorItem extends Item { } } - @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); - - if (tag.get("Trim") instanceof CompoundTag trim) { - StringTag material = trim.remove("Material"); - StringTag pattern = trim.remove("Pattern"); - // java has a lowercase key, and namespaced value - trim.put(new StringTag("material", "minecraft:" + material.getValue())); - trim.put(new StringTag("pattern", "minecraft:" + pattern.getValue())); - } - } - @Override public boolean isValidRepairItem(Item other) { return material.getRepairIngredient() == other; 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 f3c832a31..f2548e170 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 @@ -25,14 +25,16 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.StringTag; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; 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.TippedArrowPotion; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; -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.PotionContents; public class ArrowItem extends Item { public ArrowItem(String javaIdentifier, Builder builder) { @@ -40,13 +42,13 @@ public class ArrowItem extends Item { } @Override - public @NonNull ItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); - ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); + GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (tippedArrowPotion != null) { - itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getDataComponents()); - StringTag potionTag = new StringTag("Potion", tippedArrowPotion.getJavaIdentifier()); - //itemStack.getDataComponents().put(DataComponentType.POTION_CONTENTS, new PotionContents()); + itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents()); + PotionContents contents = new PotionContents(tippedArrowPotion.ordinal(), -1, Int2ObjectMaps.emptyMap()); + itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, contents); } return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 29a98e598..232f340ea 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.*; import it.unimi.dsi.fastutil.Pair; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtList; @@ -52,7 +51,7 @@ public class BannerItem extends BlockItem { * the correct ominous banner pattern if Bedrock pulls the item from creative. */ private static final List> OMINOUS_BANNER_PATTERN; - private static final ListTag OMINOUS_BANNER_PATTERN_BLOCK; + private static final List OMINOUS_BANNER_PATTERN_BLOCK; static { // Construct what an ominous banner is supposed to look like @@ -67,7 +66,7 @@ public class BannerItem extends BlockItem { Pair.of(BannerPattern.BORDER, DyeColor.BLACK) ); - OMINOUS_BANNER_PATTERN_BLOCK = new ListTag("patterns"); + OMINOUS_BANNER_PATTERN_BLOCK = new ArrayList<>(); for (Pair pair : OMINOUS_BANNER_PATTERN) { OMINOUS_BANNER_PATTERN_BLOCK.add(getJavaBannerPatternTag(pair.left(), pair.right())); } @@ -92,7 +91,7 @@ public class BannerItem extends BlockItem { return true; } - public static boolean isOminous(ListTag blockEntityPatterns) { + public static boolean isOminous(List blockEntityPatterns) { return OMINOUS_BANNER_PATTERN_BLOCK.equals(blockEntityPatterns); } @@ -102,10 +101,10 @@ public class BannerItem extends BlockItem { * @param patterns The patterns to convert * @return The new converted patterns */ - public static NbtList convertBannerPattern(ListTag patterns) { + public static NbtList convertBannerPattern(List patterns) { List tagsList = new ArrayList<>(); - for (Tag patternTag : patterns.getValue()) { - NbtMap bedrockBannerPattern = getBedrockBannerPattern((CompoundTag) patternTag); + for (NbtMap patternTag : patterns) { + NbtMap bedrockBannerPattern = getBedrockBannerPattern(patternTag); if (bedrockBannerPattern != null) { tagsList.add(bedrockBannerPattern); } @@ -120,9 +119,9 @@ public class BannerItem extends BlockItem { * @param pattern Java edition pattern nbt * @return The Bedrock edition format pattern nbt */ - private static NbtMap getBedrockBannerPattern(CompoundTag pattern) { - BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier((String) pattern.get("pattern").getValue()); - DyeColor dyeColor = DyeColor.getByJavaIdentifier((String) pattern.get("color").getValue()); + private static NbtMap getBedrockBannerPattern(NbtMap pattern) { + BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(pattern.getString("pattern")); + DyeColor dyeColor = DyeColor.getByJavaIdentifier(pattern.getString("color")); if (bannerPattern == null || dyeColor == null) { return null; } @@ -133,11 +132,11 @@ public class BannerItem extends BlockItem { .build(); } - public static CompoundTag getJavaBannerPatternTag(BannerPattern bannerPattern, DyeColor dyeColor) { - CompoundTag tag = new CompoundTag(""); - tag.put(new StringTag("pattern", bannerPattern.getJavaIdentifier())); - tag.put(new StringTag("color", dyeColor.getJavaIdentifier())); - return tag; + public static NbtMap getJavaBannerPatternTag(BannerPattern bannerPattern, DyeColor dyeColor) { + return NbtMap.builder() + .putString("pattern", bannerPattern.getJavaIdentifier()) + .putString("color", dyeColor.getJavaIdentifier()) + .build(); } /** @@ -190,31 +189,14 @@ public class BannerItem extends BlockItem { } @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { // TODO - super.translateNbtToJava(tag, mapping); + public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { // TODO + super.translateNbtToJava(bedrockTag, components, mapping); - if (tag.get("Type") instanceof IntTag type && type.getValue() == 1) { + if (bedrockTag.getInt("Type") == 1) { // Ominous banner pattern - tag.remove("Type"); - CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - blockEntityTag.put(OMINOUS_BANNER_PATTERN_BLOCK); - - tag.put(blockEntityTag); - } else if (tag.get("Patterns") instanceof ListTag patterns && patterns.getElementType() == CompoundTag.class) { - CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - - ListTag javaPatterns = new ListTag("patterns"); - for (Tag pattern : patterns.getValue()) { - BannerPattern bannerPattern = BannerPattern.getByBedrockIdentifier((String) ((CompoundTag) pattern).get("Pattern").getValue()); - DyeColor dyeColor = DyeColor.getById((int) ((CompoundTag) pattern).get("Color").getValue()); - if (bannerPattern != null && dyeColor != null) { - javaPatterns.add(getJavaBannerPatternTag(bannerPattern, dyeColor)); - } - } - blockEntityTag.put(javaPatterns); - - tag.put(blockEntityTag); - tag.remove("Patterns"); // Remove the old Bedrock patterns list + // TODO more registry stuff + //components.put(DataComponentType.BANNER_PATTERNS); } + // Bedrock's creative inventory does not support other patterns as of 1.20.5 } } 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 aa34f76ba..712e75a23 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 @@ -28,11 +28,11 @@ package org.geysermc.geyser.item.type; 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.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.geyser.translator.item.BedrockItemBuilder; -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.item.component.LodestoneTracker; @@ -78,7 +78,7 @@ public class CompassItem extends Item { } @Override - public @NonNull ItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + public @NonNull GeyserItemStack translateToJava(@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(); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java index 9a10c701c..7e1181c4e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -63,22 +59,4 @@ public class CrossbowItem extends Item { builder.putCompound("chargedItem", newProjectile.build()); } } - - @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); - - if (tag.get("chargedItem") != null) { - CompoundTag chargedItem = tag.get("chargedItem"); - - CompoundTag newProjectile = new CompoundTag(""); - newProjectile.put(new ByteTag("Count", (byte) chargedItem.get("Count").getValue())); - newProjectile.put(new StringTag("id", (String) chargedItem.get("Name").getValue())); - - ListTag chargedProjectiles = new ListTag("ChargedProjectiles"); - chargedProjectiles.add(newProjectile); - - tag.put(chargedProjectiles); - } - } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index e57470607..d4bf838bd 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -25,11 +25,9 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.item.DyeableLeatherItem; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -45,11 +43,4 @@ public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem { DyeableLeatherItem.translateComponentsToBedrock(components, builder); } - - @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); - - DyeableLeatherItem.translateNbtToJava(tag); - } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java index 881598648..b50a3b847 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java @@ -25,10 +25,8 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.DyeableLeatherItem; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -44,11 +42,4 @@ public class DyeableHorseArmorItem extends Item implements DyeableLeatherItem { DyeableLeatherItem.translateComponentsToBedrock(components, builder); } - - @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); - - DyeableLeatherItem.translateNbtToJava(tag); - } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index 952967475..98e98b4b8 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -25,9 +25,14 @@ package org.geysermc.geyser.item.type; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.inventory.item.Enchantment; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; @@ -62,4 +67,29 @@ public class EnchantedBookItem extends Item { builder.putList("ench", NbtType.COMPOUND, bedrockEnchants); } } + + @Override + public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + super.translateNbtToJava(bedrockTag, components, mapping); + + List enchantmentTag = bedrockTag.getList("ench", NbtType.COMPOUND); + if (enchantmentTag != null) { + Int2IntMap javaEnchantments = new Int2IntOpenHashMap(enchantmentTag.size()); + for (NbtMap bedrockEnchantment : enchantmentTag) { + short bedrockId = bedrockEnchantment.getShort("id"); + + Enchantment enchantment = Enchantment.getByBedrockId(bedrockId); + if (enchantment != null) { + int level = bedrockEnchantment.getShort("lvl", (short) 1); + // TODO + javaEnchantments.put(Enchantment.JavaEnchantment.valueOf(enchantment.name()).ordinal(), level); + } else { + GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId); + } + } + if (!javaEnchantments.isEmpty()) { + components.put(DataComponentType.STORED_ENCHANTMENTS, new ItemEnchantments(javaEnchantments, true)); + } + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index e5656b494..1265956da 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -25,9 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; +import it.unimi.dsi.fastutil.ints.IntArrays; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -36,7 +34,6 @@ import org.geysermc.geyser.level.FireworkColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.geyser.util.MathUtils; 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.Fireworks; @@ -73,8 +70,23 @@ public class FireworkRocketItem extends Item { } @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); + public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + super.translateNbtToJava(bedrockTag, components, mapping); + + NbtMap fireworksTag = bedrockTag.getCompound("Fireworks"); + if (!fireworksTag.isEmpty()) { + List explosions = fireworksTag.getList("Explosions", NbtType.COMPOUND); + if (!explosions.isEmpty()) { + List javaExplosions = new ArrayList<>(); + for (NbtMap explosion : explosions) { + Fireworks.FireworkExplosion javaExplosion = translateExplosionToJava(explosion); + if (javaExplosion != null) { + javaExplosions.add(javaExplosion); + } + } + components.put(DataComponentType.FIREWORKS, new Fireworks(1, javaExplosions)); + } + } } static NbtMap translateExplosionToBedrock(Fireworks.FireworkExplosion explosion) { @@ -111,45 +123,22 @@ public class FireworkRocketItem extends Item { return newExplosionData.build(); } - static CompoundTag translateExplosionToJava(CompoundTag explosion, String newName) { - CompoundTag newExplosionData = new CompoundTag(newName); - - if (explosion.get("FireworkType") != null) { - newExplosionData.put(new ByteTag("Type", MathUtils.getNbtByte(explosion.get("FireworkType").getValue()))); - } - - if (explosion.get("FireworkColor") != null) { - byte[] oldColors = (byte[]) explosion.get("FireworkColor").getValue(); - int[] colors = new int[oldColors.length]; + /** + * The only thing that the Bedrock creative inventory has - as of 1.20.80 - is color. + */ + static Fireworks.FireworkExplosion translateExplosionToJava(NbtMap explosion) { + byte[] javaColors = explosion.getByteArray("FireworkColor", null); + if (javaColors != null) { + int[] colors = new int[javaColors.length]; int i = 0; - for (byte color : oldColors) { + for (byte color : javaColors) { colors[i++] = FireworkColor.fromBedrockId(color); } - newExplosionData.put(new IntArrayTag("Colors", colors)); + return new Fireworks.FireworkExplosion(0, colors, IntArrays.EMPTY_ARRAY, false, false); + } else { + return null; } - - if (explosion.get("FireworkFade") != null) { - byte[] oldColors = (byte[]) explosion.get("FireworkFade").getValue(); - int[] colors = new int[oldColors.length]; - - int i = 0; - for (byte color : oldColors) { - colors[i++] = FireworkColor.fromBedrockId(color); - } - - newExplosionData.put(new IntArrayTag("FadeColors", colors)); - } - - if (explosion.get("FireworkTrail") != null) { - newExplosionData.put(new ByteTag("Trail", MathUtils.getNbtByte(explosion.get("FireworkTrail").getValue()))); - } - - if (explosion.get("FireworkFlicker") != null) { - newExplosionData.put(new ByteTag("Flicker", MathUtils.getNbtByte(explosion.get("FireworkFlicker").getValue()))); - } - - return newExplosionData; } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index ab6b7f300..18234975d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.registry.type.ItemMapping; @@ -80,15 +78,16 @@ public class FireworkStarItem extends Item { } @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); + public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + super.translateNbtToJava(bedrockTag, components, mapping); - Tag explosion = tag.remove("FireworksItem"); - if (explosion instanceof CompoundTag) { - CompoundTag newExplosion = FireworkRocketItem.translateExplosionToJava((CompoundTag) explosion, "Explosion"); - tag.put(newExplosion); + NbtMap explosion = bedrockTag.getCompound("FireworksItem"); + if (!explosion.isEmpty()) { + Fireworks.FireworkExplosion newExplosion = FireworkRocketItem.translateExplosionToJava(explosion); + if (newExplosion == null) { + return; + } + components.put(DataComponentType.FIREWORK_EXPLOSION, newExplosion); } - // Remove custom color, if any, since this only exists on Bedrock - tag.remove("customColor"); } } 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 0ff78676c..c31e15578 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 @@ -25,14 +25,12 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; -import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.mcprotocollib.protocol.data.game.Holder; -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.item.component.Instrument; @@ -80,18 +78,11 @@ public class GoatHornItem extends Item { } @Override - public @NonNull ItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { - ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); + public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); int damage = itemData.getDamage(); - if (damage < 0 || damage >= INSTRUMENTS.size()) { - GeyserImpl.getInstance().getLogger().debug("Unknown goat horn instrument for damage: " + damage); - damage = 0; - } - - String instrument = INSTRUMENTS.get(damage); - StringTag instrumentTag = new StringTag("instrument", "minecraft:" + instrument); - //itemStack.getNbt().put(instrumentTag); + itemStack.getOrCreateComponents().put(DataComponentType.INSTRUMENT, Holder.ofId(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 64e2dcbc6..8fcb19ad5 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -33,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; @@ -44,7 +44,6 @@ import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.Identifier; -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.item.component.ItemEnchantments; @@ -108,11 +107,8 @@ public class Item { return builder; } - public @NonNull ItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { - if (itemData.getTag() == null) { - return new ItemStack(javaId, itemData.getCount(), null); - } - return new ItemStack(javaId, itemData.getCount(), null/*ItemTranslator.translateToJavaNBT("", itemData.getTag())*/); + public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + return GeyserItemStack.of(javaId, itemData.getCount()); } public ItemMapping toBedrockDefinition(DataComponents components, ItemMappings mappings) { @@ -162,57 +158,60 @@ public class Item { * * Therefore, if translation cannot be achieved for a certain item, it is not necessarily bad. */ - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - CompoundTag displayTag = tag.get("display"); - if (displayTag != null) { - if (displayTag.contains("Name")) { - StringTag nameTag = displayTag.get("Name"); - displayTag.put(new StringTag("Name", MessageTranslator.convertToJavaMessage(nameTag.getValue()))); - } + public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + // TODO see if any items from the creative menu need this +// CompoundTag displayTag = tag.get("display"); +// if (displayTag != null) { +// if (displayTag.contains("Name")) { +// StringTag nameTag = displayTag.get("Name"); +// displayTag.put(new StringTag("Name", MessageTranslator.convertToJavaMessage(nameTag.getValue()))); +// } +// +// if (displayTag.contains("Lore")) { +// ListTag loreTag = displayTag.get("Lore"); +// List lore = new ArrayList<>(); +// for (Tag subTag : loreTag.getValue()) { +// if (!(subTag instanceof StringTag)) continue; +// lore.add(new StringTag("", MessageTranslator.convertToJavaMessage(((StringTag) subTag).getValue()))); +// } +// displayTag.put(new ListTag("Lore", lore)); +// } +// } - if (displayTag.contains("Lore")) { - ListTag loreTag = displayTag.get("Lore"); - List lore = new ArrayList<>(); - for (Tag subTag : loreTag.getValue()) { - if (!(subTag instanceof StringTag)) continue; - lore.add(new StringTag("", MessageTranslator.convertToJavaMessage(((StringTag) subTag).getValue()))); - } - displayTag.put(new ListTag("Lore", lore)); - } - } - - ListTag enchantmentTag = tag.remove("ench"); - if (enchantmentTag != null) { - List enchantments = new ArrayList<>(); - for (Tag value : enchantmentTag.getValue()) { - if (!(value instanceof CompoundTag tagValue)) - continue; - - ShortTag bedrockId = tagValue.get("id"); - if (bedrockId == null) continue; - - Enchantment enchantment = Enchantment.getByBedrockId(bedrockId.getValue()); - if (enchantment != null) { - CompoundTag javaTag = new CompoundTag(""); - Map javaValue = javaTag.getValue(); - javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier())); - ShortTag levelTag = tagValue.get("lvl"); - javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1)); - javaTag.setValue(javaValue); - - enchantments.add(javaTag); - } else { - GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId); - } - } - if (!enchantments.isEmpty()) { - if ((this instanceof EnchantedBookItem)) { - tag.put(new ListTag("StoredEnchantments", enchantments)); - } else { - tag.put(new ListTag("Enchantments", enchantments)); - } - } - } + // TODO no creative item should have enchantments *except* enchanted books +// List enchantmentTag = bedrockTag.getList("ench", NbtType.COMPOUND); +// if (enchantmentTag != null) { +// List enchantments = new ArrayList<>(); +// for (Tag value : enchantmentTag.getValue()) { +// if (!(value instanceof CompoundTag tagValue)) +// continue; +// +// ShortTag bedrockId = tagValue.get("id"); +// if (bedrockId == null) continue; +// +// Enchantment enchantment = Enchantment.getByBedrockId(bedrockId.getValue()); +// if (enchantment != null) { +// CompoundTag javaTag = new CompoundTag(""); +// Map javaValue = javaTag.getValue(); +// javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier())); +// ShortTag levelTag = tagValue.get("lvl"); +// javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1)); +// javaTag.setValue(javaValue); +// +// enchantments.add(javaTag); +// } else { +// GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId); +// } +// } +// if (!enchantments.isEmpty()) { +// if ((this instanceof EnchantedBookItem)) { +// bedrockTag.put(new ListTag("StoredEnchantments", enchantments)); +// components.put(DataComponentType.STORED_ENCHANTMENTS, enchantments); +// } else { +// components.put(DataComponentType.ENCHANTMENTS, enchantments); +// } +// } +// } } protected final @Nullable NbtMap remapEnchantment(GeyserSession session, int enchantId, int level, BedrockItemBuilder builder) { @@ -243,8 +242,8 @@ public class Item { /* Translation methods end */ - public ItemStack newItemStack(int count, DataComponents components) { - return new ItemStack(this.javaId, count, components); + public GeyserItemStack newItemStack(int count, DataComponents components) { + return GeyserItemStack.of(this.javaId, count, components); } public void setJavaId(int javaId) { // TODO like this? diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java index f6492a169..5d8a1667d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java @@ -25,10 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; @@ -52,15 +49,4 @@ public class MapItem extends Item { builder.putInt("map_name_index", mapValue); builder.putByte("map_display_players", (byte) 1); } - - @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); - - IntTag mapNameIndex = tag.remove("map_name_index"); - if (mapNameIndex != null) { - tag.put(new IntTag("map", mapNameIndex.getValue())); - tag.remove("map_uuid"); - } - } } 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 13d7ccd5e..b69f7d35f 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 @@ -25,16 +25,15 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; +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.translator.item.CustomItemTranslator; -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.item.component.PotionContents; @@ -69,12 +68,11 @@ public class PotionItem extends Item { } @Override - public @NonNull ItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { Potion potion = Potion.getByBedrockId(itemData.getDamage()); - ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); + GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (potion != null) { - StringTag potionTag = new StringTag("Potion", potion.getJavaIdentifier()); - //itemStack.getNbt().put(potionTag); + itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, potion.toComponent()); } return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index 2f2f45c5b..6b2d589d6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -85,12 +84,4 @@ public class ShulkerBoxItem extends BlockItem { } builder.putList("Items", NbtType.COMPOUND, itemsList); } - - @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); - - // Remove any extraneous Bedrock tag and don't touch the Java one - tag.remove("Items"); - } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index 8c00cb049..7c5ad26f6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -25,13 +25,12 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.entity.type.living.animal.TropicalFishEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; @@ -58,26 +57,22 @@ public class TropicalFishBucketItem extends Item { builder.putString("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale())); // Add Java's client side lore tag // Do you know how frequently Java NBT used to be before 1.20.5? It was a lot. And now it's just this lowly check. - CompoundTag entityTag = components.get(DataComponentType.BUCKET_ENTITY_DATA); + NbtMap entityTag = components.get(DataComponentType.BUCKET_ENTITY_DATA); if (entityTag != null && !entityTag.isEmpty()) { //TODO test - Tag bucketVariant = entityTag.get("BucketVariantTag"); - if (bucketVariant == null || !(bucketVariant.getValue() instanceof Number)) { - return; - } + int bucketVariant = entityTag.getInt("BucketVariantTag"); List lore = builder.getOrCreateLore(); - int varNumber = ((Number) bucketVariant.getValue()).intValue(); - int predefinedVariantId = TropicalFishEntity.getPredefinedId(varNumber); + int predefinedVariantId = TropicalFishEntity.getPredefinedId(bucketVariant); if (predefinedVariantId != -1) { Component tooltip = Component.translatable("entity.minecraft.tropical_fish.predefined." + predefinedVariantId, LORE_STYLE); lore.add(0, MessageTranslator.convertMessage(tooltip, session.locale())); } else { - Component typeTooltip = Component.translatable("entity.minecraft.tropical_fish.type." + TropicalFishEntity.getVariantName(varNumber), LORE_STYLE); + Component typeTooltip = Component.translatable("entity.minecraft.tropical_fish.type." + TropicalFishEntity.getVariantName(bucketVariant), LORE_STYLE); lore.add(0, MessageTranslator.convertMessage(typeTooltip, session.locale())); - byte baseColor = TropicalFishEntity.getBaseColor(varNumber); - byte patternColor = TropicalFishEntity.getPatternColor(varNumber); + byte baseColor = TropicalFishEntity.getBaseColor(bucketVariant); + byte patternColor = TropicalFishEntity.getPatternColor(bucketVariant); Component colorTooltip = Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(baseColor), LORE_STYLE); if (baseColor != patternColor) { colorTooltip = colorTooltip.append(Component.text(", ", LORE_STYLE)) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java index 097a5e65b..55ad16b20 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java @@ -25,15 +25,10 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -69,24 +64,4 @@ public class WritableBookItem extends Item { builder.putList("pages", NbtType.COMPOUND, bedrockPages); } - - @Override - public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) { - super.translateNbtToJava(tag, mapping); - - if (!tag.contains("pages")) { - return; - } - List pages = new ArrayList<>(); - ListTag pagesTag = tag.get("pages"); - for (Tag subTag : pagesTag.getValue()) { - if (!(subTag instanceof CompoundTag pageTag)) - continue; - - StringTag textTag = pageTag.get("text"); - pages.add(new StringTag("", textTag.getValue())); - } - tag.remove("pages"); - tag.put(new ListTag("pages", pages)); - } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index a11c4f583..dd41a5e89 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -62,7 +62,7 @@ public class WrittenBookItem extends Item { for (Filterable page : bookContent.getPages()) { NbtMapBuilder pageBuilder = NbtMap.builder(); pageBuilder.putString("photoname", ""); - pageBuilder.putString("text", MessageTranslator.convertMessage(page.getRaw())); + pageBuilder.putString("text", MessageTranslator.convertMessage(session, page.getRaw())); bedrockPages.add(pageBuilder.build()); } builder.putList("pages", NbtType.COMPOUND, bedrockPages); @@ -70,6 +70,5 @@ public class WrittenBookItem extends Item { builder.putString("title", bookContent.getTitle().getRaw()) .putString("author", bookContent.getAuthor()) .putInt("generation", bookContent.getGeneration()); - // TODO isResolved } } diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 27b2430bd..6112dc6cf 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -25,13 +25,9 @@ package org.geysermc.geyser.level; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.cloudburstmc.nbt.NbtMap; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; -import java.util.List; - /** * Represents the information we store from the current Java dimension * @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension. @@ -39,33 +35,16 @@ import java.util.List; */ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale) { - public static void load(List entries, Int2ObjectMap map) { - for (int i = 0; i < entries.size(); i++) { - RegistryEntry entry = entries.get(i); - CompoundTag dimension = entry.getData(); - int minY = ((IntTag) dimension.get("min_y")).getValue(); - int maxY = ((IntTag) dimension.get("height")).getValue(); - // Logical height can be ignored probably - seems to be for artificial limits like the Nether. - - // Set if piglins/hoglins should shake - boolean piglinSafe = ((Number) dimension.get("piglin_safe").getValue()).byteValue() != (byte) 0; - // Load world coordinate scale for the world border - double coordinateScale = ((Number) dimension.get("coordinate_scale").getValue()).doubleValue(); - - map.put(i, new JavaDimension(minY, maxY, piglinSafe, coordinateScale)); - } - } - public static JavaDimension read(RegistryEntry entry) { - CompoundTag dimension = entry.getData(); - int minY = ((IntTag) dimension.get("min_y")).getValue(); - int maxY = ((IntTag) dimension.get("height")).getValue(); + NbtMap dimension = entry.getData(); + int minY = dimension.getInt("min_y"); + int maxY = dimension.getInt("height"); // Logical height can be ignored probably - seems to be for artificial limits like the Nether. // Set if piglins/hoglins should shake - boolean piglinSafe = ((Number) dimension.get("piglin_safe").getValue()).byteValue() != (byte) 0; + boolean piglinSafe = dimension.getBoolean("piglin_safe"); // Load world coordinate scale for the world border - double coordinateScale = ((Number) dimension.get("coordinate_scale").getValue()).doubleValue(); + double coordinateScale = dimension.getDouble("coordinate_scale"); return new JavaDimension(minY, maxY, piglinSafe, coordinateScale); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java index f9515dbb4..50cdf4b5b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java @@ -25,15 +25,13 @@ package org.geysermc.geyser.session.cache; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos; -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.LodestoneTracker; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.LodestoneTracker; import java.util.Map; import java.util.WeakHashMap; @@ -54,17 +52,7 @@ public final class LodestoneCache { */ private int id = 1; - public void cacheInventoryItem(GeyserItemStack itemStack) { - DataComponents components = itemStack.getComponents(); - if (components == null) { - // invalid - return; - } - LodestoneTracker tracker = components.get(DataComponentType.LODESTONE_TRACKER); - if (tracker == null) { - return; - } - + public void cacheInventoryItem(GeyserItemStack itemStack, LodestoneTracker tracker) { GlobalPos position = tracker.getPos(); if (position == null) { diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java index 33a51fe8f..4f3a94688 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java @@ -26,10 +26,9 @@ package org.geysermc.geyser.skin; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.skin.ImageData; import org.cloudburstmc.protocol.bedrock.data.skin.SerializedSkin; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; @@ -45,6 +44,7 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Collections; +import java.util.List; import java.util.UUID; import java.util.function.Consumer; @@ -224,22 +224,22 @@ public class SkinManager { * @param tag tag to build the GameProfileData from * @return The built GameProfileData, or null if this wasn't a valid tag */ - public static @Nullable GameProfileData from(CompoundTag tag) { - if (!(tag.get("Properties") instanceof CompoundTag propertiesTag)) { + public static @Nullable GameProfileData from(NbtMap tag) { + NbtMap properties = tag.getCompound("Properties", null); + if (properties == null) { return null; } - if (!(propertiesTag.get("textures") instanceof ListTag texturesTag) || texturesTag.size() == 0) { + List textures = properties.getList("textures", NbtType.COMPOUND); + if (textures.isEmpty()) { return null; } - if (!(texturesTag.get(0) instanceof CompoundTag texturesData)) { - return null; - } - if (!(texturesData.get("Value") instanceof StringTag skinDataValue)) { + String skinDataValue = textures.get(0).getString("Value", null); + if (skinDataValue == null) { return null; } try { - return loadFromJson(skinDataValue.getValue()); + return loadFromJson(skinDataValue); } catch (IOException e) { GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for tag " + tag); if (GeyserImpl.getInstance().getConfig().isDebugMode()) { diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java index a85153d13..b2222d3b9 100644 --- a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -25,15 +25,14 @@ package org.geysermc.geyser.text; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import java.util.EnumSet; +import java.util.List; import java.util.Locale; import java.util.Set; @@ -42,28 +41,28 @@ public final class TextDecoration { private final Style style; private final Set parameters; - public TextDecoration(CompoundTag tag) { - translationKey = (String) tag.get("translation_key").getValue(); + public TextDecoration(NbtMap tag) { + translationKey = tag.getString("translation_key"); - CompoundTag styleTag = tag.get("style"); + NbtMap styleTag = tag.getCompound("style"); Style.Builder builder = Style.style(); - if (styleTag != null) { - StringTag color = styleTag.get("color"); + if (!styleTag.isEmpty()) { + String color = styleTag.getString("color", null); if (color != null) { - builder.color(NamedTextColor.NAMES.value(color.getValue())); + builder.color(NamedTextColor.NAMES.value(color)); } //TODO implement the rest - Tag italic = styleTag.get("italic"); - if (italic != null && ((Number) italic.getValue()).byteValue() == (byte) 1) { + boolean italic = styleTag.getBoolean("italic"); + if (italic) { builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC); } } style = builder.build(); this.parameters = EnumSet.noneOf(Parameter.class); - ListTag parameters = tag.get("parameters"); - for (Tag parameter : parameters) { - this.parameters.add(Parameter.valueOf(((String) parameter.getValue()).toUpperCase(Locale.ROOT))); + List parameters = tag.getList("parameters", NbtType.STRING); + for (String parameter : parameters) { + this.parameters.add(Parameter.valueOf(parameter.toUpperCase(Locale.ROOT))); } } @@ -90,8 +89,8 @@ public final class TextDecoration { public static TextDecoration readChatType(RegistryEntry entry) { // Note: The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. - CompoundTag tag = entry.getData(); - CompoundTag chat = tag.get("chat"); + NbtMap tag = entry.getData(); + NbtMap chat = tag.getCompound("chat", null); TextDecoration textDecoration = null; if (chat != null) { textDecoration = new TextDecoration(chat); 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 0914aeba8..5e4ffcafd 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 @@ -224,7 +224,7 @@ public abstract class InventoryTranslator { //only set the head if the destination is the head slot GeyserItemStack javaItem = inventory.getItem(sourceSlot); if (javaItem.asItem() == Items.PLAYER_HEAD - && javaItem.getNbt() != null) { + && javaItem.getComponents() != null) { FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents()); } } else if (sourceSlot == 5) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 142651eb4..7459ccf30 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -94,7 +94,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { contents[i - 5] = item.getItemData(session); if (i == 5 && item.asItem() == Items.PLAYER_HEAD && - item.getNbt() != null) { + item.getComponents() != null) { FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponents()); } } @@ -138,7 +138,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (slot == 5) { // Check for custom skull if (javaItem.asItem() == Items.PLAYER_HEAD - && javaItem.getNbt() != null) { + && javaItem.getComponents() != null) { FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents()); } else { FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java index 543f519c9..f9879499a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java @@ -58,7 +58,7 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator .putInt("z", position.getZ()) .putString("CustomName", inventory.getTitle()); // Don't reset facing property - shulkerBoxTranslator.translateTag(tag, null, javaBlockState); + shulkerBoxTranslator.translateTag(session, tag, null, javaBlockState); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag.build()); 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 24362f800..df54eff79 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 @@ -29,22 +29,11 @@ import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.data.GameProfile.Texture; import com.github.steveice10.mc.auth.data.GameProfile.TextureType; import com.github.steveice10.mc.auth.exception.property.PropertyException; -import org.geysermc.mcprotocollib.protocol.data.game.Identifier; -import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.AdventureModePredicate; -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.ItemAttributeModifiers; -import com.github.steveice10.opennbt.tag.builtin.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -63,6 +52,13 @@ import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.Identifier; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.AdventureModePredicate; +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.ItemAttributeModifiers; import java.text.DecimalFormat; import java.util.ArrayList; @@ -93,16 +89,17 @@ public final class ItemTranslator { ItemMapping bedrockItem = mappings.getMapping(data); Item javaItem = bedrockItem.getJavaItem(); - ItemStack itemStack = javaItem.translateToJava(data, bedrockItem, mappings); + GeyserItemStack itemStack = javaItem.translateToJava(data, bedrockItem, mappings); -// if (itemStack.getNbt() != null) { -// javaItem.translateNbtToJava(itemStack.getNbt(), bedrockItem); -// if (itemStack.getNbt().isEmpty()) { -// // Otherwise, seems to cause issues with villagers accepting books, and I don't see how this will break anything else. - Camotoy -// itemStack = new ItemStack(itemStack.getId(), itemStack.getAmount(), null); -// } -// } - return itemStack; + NbtMap nbt = data.getTag(); + if (nbt != null && !nbt.isEmpty()) { + DataComponents components = new DataComponents(new HashMap<>()); + javaItem.translateNbtToJava(nbt, components, bedrockItem); + if (!components.getDataComponents().isEmpty()) { + itemStack.setComponents(components); + } + } + return itemStack.getItemStack(); } public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, int javaId, int count, DataComponents components) { @@ -375,125 +372,6 @@ public final class ItemTranslator { } } - public static NbtMap translateNbtToBedrock(CompoundTag tag) { - if (!tag.getValue().isEmpty()) { - NbtMapBuilder builder = NbtMap.builder(); - for (Tag javaTag : tag.values()) { - Object translatedTag = translateToBedrockNBT(javaTag); - if (translatedTag == null) - continue; - - builder.put(javaTag.getName(), translatedTag); - } - return builder.build(); - } - return NbtMap.EMPTY; - } - - private static @Nullable Object translateToBedrockNBT(Tag tag) { - if (tag instanceof CompoundTag compoundTag) { - return translateNbtToBedrock(compoundTag); - } - - if (tag instanceof ListTag listTag) { - List tagList = new ArrayList<>(); - for (Tag value : listTag) { - tagList.add(translateToBedrockNBT(value)); - } - NbtType type = NbtType.COMPOUND; - if (!tagList.isEmpty()) { - type = NbtType.byClass(tagList.get(0).getClass()); - } - //noinspection unchecked,rawtypes - return new NbtList(type, tagList); - } - - if (tag instanceof LongArrayTag) { - //Long array tag does not exist in BE - //LongArrayTag longArrayTag = (LongArrayTag) tag; - //return new org.cloudburstmc.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); - return null; - } - - return tag.getValue(); - } - - public static CompoundTag translateToJavaNBT(String name, NbtMap tag) { - CompoundTag javaTag = new CompoundTag(name); - Map javaValue = javaTag.getValue(); - if (tag != null && !tag.isEmpty()) { - for (Map.Entry entry : tag.entrySet()) { - Tag translatedTag = translateToJavaNBT(entry.getKey(), entry.getValue()); - if (translatedTag == null) - continue; - - javaValue.put(translatedTag.getName(), translatedTag); - } - } - - javaTag.setValue(javaValue); - return javaTag; - } - - private static @Nullable Tag translateToJavaNBT(String name, Object object) { - if (object instanceof int[]) { - return new IntArrayTag(name, (int[]) object); - } - - if (object instanceof byte[]) { - return new ByteArrayTag(name, (byte[]) object); - } - - if (object instanceof Byte) { - return new ByteTag(name, (byte) object); - } - - if (object instanceof Float) { - return new FloatTag(name, (float) object); - } - - if (object instanceof Double) { - return new DoubleTag(name, (double) object); - } - - if (object instanceof Integer) { - return new IntTag(name, (int) object); - } - - if (object instanceof long[]) { - return new LongArrayTag(name, (long[]) object); - } - - if (object instanceof Long) { - return new LongTag(name, (long) object); - } - - if (object instanceof Short) { - return new ShortTag(name, (short) object); - } - - if (object instanceof String) { - return new StringTag(name, (String) object); - } - - if (object instanceof List) { - List tags = new ArrayList<>(); - - for (Object value : (List) object) { - Tag javaTag = translateToJavaNBT("", value); - if (javaTag != null) - tags.add(javaTag); - } - return new ListTag(name, tags); - } - - if (object instanceof NbtMap map) { - return translateToJavaNBT(name, map); - } - - return null; - } - /** * Translates the display name of the item * @param session the Bedrock client's session diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java index bc08dd93b..c87d1a217 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java @@ -25,40 +25,43 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.item.type.BannerItem; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; + +import java.util.List; @BlockEntity(type = BlockEntityType.BANNER) public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { int bannerColor = BlockStateValues.getBannerColor(blockState); if (bannerColor != -1) { - builder.put("Base", 15 - bannerColor); + bedrockNbt.putInt("Base", 15 - bannerColor); } - if (tag == null) { + if (javaNbt == null) { return; } - if (tag.get("patterns") instanceof ListTag patterns) { + List patterns = javaNbt.getList("patterns", NbtType.COMPOUND); + if (!patterns.isEmpty()) { if (BannerItem.isOminous(patterns)) { // This is an ominous banner; don't try to translate the raw patterns (it doesn't translate correctly) // and tell the Bedrock client that this is an ominous banner - builder.putInt("Type", 1); + bedrockNbt.putInt("Type", 1); } else { - builder.put("Patterns", BannerItem.convertBannerPattern(patterns)); + bedrockNbt.putList("Patterns", NbtType.COMPOUND, BannerItem.convertBannerPattern(patterns)); } } - Tag customName = tag.get("CustomName"); + String customName = javaNbt.getString("CustomName", null); if (customName != null) { - builder.put("CustomName", customName.getValue()); + bedrockNbt.putString("CustomName", customName); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java index 0db362949..f7dee2864 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java @@ -25,18 +25,19 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.BEACON) public class BeaconBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - int primary = getOrDefault(tag.get("Primary"), 0); + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + int primary = javaNbt.getInt("primary"); // The effects here generally map one-to-one Java <-> Bedrock. Only the newer ones get more complicated - builder.putInt("primary", primary == -1 ? 0 : primary); - int secondary = getOrDefault(tag.get("Secondary"), 0); - builder.putInt("secondary", secondary == -1 ? 0 : secondary); + bedrockNbt.putInt("primary", primary == -1 ? 0 : primary); + int secondary = javaNbt.getInt("secondary"); + bedrockNbt.putInt("secondary", secondary == -1 ? 0 : secondary); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java index 1c46edf0a..720ffea3c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java @@ -25,20 +25,21 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.BED) public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { byte bedcolor = BlockStateValues.getBedColor(blockState); // Just in case... if (bedcolor == -1) { bedcolor = 0; } - builder.put("color", bedcolor); + bedrockNbt.putByte("color", bedcolor); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java index 5f6487a24..45981377c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java @@ -25,13 +25,11 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; /** * The class that all block entities (on both Java and Bedrock) should translate with @@ -40,11 +38,11 @@ public abstract class BlockEntityTranslator { protected BlockEntityTranslator() { } - public abstract void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState); + public abstract void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState); - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, CompoundTag tag, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, NbtMap javaNbt, int blockState) { NbtMapBuilder tagBuilder = getConstantBedrockTag(type, x, y, z); - translateTag(tagBuilder, tag, blockState); + translateTag(session, tagBuilder, javaNbt, blockState); return tagBuilder.build(); } @@ -59,9 +57,4 @@ public abstract class BlockEntityTranslator { .putInt("z", z) .putString("id", bedrockId); } - - @SuppressWarnings("unchecked") - protected T getOrDefault(Tag tag, T defaultValue) { - return (tag != null && tag.getValue() != null) ? (T) tag.getValue() : defaultValue; - } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java index d2777d372..4f9dfec46 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java @@ -25,49 +25,46 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.network.GameProtocol; -import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.BRUSHABLE_BLOCK) public class BrushableBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - if (!(tag.remove("item") instanceof CompoundTag itemTag)) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + NbtMap itemTag = javaNbt.getCompound("item"); + if (itemTag.isEmpty()) { return; } - Tag hitDirection = tag.get("hit_direction"); - if (hitDirection == null) { + byte hitDirection = javaNbt.getByte("hit_direction", (byte) -1); + if (hitDirection == -1) { // java server sends no direction when the item recedes back into the block (if player stops brushing) return; } - String id = ((StringTag) itemTag.get("id")).getValue(); + String id = itemTag.getString("id"); if (Items.AIR.javaIdentifier().equals(id)) { return; // server sends air when the block contains nothing } - ItemMapping mapping = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getMapping(id); + ItemMapping mapping = session.getItemMappings().getMapping(id); if (mapping == null) { return; } NbtMapBuilder itemBuilder = NbtMap.builder() .putString("Name", mapping.getBedrockIdentifier()) - .putByte("Count", (byte) itemTag.get("Count").getValue()); + .putByte("Count", (byte) itemTag.getByte("Count")); - builder.putCompound("item", itemBuilder.build()); + bedrockNbt.putCompound("item", itemBuilder.build()); // controls which side the item protrudes from - builder.putByte("brush_direction", ((Number) hitDirection.getValue()).byteValue()); + bedrockNbt.putByte("brush_direction", hitDirection); // controls how much the item protrudes - builder.putInt("brush_count", BlockStateValues.getBrushProgress(blockState)); + bedrockNbt.putInt("brush_count", BlockStateValues.getBrushProgress(blockState)); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java index 390615b9e..699319bb6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java @@ -25,37 +25,37 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.network.GameProtocol; -import org.geysermc.geyser.registry.Registries; +import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +import java.util.List; + @BlockEntity(type = BlockEntityType.CAMPFIRE) public class CampfireBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - if (tag.get("Items") instanceof ListTag items) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + List items = javaNbt.getList("Items", NbtType.COMPOUND); + if (items != null) { int i = 1; - for (Tag itemTag : items.getValue()) { - builder.put("Item" + i, getItem((CompoundTag) itemTag)); + for (NbtMap itemTag : items) { + bedrockNbt.put("Item" + i, getItem(session, itemTag)); i++; } } } - protected NbtMap getItem(CompoundTag tag) { - // TODO: Version independent mappings - ItemMapping mapping = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getMapping((String) tag.get("id").getValue()); - NbtMapBuilder tagBuilder = NbtMap.builder() - .putString("Name", mapping.getBedrockIdentifier()) - .putByte("Count", (byte) tag.get("Count").getValue()) - .putShort("Damage", (short) mapping.getBedrockData()); - tagBuilder.put("tag", NbtMap.builder().build()); + protected NbtMap getItem(GeyserSession session, NbtMap tag) { + ItemMapping mapping = session.getItemMappings().getMapping(tag.getString("id")); + if (mapping == null) { + mapping = ItemMapping.AIR; + } + NbtMapBuilder tagBuilder = BedrockItemBuilder.createItemNbt(mapping, tag.getByte("Count"), mapping.getBedrockData()); + tagBuilder.put("tag", NbtMap.builder().build()); // I don't think this is necessary... - Camo, 1.20.5/1.20.80 return tagBuilder.build(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java index 31a7dbc69..0e00a19a8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java @@ -25,34 +25,31 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.*; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.COMMAND_BLOCK) public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - if (tag == null || tag.size() < 5) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + if (javaNbt == null || javaNbt.size() < 5) { return; // These values aren't here } // Java infers from the block state, but Bedrock needs it in the tag - builder.put("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0)); + bedrockNbt.putByte("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0)); // Java and Bedrock values - builder.put("conditionMet", ((ByteTag) tag.get("conditionMet")).getValue()); - builder.put("auto", ((ByteTag) tag.get("auto")).getValue()); - builder.put("CustomName", MessageTranslator.convertJsonMessage(((StringTag) tag.get("CustomName")).getValue())); - builder.put("powered", ((ByteTag) tag.get("powered")).getValue()); - builder.put("Command", ((StringTag) tag.get("Command")).getValue()); - builder.put("SuccessCount", ((IntTag) tag.get("SuccessCount")).getValue()); - builder.put("TrackOutput", ((ByteTag) tag.get("TrackOutput")).getValue()); - builder.put("UpdateLastExecution", ((ByteTag) tag.get("UpdateLastExecution")).getValue()); - if (tag.get("LastExecution") != null) { - builder.put("LastExecution", ((LongTag) tag.get("LastExecution")).getValue()); - } else { - builder.put("LastExecution", (long) 0); - } + bedrockNbt.putByte("conditionMet", javaNbt.getByte("conditionMet")); + bedrockNbt.putByte("auto", javaNbt.getByte("auto")); + bedrockNbt.putString("CustomName", MessageTranslator.convertJsonMessage(javaNbt.getString("CustomName"), session.locale())); + bedrockNbt.putByte("powered", javaNbt.getByte("powered")); + bedrockNbt.putString("Command", javaNbt.getString("Command")); + bedrockNbt.putInt("SuccessCount", javaNbt.getInt("SuccessCount")); + bedrockNbt.putByte("TrackOutput", javaNbt.getByte("TrackOutput")); + bedrockNbt.putByte("UpdateLastExecution", javaNbt.getByte("UpdateLastExecution")); + bedrockNbt.putLong("LastExecution", javaNbt.getLong("LastExecution")); // Note: may not be present? Was a null check before 1.20.5 } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java index 3ab61c489..b24558b45 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java @@ -25,33 +25,22 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import java.util.ArrayList; -import java.util.List; - @BlockEntity(type = BlockEntityType.DECORATED_POT) public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - if (tag == null) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + if (javaNbt == null) { return; } // exact same format - if (tag.get("sherds") instanceof ListTag sherds) { - List translated = new ArrayList<>(4); - for (Tag sherd : sherds) { - translated.add(((StringTag) sherd).getValue()); - } - builder.putList("sherds", NbtType.STRING, translated); - } + bedrockNbt.putList("sherds", NbtType.STRING, javaNbt.getList("sherds", NbtType.STRING)); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index 141520ed9..dcb39d22c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.DoubleChestValue; @@ -47,17 +47,17 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl @Override public void updateBlock(GeyserSession session, int blockState, Vector3i position) { NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockEntityType.CHEST), position.getX(), position.getY(), position.getZ()); - translateTag(tagBuilder, null, blockState); + translateTag(session, tagBuilder, null, blockState); BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().get(blockState); if (chestValues != null) { - int x = (int) builder.get("x"); - int z = (int) builder.get("z"); - translateChestValue(builder, chestValues, x, z); + int x = (int) bedrockNbt.get("x"); + int z = (int) bedrockNbt.get("z"); + translateChestValue(bedrockNbt, chestValues, x, z); } } @@ -88,10 +88,10 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl x = x + (chestValues.isLeft() ? 1 : -1); } } - builder.put("pairx", x); - builder.put("pairz", z); + builder.putInt("pairx", x); + builder.putInt("pairz", z); if (!chestValues.isLeft()) { - builder.put("pairlead", (byte) 1); + builder.putInt("pairlead", (byte) 1); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java index 1a7958c62..9ce0aff0a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java @@ -25,11 +25,12 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.session.GeyserSession; public class EmptyBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java index 633992431..97428eec1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java @@ -25,44 +25,28 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.LongTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import java.util.LinkedHashMap; - @BlockEntity(type = BlockEntityType.END_GATEWAY) public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - Tag ageTag = tag.get("Age"); - if (ageTag instanceof LongTag) { - builder.put("Age", (int) ((long) ageTag.getValue())); - } + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + bedrockNbt.putInt("Age", (int) javaNbt.getLong("Age")); // Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist // Linked coordinates IntList tagsList = new IntArrayList(); // Yes, the axis letters are capitalized - tagsList.add(getExitPortalCoordinate(tag, "X")); - tagsList.add(getExitPortalCoordinate(tag, "Y")); - tagsList.add(getExitPortalCoordinate(tag, "Z")); - builder.put("ExitPortal", new NbtList<>(NbtType.INT, tagsList)); - } - - private int getExitPortalCoordinate(CompoundTag tag, String axis) { - // Return 0 if it doesn't exist, otherwise give proper value - if (tag.get("ExitPortal") != null) { - LinkedHashMap compoundTag = (LinkedHashMap) tag.get("ExitPortal").getValue(); - IntTag intTag = (IntTag) compoundTag.get(axis); - return intTag.getValue(); - } - return 0; + NbtMap exitPortal = javaNbt.getCompound("ExitPortal"); + tagsList.add(exitPortal.getInt("X", 0)); + tagsList.add(exitPortal.getInt("Y", 0)); + tagsList.add(exitPortal.getInt( "Z", 0)); + bedrockNbt.put("ExitPortal", new NbtList<>(NbtType.INT, tagsList)); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java index 34c051a34..bd83e3d54 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java @@ -25,28 +25,27 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.JIGSAW) public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - Tag jointTag = tag.get("joint"); - if (jointTag instanceof StringTag) { - builder.put("joint", ((StringTag) jointTag).getValue()); + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + String joint = javaNbt.getString("joint", null); + if (joint != null) { + bedrockNbt.putString("joint", joint); } else { // Tag is not present in at least 1.14.4 Paper // Minecraft 1.18.1 deliberately has a fallback here, but not for any other value - builder.put("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState) ? "aligned" : "rollable"); + bedrockNbt.putString("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState) ? "aligned" : "rollable"); } - builder.put("name", getOrDefault(tag.get("name"), "")); - builder.put("target_pool", getOrDefault(tag.get("pool"), "")); - builder.put("final_state", ((StringTag) tag.get("final_state")).getValue()); - builder.put("target", getOrDefault(tag.get("target"), "")); + bedrockNbt.putString("name", javaNbt.getString("name")); + bedrockNbt.putString("target_pool", javaNbt.getString("target_pool")); + bedrockNbt.putString("final_state", javaNbt.getString("final_state")); + bedrockNbt.putString("target", javaNbt.getString("target")); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java index 529ed731e..ba2ddd815 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -25,10 +25,11 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.ShulkerInventoryTranslator; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -39,12 +40,12 @@ public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator imple * where {@code tag} is passed as null. */ @Override - public void translateTag(NbtMapBuilder builder, @Nullable CompoundTag tag, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { byte direction = BlockStateValues.getShulkerBoxDirection(blockState); // Just in case... if (direction == -1) { direction = 1; } - builder.put("facing", direction); + bedrockNbt.putByte("facing", direction); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java index 38a4f59c5..bbf0dbcb3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java @@ -25,15 +25,16 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.SignUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; + +import java.util.List; @BlockEntity(type = BlockEntityType.SIGN) public class SignBlockEntityTranslator extends BlockEntityTranslator { @@ -72,25 +73,21 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator { } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - builder.putCompound("FrontText", translateSide(tag.get("front_text"))); - builder.putCompound("BackText", translateSide(tag.get("back_text"))); - var waxed = tag.get("is_waxed"); - builder.putBoolean("IsWaxed", waxed != null && waxed.getValue() instanceof Number number && number.byteValue() != 0); + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + bedrockNbt.putCompound("FrontText", translateSide(javaNbt.getCompound("front_text"))); + bedrockNbt.putCompound("BackText", translateSide(javaNbt.getCompound("back_text"))); + bedrockNbt.putBoolean("IsWaxed", javaNbt.getBoolean("is_waxed")); } - private NbtMap translateSide(Tag tag) { - if (!(tag instanceof CompoundTag signData)) { - return NbtMap.EMPTY; - } + private NbtMap translateSide(NbtMap javaNbt) { NbtMapBuilder builder = NbtMap.builder(); StringBuilder signText = new StringBuilder(); - Tag messages = signData.get("messages"); - if (messages instanceof ListTag listTag) { - var it = listTag.iterator(); + List messages = javaNbt.getList("messages", NbtType.STRING); + if (!messages.isEmpty()) { + var it = messages.iterator(); while (it.hasNext()) { - String signLine = (String) it.next().getValue(); + String signLine = it.next(); signLine = MessageTranslator.convertMessageLenient(signLine); // Check the character width on the sign to ensure there is no overflow that is usually hidden @@ -133,13 +130,13 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator { builder.putString("Text", signText.toString()); // Java Edition 1.14 added the ability to change the text color of the whole sign using dye - Tag color = signData.get("color"); + String color = javaNbt.getString("color", null); if (color != null) { - builder.putInt("SignTextColor", getBedrockSignColor(color.getValue().toString())); + builder.putInt("SignTextColor", getBedrockSignColor(color)); } // Glowing text - boolean isGlowing = getOrDefault(signData.get("has_glowing_text"), (byte) 0) != (byte) 0; + boolean isGlowing = javaNbt.getBoolean("has_glowing_text"); builder.putBoolean("IgnoreLighting", isGlowing); return builder.build(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index 38a056bd0..b1ab017e8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -25,24 +25,22 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.GeyserImpl; -import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.skin.SkinProvider; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import java.nio.charset.StandardCharsets; -import java.util.LinkedHashMap; +import java.util.List; import java.util.Locale; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -52,56 +50,60 @@ import java.util.concurrent.ExecutionException; public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { byte skullVariant = BlockStateValues.getSkullVariant(blockState); float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f; // Just in case... if (skullVariant == -1) { skullVariant = 0; } - builder.put("Rotation", rotation); - builder.put("SkullType", skullVariant); + bedrockNbt.putFloat("Rotation", rotation); + bedrockNbt.putByte("SkullType", skullVariant); if (BlockStateValues.isSkullPowered(blockState)) { - builder.putBoolean("MouthMoving", true); + bedrockNbt.putBoolean("MouthMoving", true); } } - private static UUID getUUID(CompoundTag profile) { - if (profile.get("id") instanceof IntArrayTag uuidTag && uuidTag.length() == 4) { - int[] uuidAsArray = uuidTag.getValue(); + private static UUID getUUID(NbtMap profile) { + int[] uuidAsArray = profile.getIntArray("id"); + if (uuidAsArray.length == 4) { // thank u viaversion return new UUID((long) uuidAsArray[0] << 32 | ((long) uuidAsArray[1] & 0xFFFFFFFFL), (long) uuidAsArray[2] << 32 | ((long) uuidAsArray[3] & 0xFFFFFFFFL)); } // Convert username to an offline UUID String username = null; - if (profile.get("name") instanceof StringTag nameTag) { - username = nameTag.getValue().toLowerCase(Locale.ROOT); + String nameTag = profile.getString("name", null); + if (nameTag != null) { + username = nameTag.toLowerCase(Locale.ROOT); } return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)); } - private static CompletableFuture getTextures(CompoundTag profile, UUID uuid) { - ListTag properties = profile.get("properties"); - if (properties == null) { + private static CompletableFuture<@Nullable String> getTextures(NbtMap profile, UUID uuid) { + List properties = profile.getList("properties", NbtType.COMPOUND); + if (properties.isEmpty()) { if (uuid != null && uuid.version() == 4) { String uuidString = uuid.toString().replace("-", ""); return SkinProvider.requestTexturesFromUUID(uuidString); - } else if (profile.get("name") instanceof StringTag nameTag) { - // Fall back to username if UUID was missing or was an offline mode UUID - return SkinProvider.requestTexturesFromUsername(nameTag.getValue()); + } else { + String nameTag = profile.getString("name", null); + if (nameTag != null) { + // Fall back to username if UUID was missing or was an offline mode UUID + return SkinProvider.requestTexturesFromUsername(nameTag); + } } return CompletableFuture.completedFuture(null); } - LinkedHashMap tag1 = (LinkedHashMap) properties.get(0).getValue(); - StringTag texture = (StringTag) tag1.get("value"); - return CompletableFuture.completedFuture(texture.getValue()); + NbtMap tag1 = properties.get(0); + String texture = tag1.getString("value", null); + return CompletableFuture.completedFuture(texture); } - public static @Nullable BlockDefinition translateSkull(GeyserSession session, CompoundTag tag, Vector3i blockPosition, int blockState) { - CompoundTag profile = tag.get("profile"); - if (profile == null) { + public static @Nullable BlockDefinition translateSkull(GeyserSession session, NbtMap javaNbt, Vector3i blockPosition, int blockState) { + NbtMap profile = javaNbt.getCompound("profile"); + if (profile.isEmpty()) { session.getSkullCache().removeSkull(blockPosition); return null; } @@ -112,13 +114,13 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements try { String texture = texturesFuture.get(); if (texture == null) { - session.getGeyser().getLogger().debug("Custom skull with invalid profile tag: " + blockPosition + " " + tag); + session.getGeyser().getLogger().debug("Custom skull with invalid profile tag: " + blockPosition + " " + javaNbt); return null; } SkullCache.Skull skull = session.getSkullCache().putSkull(blockPosition, uuid, texture, blockState); return skull.getBlockDefinition(); } catch (InterruptedException | ExecutionException e) { - session.getGeyser().getLogger().debug("Failed to acquire textures for custom skull: " + blockPosition + " " + tag); + session.getGeyser().getLogger().debug("Failed to acquire textures for custom skull: " + blockPosition + " " + javaNbt); if (GeyserImpl.getInstance().getConfig().isDebugMode()) { e.printStackTrace(); } @@ -129,7 +131,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements // profile contained a username, so we have to wait for it to be retrieved texturesFuture.whenComplete((texturesProperty, throwable) -> { if (texturesProperty == null) { - session.getGeyser().getLogger().debug("Custom skull with invalid profile tag: " + blockPosition + " " + tag); + session.getGeyser().getLogger().debug("Custom skull with invalid profile tag: " + blockPosition + " " + javaNbt); return; } if (session.getEventLoop().inEventLoop()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index 5611bf90c..05b763e6b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; @@ -38,17 +34,18 @@ import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.MOB_SPAWNER) public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { @Override - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, CompoundTag tag, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, NbtMap javaNbt, int blockState) { // Sending an empty EntityIdentifier to empty the spawner is ignored by the client, so we send a whole new spawner! // Fixes https://github.com/GeyserMC/Geyser/issues/4214 - CompoundTag spawnData = tag.get("SpawnData"); + NbtMap spawnData = javaNbt.getCompound("SpawnData"); if (spawnData != null) { - CompoundTag entityTag = spawnData.get("entity"); + NbtMap entityTag = spawnData.getCompound("entity"); if (entityTag.isEmpty()) { Vector3i position = Vector3i.from(x, y, z); // Set to air and back to reset the spawner - "just" updating the spawner doesn't work @@ -66,62 +63,63 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { } } - return super.getBlockEntityTag(session, type, x, y, z, tag, blockState); + return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState); } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - Tag current; + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + Object current; - if ((current = tag.get("MaxNearbyEntities")) != null) { - builder.put("MaxNearbyEntities", current.getValue()); + // TODO use primitive get and put methods + if ((current = javaNbt.get("MaxNearbyEntities")) != null) { + bedrockNbt.put("MaxNearbyEntities", current); } - if ((current = tag.get("RequiredPlayerRange")) != null) { - builder.put("RequiredPlayerRange", current.getValue()); + if ((current = javaNbt.get("RequiredPlayerRange")) != null) { + bedrockNbt.put("RequiredPlayerRange", current); } - if ((current = tag.get("SpawnCount")) != null) { - builder.put("SpawnCount", current.getValue()); + if ((current = javaNbt.get("SpawnCount")) != null) { + bedrockNbt.put("SpawnCount", current); } - if ((current = tag.get("MaxSpawnDelay")) != null) { - builder.put("MaxSpawnDelay", current.getValue()); + if ((current = javaNbt.get("MaxSpawnDelay")) != null) { + bedrockNbt.put("MaxSpawnDelay", current); } - if ((current = tag.get("Delay")) != null) { - builder.put("Delay", current.getValue()); + if ((current = javaNbt.get("Delay")) != null) { + bedrockNbt.put("Delay", current); } - if ((current = tag.get("SpawnRange")) != null) { - builder.put("SpawnRange", current.getValue()); + if ((current = javaNbt.get("SpawnRange")) != null) { + bedrockNbt.put("SpawnRange", current); } - if ((current = tag.get("MinSpawnDelay")) != null) { - builder.put("MinSpawnDelay", current.getValue()); + if ((current = javaNbt.get("MinSpawnDelay")) != null) { + bedrockNbt.put("MinSpawnDelay", current); } - translateSpawnData(builder, tag.get("SpawnData")); + translateSpawnData(bedrockNbt, javaNbt.getCompound("SpawnData", null)); - builder.put("isMovable", (byte) 1); + bedrockNbt.put("isMovable", (byte) 1); } - static void translateSpawnData(@NonNull NbtMapBuilder builder, @Nullable CompoundTag spawnData) { + static void translateSpawnData(@NonNull NbtMapBuilder builder, @Nullable NbtMap spawnData) { if (spawnData == null) { return; } - CompoundTag entityTag = spawnData.get("entity"); - if (entityTag.get("id") instanceof StringTag idTag) { + NbtMap entityTag = spawnData.getCompound("entity"); + String entityId = entityTag.getString("id"); + if (entityId != null) { // As of 1.19.3, spawners can be empty - String entityId = idTag.getValue(); builder.put("EntityIdentifier", entityId); EntityDefinition definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityId); if (definition != null) { - builder.put("DisplayEntityWidth", definition.width()); - builder.put("DisplayEntityHeight", definition.height()); - builder.put("DisplayEntityScale", 1.0f); + builder.putFloat("DisplayEntityWidth", definition.width()); + builder.putFloat("DisplayEntityHeight", definition.height()); + builder.putFloat("DisplayEntityScale", 1.0f); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java index 40b10de40..aefd97dd5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -35,22 +33,23 @@ import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.StructureBlockUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.STRUCTURE_BLOCK) public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { @Override - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, CompoundTag tag, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, NbtMap javaNbt, int blockState) { // Sending a structure with size 0 doesn't clear the outline. Hence, we have to force it by replacing the block :/ - int xStructureSize = getOrDefault(tag.get("sizeX"), 0); - int yStructureSize = getOrDefault(tag.get("sizeY"), 0); - int zStructureSize = getOrDefault(tag.get("sizeZ"), 0); + int xStructureSize = javaNbt.getInt("sizeX"); + int yStructureSize = javaNbt.getInt("sizeY"); + int zStructureSize = javaNbt.getInt("sizeZ"); Vector3i size = Vector3i.from(xStructureSize, yStructureSize, zStructureSize); if (size.equals(Vector3i.ZERO)) { Vector3i position = Vector3i.from(x, y, z); - String mode = getOrDefault(tag.get("mode"), ""); + String mode = javaNbt.getString("mode"); // Set to air and back to reset the structure block UpdateBlockPacket emptyBlockPacket = new UpdateBlockPacket(); @@ -66,18 +65,18 @@ public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { session.sendUpstreamPacket(spawnerBlockPacket); } - return super.getBlockEntityTag(session, type, x, y, z, tag, blockState); + return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState); } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - if (tag.size() < 5) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + if (javaNbt.size() < 5) { return; // These values aren't here } - builder.putString("structureName", getOrDefault(tag.get("name"), "")); + bedrockNbt.putString("structureName", javaNbt.getString("name")); - String mode = getOrDefault(tag.get("mode"), ""); + String mode = javaNbt.getString("mode"); int bedrockData = switch (mode) { case "LOAD" -> 2; case "CORNER" -> 3; @@ -85,53 +84,53 @@ public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { default -> 1; // SAVE }; - builder.putInt("data", bedrockData); - builder.putString("dataField", ""); // ??? possibly related to Java's "metadata" + bedrockNbt.putInt("data", bedrockData); + bedrockNbt.putString("dataField", ""); // ??? possibly related to Java's "metadata" // Mirror behaves different in Java and Bedrock - it requires modifying the position in space as well - String mirror = getOrDefault(tag.get("mirror"), ""); + String mirror = javaNbt.getString("mirror"); StructureMirror bedrockMirror = switch (mirror) { case "FRONT_BACK" -> StructureMirror.X; case "LEFT_RIGHT" -> StructureMirror.Z; default -> StructureMirror.NONE; }; - builder.putByte("mirror", (byte) bedrockMirror.ordinal()); + bedrockNbt.putByte("mirror", (byte) bedrockMirror.ordinal()); - builder.putByte("ignoreEntities", getOrDefault(tag.get("ignoreEntities"), (byte) 0)); - builder.putByte("isPowered", getOrDefault(tag.get("powered"), (byte) 0)); - builder.putLong("seed", getOrDefault(tag.get("seed"), 0L)); - builder.putByte("showBoundingBox", getOrDefault(tag.get("showboundingbox"), (byte) 0)); + bedrockNbt.putByte("ignoreEntities", javaNbt.getByte("ignoreEntities")); + bedrockNbt.putByte("isPowered", javaNbt.getByte("powered")); + bedrockNbt.putLong("seed", javaNbt.getLong("seed")); + bedrockNbt.putByte("showBoundingBox", javaNbt.getByte("showboundingbox")); - String rotation = getOrDefault(tag.get("rotation"), ""); + String rotation = javaNbt.getString("rotation"); StructureRotation bedrockRotation = switch (rotation) { case "CLOCKWISE_90" -> StructureRotation.ROTATE_90; case "CLOCKWISE_180" -> StructureRotation.ROTATE_180; case "COUNTERCLOCKWISE_90" -> StructureRotation.ROTATE_270; default -> StructureRotation.NONE; }; - builder.putByte("rotation", (byte) bedrockRotation.ordinal()); + bedrockNbt.putByte("rotation", (byte) bedrockRotation.ordinal()); - int xStructureSize = getOrDefault(tag.get("sizeX"), 0); - int yStructureSize = getOrDefault(tag.get("sizeY"), 0); - int zStructureSize = getOrDefault(tag.get("sizeZ"), 0); + int xStructureSize = javaNbt.getInt("sizeX"); + int yStructureSize = javaNbt.getInt("sizeY"); + int zStructureSize = javaNbt.getInt("sizeZ"); // The "positions" are also offsets on Java - int posX = getOrDefault(tag.get("posX"), 0); - int posY = getOrDefault(tag.get("posY"), 0); - int posZ = getOrDefault(tag.get("posZ"), 0); + int posX = javaNbt.getInt("posX"); + int posY = javaNbt.getInt("posY"); + int posZ = javaNbt.getInt("posZ"); Vector3i offset = StructureBlockUtils.calculateOffset(bedrockRotation, bedrockMirror, xStructureSize, zStructureSize); - builder.putInt("xStructureOffset", posX + offset.getX()); - builder.putInt("yStructureOffset", posY); - builder.putInt("zStructureOffset", posZ + offset.getZ()); + bedrockNbt.putInt("xStructureOffset", posX + offset.getX()); + bedrockNbt.putInt("yStructureOffset", posY); + bedrockNbt.putInt("zStructureOffset", posZ + offset.getZ()); - builder.putInt("xStructureSize", xStructureSize); - builder.putInt("yStructureSize", yStructureSize); - builder.putInt("zStructureSize", zStructureSize); + bedrockNbt.putInt("xStructureSize", xStructureSize); + bedrockNbt.putInt("yStructureSize", yStructureSize); + bedrockNbt.putInt("zStructureSize", zStructureSize); - builder.putFloat("integrity", getOrDefault(tag.get("integrity"), 0f)); // Is 1.0f by default on Java but 100.0f on Bedrock + bedrockNbt.putFloat("integrity", javaNbt.getFloat("integrity")); // Is 1.0f by default on Java but 100.0f on Bedrock // Java's "showair" is unrepresented } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java index da013cf3c..ff3f89f3f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java @@ -25,23 +25,24 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.TRIAL_SPAWNER) public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - if (tag == null) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + if (javaNbt == null) { return; } // trial spawners have "spawn_data" instead of "SpawnData" - SpawnerBlockEntityTranslator.translateSpawnData(builder, tag.get("spawn_data")); + SpawnerBlockEntityTranslator.translateSpawnData(bedrockNbt, javaNbt.getCompound("spawn_data", null)); // Because trial spawners don't exist on bedrock yet - builder.put("id", "MobSpawner"); + bedrockNbt.put("id", "MobSpawner"); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java index 82b51dfdd..b13344fd3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java @@ -25,9 +25,8 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror; @@ -71,7 +70,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator 5 ) { - CompoundTag map = packet.getNbt(); + NbtMap map = packet.getNbt(); - String mode = getOrDefault(map.get("mode"), ""); + String mode = map.getString("mode"); if (!mode.equalsIgnoreCase("LOAD")) { return; } - String mirror = getOrDefault(map.get("mirror"), ""); + String mirror = map.getString("mirror"); StructureMirror bedrockMirror = switch (mirror) { case "FRONT_BACK" -> StructureMirror.X; case "LEFT_RIGHT" -> StructureMirror.Z; default -> StructureMirror.NONE; }; - String rotation = getOrDefault(map.get("rotation"), ""); + String rotation = map.getString("rotation"); StructureRotation bedrockRotation = switch (rotation) { case "CLOCKWISE_90" -> StructureRotation.ROTATE_90; case "CLOCKWISE_180" -> StructureRotation.ROTATE_180; @@ -129,10 +128,10 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator StructureRotation.NONE; }; - String name = getOrDefault(map.get("name"), ""); - int sizeX = getOrDefault(map.get("sizeX"), 0); - int sizeY = getOrDefault(map.get("sizeY"), 0); - int sizeZ = getOrDefault(map.get("sizeZ"), 0); + String name = map.getString("name"); + int sizeX = map.getInt("sizeX"); + int sizeY = map.getInt("sizeY"); + int sizeZ = map.getInt("sizeZ"); session.getStructureBlockCache().setCurrentStructureBlock(null); @@ -149,10 +148,4 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator T getOrDefault(Tag tag, T defaultValue) { - //noinspection unchecked - return (tag != null && tag.getValue() != null) ? (T) tag.getValue() : defaultValue; - } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index 609574cdd..c3a399863 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufOutputStream; @@ -385,7 +384,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4) - (bedrockDimension.minY() >> 4); diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/BlockSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/BlockSoundInteractionTranslator.java index ead619b68..02e5044bb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/BlockSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/BlockSoundInteractionTranslator.java @@ -25,16 +25,12 @@ package org.geysermc.geyser.translator.sound; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import java.util.Map; @@ -104,25 +100,14 @@ public interface BlockSoundInteractionTranslator extends SoundInteractionTransla return true; } - CompoundTag tag = itemInHand.getNbt(); - if (tag == null) { - // No CanPlaceOn tag can exist - return false; - } - ListTag canPlaceOn = tag.get("CanPlaceOn"); - if (canPlaceOn == null || canPlaceOn.size() == 0) { - return false; + var canPlaceOn = itemInHand.getComponent(DataComponentType.CAN_PLACE_ON); + if (canPlaceOn == null || canPlaceOn.getPredicates().isEmpty()) { + // Component doesn't exist - no restrictions apply. + return true; } - String cleanIdentifier = BlockUtils.getCleanIdentifier(blockIdentifier); - - for (Tag t : canPlaceOn) { - if (t instanceof StringTag stringTag) { - if (cleanIdentifier.equals(stringTag.getValue())) { - // This operation would/could be a success! - return true; - } - } + for (var blockPredicate : canPlaceOn.getPredicates()) { + // I don't want to deal with this right now. TODO } // The block in world is not present in the CanPlaceOn tag on the item 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 612b9c38b..3f1c902c7 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 @@ -187,14 +187,28 @@ public class MessageTranslator { } } + /** + * Convenience method for locale getting. + */ + public static String convertJsonMessage(GeyserSession session, String message) { + return convertJsonMessage(message, session.locale()); + } + public static String convertJsonMessage(String message, String locale) { return convertMessage(GSON_SERIALIZER.deserialize(message), locale); } - public static String convertJsonMessage(String message) { - return convertJsonMessage(message, GeyserLocale.getDefaultLocale()); + /** + * Convenience method for locale getting. + */ + public static String convertMessage(GeyserSession session, Component message) { + return convertMessage(message, session.locale()); } + /** + * DO NOT USE THIS METHOD unless where you're calling from does not have a (reliable) way of getting the + * context's locale. + */ public static String convertMessage(Component message) { return convertMessage(message, GeyserLocale.getDefaultLocale()); } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3cb136683..f8f979539 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "1ca8808" # Revert from jitpack after release +mcprotocollib = "98410a1" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From f47754be03819954a9d9499831b5e59595a0930a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 27 Apr 2024 15:49:19 -0400 Subject: [PATCH 087/897] Goat horns --- .../geyser/item/type/GoatHornItem.java | 28 ++----------------- .../translator/item/ItemTranslator.java | 5 ++-- 2 files changed, 5 insertions(+), 28 deletions(-) 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 c31e15578..cd21c0b6e 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 @@ -35,20 +35,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument; -import java.util.List; - public class GoatHornItem extends Item { - private static final List INSTRUMENTS = List.of( - "ponder_goat_horn", - "sing_goat_horn", - "seek_goat_horn", - "feel_goat_horn", - "admire_goat_horn", - "call_goat_horn", - "yearn_goat_horn", - "dream_goat_horn" // Called "Resist" on Bedrock 1.19.0 due to https://bugs.mojang.com/browse/MCPE-155059 - ); - public GoatHornItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } @@ -60,19 +47,8 @@ public class GoatHornItem extends Item { return builder; } Holder instrument = components.get(DataComponentType.INSTRUMENT); - // TODO registry - if (instrument != null) { - // Drop the Minecraft namespace if applicable -// if (instrument.startsWith("minecraft:")) { -// instrument = instrument.substring("minecraft:".length()); -// } -// -// int damage = INSTRUMENTS.indexOf(instrument); -// if (damage == -1) { -// damage = 0; -// GeyserImpl.getInstance().getLogger().debug("Unknown goat horn instrument: " + instrumentTag.getValue()); -// } -// builder.damage(damage); + if (instrument != null && instrument.isId()) { + builder.damage(instrument.id()); } return builder; } 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 2535a5652..629192e01 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 @@ -93,7 +93,8 @@ public final class ItemTranslator { NbtMap nbt = data.getTag(); if (nbt != null && !nbt.isEmpty()) { - DataComponents components = new DataComponents(new HashMap<>()); + // translateToJava may have added components + DataComponents components = itemStack.getComponents() == null ? new DataComponents(new HashMap<>()) : itemStack.getComponents(); javaItem.translateNbtToJava(nbt, components, bedrockItem); if (!components.getDataComponents().isEmpty()) { itemStack.setComponents(components); @@ -394,7 +395,7 @@ public final class ItemTranslator { customName = components.get(DataComponentType.ITEM_NAME); } if (customName != null) { - // Get the translated name and prefix it with a reset char TODO test + // Get the translated name and prefix it with a reset char return MessageTranslator.convertMessage(customName, session.locale()); } } From 6d5ac233d6112dd65f162064c55963b20373285d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 27 Apr 2024 21:00:10 -0400 Subject: [PATCH 088/897] Dyeable items work. --- .../geyser/entity/EntityDefinitions.java | 6 +-- ...ippedArrowEntity.java => ArrowEntity.java} | 7 +-- .../geyser/inventory/item/Potion.java | 9 ---- .../inventory/item/TippedArrowPotion.java | 9 ---- .../geyser/item/DyeableLeatherItem.java | 42 ----------------- .../java/org/geysermc/geyser/item/Items.java | 46 +++++++++---------- .../geysermc/geyser/item/type/ChestItem.java | 44 ------------------ .../geyser/item/type/DyeableArmorItem.java | 12 +++-- .../item/type/DyeableHorseArmorItem.java | 45 ------------------ .../geysermc/geyser/item/type/FlowerItem.java | 33 ------------- .../translator/item/ItemTranslator.java | 16 +++---- 11 files changed, 45 insertions(+), 224 deletions(-) rename core/src/main/java/org/geysermc/geyser/entity/type/{TippedArrowEntity.java => ArrowEntity.java} (86%) delete mode 100644 core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java delete mode 100644 core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java delete mode 100644 core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java delete mode 100644 core/src/main/java/org/geysermc/geyser/item/type/FlowerItem.java 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 317892676..4063a675c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -56,7 +56,7 @@ public final class EntityDefinitions { 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 ARROW; public static final EntityDefinition AXOLOTL; public static final EntityDefinition BAT; public static final EntityDefinition BEE; @@ -378,10 +378,10 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags) .addTranslator(null) // "Piercing level" .build(); - ARROW = EntityDefinition.inherited(TippedArrowEntity::new, abstractArrowBase) + ARROW = EntityDefinition.inherited(ArrowEntity::new, abstractArrowBase) .type(EntityType.ARROW) .heightAndWidth(0.25f) - .addTranslator(MetadataType.INT, TippedArrowEntity::setPotionEffectColor) + .addTranslator(MetadataType.INT, ArrowEntity::setPotionEffectColor) .build(); SPECTRAL_ARROW = EntityDefinition.inherited(abstractArrowBase.factory(), abstractArrowBase) .type(EntityType.SPECTRAL_ARROW) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java similarity index 86% rename from core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java rename to core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java index be4133028..1ee706811 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java @@ -34,12 +34,9 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEnt import java.util.UUID; -/** - * Internally this is known as TippedArrowEntity but is used with tipped arrows and normal arrows - */ -public class TippedArrowEntity extends AbstractArrowEntity { +public class ArrowEntity extends AbstractArrowEntity { - public TippedArrowEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ArrowEntity(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/inventory/item/Potion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java index 79b9565fb..00a9b091e 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 @@ -91,15 +91,6 @@ public enum Potion { return new PotionContents(this.ordinal(), -1, Int2ObjectMaps.emptyMap()); } - public static @Nullable Potion getByJavaIdentifier(String javaIdentifier) { - for (Potion potion : VALUES) { - if (potion.javaIdentifier.equals(javaIdentifier)) { - return potion; - } - } - return null; - } - public static @Nullable Potion getByBedrockId(int bedrockId) { for (Potion potion : VALUES) { if (potion.bedrockId == bedrockId) { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java index 5c33fec67..ec6b10ec8 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java @@ -99,15 +99,6 @@ public enum TippedArrowPotion { return VALUES[id]; } - public static @Nullable TippedArrowPotion getByJavaIdentifier(String javaIdentifier) { - for (TippedArrowPotion potion : VALUES) { - if (potion.javaIdentifier.equals(javaIdentifier)) { - return potion; - } - } - return null; - } - public static @Nullable TippedArrowPotion getByBedrockId(int bedrockId) { for (TippedArrowPotion potion : VALUES) { if (potion.bedrockId == bedrockId) { diff --git a/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java b/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java deleted file mode 100644 index eabdbee87..000000000 --- a/core/src/main/java/org/geysermc/geyser/item/DyeableLeatherItem.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.item; - -import org.geysermc.geyser.translator.item.BedrockItemBuilder; -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.DyedItemColor; - -public interface DyeableLeatherItem { - - static void translateComponentsToBedrock(DataComponents components, BedrockItemBuilder builder) { - DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR); - if (dyedItemColor == null) { - return; - } - builder.putInt("customColor", dyedItemColor.getRgb()); - } -} 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 42a087acf..f13330700 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -256,20 +256,20 @@ public final class Items { public static final Item GREEN_WOOL = register(new BlockItem("green_wool", builder())); public static final Item RED_WOOL = register(new BlockItem("red_wool", builder())); public static final Item BLACK_WOOL = register(new BlockItem("black_wool", builder())); - public static final Item DANDELION = register(new FlowerItem("dandelion", builder())); - public static final Item POPPY = register(new FlowerItem("poppy", builder())); - public static final Item BLUE_ORCHID = register(new FlowerItem("blue_orchid", builder())); - public static final Item ALLIUM = register(new FlowerItem("allium", builder())); - public static final Item AZURE_BLUET = register(new FlowerItem("azure_bluet", builder())); - public static final Item RED_TULIP = register(new FlowerItem("red_tulip", builder())); - public static final Item ORANGE_TULIP = register(new FlowerItem("orange_tulip", builder())); - public static final Item WHITE_TULIP = register(new FlowerItem("white_tulip", builder())); - public static final Item PINK_TULIP = register(new FlowerItem("pink_tulip", builder())); - public static final Item OXEYE_DAISY = register(new FlowerItem("oxeye_daisy", builder())); - public static final Item CORNFLOWER = register(new FlowerItem("cornflower", builder())); - public static final Item LILY_OF_THE_VALLEY = register(new FlowerItem("lily_of_the_valley", builder())); - public static final Item WITHER_ROSE = register(new FlowerItem("wither_rose", builder())); - public static final Item TORCHFLOWER = register(new FlowerItem("torchflower", builder())); + public static final Item DANDELION = register(new BlockItem("dandelion", builder())); + public static final Item POPPY = register(new BlockItem("poppy", builder())); + public static final Item BLUE_ORCHID = register(new BlockItem("blue_orchid", builder())); + public static final Item ALLIUM = register(new BlockItem("allium", builder())); + public static final Item AZURE_BLUET = register(new BlockItem("azure_bluet", builder())); + public static final Item RED_TULIP = register(new BlockItem("red_tulip", builder())); + public static final Item ORANGE_TULIP = register(new BlockItem("orange_tulip", builder())); + public static final Item WHITE_TULIP = register(new BlockItem("white_tulip", builder())); + public static final Item PINK_TULIP = register(new BlockItem("pink_tulip", builder())); + public static final Item OXEYE_DAISY = register(new BlockItem("oxeye_daisy", builder())); + public static final Item CORNFLOWER = register(new BlockItem("cornflower", builder())); + public static final Item LILY_OF_THE_VALLEY = register(new BlockItem("lily_of_the_valley", builder())); + public static final Item WITHER_ROSE = register(new BlockItem("wither_rose", builder())); + public static final Item TORCHFLOWER = register(new BlockItem("torchflower", builder())); public static final Item PITCHER_PLANT = register(new BlockItem("pitcher_plant", builder())); public static final Item SPORE_BLOSSOM = register(new BlockItem("spore_blossom", builder())); public static final Item BROWN_MUSHROOM = register(new BlockItem("brown_mushroom", builder())); @@ -337,7 +337,7 @@ public final class Items { public static final Item PURPUR_PILLAR = register(new BlockItem("purpur_pillar", builder())); public static final Item PURPUR_STAIRS = register(new BlockItem("purpur_stairs", builder())); public static final Item SPAWNER = register(new BlockItem("spawner", builder())); - public static final Item CHEST = register(new ChestItem("chest", builder())); + public static final Item CHEST = register(new BlockItem("chest", builder())); public static final Item CRAFTING_TABLE = register(new BlockItem("crafting_table", builder())); public static final Item FARMLAND = register(new BlockItem("farmland", builder())); public static final Item FURNACE = register(new BlockItem("furnace", builder())); @@ -419,7 +419,7 @@ public final class Items { public static final Item END_STONE_BRICKS = register(new BlockItem("end_stone_bricks", builder())); public static final Item DRAGON_EGG = register(new BlockItem("dragon_egg", builder())); public static final Item SANDSTONE_STAIRS = register(new BlockItem("sandstone_stairs", builder())); - public static final Item ENDER_CHEST = register(new ChestItem("ender_chest", builder())); + public static final Item ENDER_CHEST = register(new BlockItem("ender_chest", builder())); public static final Item EMERALD_BLOCK = register(new BlockItem("emerald_block", builder())); public static final Item OAK_STAIRS = register(new BlockItem("oak_stairs", builder())); public static final Item SPRUCE_STAIRS = register(new BlockItem("spruce_stairs", builder())); @@ -716,7 +716,7 @@ public final class Items { public static final Item SCULK_SENSOR = register(new BlockItem("sculk_sensor", builder())); public static final Item CALIBRATED_SCULK_SENSOR = register(new BlockItem("calibrated_sculk_sensor", builder())); public static final Item TRIPWIRE_HOOK = register(new BlockItem("tripwire_hook", builder())); - public static final Item TRAPPED_CHEST = register(new ChestItem("trapped_chest", builder())); + public static final Item TRAPPED_CHEST = register(new BlockItem("trapped_chest", builder())); public static final Item TNT = register(new BlockItem("tnt", builder())); public static final Item REDSTONE_LAMP = register(new BlockItem("redstone_lamp", builder())); public static final Item NOTE_BLOCK = register(new BlockItem("note_block", builder())); @@ -894,10 +894,10 @@ public final class Items { public static final Item WHEAT_SEEDS = register(new BlockItem("wheat_seeds", builder())); public static final Item WHEAT = register(new Item("wheat", builder())); public static final Item BREAD = register(new Item("bread", builder())); - public static final Item LEATHER_HELMET = register(new ArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(55))); - public static final Item LEATHER_CHESTPLATE = register(new ArmorItem("leather_chestplate", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(80))); - public static final Item LEATHER_LEGGINGS = register(new ArmorItem("leather_leggings", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(75))); - public static final Item LEATHER_BOOTS = register(new ArmorItem("leather_boots", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(65))); + public static final Item LEATHER_HELMET = register(new DyeableArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(55))); + public static final Item LEATHER_CHESTPLATE = register(new DyeableArmorItem("leather_chestplate", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(80))); + public static final Item LEATHER_LEGGINGS = register(new DyeableArmorItem("leather_leggings", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(75))); + public static final Item LEATHER_BOOTS = register(new DyeableArmorItem("leather_boots", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(65))); public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(165))); public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(240))); public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(225))); @@ -1165,7 +1165,7 @@ public final class Items { 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 LEATHER_HORSE_ARMOR = register(new ArmorItem("leather_horse_armor", ArmorMaterial.LEATHER, 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))); @@ -1240,7 +1240,7 @@ public final class Items { public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_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("composter", builder())); - public static final Item BARREL = register(new ChestItem("barrel", builder())); + public static final Item BARREL = register(new BlockItem("barrel", builder())); public static final Item SMOKER = register(new BlockItem("smoker", builder())); public static final Item BLAST_FURNACE = register(new BlockItem("blast_furnace", builder())); public static final Item CARTOGRAPHY_TABLE = register(new BlockItem("cartography_table", builder())); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java deleted file mode 100644 index 09718ba66..000000000 --- a/core/src/main/java/org/geysermc/geyser/item/type/ChestItem.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.item.type; - -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; - -@Deprecated -public class ChestItem extends BlockItem { - - public ChestItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); - } - - @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index d4bf838bd..b2dbb95e5 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -27,12 +27,13 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.ArmorMaterial; -import org.geysermc.geyser.item.DyeableLeatherItem; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +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.DyedItemColor; -public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem { +public class DyeableArmorItem extends ArmorItem { public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) { super(javaIdentifier, material, builder); } @@ -41,6 +42,11 @@ public class DyeableArmorItem extends ArmorItem implements DyeableLeatherItem { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - DyeableLeatherItem.translateComponentsToBedrock(components, builder); + // Note that this is handled as of 1.20.5 in the ItemColors class. + // But horse leather armor and body leather armor are now both armor items. So it works! + DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR); + if (dyedItemColor != null) { + builder.putInt("customColor", dyedItemColor.getRgb()); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java deleted file mode 100644 index b50a3b847..000000000 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableHorseArmorItem.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.item.type; - -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.item.DyeableLeatherItem; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; - -public class DyeableHorseArmorItem extends Item implements DyeableLeatherItem { - public DyeableHorseArmorItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); - } - - @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); - - DyeableLeatherItem.translateComponentsToBedrock(components, builder); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FlowerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FlowerItem.java deleted file mode 100644 index c65eec1d2..000000000 --- a/core/src/main/java/org/geysermc/geyser/item/type/FlowerItem.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.item.type; - -// If blocks are implemented, then this class is not needed. -public class FlowerItem extends BlockItem { - public FlowerItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); - } -} 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 629192e01..11e092b57 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 @@ -71,7 +71,7 @@ public final class ItemTranslator { /** * The order of these slots is their display order on Java Edition clients */ - private static final String[] ALL_SLOTS = new String[]{"mainhand", "offhand", "feet", "legs", "chest", "head"}; + private static final ItemAttributeModifiers.EquipmentSlotGroup[] ALL_SLOTS = ItemAttributeModifiers.EquipmentSlotGroup.values(); private static final DecimalFormat ATTRIBUTE_FORMAT = new DecimalFormat("0.#####"); private ItemTranslator() { @@ -128,7 +128,7 @@ public final class ItemTranslator { .build(); } - private static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, DataComponents components) { + private static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents components) { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); if (components != null) { @@ -208,8 +208,8 @@ public final class ItemTranslator { ItemAttributeModifiers.EquipmentSlotGroup slotGroup = entry.getSlot(); if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ANY) { // modifier applies to all slots implicitly - for (String slot : ALL_SLOTS) { // TODO SOMEONE LOOK HERE PLZ - //slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreEntry); + for (var slot : ALL_SLOTS) { + slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreEntry); } } else { // modifier applies to only the specified slot @@ -218,7 +218,7 @@ public final class ItemTranslator { } // iterate through the small array, not the map, so that ordering matches Java Edition - for (String slot : ALL_SLOTS) { + for (var slot : ALL_SLOTS) { List modifierStrings = slotsToModifiers.get(slot); if (modifierStrings == null || modifierStrings.isEmpty()) { continue; @@ -275,10 +275,10 @@ public final class ItemTranslator { return MessageTranslator.convertMessage(attributeComponent, language); } - private static void addAdvancedTooltips(DataComponents components, BedrockItemBuilder builder, Item item, String language) { + private static void addAdvancedTooltips(@Nullable DataComponents components, BedrockItemBuilder builder, Item item, String language) { int maxDurability = item.maxDamage(); - if (maxDurability != 0) { + if (maxDurability != 0 && components != null) { Integer durabilityComponent = components.get(DataComponentType.DAMAGE); if (durabilityComponent != null) { int durability = maxDurability - durabilityComponent; @@ -300,7 +300,7 @@ public final class ItemTranslator { Component component = Component.text() .resetStyle() .color(NamedTextColor.DARK_GRAY) - .append(Component.translatable("item.nbt_tags", // TODO + .append(Component.translatable("item.components", Component.text(components.getDataComponents().size()))) .build(); builder.getOrCreateLore().add(MessageTranslator.convertMessage(component, language)); From e97bbcc483f0e2ad6787e89ff03366eef2dff2ab Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 28 Apr 2024 02:10:20 -0400 Subject: [PATCH 089/897] Potion effect colors --- .../geyser/entity/EntityDefinitions.java | 3 +- .../geyser/entity/type/LivingEntity.java | 35 +++++++++++++++++++ gradle/libs.versions.toml | 2 +- 3 files changed, 37 insertions(+), 3 deletions(-) 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 4063a675c..fd0673062 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -454,8 +454,7 @@ public final class EntityDefinitions { EntityDefinition livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase) .addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags) .addTranslator(MetadataType.FLOAT, LivingEntity::setHealth) - .addTranslator(MetadataType.INT, - (livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityDataTypes.EFFECT_COLOR, entityMetadata.getValue())) + .addTranslator(MetadataType.PARTICLES, LivingEntity::setParticles) .addTranslator(MetadataType.BOOLEAN, (livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityDataTypes.EFFECT_AMBIENCE, (byte) (((BooleanEntityMetadata) entityMetadata).getPrimitiveValue() ? 1 : 0))) .addTranslator(null) // Arrow count 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 401135bbf..58a3bf8e7 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 @@ -55,9 +55,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; 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.level.particle.EntityEffectParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; import java.util.*; @@ -152,6 +156,37 @@ public class LivingEntity extends Entity { session.sendUpstreamPacket(attributesPacket); } + // TODO: support all particle types + public void setParticles(ObjectEntityMetadata> entityMetadata) { + List particles = entityMetadata.getValue(); + float r = 0f; + float g = 0f; + float b = 0f; + + int count = 0; + for (Particle particle : particles) { + if (particle.getType() != ParticleType.ENTITY_EFFECT) { + continue; + } + + int color = ((EntityEffectParticleData) particle.getData()).getColor(); + r += ((color >> 16) & 0xFF) / 255f; + g += ((color >> 8) & 0xFF) / 255f; + b += ((color) & 0xFF) / 255f; + count++; + } + + int result = 0; + if (count > 0) { + r = r / count * 255f; + g = g / count * 255f; + b = b / count * 255f; + result = (int) r << 16 | (int) g << 8 | (int) b; + } + + dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, result); + } + public @Nullable Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { Optional optionalPos = entityMetadata.getValue(); if (optionalPos.isPresent()) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f8f979539..7c16b883b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "98410a1" # Revert from jitpack after release +mcprotocollib = "400f1b4" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 9cb9a1450e6740df5abef30ff4261a0f75b8c32d Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Sun, 28 Apr 2024 07:43:33 -0700 Subject: [PATCH 090/897] Don't use tee to write metadata.json to downloads API (#4612) --- .github/workflows/build.yml | 7 ++++--- .github/workflows/preview.yml | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 284fa265a..7ec013dc2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -136,14 +136,15 @@ jobs: run: | cat metadata.json echo + mv metadata.json metadata.json.tmp version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) - cat metadata.json | jq --arg project "${PROJECT}" --arg version "${version}" ' + jq --arg project "${PROJECT}" --arg version "${version}" ' . | .changes |= map({"commit", "summary", "message"}) | .downloads |= map_values({"name", "sha256"}) | {$project, "repo", $version, "number": .build, "changes", "downloads"} - ' | tee metadata.json - echo + ' metadata.json.tmp > metadata.json + cat metadata.json - name: Publish to Downloads API if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} shell: bash diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 13712d5ef..1268f0674 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -69,11 +69,13 @@ jobs: run: | cat metadata.json echo - cat metadata.json | jq --arg project "${PROJECT}" --arg version "${VERSION}" --arg number "${BUILD}" ' + mv metadata.json metadata.json.tmp + jq --arg project "${PROJECT}" --arg version "${VERSION}" --arg number "${BUILD}" ' . | .downloads |= map_values({"name", "sha256"}) | {$project, "repo", $version, "number": $number | tonumber, "changes": [], "downloads"} - ' | tee metadata.json + ' metadata.json.tmp > metadata.json + cat metadata.json - name: Publish to Downloads API if: success() shell: bash From 420f67752cae958be277bd0d9374b6c019d97ae2 Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Sun, 28 Apr 2024 18:54:34 +0100 Subject: [PATCH 091/897] Fix suspicious stew NPEs --- .../java/org/geysermc/geyser/registry/type/ItemMappings.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index f3cfa3f0f..94c863660 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -148,9 +148,10 @@ public class ItemMappings implements DefinitionRegistry { } } else { if (!(mapping.getBedrockData() == data.getDamage() || - // Make exceptions for potions, tipped arrows, firework stars, and goat horns, whose damage values can vary + // Make exceptions for potions, tipped arrows, firework stars, goat horns, and suspicious stews, whose damage values can vary (mapping.getJavaItem() instanceof PotionItem || mapping.getJavaItem() == Items.ARROW - || mapping.getJavaItem() == Items.FIREWORK_STAR || mapping.getJavaItem() == Items.GOAT_HORN))) { + || mapping.getJavaItem() == Items.FIREWORK_STAR || mapping.getJavaItem() == Items.GOAT_HORN + || mapping.getJavaItem() == Items.SUSPICIOUS_STEW))) { continue; } } From 9b1e45007aeca1c64000d26da8dbf316d2e887ab Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 28 Apr 2024 23:41:13 +0200 Subject: [PATCH 092/897] Fix injectors, should work with Spigot/Paper 1.20.5 now --- .../org/geysermc/geyser/platform/mod/GeyserModInjector.java | 5 ++++- .../geyser/platform/spigot/GeyserSpigotInjector.java | 5 ++++- .../java/entity/player/JavaCookieRequestTranslator.java | 1 + .../java/entity/player/JavaStoreCookieTranslator.java | 1 + .../java/entity/player/JavaTransferPacketTranslator.java | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModInjector.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModInjector.java index 06496293f..624eccb3f 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModInjector.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModInjector.java @@ -93,8 +93,11 @@ public class GeyserModInjector extends GeyserInjector { protected void initChannel(@NonNull Channel ch) throws Exception { initChannel.invoke(childHandler, ch); + int index = ch.pipeline().names().indexOf("encoder"); + String baseName = index != -1 ? "encoder" : "outbound_config"; + if (bootstrap.getGeyserConfig().isDisableCompression()) { - ch.pipeline().addAfter("encoder", "geyser-compression-disabler", new GeyserModCompressionDisabler()); + ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserModCompressionDisabler()); } } }) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index 6aa5d563f..6d22a77ae 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -119,8 +119,11 @@ public class GeyserSpigotInjector extends GeyserInjector { protected void initChannel(@NonNull Channel ch) throws Exception { initChannel.invoke(childHandler, ch); + int index = ch.pipeline().names().indexOf("encoder"); + String baseName = index != -1 ? "encoder" : "outbound_config"; + if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserSpigotCompressionDisabler.ENABLED) { - ch.pipeline().addAfter("encoder", "geyser-compression-disabler", new GeyserSpigotCompressionDisabler()); + ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserSpigotCompressionDisabler()); } } }) 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 5266ebabd..33bfa7be8 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 @@ -33,6 +33,7 @@ import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.Serverbound @Translator(packet = ClientboundCookieRequestPacket.class) public class JavaCookieRequestTranslator extends PacketTranslator { + @Override public void translate(GeyserSession session, ClientboundCookieRequestPacket packet) { ServerboundCookieResponsePacket responsePacket = new ServerboundCookieResponsePacket( diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java index 19237b646..342618ff8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java @@ -32,6 +32,7 @@ import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.Clientbound @Translator(packet = ClientboundStoreCookiePacket.class) public class JavaStoreCookieTranslator extends PacketTranslator { + @Override public void translate(GeyserSession session, ClientboundStoreCookiePacket packet) { session.getCookies().put(packet.getKey(), packet.getPayload()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java index 86fd70677..ad793f934 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaTransferPacketTranslator.java @@ -35,6 +35,7 @@ import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.Clientbound @Translator(packet = ClientboundTransferPacket.class) public class JavaTransferPacketTranslator extends PacketTranslator { + @Override public void translate(GeyserSession session, ClientboundTransferPacket packet) { ServerTransferEvent event = new ServerTransferEvent( From 82123aecf121b4fe688d6b166500821ecd036876 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 28 Apr 2024 23:52:23 +0200 Subject: [PATCH 093/897] Fix: Modded platform injector not being used --- .../geysermc/geyser/platform/mod/GeyserModBootstrap.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java index db966ec1a..9622736de 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java @@ -58,6 +58,7 @@ import org.geysermc.geyser.util.FileUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.SocketAddress; import java.nio.file.Path; import java.util.Map; import java.util.UUID; @@ -240,6 +241,11 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { return ip != null ? ip : ""; // See issue #3812 } + @Override + public SocketAddress getSocketAddress() { + return this.geyserInjector.getServerSocketAddress(); + } + @Override public int getServerPort() { return ((GeyserServerPortGetter) server).geyser$getServerPort(); From e8c1c2218f99c6abbaa981d71fd360cba7b9f2c7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 29 Apr 2024 00:35:44 -0400 Subject: [PATCH 094/897] Fix banners on shields --- .../geysermc/geyser/item/type/BannerItem.java | 45 +++++++++++-------- .../geysermc/geyser/item/type/ShieldItem.java | 29 ++++++------ 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 232f340ea..9f5138323 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -113,6 +113,31 @@ public class BannerItem extends BlockItem { return new NbtList<>(NbtType.COMPOUND, tagsList); } + /** + * Converts a Java item component for banners into Bedrock item NBT. + */ + static void convertBannerPattern(GeyserSession session, List patterns, BedrockItemBuilder builder) { + if (isOminous(session, patterns)) { + // Remove the current patterns and set the ominous banner type + builder.putInt("Type", 1); + } else { + List patternList = new ArrayList<>(patterns.size()); + for (BannerPatternLayer patternLayer : patterns) { + patternLayer.getPattern().ifId(holder -> { + BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(holder.id()); + if (bannerPattern != null) { + NbtMap tag = NbtMap.builder() + .putString("Pattern", bannerPattern.getBedrockIdentifier()) + .putInt("Color", 15 - patternLayer.getColorId()) + .build(); + patternList.add(tag); + } + }); + } + builder.putList("Patterns", NbtType.COMPOUND, patternList); + } + } + /** * Convert the Java edition banner pattern nbt to Bedrock edition, null if the pattern doesn't exist * @@ -166,25 +191,7 @@ public class BannerItem extends BlockItem { List patterns = components.get(DataComponentType.BANNER_PATTERNS); if (patterns != null) { - if (isOminous(session, patterns)) { - // Remove the current patterns and set the ominous banner type - builder.putInt("Type", 1); - } else { - List patternList = new ArrayList<>(patterns.size()); - for (BannerPatternLayer patternLayer : patterns) { - patternLayer.getPattern().ifId(holder -> { - BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(holder.id()); - if (bannerPattern != null) { - NbtMap tag = NbtMap.builder() - .putString("Pattern", bannerPattern.getBedrockIdentifier()) - .putInt("Color", 15 - patternLayer.getColorId()) - .build(); - patternList.add(tag); - } - }); - } - builder.putList("Patterns", NbtType.COMPOUND, patternList); - } + convertBannerPattern(session, patterns, builder); } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index 001fa74b6..14d41a073 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -29,8 +29,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import java.util.List; + public class ShieldItem extends Item { public ShieldItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); @@ -40,22 +44,15 @@ public class ShieldItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - // TODO figure out patterns first. -// if (tag.remove("BlockEntityTag") instanceof CompoundTag blockEntityTag) { -// if (blockEntityTag.get("Patterns") instanceof ListTag patterns) { -// for (Tag pattern : patterns) { -// if (((CompoundTag) pattern).get("Color") instanceof IntTag color) { -// color.setValue(15 - color.getValue()); -// } -// } -// // Bedrock looks for patterns at the root -// tag.put(patterns); -// } -// if (blockEntityTag.get("Base") instanceof IntTag base) { -// base.setValue(15 - base.getValue()); -// tag.put(base); -// } -// } + List patterns = components.get(DataComponentType.BANNER_PATTERNS); + if (patterns != null) { + BannerItem.convertBannerPattern(session, patterns, builder); + } + // Shield pattern backing color + Integer baseColor = components.get(DataComponentType.BASE_COLOR); + if (baseColor != null) { + builder.putInt("Base", 15 - baseColor); + } } @Override From 88ae447fc6ee9667494bfefb5cd258c00d4535fc Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 29 Apr 2024 00:47:52 -0400 Subject: [PATCH 095/897] Fix banner block entity base colors with no patterns --- .../level/block/entity/BlockEntityTranslator.java | 9 +++++++-- .../block/entity/SpawnerBlockEntityTranslator.java | 5 ++++- .../entity/StructureBlockBlockEntityTranslator.java | 6 +++++- .../java/level/JavaLevelChunkWithLightTranslator.java | 11 ++++------- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java index 45981377c..6df7781be 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.session.GeyserSession; @@ -40,9 +41,13 @@ public abstract class BlockEntityTranslator { public abstract void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState); - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, NbtMap javaNbt, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { NbtMapBuilder tagBuilder = getConstantBedrockTag(type, x, y, z); - translateTag(session, tagBuilder, javaNbt, blockState); + if (javaNbt != null || this instanceof RequiresBlockState) { + // Always process tags if the block state is part of the tag. + // See: banner base colors. + translateTag(session, tagBuilder, javaNbt, blockState); + } return tagBuilder.build(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index 05b763e6b..edf71d384 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -40,7 +40,10 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { @Override - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, NbtMap javaNbt, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { + if (javaNbt == null) { + return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState); + } // Sending an empty EntityIdentifier to empty the spawner is ignored by the client, so we send a whole new spawner! // Fixes https://github.com/GeyserMC/Geyser/issues/4214 NbtMap spawnData = javaNbt.getCompound("SpawnData"); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java index aefd97dd5..4bb9c5676 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -39,7 +40,10 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { @Override - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, NbtMap javaNbt, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { + if (javaNbt == null) { + return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState); + } // Sending a structure with size 0 doesn't clear the outline. Hence, we have to force it by replacing the block :/ int xStructureSize = javaNbt.getInt("sizeX"); int yStructureSize = javaNbt.getInt("sizeY"); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index c3a399863..29db95e3f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -412,13 +412,10 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator Date: Mon, 29 Apr 2024 01:03:18 -0400 Subject: [PATCH 096/897] Firework shapes --- .../org/geysermc/geyser/item/type/FireworkRocketItem.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index 1265956da..bba13e753 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -92,10 +92,7 @@ public class FireworkRocketItem extends Item { static NbtMap translateExplosionToBedrock(Fireworks.FireworkExplosion explosion) { NbtMapBuilder newExplosionData = NbtMap.builder(); -// if (explosion.get("Type") != null) { -// newExplosionData.put(new ByteTag("FireworkType", MathUtils.getNbtByte(explosion.get("Type").getValue()))); -// } - //newExplosionData.putByte("FireworkType", explosion.get) //TODO??? + newExplosionData.putByte("FireworkType", (byte) explosion.getShapeId()); int[] oldColors = explosion.getColors(); byte[] colors = new byte[oldColors.length]; From 4ff746e48ab4562978fab9981df2ea1f7cc8a039 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 29 Apr 2024 04:20:24 -0400 Subject: [PATCH 097/897] Fix translateTag NPE --- .../level/block/entity/BannerBlockEntityTranslator.java | 3 ++- .../level/block/entity/BrushableBlockEntityTranslator.java | 7 ++++++- .../block/entity/JigsawBlockBlockEntityTranslator.java | 7 ++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java index c87d1a217..81f58214c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; @@ -38,7 +39,7 @@ import java.util.List; @BlockEntity(type = BlockEntityType.BANNER) public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { int bannerColor = BlockStateValues.getBannerColor(blockState); if (bannerColor != -1) { bedrockNbt.putInt("Base", 15 - bannerColor); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java index 4f9dfec46..b4012236b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.Items; @@ -37,7 +38,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class BrushableBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { + if (javaNbt == null) { + return; + } + NbtMap itemTag = javaNbt.getCompound("item"); if (itemTag.isEmpty()) { return; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java index bd83e3d54..53f32682c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; @@ -34,7 +35,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType @BlockEntity(type = BlockEntityType.JIGSAW) public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { + if (javaNbt == null) { + return; + } + String joint = javaNbt.getString("joint", null); if (joint != null) { bedrockNbt.putString("joint", joint); From 8b7b8cdffdb7aba97ef817037859d1151f4b2665 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 29 Apr 2024 16:08:14 +0200 Subject: [PATCH 098/897] Properly shutdown LocalSession's, ensure transferring works properly regardless if we're injected or not --- bootstrap/mod/fabric/build.gradle.kts | 2 -- .../platform/spigot/GeyserSpigotInjector.java | 2 +- .../geysermc/geyser/network/netty/LocalSession.java | 13 +++++++------ .../org/geysermc/geyser/session/GeyserSession.java | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index 53e4dfe53..cd513c1e4 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -49,9 +49,7 @@ application { relocate("org.cloudburstmc.netty") relocate("org.cloudburstmc.protocol") -relocate("com.github.steveice10.mc.protocol") relocate("com.github.steveice10.mc.auth") -relocate("com.github.steveice10.packetlib") tasks { remapJar { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index 6d22a77ae..5dcfbd0f8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -178,7 +178,7 @@ public class GeyserSpigotInjector extends GeyserInjector { MinecraftProtocol protocol = new MinecraftProtocol(); LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().address(), bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress, - InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper(), false); + InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper()); session.connect(); session.disconnect(""); } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index b5598d063..958e88288 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -30,6 +30,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.*; import io.netty.channel.unix.PreferredDirectByteBufAllocator; import io.netty.handler.codec.haproxy.*; +import io.netty.util.concurrent.DefaultThreadFactory; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.mcprotocollib.network.BuiltinFlags; import org.geysermc.mcprotocollib.network.codec.PacketCodecHelper; @@ -42,6 +43,7 @@ import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.concurrent.TimeUnit; /** * Manages a Minecraft Java session over our LocalChannel implementations. @@ -54,24 +56,23 @@ public final class LocalSession extends TcpSession { private final String clientIp; private final PacketCodecHelper codecHelper; - private final boolean transferring; - - public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, MinecraftCodecHelper codecHelper, boolean transferring) { + public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, MinecraftCodecHelper codecHelper) { super(host, port, protocol); this.targetAddress = targetAddress; this.clientIp = clientIp; this.codecHelper = codecHelper; - this.transferring = transferring; } @Override - public void connect(boolean wait) { + public void connect(boolean wait, boolean transferring) { if (this.disconnected) { throw new IllegalStateException("Connection has already been disconnected."); } if (DEFAULT_EVENT_LOOP_GROUP == null) { - DEFAULT_EVENT_LOOP_GROUP = new DefaultEventLoopGroup(); + DEFAULT_EVENT_LOOP_GROUP = new DefaultEventLoopGroup(new DefaultThreadFactory(this.getClass(), true)); + Runtime.getRuntime().addShutdownHook(new Thread( + () -> DEFAULT_EVENT_LOOP_GROUP.shutdownGracefully(100, 500, TimeUnit.MILLISECONDS))); } try { 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 869999357..d10a20b3d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -880,7 +880,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // We're going to connect through the JVM and not through TCP downstream = new LocalSession(this.remoteServer.address(), this.remoteServer.port(), geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), - this.protocol, this.protocol.createHelper(), loginEvent.transferring()); + this.protocol, this.protocol.createHelper()); this.downstream = new DownstreamSession(downstream); } else { downstream = new TcpClientSession(this.remoteServer.address(), this.remoteServer.port(), this.protocol); @@ -1070,7 +1070,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { setDaylightCycle(true); } - downstream.connect(false); + downstream.connect(false, loginEvent.transferring()); } public void disconnect(String reason) { From 5d3630cf236aa47eb4e494272764ea58a02857d6 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 29 Apr 2024 23:19:18 +0200 Subject: [PATCH 099/897] ominous banners - this really isn't ideal --- .../platform/spigot/GeyserSpigotPlugin.java | 4 +-- .../geyser/inventory/item/BannerPattern.java | 16 +++++----- .../geysermc/geyser/item/type/BannerItem.java | 32 ++++++++++++++----- .../geyser/session/GeyserSession.java | 1 + .../geyser/session/cache/RegistryCache.java | 19 +++++++++-- 5 files changed, 52 insertions(+), 20 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 1f14a2f65..1170ce678 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -244,8 +244,8 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { if (Boolean.parseBoolean(System.getProperty("Geyser.UseDirectAdapters", "true"))) { try { - String name = Bukkit.getServer().getClass().getPackage().getName(); - String nmsVersion = name.substring(name.lastIndexOf('.') + 1); + String version = Bukkit.getBukkitVersion().split("-")[0]; + String nmsVersion = "v" + version.replace(".", "_"); SpigotAdapters.registerWorldAdapter(nmsVersion); if (isViaVersion && isViaVersionNeeded()) { this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java index 442690d7d..ae225073a 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java @@ -45,7 +45,7 @@ public enum BannerPattern { STRIPE_MIDDLE("ms"), STRIPE_DOWNRIGHT("drs"), STRIPE_DOWNLEFT("dls"), - SMALL_STRIPES("ss"), + STRIPE_SMALL("ss"), CROSS("cr"), STRAIGHT_CROSS("sc"), TRIANGLE_BOTTOM("bt"), @@ -53,15 +53,15 @@ public enum BannerPattern { TRIANGLES_BOTTOM("bts"), TRIANGLES_TOP("tts"), DIAGONAL_LEFT("ld"), - DIAGONAL_UP_RIGHT("rd"), - DIAGONAL_UP_LEFT("lud"), - DIAGONAL_RIGHT("rud"), - CIRCLE("mc"), - RHOMBUS("mr"), + DIAGONAL_RIGHT("rd"), + DIAGONAL_LEFT_MIRROR("lud"), + DIAGONAL_RIGHT_MIRROR("rud"), + CIRCLE_MIDDLE("mc"), + RHOMBUS_MIDDLE("mr"), HALF_VERTICAL("vh"), HALF_HORIZONTAL("hh"), - HALF_VERTICAL_RIGHT("vhr"), - HALF_HORIZONTAL_BOTTOM("hhb"), + HALF_VERTICAL_MIRROR("vhr"), + HALF_HORIZONTAL_MIRROR("hhb"), BORDER("bo"), CURLY_BORDER("cbo"), GRADIENT("gra"), diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 9f5138323..255e320a6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -26,18 +26,26 @@ package org.geysermc.geyser.item.type; import it.unimi.dsi.fastutil.Pair; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextColor; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.protocol.common.util.Int2ObjectBiMap; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.item.DyeColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; 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.Unit; import java.util.ArrayList; import java.util.List; @@ -56,13 +64,13 @@ public class BannerItem extends BlockItem { static { // Construct what an ominous banner is supposed to look like OMINOUS_BANNER_PATTERN = List.of( - Pair.of(BannerPattern.RHOMBUS, DyeColor.CYAN), + Pair.of(BannerPattern.RHOMBUS_MIDDLE, DyeColor.CYAN), Pair.of(BannerPattern.STRIPE_BOTTOM, DyeColor.LIGHT_GRAY), Pair.of(BannerPattern.STRIPE_CENTER, DyeColor.GRAY), Pair.of(BannerPattern.BORDER, DyeColor.LIGHT_GRAY), Pair.of(BannerPattern.STRIPE_MIDDLE, DyeColor.BLACK), Pair.of(BannerPattern.HALF_HORIZONTAL, DyeColor.LIGHT_GRAY), - Pair.of(BannerPattern.CIRCLE, DyeColor.LIGHT_GRAY), + Pair.of(BannerPattern.CIRCLE_MIDDLE, DyeColor.LIGHT_GRAY), Pair.of(BannerPattern.BORDER, DyeColor.BLACK) ); @@ -171,14 +179,13 @@ public class BannerItem extends BlockItem { * @return The Java edition format pattern layer */ public static BannerPatternLayer getJavaBannerPattern(GeyserSession session, NbtMap pattern) { - return null; // TODO - /*Int2ObjectBiMap registry = session.getRegistryCache().bannerPatterns(); + Int2ObjectBiMap registry = session.getRegistryCache().bannerPatterns(); BannerPattern bannerPattern = BannerPattern.getByBedrockIdentifier(pattern.getString("Pattern")); DyeColor dyeColor = DyeColor.getById(15 - pattern.getInt("Color")); if (bannerPattern != null && dyeColor != null && registry.containsValue(bannerPattern)) { return new BannerPatternLayer(Holder.ofId(registry.get(bannerPattern)), dyeColor.ordinal()); } - return null;*/ + return null; } public BannerItem(String javaIdentifier, Builder builder) { @@ -196,13 +203,22 @@ public class BannerItem extends BlockItem { } @Override - public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { // TODO + public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { super.translateNbtToJava(bedrockTag, components, mapping); if (bedrockTag.getInt("Type") == 1) { // Ominous banner pattern - // TODO more registry stuff - //components.put(DataComponentType.BANNER_PATTERNS); + List patternLayers = new ArrayList<>(); + for (Pair pair : OMINOUS_BANNER_PATTERN) { + patternLayers.add(new BannerPatternLayer(Holder.ofId(pair.left().ordinal()), pair.right().ordinal())); + } + + components.put(DataComponentType.BANNER_PATTERNS, patternLayers); + components.put(DataComponentType.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE); + components.put(DataComponentType.ITEM_NAME, Component.text( + MinecraftLocale.getLocaleString("block.minecraft.ominous_banner", GeyserLocale.getDefaultLocale()) + ).style(Style.style(TextColor.color(16755200))) + ); } // Bedrock's creative inventory does not support other patterns as of 1.20.5 } 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 d10a20b3d..869917b4c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -579,6 +579,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final GeyserEntityData entityData; + @Getter private MinecraftProtocol protocol; public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop eventLoop) { 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 7ad2afec7..22fc72cf4 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 @@ -34,6 +34,7 @@ import lombok.Getter; import lombok.experimental.Accessors; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; +import org.cloudburstmc.protocol.common.util.Int2ObjectBiMap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; @@ -70,7 +71,7 @@ public final class RegistryCache { register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); - register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); + registerBannerRegistry(($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId())); } @@ -89,7 +90,7 @@ public final class RegistryCache { private final Int2ObjectMap trimMaterials = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap trimPatterns = new Int2ObjectOpenHashMap<>(); - private final Int2ObjectMap bannerPatterns = new Int2ObjectOpenHashMap<>(); + private Int2ObjectBiMap bannerPatterns = new Int2ObjectBiMap<>(); private final Int2ObjectMap wolfVariants = new Int2ObjectOpenHashMap<>(); public RegistryCache(GeyserSession session) { @@ -108,6 +109,20 @@ public final class RegistryCache { } } + private static void registerBannerRegistry(BiFunction reader) { + REGISTRIES.put("minecraft:banner_pattern", ((registryCache, entries) -> { + // Clear each local cache every time a new registry entry is given to us + // (e.g. proxy server switches) + registryCache.bannerPatterns = new Int2ObjectBiMap<>(); + for (int i = 0; i < entries.size(); i++) { + RegistryEntry entry = entries.get(i); + // This is what Geyser wants to keep as a value for this registry. + T cacheEntry = reader.apply(registryCache.session, entry); + registryCache.bannerPatterns.put(i, (BannerPattern) cacheEntry); + } + })); + } + /** * @param registry the Java registry resource location, without the "minecraft:" prefix. * @param localCacheFunction which local field in RegistryCache are we caching entries for this registry? From 28d5db622bbe60f583d7727de147949173b3d093 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 29 Apr 2024 23:41:14 +0200 Subject: [PATCH 100/897] revert bad change --- .../geyser/inventory/item/BannerPattern.java | 16 ++++++++-------- .../geysermc/geyser/item/type/BannerItem.java | 5 +++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java index ae225073a..442690d7d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java @@ -45,7 +45,7 @@ public enum BannerPattern { STRIPE_MIDDLE("ms"), STRIPE_DOWNRIGHT("drs"), STRIPE_DOWNLEFT("dls"), - STRIPE_SMALL("ss"), + SMALL_STRIPES("ss"), CROSS("cr"), STRAIGHT_CROSS("sc"), TRIANGLE_BOTTOM("bt"), @@ -53,15 +53,15 @@ public enum BannerPattern { TRIANGLES_BOTTOM("bts"), TRIANGLES_TOP("tts"), DIAGONAL_LEFT("ld"), - DIAGONAL_RIGHT("rd"), - DIAGONAL_LEFT_MIRROR("lud"), - DIAGONAL_RIGHT_MIRROR("rud"), - CIRCLE_MIDDLE("mc"), - RHOMBUS_MIDDLE("mr"), + DIAGONAL_UP_RIGHT("rd"), + DIAGONAL_UP_LEFT("lud"), + DIAGONAL_RIGHT("rud"), + CIRCLE("mc"), + RHOMBUS("mr"), HALF_VERTICAL("vh"), HALF_HORIZONTAL("hh"), - HALF_VERTICAL_MIRROR("vhr"), - HALF_HORIZONTAL_MIRROR("hhb"), + HALF_VERTICAL_RIGHT("vhr"), + HALF_HORIZONTAL_BOTTOM("hhb"), BORDER("bo"), CURLY_BORDER("cbo"), GRADIENT("gra"), diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 255e320a6..2f2d09669 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -64,13 +64,13 @@ public class BannerItem extends BlockItem { static { // Construct what an ominous banner is supposed to look like OMINOUS_BANNER_PATTERN = List.of( - Pair.of(BannerPattern.RHOMBUS_MIDDLE, DyeColor.CYAN), + Pair.of(BannerPattern.RHOMBUS, DyeColor.CYAN), Pair.of(BannerPattern.STRIPE_BOTTOM, DyeColor.LIGHT_GRAY), Pair.of(BannerPattern.STRIPE_CENTER, DyeColor.GRAY), Pair.of(BannerPattern.BORDER, DyeColor.LIGHT_GRAY), Pair.of(BannerPattern.STRIPE_MIDDLE, DyeColor.BLACK), Pair.of(BannerPattern.HALF_HORIZONTAL, DyeColor.LIGHT_GRAY), - Pair.of(BannerPattern.CIRCLE_MIDDLE, DyeColor.LIGHT_GRAY), + Pair.of(BannerPattern.CIRCLE, DyeColor.LIGHT_GRAY), Pair.of(BannerPattern.BORDER, DyeColor.BLACK) ); @@ -211,6 +211,7 @@ public class BannerItem extends BlockItem { List patternLayers = new ArrayList<>(); for (Pair pair : OMINOUS_BANNER_PATTERN) { patternLayers.add(new BannerPatternLayer(Holder.ofId(pair.left().ordinal()), pair.right().ordinal())); + System.out.println("adding: " + pair.left().getJavaIdentifier() + " " + pair.right().name()); } components.put(DataComponentType.BANNER_PATTERNS, patternLayers); From c963503fef83d17fe0286e665142b474120e8ded Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 30 Apr 2024 00:33:49 -0400 Subject: [PATCH 101/897] Entity scale attribute is now applied --- .../geyser/entity/EntityDefinitions.java | 2 +- .../entity/attribute/GeyserAttributeType.java | 1 + .../geyser/entity/type/LivingEntity.java | 36 +++++++++++++++++++ .../entity/type/living/AgeableEntity.java | 5 ++- .../entity/type/living/ArmorStandEntity.java | 10 +++--- .../entity/type/living/SlimeEntity.java | 5 ++- .../type/living/monster/GiantEntity.java | 7 ++-- .../type/living/monster/PhantomEntity.java | 3 +- .../type/living/monster/PiglinEntity.java | 3 +- .../type/living/monster/ZoglinEntity.java | 3 +- .../type/living/monster/ZombieEntity.java | 3 +- .../org/geysermc/geyser/util/MathUtils.java | 11 ------ 12 files changed, 56 insertions(+), 33 deletions(-) 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 fd0673062..ed2cda9b9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -673,7 +673,7 @@ public final class EntityDefinitions { SLIME = EntityDefinition.inherited(SlimeEntity::new, mobEntityBase) .type(EntityType.SLIME) .heightAndWidth(0.51f) - .addTranslator(MetadataType.INT, SlimeEntity::setScale) + .addTranslator(MetadataType.INT, SlimeEntity::setSlimeScale) .build(); MAGMA_CUBE = EntityDefinition.inherited(MagmaCubeEntity::new, SLIME) .type(EntityType.MAGMA_CUBE) diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index 88d493275..f19912a8c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -49,6 +49,7 @@ public enum GeyserAttributeType { ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f), ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f), MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f), + SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), // Unused. Do we need this? // Bedrock Attributes ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f), 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 58a3bf8e7..d27fa3cad 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 @@ -86,6 +86,19 @@ public class LivingEntity extends Entity { */ private boolean isMaxFrozenState = false; + /** + * The base scale entity data, without attributes applied. Used for such cases as baby variants. + */ + @Getter(AccessLevel.NONE) + @Setter(AccessLevel.NONE) + private float scale; + /** + * The scale sent through the Java attributes packet + */ + @Getter(AccessLevel.NONE) + @Setter(AccessLevel.NONE) + private float attributeScale; + public LivingEntity(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); } @@ -122,6 +135,9 @@ public class LivingEntity extends Entity { @Override protected void initializeMetadata() { + // Initialize here so overriding classes don't have 0 values + this.scale = 1f; + this.attributeScale = 1f; super.initializeMetadata(); // Matches Bedrock behavior; is always set to this dirtyMetadata.put(EntityDataTypes.STRUCTURAL_INTEGRITY, 1); @@ -230,6 +246,21 @@ public class LivingEntity extends Entity { return freezingPercentage; } + protected void setScale(float scale) { + this.scale = scale; + applyScale(); + } + + private void setAttributeScale(float scale) { + this.attributeScale = scale; + applyScale(); + } + + private void applyScale() { + // Take any adjustments Bedrock requires, and compute it alongside the attribute's additional changes + this.dirtyMetadata.put(EntityDataTypes.SCALE, scale * attributeScale); + } + /** * @return a Bedrock health attribute constructed from the data sent from the server */ @@ -366,6 +397,11 @@ public class LivingEntity extends Entity { 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 -> { + // 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/AgeableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java index 5b1d682ce..8f84e051b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.entity.type.living; 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.session.GeyserSession; @@ -44,12 +43,12 @@ public class AgeableEntity extends CreatureEntity { protected void initializeMetadata() { super.initializeMetadata(); // Required as of 1.19.3 Java - dirtyMetadata.put(EntityDataTypes.SCALE, getAdultSize()); + setScale(getAdultSize()); } public void setBaby(BooleanEntityMetadata entityMetadata) { boolean isBaby = entityMetadata.getPrimitiveValue(); - dirtyMetadata.put(EntityDataTypes.SCALE, isBaby ? getBabySize() : getAdultSize()); + setScale(isBaby ? getBabySize() : getAdultSize()); setFlag(EntityFlag.BABY, isBaby); setBoundingBoxHeight(definition.height() * (isBaby ? getBabySize() : getAdultSize())); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index fce51e741..d057f09c7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -311,7 +311,7 @@ public class ArmorStandEntity extends LivingEntity { if (!isInvisible) { // The armor stand isn't invisible. We good. setFlag(EntityFlag.INVISIBLE, false); - dirtyMetadata.put(EntityDataTypes.SCALE, getScale()); + setScale(getScale()); updateOffsetRequirement(false); if (secondEntity != null) { @@ -327,7 +327,7 @@ public class ArmorStandEntity extends LivingEntity { if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR) || !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offhand.equals(ItemData.AIR))) { // Reset scale of the proper armor stand - this.dirtyMetadata.put(EntityDataTypes.SCALE, getScale()); + setScale(getScale()); // Set the proper armor stand to invisible to show armor setFlag(EntityFlag.INVISIBLE, true); // Update the position of the armor stand @@ -350,7 +350,7 @@ public class ArmorStandEntity extends LivingEntity { // Guarantee this copy is NOT invisible secondEntity.setFlag(EntityFlag.INVISIBLE, false); // Scale to 0 to show nametag - secondEntity.getDirtyMetadata().put(EntityDataTypes.SCALE, 0.0f); + secondEntity.setScale(0f); // No bounding box as we don't want to interact with this entity secondEntity.getDirtyMetadata().put(EntityDataTypes.WIDTH, 0.0f); secondEntity.getDirtyMetadata().put(EntityDataTypes.HEIGHT, 0.0f); @@ -360,7 +360,7 @@ public class ArmorStandEntity extends LivingEntity { } else if (isNametagEmpty) { // We can just make an invisible entity // Reset scale of the proper armor stand - dirtyMetadata.put(EntityDataTypes.SCALE, getScale()); + setScale(getScale()); // Set the proper armor stand to invisible to show armor setFlag(EntityFlag.INVISIBLE, true); // Update offset @@ -374,7 +374,7 @@ public class ArmorStandEntity extends LivingEntity { // Nametag is not empty and there is no armor // We don't need to make a new entity setFlag(EntityFlag.INVISIBLE, false); - dirtyMetadata.put(EntityDataTypes.SCALE, 0.0f); + setScale(0f); // As the above is applied, we need an offset updateOffsetRequirement(!isMarker); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java index 50095fe3f..3be2db1db 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.entity.type.living; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; @@ -39,8 +38,8 @@ public class SlimeEntity extends MobEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - public void setScale(IntEntityMetadata entityMetadata) { - dirtyMetadata.put(EntityDataTypes.SCALE, 0.10f + entityMetadata.getPrimitiveValue()); + public void setSlimeScale(IntEntityMetadata entityMetadata) { + setScale(0.10f + entityMetadata.getPrimitiveValue()); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java index e98c8f120..6bef3ae3e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.entity.type.living.monster; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; @@ -36,7 +35,11 @@ public class GiantEntity extends MonsterEntity { public GiantEntity(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); + } - dirtyMetadata.put(EntityDataTypes.SCALE, 6f); + @Override + protected void initializeMetadata() { + super.initializeMetadata(); + setScale(6f); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java index cb4b7a8cf..18b7f6ae1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.entity.type.living.monster; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.FlyingEntity; import org.geysermc.geyser.session.GeyserSession; @@ -46,7 +45,7 @@ public class PhantomEntity extends FlyingEntity { setBoundingBoxWidth(boundsScale * definition.width()); setBoundingBoxHeight(boundsScale * definition.height()); - dirtyMetadata.put(EntityDataTypes.SCALE, modelScale); + setScale(modelScale); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java index 9c43ab23a..f0f01272f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.entity.type.living.monster; import org.checkerframework.checker.nullness.qual.NonNull; 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.inventory.GeyserItemStack; @@ -49,7 +48,7 @@ public class PiglinEntity extends BasePiglinEntity { public void setBaby(BooleanEntityMetadata entityMetadata) { boolean isBaby = entityMetadata.getPrimitiveValue(); - dirtyMetadata.put(EntityDataTypes.SCALE, isBaby? .55f : 1f); + setScale(isBaby? .55f : 1f); setFlag(EntityFlag.BABY, isBaby); updateMountOffset(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java index efbb7753c..7eb950e21 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.entity.type.living.monster; 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.session.GeyserSession; @@ -43,7 +42,7 @@ public class ZoglinEntity extends MonsterEntity { public void setBaby(BooleanEntityMetadata entityMetadata) { boolean isBaby = entityMetadata.getPrimitiveValue(); if (isBaby != getFlag(EntityFlag.BABY)) { - dirtyMetadata.put(EntityDataTypes.SCALE, isBaby ? .55f : 1f); + setScale(isBaby ? .55f : 1f); setFlag(EntityFlag.BABY, isBaby); updatePassengerOffsets(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java index 11354fbf8..b8351089d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.entity.type.living.monster; 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.session.GeyserSession; @@ -43,7 +42,7 @@ public class ZombieEntity extends MonsterEntity { public void setZombieBaby(BooleanEntityMetadata entityMetadata) { boolean isBaby = entityMetadata.getPrimitiveValue(); - dirtyMetadata.put(EntityDataTypes.SCALE, isBaby ? .55f : 1.0f); + setScale(isBaby ? .55f : 1.0f); setFlag(EntityFlag.BABY, isBaby); updateMountOffset(); diff --git a/core/src/main/java/org/geysermc/geyser/util/MathUtils.java b/core/src/main/java/org/geysermc/geyser/util/MathUtils.java index 32f8b7ef5..08bed56f4 100644 --- a/core/src/main/java/org/geysermc/geyser/util/MathUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/MathUtils.java @@ -168,17 +168,6 @@ public class MathUtils { return value; } - /** - * Ensures the resulting object is a byte. Java Edition does not care whether a byte is encoded as an integer or not; - * it converts it into a byte anyway. - * - * @param value The value to convert - * @return The converted byte - */ - public static byte getNbtByte(Object value) { - return ((Number) value).byteValue(); - } - /** * Packs a chunk's X and Z coordinates into a single {@code long}. * From dacacc6df8ce009f74bca901196bc69c0cf7c5ca Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 30 Apr 2024 04:45:07 -0400 Subject: [PATCH 102/897] Anvil renaming --- .../org/geysermc/geyser/inventory/AnvilContainer.java | 8 ++++---- .../inventory/updater/AnvilInventoryUpdater.java | 3 +-- .../geyser/translator/text/MessageTranslator.java | 10 +++++++--- gradle/libs.versions.toml | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index e6332bc41..88838d068 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.inventory; +import net.kyori.adventure.text.Component; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import lombok.Getter; @@ -72,10 +73,9 @@ public class AnvilContainer extends Container { String correctRename; newName = rename; - // TODO 1.20.5 fix properly - this name is apparently nullable?? - String originalName = MessageTranslator.convertMessage(ItemUtils.getCustomName(getInput().getComponents())); + Component originalName = ItemUtils.getCustomName(getInput().getComponents()); - String plainOriginalName = MessageTranslator.convertToPlainTextLenient(originalName, session.locale()); + String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.locale()); String plainNewName = MessageTranslator.convertToPlainText(rename); if (!plainOriginalName.equals(plainNewName)) { // Strip out formatting since Java Edition does not allow it @@ -85,7 +85,7 @@ public class AnvilContainer extends Container { session.sendDownstreamGamePacket(renameItemPacket); } else { // Restore formatting for item since we're not renaming - correctRename = MessageTranslator.convertMessageLenient(originalName); + correctRename = MessageTranslator.convertMessage(originalName, session.locale()); // Java Edition sends the original custom name when not renaming, // if there isn't a custom name an empty string is sent ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainOriginalName); 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 1021a5fb9..42924435e 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 @@ -118,8 +118,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // Changing the item in the input slot resets the name field on Bedrock, but // does not result in a FilterTextPacket - // TODO test - String originalName = MessageTranslator.convertToPlainText(ItemUtils.getCustomName(input.getComponents())); + String originalName = MessageTranslator.convertToPlainText(ItemUtils.getCustomName(input.getComponents()), session.locale()); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName); session.sendDownstreamGamePacket(renameItemPacket); 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 3f1c902c7..884f05256 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 @@ -260,13 +260,17 @@ public class MessageTranslator { } /** - * Convert legacy format message to plain text + * Convert a Java message to plain text * * @param message Message to convert + * @param locale Locale to use for translation strings * @return The plain text of the message */ - public static String convertToPlainText(Component message) { - return PlainTextComponentSerializer.plainText().serialize(message); + public static String convertToPlainText(Component message, String locale) { + if (message == null) { + return ""; + } + return PlainTextComponentSerializer.plainText().serialize(RENDERER.render(message, locale)); } /** diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c16b883b..ab607495a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "400f1b4" # Revert from jitpack after release +mcprotocollib = "bc8526b" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 74d6a37261c4516eab154f5622204b619156f609 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 30 Apr 2024 05:13:00 -0400 Subject: [PATCH 103/897] Fix bug when adding enchantments in anvil --- .../geyser/inventory/updater/AnvilInventoryUpdater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 42924435e..d6a0d922b 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 @@ -387,7 +387,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } return enchantments; } - return Object2IntMaps.emptyMap(); + return new Object2IntOpenHashMap<>(); } private boolean isEnchantedBook(GeyserItemStack itemStack) { From ff9965f5590c9c93bb1d01377de139f8ac1c490f Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 30 Apr 2024 05:49:22 -0400 Subject: [PATCH 104/897] Translate item repair cost component --- core/src/main/java/org/geysermc/geyser/item/type/Item.java | 5 +++++ 1 file changed, 5 insertions(+) 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 8fcb19ad5..cc49f3785 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 @@ -146,6 +146,11 @@ public class Item { if (!enchantNbtList.isEmpty()) { builder.putList("ench", NbtType.COMPOUND, enchantNbtList); } + + Integer repairCost = components.get(DataComponentType.REPAIR_COST); + if (repairCost != null) { + builder.putInt("RepairCost", repairCost); + } } /** From dd745b901f7826a3ef85ab7a2f0ea4f6e575e9b2 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 30 Apr 2024 20:48:10 +0200 Subject: [PATCH 105/897] move to paper-adapters --- bootstrap/spigot/build.gradle.kts | 9 +++++++ .../platform/spigot/GeyserSpigotPlugin.java | 24 ++++++++++++++----- .../GeyserSpigotLegacyNativeWorldManager.java | 4 ++-- .../GeyserSpigotNativeWorldManager.java | 14 +++++++---- gradle/libs.versions.toml | 3 ++- 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 1d135c33d..8143d96a1 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -7,6 +7,9 @@ dependencies { implementation(variantOf(libs.adapters.spigot) { classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations }) + implementation(variantOf(libs.adapters.paper) { + classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations + }) implementation(libs.commodore) @@ -34,6 +37,12 @@ application { } tasks.withType { + + // Prevents Paper 1.20.5+ from remapping Geyser + manifest { + attributes["paperweight-mappings-namespace"] = "mojang" + } + archiveBaseName.set("Geyser-Spigot") dependencies { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 1170ce678..e33de5f9b 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -46,6 +46,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.adapters.paper.PaperAdapters; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.extension.Extension; @@ -244,16 +245,27 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { if (Boolean.parseBoolean(System.getProperty("Geyser.UseDirectAdapters", "true"))) { try { - String version = Bukkit.getBukkitVersion().split("-")[0]; - String nmsVersion = "v" + version.replace(".", "_"); - SpigotAdapters.registerWorldAdapter(nmsVersion); + boolean isPaper = false; + try { + String name = Bukkit.getServer().getClass().getPackage().getName(); + String nmsVersion = name.substring(name.lastIndexOf('.') + 1); + SpigotAdapters.registerWorldAdapter(nmsVersion); + geyserLogger.debug("Using spigot NMS adapter for nms version: " + nmsVersion); + } catch (Exception e) { // Likely running on Paper 1.20.5+ + //noinspection deprecation + int protocolVersion = Bukkit.getUnsafe().getProtocolVersion(); + PaperAdapters.registerClosestWorldAdapter(protocolVersion); + isPaper = true; + geyserLogger.debug("Using paper world adapter for protocol version: " + protocolVersion); + } + if (isViaVersion && isViaVersionNeeded()) { - this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this); + this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, isPaper); } else { // No ViaVersion - this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this); + this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, isPaper); } - geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion); + geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName()); } catch (Exception e) { if (geyserConfig.isDebugMode()) { geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)"); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java index 021db5ec1..5d226e19e 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java @@ -46,8 +46,8 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl private final Int2IntMap oldToNewBlockId; - public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin) { - super(plugin); + public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean isPaper) { + super(plugin, isPaper); IntList allBlockStates = adapter.getAllBlockStates(); oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size()); ProtocolVersion serverVersion = plugin.getServerProtocolVersion(); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java index 00212663c..45e84d254 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java @@ -26,20 +26,26 @@ package org.geysermc.geyser.platform.spigot.world.manager; import org.bukkit.Bukkit; +import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.adapters.WorldAdapter; +import org.geysermc.geyser.adapters.paper.PaperAdapters; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; -import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { - protected final SpigotWorldAdapter adapter; + protected final WorldAdapter adapter; - public GeyserSpigotNativeWorldManager(Plugin plugin) { + public GeyserSpigotNativeWorldManager(Plugin plugin, boolean isPaper) { super(plugin); - adapter = SpigotAdapters.getWorldAdapter(); + if (isPaper) { + adapter = PaperAdapters.getWorldAdapter(); + } else { + adapter = SpigotAdapters.getWorldAdapter(); + } } @Override diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c16b883b..6a88f0b0f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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.11-SNAPSHOT" +adapters = "1.12-SNAPSHOT" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.1.1" @@ -100,6 +100,7 @@ fabric-permissions = { group = "me.lucko", name = "fabric-permissions-api", vers neoforge-minecraft = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge-minecraft" } adapters-spigot = { group = "org.geysermc.geyser.adapters", name = "spigot-all", version.ref = "adapters" } +adapters-paper = { group = "org.geysermc.geyser.adapters", name = "paper-all", version.ref = "adapters" } bungeecord-proxy = { group = "com.github.SpigotMC.BungeeCord", name = "bungeecord-proxy", version.ref = "bungeecord" } checker-qual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerframework" } commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" } From d99f49890100c5aa891d694a3c7619dc92520401 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 30 Apr 2024 21:35:21 +0200 Subject: [PATCH 106/897] translate ominous banners --- .../geysermc/geyser/item/type/BannerItem.java | 16 ++++++++-------- .../geyser/session/cache/RegistryCache.java | 9 +++++++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 2f2d09669..2f5d96b5a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -38,8 +38,6 @@ import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.item.DyeColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; @@ -61,6 +59,9 @@ public class BannerItem extends BlockItem { private static final List> OMINOUS_BANNER_PATTERN; private static final List OMINOUS_BANNER_PATTERN_BLOCK; + // TODO fix - we somehow need to be able to get the sessions banner pattern registry, which we don't have where we need this :/ + private static final int[] ominousBannerPattern = new int[] { 21, 29, 30, 1, 34, 15, 3, 1 }; + static { // Construct what an ominous banner is supposed to look like OMINOUS_BANNER_PATTERN = List.of( @@ -209,16 +210,15 @@ public class BannerItem extends BlockItem { if (bedrockTag.getInt("Type") == 1) { // Ominous banner pattern List patternLayers = new ArrayList<>(); - for (Pair pair : OMINOUS_BANNER_PATTERN) { - patternLayers.add(new BannerPatternLayer(Holder.ofId(pair.left().ordinal()), pair.right().ordinal())); - System.out.println("adding: " + pair.left().getJavaIdentifier() + " " + pair.right().name()); + for (int i = 0; i < ominousBannerPattern.length; i++) { + patternLayers.add(new BannerPatternLayer(Holder.ofId(ominousBannerPattern[i]), OMINOUS_BANNER_PATTERN.get(i).right().ordinal())); } components.put(DataComponentType.BANNER_PATTERNS, patternLayers); components.put(DataComponentType.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE); - components.put(DataComponentType.ITEM_NAME, Component.text( - MinecraftLocale.getLocaleString("block.minecraft.ominous_banner", GeyserLocale.getDefaultLocale()) - ).style(Style.style(TextColor.color(16755200))) + components.put(DataComponentType.ITEM_NAME, Component + .translatable("block.minecraft.ominous_banner") // thank god this works + .style(Style.style(TextColor.color(16755200))) ); } // Bedrock's creative inventory does not support other patterns as of 1.20.5 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 22fc72cf4..4dfc603ee 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 @@ -113,12 +113,17 @@ public final class RegistryCache { REGISTRIES.put("minecraft:banner_pattern", ((registryCache, entries) -> { // Clear each local cache every time a new registry entry is given to us // (e.g. proxy server switches) - registryCache.bannerPatterns = new Int2ObjectBiMap<>(); + registryCache.bannerPatterns = new Int2ObjectBiMap<>(); // Cannot clear it, must re-create :( for (int i = 0; i < entries.size(); i++) { RegistryEntry entry = entries.get(i); // This is what Geyser wants to keep as a value for this registry. T cacheEntry = reader.apply(registryCache.session, entry); - registryCache.bannerPatterns.put(i, (BannerPattern) cacheEntry); + if (cacheEntry != null) { + registryCache.bannerPatterns.put(i, (BannerPattern) cacheEntry); + } else { + // TODO - seems to be possible with viaversion :/ + GeyserImpl.getInstance().getLogger().warning("Was not able to translate entry: "); + } } })); } From 4a0a694eb9c6789c19ee724d55a132c8668993d7 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 30 Apr 2024 21:38:25 +0200 Subject: [PATCH 107/897] revert bad diff --- .../src/main/java/org/geysermc/geyser/session/GeyserSession.java | 1 - 1 file changed, 1 deletion(-) 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 869917b4c..d10a20b3d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -579,7 +579,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final GeyserEntityData entityData; - @Getter private MinecraftProtocol protocol; public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop eventLoop) { From 255835438d7392f466b84841d7aedb6cfc3146be Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 30 Apr 2024 21:59:38 +0200 Subject: [PATCH 108/897] viaversion 4.10.0 compat, indicate 1.20.6 support on modrinth --- .../world/manager/GeyserSpigotLegacyNativeWorldManager.java | 2 +- .../src/main/kotlin/geyser.modded-conventions.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java index 5d226e19e..fe2dda053 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java @@ -58,7 +58,7 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl int newBlockId = oldBlockId; // protocolList should *not* be null; we checked for that before initializing this class for (int i = protocolList.size() - 1; i >= 0; i--) { - MappingData mappingData = protocolList.get(i).getProtocol().getMappingData(); + MappingData mappingData = protocolList.get(i).protocol().getMappingData(); if (mappingData != null) { newBlockId = mappingData.getNewBlockStateId(newBlockId); } diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index afea247a7..b75e9c5be 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -134,6 +134,6 @@ modrinth { syncBodyFrom.set(rootProject.file("README.md").readText()) uploadFile.set(tasks.getByPath("remapModrinthJar")) - gameVersions.addAll("1.20.5") + gameVersions.addAll("1.20.5", "1.20.6") failSilently.set(true) } \ No newline at end of file From aff7d2cf35d5e8799b59fca67d781b31e8e19a96 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 30 Apr 2024 18:05:46 -0400 Subject: [PATCH 109/897] Fix potential NPE --- .../main/java/org/geysermc/geyser/inventory/AnvilContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 88838d068..45a062468 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -85,7 +85,7 @@ public class AnvilContainer extends Container { session.sendDownstreamGamePacket(renameItemPacket); } else { // Restore formatting for item since we're not renaming - correctRename = MessageTranslator.convertMessage(originalName, session.locale()); + correctRename = originalName != null ? MessageTranslator.convertMessage(originalName, session.locale()) : ""; // Java Edition sends the original custom name when not renaming, // if there isn't a custom name an empty string is sent ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainOriginalName); From 59a2c0dc02abacd00fe3a72788cc9317c891557e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:35:52 -0400 Subject: [PATCH 110/897] Use item tags for all animal loved food --- .../geyser/entity/EntityDefinitions.java | 2 +- .../entity/type/living/TadpoleEntity.java | 4 +-- .../type/living/animal/AnimalEntity.java | 21 ++++++++-------- .../type/living/animal/ArmadilloEntity.java | 8 ++++++ .../type/living/animal/AxolotlEntity.java | 7 +++--- .../entity/type/living/animal/BeeEntity.java | 7 +++--- .../type/living/animal/ChickenEntity.java | 11 ++++---- .../entity/type/living/animal/CowEntity.java | 8 ++++++ .../entity/type/living/animal/FoxEntity.java | 7 +++--- .../entity/type/living/animal/FrogEntity.java | 9 ++++--- .../entity/type/living/animal/GoatEntity.java | 8 ++++++ .../type/living/animal/HoglinEntity.java | 9 ++++--- .../type/living/animal/MooshroomEntity.java | 2 +- .../type/living/animal/OcelotEntity.java | 9 ++++--- .../type/living/animal/PandaEntity.java | 8 +++--- .../entity/type/living/animal/PigEntity.java | 9 ++++--- .../type/living/animal/PolarBearEntity.java | 8 +++--- .../type/living/animal/RabbitEntity.java | 9 ++++--- .../type/living/animal/SheepEntity.java | 8 ++++++ .../type/living/animal/SnifferEntity.java | 7 +++--- .../type/living/animal/StriderEntity.java | 9 ++++--- .../type/living/animal/TurtleEntity.java | 9 ++++--- .../animal/horse/AbstractHorseEntity.java | 15 ++++------- .../type/living/animal/horse/CamelEntity.java | 8 +++--- .../type/living/animal/horse/LlamaEntity.java | 8 +++--- .../living/animal/tameable/CatEntity.java | 8 +++--- .../living/animal/tameable/ParrotEntity.java | 11 +++++--- .../animal/tameable/TameableEntity.java | 2 +- .../living/animal/tameable/WolfEntity.java | 7 +++--- .../geyser/item/type/FireworkRocketItem.java | 2 +- .../geyser/session/cache/tags/ItemTag.java | 25 +++++++++++++++++-- .../translator/item/ItemTranslator.java | 20 +++++++-------- 32 files changed, 174 insertions(+), 111 deletions(-) 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 ed2cda9b9..6cd5f3fc2 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -964,7 +964,7 @@ public final class EntityDefinitions { .build(); } - EntityDefinition tameableEntityBase = EntityDefinition.inherited(TameableEntity::new, ageableEntityBase) + EntityDefinition tameableEntityBase = EntityDefinition.inherited(null, ageableEntityBase) // No factory, is abstract .addTranslator(MetadataType.BYTE, TameableEntity::setTameableFlags) .addTranslator(MetadataType.OPTIONAL_UUID, TameableEntity::setOwner) .build(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java index 4fdaa1059..68cf763c3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java @@ -29,8 +29,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -62,6 +62,6 @@ public class TadpoleEntity extends AbstractFishEntity { } private boolean isFood(GeyserItemStack itemStack) { - return itemStack.asItem() == Items.SLIME_BALL; + return session.getTagCache().is(ItemTag.FROG_FOOD, itemStack); } } 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 bf23a5418..2e627b461 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 @@ -26,38 +26,39 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; 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.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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class AnimalEntity extends AgeableEntity { +public abstract class AnimalEntity extends AgeableEntity { public AnimalEntity(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 final boolean canEat(GeyserItemStack itemStack) { - return canEat(itemStack.asItem()); + protected final boolean canEat(GeyserItemStack itemStack) { + ItemTag tag = getFoodTag(); + if (tag == null) { + return false; + } + return session.getTagCache().is(tag, itemStack); } /** - * @return true if this is a valid item to breed with for this animal. + * @return the tag associated with this animal for eating food. Null for nothing or different behavior. */ - public boolean canEat(Item item) { - // This is what it defaults to. OK. - return item == Items.WHEAT; - } + protected abstract @Nullable ItemTag 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 51fe09383..968520bb6 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 @@ -25,9 +25,11 @@ 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.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.ArmadilloState; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; @@ -70,4 +72,10 @@ public class ArmadilloEntity extends AnimalEntity { }, 250, TimeUnit.MILLISECONDS); } } + + @Override + @Nullable + protected ItemTag 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 37cd5f1e6..a87b1dd5e 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 @@ -26,12 +26,12 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; 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.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.util.EntityUtils; @@ -61,8 +61,9 @@ public class AxolotlEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return session.getTagCache().is(ItemTag.AXOLOTL_FOOD, item); + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.AXOLOTL_FOOD; } @Override 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 28ebad473..4fcf0e178 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 @@ -25,13 +25,13 @@ package org.geysermc.geyser.entity.type.living.animal; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; 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.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -68,7 +68,8 @@ public class BeeEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return session.getTagCache().is(ItemTag.FLOWERS, item); + @Nullable + protected ItemTag 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 164fb1b6c..075a49923 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 @@ -25,24 +25,23 @@ 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.Items; -import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; -import java.util.Set; import java.util.UUID; public class ChickenEntity extends AnimalEntity { - private static final Set VALID_FOOD = Set.of(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS); public ChickenEntity(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 canEat(Item item) { - return VALID_FOOD.contains(item); + @Nullable + protected ItemTag 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 d542cb46f..64e7de193 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -33,6 +34,7 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -64,4 +66,10 @@ public class CowEntity extends AnimalEntity { session.playSoundEvent(SoundEvent.MILK, position); return InteractionResult.SUCCESS; } + + @Override + @Nullable + protected ItemTag 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 18e346b98..e20031baa 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 @@ -25,11 +25,11 @@ package org.geysermc.geyser.entity.type.living.animal; +import org.checkerframework.checker.nullness.qual.Nullable; 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.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -56,7 +56,8 @@ public class FoxEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return session.getTagCache().is(ItemTag.FOX_FOOD, item); + @Nullable + protected ItemTag 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 ed21a9609..120bfcdd4 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 @@ -25,14 +25,14 @@ package org.geysermc.geyser.entity.type.living.animal; +import org.checkerframework.checker.nullness.qual.Nullable; 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.entity.type.Entity; -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.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; @@ -76,7 +76,8 @@ public class FrogEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return item == Items.SLIME_BALL; + @Nullable + protected ItemTag 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 7cbbd4433..4e919b81c 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -34,6 +35,7 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; 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; @@ -94,4 +96,10 @@ public class GoatEntity extends AnimalEntity { private void setHornCount() { dirtyMetadata.put(EntityDataTypes.GOAT_HORN_COUNT, (hasLeftHorn ? 1 : 0) + (hasRightHorn ? 1 : 0)); } + + @Override + @Nullable + protected ItemTag 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 29d1839c7..46cafad02 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 @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living.animal; +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.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.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; @@ -54,8 +54,9 @@ public class HoglinEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return item == Items.CRIMSON_FUNGUS; + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.HOGLIN_FOOD; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 55c3c406f..2c9040b53 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -40,7 +40,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class MooshroomEntity extends AnimalEntity { +public class MooshroomEntity extends CowEntity { private boolean isBrown = false; public MooshroomEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { 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 8a3dd6c72..9d6d33227 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 @@ -26,13 +26,13 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; +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.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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -46,8 +46,9 @@ public class OcelotEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return item == Items.COD || item == Items.SALMON; + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.OCELOT_FOOD; } @NonNull 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 df72fdc63..595e79e32 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,9 +34,8 @@ 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.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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -89,8 +88,9 @@ public class PandaEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return item == Items.BAMBOO; + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.PANDA_FOOD; } @NonNull 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 4dbf3064a..446e3e109 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 @@ -26,13 +26,13 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; +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.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.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -47,8 +47,9 @@ public class PigEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return item == Items.CARROT || item == Items.POTATO || item == Items.BEETROOT; + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.PIG_FOOD; } @NonNull 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 1d7777cdb..0e83615f7 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 @@ -25,10 +25,11 @@ 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 java.util.UUID; @@ -39,7 +40,8 @@ public class PolarBearEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return false; + @Nullable + protected ItemTag 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 09db7257b..0a108be73 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 @@ -25,13 +25,13 @@ package org.geysermc.geyser.entity.type.living.animal; +import org.checkerframework.checker.nullness.qual.Nullable; 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.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.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; @@ -67,7 +67,8 @@ public class RabbitEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return item == Items.DANDELION || item == Items.CARROT || item == Items.GOLDEN_CARROT; + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.RABBIT_FOOD; } } \ No newline at end of file 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 e87186bf6..155ddf00c 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -34,6 +35,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -55,6 +57,12 @@ public class SheepEntity extends AnimalEntity { dirtyMetadata.put(EntityDataTypes.COLOR, (byte) color); } + @Override + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.SHEEP_FOOD; + } + @NonNull @Override protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { 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 35b2b4183..11fee5bbf 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; @@ -34,7 +35,6 @@ 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.mcprotocollib.protocol.data.game.entity.metadata.Pose; @@ -72,8 +72,9 @@ public class SnifferEntity extends AnimalEntity implements Tickable { } @Override - public boolean canEat(Item item) { - return session.getTagCache().is(ItemTag.SNIFFER_FOOD, item); + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.SNIFFER_FOOD; } public void setSnifferState(ObjectEntityMetadata entityMetadata) { 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 dcdd40199..0291f75d9 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 @@ -26,14 +26,14 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; +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.entity.type.Entity; 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.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -94,8 +94,9 @@ public class StriderEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return item == Items.WARPED_FUNGUS; + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.STRIDER_FOOD; } @NonNull 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 1d0aec75f..b3c1128e3 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 @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living.animal; +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.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.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; @@ -50,8 +50,9 @@ public class TurtleEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return item == Items.SEAGRASS; + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.TURTLE_FOOD; } @Override 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 76416c146..ddc212053 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.animal.horse; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; @@ -38,23 +39,16 @@ 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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import java.util.Set; import java.util.UUID; public class AbstractHorseEntity extends AnimalEntity { - /** - * A list of all foods a horse/donkey can eat on Java Edition. - * Used to display interactive tag if needed. - */ - private static final Set DONKEY_AND_HORSE_FOODS = Set.of(Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE, - Items.GOLDEN_CARROT, Items.SUGAR, Items.APPLE, Items.WHEAT, Items.HAY_BLOCK); public AbstractHorseEntity(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); @@ -124,8 +118,9 @@ public class AbstractHorseEntity extends AnimalEntity { } @Override - public boolean canEat(Item item) { - return DONKEY_AND_HORSE_FOODS.contains(item); + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.HORSE_FOOD; } @NonNull 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 00144617a..ee3b2be70 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal.horse; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; @@ -32,9 +33,8 @@ 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.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.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -90,8 +90,8 @@ public class CamelEntity extends AbstractHorseEntity { } @Override - public boolean canEat(Item item) { - return item == Items.CACTUS; + protected @Nullable ItemTag getFoodTag() { + return ItemTag.CAMEL_FOOD; } @Override 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 346b6da9b..76939ceb9 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 @@ -26,12 +26,12 @@ package org.geysermc.geyser.entity.type.living.animal.horse; import lombok.Getter; +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.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.util.MathUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; @@ -56,7 +56,7 @@ public class LlamaEntity extends ChestedHorseEntity { } @Override - public boolean canEat(Item item) { - return item == Items.WHEAT || item == Items.HAY_BLOCK; + protected @Nullable ItemTag 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 fc5978c2b..bf1555e9d 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 @@ -26,14 +26,14 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; 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.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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -109,8 +109,8 @@ public class CatEntity extends TameableEntity { } @Override - public boolean canEat(Item item) { - return item == Items.COD || item == Items.SALMON; + protected @Nullable ItemTag getFoodTag() { + return ItemTag.CAT_FOOD; } @NonNull 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 18feec979..8baba6f00 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; import org.checkerframework.checker.nullness.qual.NonNull; +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; @@ -33,6 +34,7 @@ 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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -49,16 +51,17 @@ public class ParrotEntity extends TameableEntity { } @Override - public boolean canEat(Item item) { - return false; + @Nullable + protected ItemTag getFoodTag() { + return null; } private boolean isTameFood(Item item) { - return TAMING_FOOD.contains(item); + return session.getTagCache().is(ItemTag.PARROT_FOOD, item); } private boolean isPoisonousFood(Item item) { - return item == Items.COOKIE; + return session.getTagCache().is(ItemTag.PARROT_POISONOUS_FOOD, item); } @NonNull diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java index 4a1cd70e9..e16823d37 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java @@ -39,7 +39,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEn import java.util.Optional; import java.util.UUID; -public class TameableEntity extends AnimalEntity { +public abstract class TameableEntity extends AnimalEntity { /** * Used in the interactive tag manager to track if the session player owns this entity */ 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 833d0e175..ceb29695a 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 @@ -38,6 +38,7 @@ 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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.ItemUtils; @@ -120,9 +121,9 @@ public class WolfEntity extends TameableEntity { } @Override - public boolean canEat(Item item) { - // Cannot be a baby to eat these foods - return WOLF_FOODS.contains(item) && !isBaby(); + @Nullable + protected ItemTag getFoodTag() { + return ItemTag.WOLF_FOOD; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index bba13e753..c70467b4c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -115,7 +115,7 @@ public class FireworkRocketItem extends Item { newExplosionData.putByteArray("FireworkFade", colors); newExplosionData.putBoolean("FireworkTrail", explosion.isHasTrail()); - newExplosionData.putBoolean("FireworkFlicker", explosion.isHasTwinkle()); // TODO verify + newExplosionData.putBoolean("FireworkFlicker", explosion.isHasTwinkle()); return newExplosionData.build(); } 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 df9a423ed..f064d0763 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 @@ -31,11 +31,32 @@ public enum ItemTag { AXOLOTL_FOOD("axolotl_food"), CREEPER_IGNITERS("creeper_igniters"), FISHES("fishes"), - FLOWERS("flowers"), FOX_FOOD("fox_food"), PIGLIN_LOVED("piglin_loved"), SMALL_FLOWERS("small_flowers"), - SNIFFER_FOOD("sniffer_food"); + SNIFFER_FOOD("sniffer_food"), + PIGLIN_FOOD("piglin_food"), + COW_FOOD("cow_food"), + GOAT_FOOD("goat_food"), + SHEEP_FOOD("sheep_food"), + WOLF_FOOD("wolf_food"), + CAT_FOOD("cat_food"), + HORSE_FOOD("horse_food"), + CAMEL_FOOD("camel_food"), + ARMADILLO_FOOD("armadillo_food"), + BEE_FOOD("bee_food"), + CHICKEN_FOOD("chicken_food"), + FROG_FOOD("frog_food"), + HOGLIN_FOOD("hoglin_food"), + LLAMA_FOOD("llama_food"), + OCELOT_FOOD("ocelot_food"), + PANDA_FOOD("panda_food"), + PIG_FOOD("pig_food"), + RABBIT_FOOD("rabbit_food"), + STRIDER_FOOD("strider_food"), + TURTLE_FOOD("turtle_food"), + PARROT_FOOD("parrot_food"), + PARROT_POISONOUS_FOOD("parrot_poisonous_food"); ItemTag(String identifier) { register(identifier, this); 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 11e092b57..49ee498b9 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 @@ -249,19 +249,17 @@ public final class ItemTranslator { String name = modifier.getName().replace("minecraft:", ""); // the namespace does not need to be present, but if it is, the java client ignores it as of pre-1.20.5 - String operationTotal; ModifierOperation operation = modifier.getOperation(); - if (operation == ModifierOperation.ADD) { - if (name.equals("generic.knockback_resistance")) { - amount *= 10; + String operationTotal = switch (operation) { + case ADD -> { + if (name.equals("generic.knockback_resistance")) { + amount *= 10; + } + yield ATTRIBUTE_FORMAT.format(amount); } - operationTotal = ATTRIBUTE_FORMAT.format(amount); - } else if (operation == ModifierOperation.ADD_MULTIPLIED_BASE || operation == ModifierOperation.ADD_MULTIPLIED_TOTAL) { - operationTotal = ATTRIBUTE_FORMAT.format(amount * 100) + "%"; - } else { - GeyserImpl.getInstance().getLogger().warning("Unhandled ModifierOperation while adding item attributes: " + operation); - return null; - } + case ADD_MULTIPLIED_BASE, ADD_MULTIPLIED_TOTAL -> + ATTRIBUTE_FORMAT.format(amount * 100) + "%"; + }; if (amount > 0) { operationTotal = "+" + operationTotal; } From abb1d7d9e9fb1de2c5959fc679cb5afbda7b0978 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:50:41 -0400 Subject: [PATCH 111/897] Indicate Java 1.20.6 support --- README.md | 2 +- .../src/main/java/org/geysermc/geyser/network/GameProtocol.java | 2 +- gradle/libs.versions.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 314876d60..2fdc93fa1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80 and Minecraft Java 1.20.5 +### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80 and Minecraft Java 1.20.5/1.20.6 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index cf80e8c6e..fdaecbb69 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -124,7 +124,7 @@ public final class GameProtocol { * @return the supported Minecraft: Java Edition version names */ public static List getJavaVersions() { - return List.of(DEFAULT_JAVA_CODEC.getMinecraftVersion()); + return List.of("1.20.5", DEFAULT_JAVA_CODEC.getMinecraftVersion()); } /** diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9e5a0a53f..e975ba0c8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "bc8526b" # Revert from jitpack after release +mcprotocollib = "209e79f8" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 1e8d6b23cf5f5058f6bf11c362346e0f48871a20 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 1 May 2024 15:35:30 -0400 Subject: [PATCH 112/897] Different registry implementation; fix banner blocks with ViaVersion --- .../living/animal/tameable/WolfEntity.java | 2 +- .../geysermc/geyser/item/type/ArmorItem.java | 4 +- .../geysermc/geyser/item/type/BannerItem.java | 52 +++++++++------- .../geyser/session/cache/RegistryCache.java | 52 +++++----------- .../session/cache/registry/JavaRegistry.java | 56 ++++++++++++++++++ .../cache/registry/SimpleJavaRegistry.java | 59 +++++++++++++++++++ .../translator/text/MessageTranslator.java | 2 +- .../org/geysermc/geyser/util/ChunkUtils.java | 2 +- 8 files changed, 166 insertions(+), 63 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java 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 ceb29695a..4573f0e7a 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 @@ -113,7 +113,7 @@ public class WolfEntity extends TameableEntity { // 1.20.5+ public void setWolfVariant(IntEntityMetadata entityMetadata) { - WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().get(entityMetadata.getPrimitiveValue()); + WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(entityMetadata.getPrimitiveValue()); if (wolfVariant == null) { wolfVariant = WolfVariant.PALE; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index 76f951c66..fc0dd3ba4 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -56,8 +56,8 @@ public class ArmorItem extends Item { return; } - TrimMaterial material = session.getRegistryCache().trimMaterials().get(trim.material().id()); - TrimPattern pattern = session.getRegistryCache().trimPatterns().get(trim.pattern().id()); + TrimMaterial material = session.getRegistryCache().trimMaterials().byId(trim.material().id()); + TrimPattern pattern = session.getRegistryCache().trimPatterns().byId(trim.pattern().id()); NbtMapBuilder trimBuilder = NbtMap.builder(); // bedrock has an uppercase first letter key, and the value is not namespaced diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 2f5d96b5a..6c2678db9 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -33,13 +33,14 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; -import org.cloudburstmc.protocol.common.util.Int2ObjectBiMap; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.item.DyeColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistry; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.Identifier; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -57,7 +58,6 @@ public class BannerItem extends BlockItem { * the correct ominous banner pattern if Bedrock pulls the item from creative. */ private static final List> OMINOUS_BANNER_PATTERN; - private static final List OMINOUS_BANNER_PATTERN_BLOCK; // TODO fix - we somehow need to be able to get the sessions banner pattern registry, which we don't have where we need this :/ private static final int[] ominousBannerPattern = new int[] { 21, 29, 30, 1, 34, 15, 3, 1 }; @@ -74,11 +74,6 @@ public class BannerItem extends BlockItem { Pair.of(BannerPattern.CIRCLE, DyeColor.LIGHT_GRAY), Pair.of(BannerPattern.BORDER, DyeColor.BLACK) ); - - OMINOUS_BANNER_PATTERN_BLOCK = new ArrayList<>(); - for (Pair pair : OMINOUS_BANNER_PATTERN) { - OMINOUS_BANNER_PATTERN_BLOCK.add(getJavaBannerPatternTag(pair.left(), pair.right())); - } } public static boolean isOminous(GeyserSession session, List patternLayers) { @@ -92,7 +87,7 @@ public class BannerItem extends BlockItem { !patternLayer.getPattern().isId()) { return false; } - BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(patternLayer.getPattern().id()); + BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(patternLayer.getPattern().id()); if (bannerPattern != pair.left()) { return false; } @@ -101,7 +96,25 @@ public class BannerItem extends BlockItem { } public static boolean isOminous(List blockEntityPatterns) { - return OMINOUS_BANNER_PATTERN_BLOCK.equals(blockEntityPatterns); + // Cannot do a simple NBT equals check here because the IDs may not be full resource locations + // ViaVersion's fault, 1.20.4 -> 1.20.5, but it works on Java so we need to support it. + if (OMINOUS_BANNER_PATTERN.size() != blockEntityPatterns.size()) { + return false; + } + for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) { + NbtMap patternLayer = blockEntityPatterns.get(i); + Pair pair = OMINOUS_BANNER_PATTERN.get(i); + DyeColor color = DyeColor.getByJavaIdentifier(patternLayer.getString("color")); + if (color != pair.right()) { + return false; + } + String id = Identifier.formalize(patternLayer.getString("pattern")); // Ouch + BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(id); + if (bannerPattern != pair.left()) { + return false; + } + } + return true; } /** @@ -133,7 +146,7 @@ public class BannerItem extends BlockItem { List patternList = new ArrayList<>(patterns.size()); for (BannerPatternLayer patternLayer : patterns) { patternLayer.getPattern().ifId(holder -> { - BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(holder.id()); + BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(holder.id()); if (bannerPattern != null) { NbtMap tag = NbtMap.builder() .putString("Pattern", bannerPattern.getBedrockIdentifier()) @@ -154,7 +167,8 @@ public class BannerItem extends BlockItem { * @return The Bedrock edition format pattern nbt */ private static NbtMap getBedrockBannerPattern(NbtMap pattern) { - BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(pattern.getString("pattern")); + // ViaVersion 1.20.4 -> 1.20.5 can send without the namespace + BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(Identifier.formalize(pattern.getString("pattern"))); DyeColor dyeColor = DyeColor.getByJavaIdentifier(pattern.getString("color")); if (bannerPattern == null || dyeColor == null) { return null; @@ -166,13 +180,6 @@ public class BannerItem extends BlockItem { .build(); } - public static NbtMap getJavaBannerPatternTag(BannerPattern bannerPattern, DyeColor dyeColor) { - return NbtMap.builder() - .putString("pattern", bannerPattern.getJavaIdentifier()) - .putString("color", dyeColor.getJavaIdentifier()) - .build(); - } - /** * Convert the Bedrock edition banner pattern nbt to Java edition * @@ -180,11 +187,14 @@ public class BannerItem extends BlockItem { * @return The Java edition format pattern layer */ public static BannerPatternLayer getJavaBannerPattern(GeyserSession session, NbtMap pattern) { - Int2ObjectBiMap registry = session.getRegistryCache().bannerPatterns(); + JavaRegistry registry = session.getRegistryCache().bannerPatterns(); BannerPattern bannerPattern = BannerPattern.getByBedrockIdentifier(pattern.getString("Pattern")); DyeColor dyeColor = DyeColor.getById(15 - pattern.getInt("Color")); - if (bannerPattern != null && dyeColor != null && registry.containsValue(bannerPattern)) { - return new BannerPatternLayer(Holder.ofId(registry.get(bannerPattern)), dyeColor.ordinal()); + if (bannerPattern != null && dyeColor != null) { + int id = registry.byValue(bannerPattern); + if (id != -1) { + return new BannerPatternLayer(Holder.ofId(id), dyeColor.ordinal()); + } } return null; } 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 4dfc603ee..9581df253 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 @@ -27,25 +27,25 @@ package org.geysermc.geyser.session.cache; 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 lombok.AccessLevel; import lombok.Getter; import lombok.experimental.Accessors; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; -import org.cloudburstmc.protocol.common.util.Int2ObjectBiMap; 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.recipe.TrimRecipe; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistry; +import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -71,7 +71,7 @@ public final class RegistryCache { register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); - registerBannerRegistry(($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); + register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId())); } @@ -82,16 +82,16 @@ public final class RegistryCache { * Java -> Bedrock biome network IDs. */ private int[] biomeTranslations; - private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); + private final JavaRegistry chatTypes = new SimpleJavaRegistry<>(); /** * All dimensions that the client could possibly connect to. */ - private final Int2ObjectMap dimensions = new Int2ObjectOpenHashMap<>(4); - private final Int2ObjectMap trimMaterials = new Int2ObjectOpenHashMap<>(); - private final Int2ObjectMap trimPatterns = new Int2ObjectOpenHashMap<>(); + private final JavaRegistry dimensions = new SimpleJavaRegistry<>(); + private final JavaRegistry trimMaterials = new SimpleJavaRegistry<>(); + private final JavaRegistry trimPatterns = new SimpleJavaRegistry<>(); - private Int2ObjectBiMap bannerPatterns = new Int2ObjectBiMap<>(); - private final Int2ObjectMap wolfVariants = new Int2ObjectOpenHashMap<>(); + private final JavaRegistry bannerPatterns = new SimpleJavaRegistry<>(); + private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); public RegistryCache(GeyserSession session) { this.session = session; @@ -109,47 +109,25 @@ public final class RegistryCache { } } - private static void registerBannerRegistry(BiFunction reader) { - REGISTRIES.put("minecraft:banner_pattern", ((registryCache, entries) -> { - // Clear each local cache every time a new registry entry is given to us - // (e.g. proxy server switches) - registryCache.bannerPatterns = new Int2ObjectBiMap<>(); // Cannot clear it, must re-create :( - for (int i = 0; i < entries.size(); i++) { - RegistryEntry entry = entries.get(i); - // This is what Geyser wants to keep as a value for this registry. - T cacheEntry = reader.apply(registryCache.session, entry); - if (cacheEntry != null) { - registryCache.bannerPatterns.put(i, (BannerPattern) cacheEntry); - } else { - // TODO - seems to be possible with viaversion :/ - GeyserImpl.getInstance().getLogger().warning("Was not able to translate entry: "); - } - } - })); - } - /** * @param registry the Java registry resource location, without the "minecraft:" prefix. * @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(String registry, Function> localCacheFunction, BiFunction reader) { + private static void register(String registry, Function> localCacheFunction, BiFunction reader) { REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> { - Int2ObjectMap localCache = localCacheFunction.apply(registryCache); + JavaRegistry localCache = localCacheFunction.apply(registryCache); // Clear each local cache every time a new registry entry is given to us // (e.g. proxy server switches) - localCache.clear(); + List builder = new ArrayList<>(entries.size()); for (int i = 0; i < entries.size(); i++) { RegistryEntry entry = entries.get(i); // This is what Geyser wants to keep as a value for this registry. T cacheEntry = reader.apply(registryCache.session, entry); - localCache.put(i, cacheEntry); - } - // Trim registry down to needed size - if (localCache instanceof Int2ObjectOpenHashMap hashMap) { - hashMap.trim(); + builder.add(i, cacheEntry); } + localCache.reset(builder); }); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java new file mode 100644 index 000000000..d7c7782ea --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java @@ -0,0 +1,56 @@ +/* + * 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.session.cache.registry; + +import org.checkerframework.checker.index.qual.NonNegative; + +import java.util.List; + +/** + * A wrapper for a list, holding Java registry values. + */ +public interface JavaRegistry { + + /** + * Looks up a registry entry by its ID. The object can be null, or not present. + */ + T byId(@NonNegative int id); + + /** + * Reverse looks-up an object to return its network ID, or -1. + */ + int byValue(T value); + + /** + * Resets the objects by these IDs. + */ + void reset(List values); + + /** + * All values of this registry, as a list. + */ + List values(); +} diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java new file mode 100644 index 000000000..633e5fbd1 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java @@ -0,0 +1,59 @@ +/* + * 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.session.cache.registry; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.checkerframework.checker.index.qual.NonNegative; + +import java.util.List; + +public class SimpleJavaRegistry implements JavaRegistry { + protected final ObjectArrayList values = new ObjectArrayList<>(); + + @Override + public T byId(@NonNegative int id) { + if (id < 0 || id >= this.values.size()) { + return null; + } + return this.values.get(id); + } + + @Override + public int byValue(T value) { + return this.values.indexOf(value); + } + + @Override + public void reset(List values) { + this.values.addAll(values); + this.values.trim(); + } + + @Override + public List values() { + return this.values; + } +} 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 884f05256..5a0121039 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 @@ -330,7 +330,7 @@ public class MessageTranslator { textPacket.setNeedsTranslation(false); - TextDecoration decoration = session.getRegistryCache().chatTypes().get(chatType); + TextDecoration decoration = session.getRegistryCache().chatTypes().byId(chatType); if (decoration != null) { // As of 1.19 - do this to apply all the styling for signed messages // Though, Bedrock cannot care about the signed stuff. diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index a542f7431..379162540 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -280,7 +280,7 @@ public class ChunkUtils { * This must be done after the player has switched dimensions so we know what their dimension is */ public static void loadDimension(GeyserSession session) { - JavaDimension dimension = session.getRegistryCache().dimensions().get(session.getDimension()); + JavaDimension dimension = session.getRegistryCache().dimensions().byId(session.getDimension()); session.setDimensionType(dimension); int minY = dimension.minY(); int maxY = dimension.maxY(); From cc635d4447abb15089065b3948565e0382493684 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 1 May 2024 15:41:27 -0400 Subject: [PATCH 113/897] This would probably end up being an issue... --- .../geyser/session/cache/registry/SimpleJavaRegistry.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java index 633e5fbd1..9839a1568 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java @@ -48,6 +48,7 @@ public class SimpleJavaRegistry implements JavaRegistry { @Override public void reset(List values) { + this.values.clear(); this.values.addAll(values); this.values.trim(); } From 1291b89e64e0ff5e96e90ad6a354add0c0f94365 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 2 May 2024 00:29:33 +0200 Subject: [PATCH 114/897] Ensure proper Geyser starting/disabling when Geyser is used on a client (#4621) * Ensure proper Geyser starting/disabling when Geyser is used on a client * also set correct remote port * only use direct connection on server, not client, actually override remote port --- .../fabric/GeyserFabricBootstrap.java | 23 ++++++++++++++++--- .../neoforge/GeyserNeoForgeBootstrap.java | 19 +++++++++++++-- .../platform/mod/GeyserModBootstrap.java | 19 +++++++++++++-- .../mixin/client/IntegratedServerMixin.java | 6 +++-- 4 files changed, 58 insertions(+), 9 deletions(-) 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 81e329c03..c363ade8f 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 @@ -28,14 +28,15 @@ package org.geysermc.geyser.platform.fabric; import me.lucko.fabric.api.permissions.v0.Permissions; import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; 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 org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.platform.mod.GeyserModBootstrap; import org.geysermc.geyser.platform.mod.GeyserModUpdateListener; -import org.checkerframework.checker.nullness.qual.NonNull; public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInitializer { @@ -45,21 +46,37 @@ public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInit @Override public void onInitialize() { - if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) { + if (isServer()) { // Set as an event, so we can get the proper IP and port if needed ServerLifecycleEvents.SERVER_STARTED.register((server) -> { this.setServer(server); onGeyserEnable(); }); + } else { + ClientLifecycleEvents.CLIENT_STOPPING.register(($)-> { + onGeyserShutdown(); + }); } // These are only registered once - ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onGeyserShutdown()); + ServerLifecycleEvents.SERVER_STOPPING.register((server) -> { + if (isServer()) { + onGeyserShutdown(); + } else { + onGeyserDisable(); + } + }); + ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserModUpdateListener.onPlayReady(handler.getPlayer())); this.onGeyserInitialize(); } + @Override + public boolean isServer() { + return FabricLoader.getInstance().getEnvironmentType().equals(EnvType.SERVER); + } + @Override public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) { return Permissions.check(source, permissionNode); 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 67cad1683..1655dea91 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 @@ -27,10 +27,10 @@ package org.geysermc.geyser.platform.neoforge; import net.minecraft.commands.CommandSourceStack; import net.minecraft.world.entity.player.Player; -import net.neoforged.api.distmarker.Dist; import net.neoforged.fml.common.Mod; import net.neoforged.fml.loading.FMLLoader; import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.GameShuttingDownEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.server.ServerStartedEvent; import net.neoforged.neoforge.event.server.ServerStoppingEvent; @@ -46,9 +46,11 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { public GeyserNeoForgeBootstrap() { super(new GeyserNeoForgePlatform()); - if (FMLLoader.getDist() == Dist.DEDICATED_SERVER) { + if (isServer()) { // Set as an event so we can get the proper IP and port if needed NeoForge.EVENT_BUS.addListener(this::onServerStarted); + } else { + NeoForge.EVENT_BUS.addListener(this::onClientStopping); } NeoForge.EVENT_BUS.addListener(this::onServerStopping); @@ -64,6 +66,14 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { } private void onServerStopping(ServerStoppingEvent event) { + if (isServer()) { + this.onGeyserShutdown(); + } else { + this.onGeyserDisable(); + } + } + + private void onClientStopping(GameShuttingDownEvent ignored) { this.onGeyserShutdown(); } @@ -71,6 +81,11 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { GeyserModUpdateListener.onPlayReady(event.getEntity()); } + @Override + public boolean isServer() { + return FMLLoader.getDist().isDedicatedServer(); + } + @Override public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) { return this.permissionHandler.hasPermission(source, permissionNode); diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java index db966ec1a..d3d3a9104 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java @@ -58,6 +58,7 @@ import org.geysermc.geyser.util.FileUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.SocketAddress; import java.nio.file.Path; import java.util.Map; import java.util.UUID; @@ -127,7 +128,9 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { // We want to do this late in the server startup process to allow other mods // To do their job injecting, then connect into *that* this.geyserInjector = new GeyserModInjector(server, this.platform); - this.geyserInjector.initializeLocalChannel(this); + if (isServer()) { + this.geyserInjector.initializeLocalChannel(this); + } // Start command building // Set just "geyser" as the help command @@ -242,7 +245,19 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { @Override public int getServerPort() { - return ((GeyserServerPortGetter) server).geyser$getServerPort(); + if (isServer()) { + return ((GeyserServerPortGetter) server).geyser$getServerPort(); + } else { + // Set in the IntegratedServerMixin + return geyserConfig.getRemote().port(); + } + } + + public abstract boolean isServer(); + + @Override + public @Nullable SocketAddress getSocketAddress() { + return this.geyserInjector.getServerSocketAddress(); } @Override diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/client/IntegratedServerMixin.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/client/IntegratedServerMixin.java index 4db1165fc..ece2f730a 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/client/IntegratedServerMixin.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/client/IntegratedServerMixin.java @@ -54,8 +54,10 @@ public class IntegratedServerMixin implements GeyserServerPortGetter { private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable cir) { if (cir.getReturnValueZ()) { // If the LAN is opened, starts Geyser. - GeyserModBootstrap.getInstance().setServer((MinecraftServer) (Object) this); - GeyserModBootstrap.getInstance().onGeyserEnable(); + GeyserModBootstrap instance = GeyserModBootstrap.getInstance(); + instance.setServer((MinecraftServer) (Object) this); + instance.getGeyserConfig().getRemote().setPort(port); + instance.onGeyserEnable(); // Ensure player locale has been loaded, in case it's different from Java system language GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode); // Give indication that Geyser is loaded From fdae333351a6e4f9e6b5aa4536133dee7ea35e91 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 1 May 2024 19:00:39 -0400 Subject: [PATCH 115/897] Add data components hash code to translated NBT --- .../java/org/geysermc/geyser/item/type/Item.java | 4 ++++ .../inventory/PlayerInventoryTranslator.java | 6 ++++++ .../org/geysermc/geyser/util/InventoryUtils.java | 15 +++++++++++++++ 3 files changed, 25 insertions(+) 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 cc49f3785..bfcfb23d1 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 @@ -151,6 +151,10 @@ public class Item { if (repairCost != null) { builder.putInt("RepairCost", repairCost); } + + // Prevents the client from trying to stack items with untranslated components + // Relies on correct hash code implementation, and some luck + builder.putInt("GeyserHash", components.hashCode()); // TODO: don't rely on this } /** diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 7459ccf30..36752e582 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -261,6 +261,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { GeyserItemStack sourceItem = inventory.getItem(sourceSlot); if (playerInv.getCursor().isEmpty()) { playerInv.setCursor(sourceItem.copy(0), session); + } else if (!InventoryUtils.canStack(sourceItem, playerInv.getCursor())) { + return rejectRequest(request); } playerInv.getCursor().add(transferAmount); @@ -272,6 +274,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { GeyserItemStack sourceItem = playerInv.getCursor(); if (inventory.getItem(destSlot).isEmpty()) { inventory.setItem(destSlot, sourceItem.copy(0), session); + } else if (!InventoryUtils.canStack(sourceItem, inventory.getItem(destSlot))) { + return rejectRequest(request); } inventory.getItem(destSlot).add(transferAmount); @@ -284,6 +288,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { GeyserItemStack sourceItem = inventory.getItem(sourceSlot); if (inventory.getItem(destSlot).isEmpty()) { inventory.setItem(destSlot, sourceItem.copy(0), session); + } else if (!InventoryUtils.canStack(sourceItem, inventory.getItem(destSlot))) { + return rejectRequest(request); } inventory.getItem(destSlot).add(transferAmount); 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 63644d5fc..64c95afdd 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -178,11 +178,26 @@ public class InventoryUtils { } public static boolean canStack(GeyserItemStack item1, GeyserItemStack item2) { + if (GeyserImpl.getInstance().getConfig().isDebugMode()) + canStackDebug(item1, item2); if (item1.isEmpty() || item2.isEmpty()) return false; return item1.getJavaId() == item2.getJavaId() && Objects.equals(item1.getComponents(), item2.getComponents()); } + private static void canStackDebug(GeyserItemStack item1, GeyserItemStack item2) { + DataComponents components1 = item1.getComponents(); + DataComponents components2 = item2.getComponents(); + if (components1 != null && components2 != null) { + if (components1.hashCode() == components2.hashCode() && !components1.equals(components2)) { + GeyserImpl.getInstance().getLogger().error("DEBUG: DataComponents hash collision"); + GeyserImpl.getInstance().getLogger().error("hash: " + components1.hashCode()); + GeyserImpl.getInstance().getLogger().error("components1: " + components1); + GeyserImpl.getInstance().getLogger().error("components2: " + components2); + } + } + } + /** * Checks to see if an item stack represents air or has no count. */ From d003818e73c07b6e5b31370439f46bb1fb83c46f Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 2 May 2024 03:47:30 -0400 Subject: [PATCH 116/897] Potion fixes --- .../geyser/entity/EntityDefinitions.java | 1 - .../entity/type/AreaEffectCloudEntity.java | 7 +++++- .../entity/type/ThrownPotionEntity.java | 8 +++--- .../geyser/inventory/item/Potion.java | 25 ++++++++++++------- .../geysermc/geyser/item/type/PotionItem.java | 2 +- 5 files changed, 27 insertions(+), 16 deletions(-) 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 6cd5f3fc2..2c5fe7a86 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -202,7 +202,6 @@ public final class EntityDefinitions { .type(EntityType.AREA_EFFECT_CLOUD) .height(0.5f).width(1.0f) .addTranslator(MetadataType.FLOAT, AreaEffectCloudEntity::setRadius) - .addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.EFFECT_COLOR, entityMetadata.getValue())) .addTranslator(null) // Waiting .addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle) .build(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java index 4b8eea061..83484b732 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java @@ -34,6 +34,7 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; import java.util.UUID; @@ -51,7 +52,7 @@ public class AreaEffectCloudEntity extends Entity { dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_DURATION, Integer.MAX_VALUE); // This disabled client side shrink of the cloud - dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, 0.0f); + dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, 0.5f); dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_CHANGE_RATE, Float.MIN_VALUE); dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, Float.MIN_VALUE); @@ -69,5 +70,9 @@ public class AreaEffectCloudEntity extends Entity { Particle particle = entityMetadata.getValue(); Registries.PARTICLES.map(particle.getType(), p -> p.levelEventType() instanceof ParticleType particleType ? particleType : null).ifPresent(type -> dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_PARTICLE, type)); + + if (particle.getData() instanceof EntityEffectParticleData effectParticleData) { + dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, effectParticleData.getColor()); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java index bfe429f33..88cf4f8b9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java @@ -54,7 +54,7 @@ public class ThrownPotionEntity extends ThrowableItemEntity { public void setItem(EntityMetadata entityMetadata) { ItemStack itemStack = entityMetadata.getValue(); if (itemStack == null) { - dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0); + dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, (short) 0); setFlag(EntityFlag.ENCHANTED, false); setFlag(EntityFlag.LINGERING, false); } else { @@ -63,12 +63,12 @@ public class ThrownPotionEntity extends ThrowableItemEntity { if (components != null) { PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); if (potionContents != null) { - Potion potion = Potion.VALUES[potionContents.getPotionId()]; + Potion potion = Potion.getByJavaId(potionContents.getPotionId()); if (potion != null) { - dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, (int) potion.getBedrockId()); + dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, potion.getBedrockId()); setFlag(EntityFlag.ENCHANTED, !NON_ENCHANTED_POTIONS.contains(potion)); } else { - dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0); + dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, (short) 0); GeyserImpl.getInstance().getLogger().debug("Unknown java potion: " + potionContents.getPotionId()); } } 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 00a9b091e..cf3a37afd 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 @@ -43,16 +43,19 @@ public enum Potion { INVISIBILITY(7), LONG_INVISIBILITY(8), LEAPING(9), - STRONG_LEAPING(11), LONG_LEAPING(10), + STRONG_LEAPING(11), FIRE_RESISTANCE(12), LONG_FIRE_RESISTANCE(13), SWIFTNESS(14), - STRONG_SWIFTNESS(16), LONG_SWIFTNESS(15), + STRONG_SWIFTNESS(16), SLOWNESS(17), - STRONG_SLOWNESS(42), LONG_SLOWNESS(18), + STRONG_SLOWNESS(42), + TURTLE_MASTER(37), + LONG_TURTLE_MASTER(38), + STRONG_TURTLE_MASTER(39), WATER_BREATHING(19), LONG_WATER_BREATHING(20), HEALING(21), @@ -60,20 +63,17 @@ public enum Potion { HARMING(23), STRONG_HARMING(24), POISON(25), - STRONG_POISON(27), LONG_POISON(26), + STRONG_POISON(27), REGENERATION(28), - STRONG_REGENERATION(30), LONG_REGENERATION(29), + STRONG_REGENERATION(30), STRENGTH(31), - STRONG_STRENGTH(33), LONG_STRENGTH(32), + STRONG_STRENGTH(33), WEAKNESS(34), LONG_WEAKNESS(35), LUCK(2), //does not exist - TURTLE_MASTER(37), - STRONG_TURTLE_MASTER(39), - LONG_TURTLE_MASTER(38), SLOW_FALLING(40), LONG_SLOW_FALLING(41); @@ -91,6 +91,13 @@ public enum Potion { return new PotionContents(this.ordinal(), -1, Int2ObjectMaps.emptyMap()); } + public static @Nullable Potion getByJavaId(int javaId) { + if (javaId >= 0 && javaId < VALUES.length) { + return VALUES[javaId]; + } + return null; + } + public static @Nullable Potion getByBedrockId(int bedrockId) { for (Potion potion : VALUES) { if (potion.bedrockId == bedrockId) { 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 b69f7d35f..e9889c882 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 @@ -50,7 +50,7 @@ public class PotionItem extends Item { if (potionContents != null) { ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(components, mapping); if (customItemDefinition == null) { - Potion potion = Potion.VALUES[potionContents.getPotionId()]; + Potion potion = Potion.getByJavaId(potionContents.getPotionId()); if (potion != null) { return ItemData.builder() .definition(mapping.getBedrockDefinition()) From 29a613b85c59f030bcfbaf9f1b80b1fe1a8a2aba Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 2 May 2024 05:04:19 -0400 Subject: [PATCH 117/897] Use java default area effect cloud radius --- .../geysermc/geyser/entity/type/AreaEffectCloudEntity.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java index 83484b732..165495506 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java @@ -32,6 +32,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.MathUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData; @@ -52,7 +53,7 @@ public class AreaEffectCloudEntity extends Entity { dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_DURATION, Integer.MAX_VALUE); // This disabled client side shrink of the cloud - dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, 0.5f); + dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, 3.0f); dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_CHANGE_RATE, Float.MIN_VALUE); dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, Float.MIN_VALUE); @@ -61,7 +62,7 @@ public class AreaEffectCloudEntity extends Entity { public void setRadius(FloatEntityMetadata entityMetadata) { // Anything less than 0.5 will cause the cloud to despawn - float value = Math.max(entityMetadata.getPrimitiveValue(), 0.5f); + float value = MathUtils.clamp(entityMetadata.getPrimitiveValue(), 0.5f, 32.0f); dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, value); dirtyMetadata.put(EntityDataTypes.WIDTH, 2.0f * value); } From 60f8532be3826cb6e7a70750d4996045d4b3f26a Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 2 May 2024 06:06:12 -0400 Subject: [PATCH 118/897] Fix attribute display text --- .../translator/item/ItemTranslator.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) 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 49ee498b9..768c94791 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 @@ -62,6 +62,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttribut import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -71,9 +72,21 @@ public final class ItemTranslator { /** * The order of these slots is their display order on Java Edition clients */ - private static final ItemAttributeModifiers.EquipmentSlotGroup[] ALL_SLOTS = ItemAttributeModifiers.EquipmentSlotGroup.values(); + private static final EnumMap SLOT_NAMES; private static final DecimalFormat ATTRIBUTE_FORMAT = new DecimalFormat("0.#####"); + static { + // These are the only slots that are used and have translation strings + SLOT_NAMES = new EnumMap<>(ItemAttributeModifiers.EquipmentSlotGroup.class); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.MAIN_HAND, "mainhand"); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.OFF_HAND, "offhand"); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.FEET, "feet"); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.LEGS, "legs"); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.CHEST, "chest"); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.HEAD, "head"); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.BODY, "body"); + } + private ItemTranslator() { } @@ -208,7 +221,7 @@ public final class ItemTranslator { ItemAttributeModifiers.EquipmentSlotGroup slotGroup = entry.getSlot(); if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ANY) { // modifier applies to all slots implicitly - for (var slot : ALL_SLOTS) { + for (var slot : SLOT_NAMES.keySet()) { slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreEntry); } } else { @@ -218,7 +231,7 @@ public final class ItemTranslator { } // iterate through the small array, not the map, so that ordering matches Java Edition - for (var slot : ALL_SLOTS) { + for (var slot : SLOT_NAMES.keySet()) { List modifierStrings = slotsToModifiers.get(slot); if (modifierStrings == null || modifierStrings.isEmpty()) { continue; @@ -228,7 +241,7 @@ public final class ItemTranslator { Component slotComponent = Component.text() .resetStyle() .color(NamedTextColor.GRAY) - .append(Component.newline(), Component.translatable("item.modifiers." + slot)) + .append(Component.newline(), Component.translatable("item.modifiers." + SLOT_NAMES.get(slot))) .build(); builder.getOrCreateLore().add(MessageTranslator.convertMessage(slotComponent, language)); From f7c65f38d1b4bb606797bda161efb1ab276e6672 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 2 May 2024 12:51:14 +0200 Subject: [PATCH 119/897] properly annotate methods in the ServerTransferEvent --- .../geyser/api/event/java/ServerTransferEvent.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java index b3b580ec3..594e28ef0 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.api.event.java; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.value.qual.IntRange; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.connection.ConnectionEvent; @@ -44,7 +45,8 @@ public class ServerTransferEvent extends ConnectionEvent { private int bedrockPort; private final Map cookies; - public ServerTransferEvent(@NonNull GeyserConnection connection, String host, int port, Map cookies) { + public ServerTransferEvent(@NonNull GeyserConnection connection, + @NonNull String host, int port, @NonNull Map cookies) { super(connection); this.host = host; this.port = port; @@ -58,7 +60,7 @@ public class ServerTransferEvent extends ConnectionEvent { * * @return the host */ - public String host() { + public @NonNull String host() { return this.host; } @@ -77,7 +79,7 @@ public class ServerTransferEvent extends ConnectionEvent { * * @return the host where the Bedrock client will be transferred to, or null if not set. */ - public String bedrockHost() { + public @Nullable String bedrockHost() { return this.bedrockHost; } From 6a214f235c21fb2c36e30a5ecbdbd15aa21706ff Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 2 May 2024 13:07:18 -0400 Subject: [PATCH 120/897] Remove duplicate method --- .../org/geysermc/geyser/platform/mod/GeyserModBootstrap.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java index 98024ae45..786faac93 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java @@ -260,11 +260,6 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { public abstract boolean isServer(); - @Override - public @Nullable SocketAddress getSocketAddress() { - return this.geyserInjector.getServerSocketAddress(); - } - @Override public boolean testFloodgatePluginPresent() { return this.platform.testFloodgatePluginPresent(this); From cab1a20034c05302ac5e61b6c9c401f6a396cc2a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 2 May 2024 13:08:09 -0400 Subject: [PATCH 121/897] Set mappings commit to master --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index cb2cbe9f2..7c01501ed 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit cb2cbe9f262d14640f7c46885f1c8c9d23f2beaa +Subproject commit 7c01501ed6a0ee8848a66d729000539f2661f785 From b39ed5de53fd9b820023a3ac9c603a9936fa3e63 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 2 May 2024 20:33:28 -0400 Subject: [PATCH 122/897] Panda eating particles are not necessarily bamboo --- .../geysermc/geyser/entity/type/living/animal/PandaEntity.java | 3 ++- .../org/geysermc/geyser/inventory/item/StoredItemMappings.java | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) 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 595e79e32..79401f63f 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 @@ -61,7 +61,8 @@ public class PandaEntity extends AnimalEntity { EntityEventPacket packet = new EntityEventPacket(); packet.setRuntimeEntityId(geyserId); packet.setType(EntityEventType.EATING_ITEM); - packet.setData(session.getItemMappings().getStoredItems().bamboo().getBedrockDefinition().getRuntimeId() << 16); + // As of 1.20.5 - pandas can eat cake + packet.setData(this.hand.getDefinition().getRuntimeId() << 16); session.sendUpstreamPacket(packet); } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java index c15a5d3b4..0305df685 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java @@ -40,7 +40,6 @@ import java.util.Map; @Getter @Accessors(fluent = true) public class StoredItemMappings { - private final ItemMapping bamboo; private final ItemMapping banner; private final ItemMapping barrier; private final ItemMapping compass; @@ -56,7 +55,6 @@ public class StoredItemMappings { private final ItemMapping writtenBook; public StoredItemMappings(Map itemMappings) { - this.bamboo = load(itemMappings, Items.BAMBOO); this.banner = load(itemMappings, Items.WHITE_BANNER); // As of 1.17.10, all banners have the same Bedrock ID this.barrier = load(itemMappings, Items.BARRIER); this.compass = load(itemMappings, Items.COMPASS); From a39cd65537cbcdbf8e958f0378e25588387df35e Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Fri, 3 May 2024 12:53:47 +0100 Subject: [PATCH 123/897] Fix velocity ping passthrough (#4626) --- .../platform/velocity/GeyserVelocityPingPassthrough.java | 6 ++++++ gradle/libs.versions.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java index 8944ea134..b2258d3a3 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.platform.velocity; import com.velocitypowered.api.event.proxy.ProxyPingEvent; +import com.velocitypowered.api.network.ProtocolState; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.ProxyServer; @@ -88,6 +89,11 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough { public ProtocolVersion getProtocolVersion() { return ProtocolVersion.MAXIMUM_VERSION; } + + @Override + public ProtocolState getProtocolState() { + return ProtocolState.STATUS; + } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24d0d5050..2cca857f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ viaversion = "4.9.2" adapters = "1.12-SNAPSHOT" commodore = "2.2" bungeecord = "a7c6ede" -velocity = "3.1.1" +velocity = "3.3.0-SNAPSHOT" viaproxy = "3.2.1" fabric-minecraft = "1.20.5" fabric-loader = "0.15.10" From 9d299ee83bf7e4b3bf7fd82048c85d8642248bab Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Fri, 3 May 2024 15:29:15 +0100 Subject: [PATCH 124/897] Fix particle reading issues (#4631) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2cca857f3..3756faa0e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "209e79f8" # Revert from jitpack after release +mcprotocollib = "9b96ebda" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From b8fe71a8bc9762443e0a2814a151a57f14c305cd Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sat, 4 May 2024 01:06:59 -0400 Subject: [PATCH 125/897] Bump MCPL to fix ClientboundExplodePacket (#4635) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3756faa0e..b00db373f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "9b96ebda" # Revert from jitpack after release +mcprotocollib = "c1786e2" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 5770c96f48c4713be5786394963b73dc06806232 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 5 May 2024 01:29:37 -0400 Subject: [PATCH 126/897] Indicate support for 1.20.81 --- README.md | 2 +- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2fdc93fa1..9257af9ac 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80 and Minecraft Java 1.20.5/1.20.6 +### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80/81 and Minecraft Java 1.20.5/1.20.6 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index fdaecbb69..f9292671f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -50,7 +50,9 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v671.CODEC); + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v671.CODEC.toBuilder() + .minecraftVersion("1.20.81") + .build()); /** * A list of all supported Bedrock versions that can join Geyser @@ -77,7 +79,7 @@ public final class GameProtocol { .minecraftVersion("1.20.70/1.20.73") .build())); SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.20.80") + .minecraftVersion("1.20.80/1.20.81") .build())); } From 8addcadb71993236730764963e3d776ac007b7a7 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 5 May 2024 02:24:28 -0400 Subject: [PATCH 127/897] Bump MCPL to increase NBT max depth (#4639) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b00db373f..b1eb616b3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "d9d773e" -mcprotocollib = "c1786e2" # Revert from jitpack after release +mcprotocollib = "1234962" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 0a261f1d9d2a6b1aae8880af8811064e7ccbacec Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 6 May 2024 21:40:32 -0400 Subject: [PATCH 128/897] Update MCPL and MCAuthLib (#4645) * Update MCPL and MCAuthLib * Bump MCPL --- .../java/org/geysermc/geyser/inventory/item/Potion.java | 4 ++-- .../geysermc/geyser/inventory/item/TippedArrowPotion.java | 7 +++++-- .../main/java/org/geysermc/geyser/item/type/ArrowItem.java | 5 +++-- gradle/libs.versions.toml | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) 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 cf3a37afd..86c19de80 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 @@ -25,11 +25,11 @@ package org.geysermc.geyser.inventory.item; -import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import lombok.Getter; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; +import java.util.Collections; import java.util.Locale; @Getter @@ -88,7 +88,7 @@ public enum Potion { } public PotionContents toComponent() { - return new PotionContents(this.ordinal(), -1, Int2ObjectMaps.emptyMap()); + return new PotionContents(this.ordinal(), -1, Collections.emptyList()); } public static @Nullable Potion getByJavaId(int javaId) { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java index ec6b10ec8..b849e07e2 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java @@ -95,8 +95,11 @@ public enum TippedArrowPotion { this.javaColor = arrowParticleColor.getColor(); } - public static TippedArrowPotion of(int id) { - return VALUES[id]; + public static @Nullable TippedArrowPotion of(int id) { + if (id >= 0 && id < VALUES.length) { + return VALUES[id]; + } + return null; } public static @Nullable TippedArrowPotion getByBedrockId(int bedrockId) { 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 f2548e170..84c3b1a39 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.item.type; -import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -36,6 +35,8 @@ import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; +import java.util.Collections; + public class ArrowItem extends Item { public ArrowItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); @@ -47,7 +48,7 @@ public class ArrowItem extends Item { GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); if (tippedArrowPotion != null) { itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents()); - PotionContents contents = new PotionContents(tippedArrowPotion.ordinal(), -1, Int2ObjectMaps.emptyMap()); + PotionContents contents = new PotionContents(tippedArrowPotion.ordinal(), -1, Collections.emptyList()); itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, contents); } return itemStack; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b1eb616b3..65a5e3a52 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,8 +14,8 @@ protocol = "3.0.0.Beta1-20240411.165033-129" protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" -mcauthlib = "d9d773e" -mcprotocollib = "1234962" # Revert from jitpack after release +mcauthlib = "e5b0bcc" +mcprotocollib = "42ea4a4" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From cda7a19a08f5b9d62ce492f6fdd87af3bc461e8b Mon Sep 17 00:00:00 2001 From: Eclipse <116838833+eclipseisoffline@users.noreply.github.com> Date: Tue, 7 May 2024 07:16:21 +0100 Subject: [PATCH 129/897] Fix discarding of custom trim patterns/materials (#4642) * Fix discarding of custom trim patterns/materials * Rename `stripNamespace` method to reflect its behaviour --- .../geyser/inventory/recipe/TrimRecipe.java | 12 +++++++---- .../geysermc/geyser/item/type/ArmorItem.java | 20 ++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java index 37eb905a4..9d9dbe0db 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java @@ -47,7 +47,7 @@ public final class TrimRecipe { public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates"); public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) { - String key = stripNamespace(entry.getId()); + String key = stripMinecraftNamespace(entry.getId()); // Color is used when hovering over the item // Find the nearest legacy color from the RGB Java gives us to work with @@ -67,7 +67,7 @@ public final class TrimRecipe { } public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) { - String key = stripNamespace(entry.getId()); + String key = stripMinecraftNamespace(entry.getId()); String itemIdentifier = entry.getData().getString("template_item"); ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier); @@ -79,10 +79,14 @@ public final class TrimRecipe { } // TODO find a good place for a stripNamespace util method - private static String stripNamespace(String identifier) { + private static String stripMinecraftNamespace(String identifier) { int i = identifier.indexOf(':'); if (i >= 0) { - return identifier.substring(i + 1); + String namespace = identifier.substring(0, i); + // Only strip minecraft namespace + if (namespace.equals("minecraft")) { + return identifier.substring(i + 1); + } } return identifier; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index fc0dd3ba4..0a25a8d4f 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -51,14 +51,15 @@ public class ArmorItem extends Item { ArmorTrim trim = components.get(DataComponentType.TRIM); if (trim != null) { - // discard custom trim patterns/materials to prevent visual glitches on bedrock - if (trim.material().isCustom() || trim.pattern().isCustom()) { - return; - } - TrimMaterial material = session.getRegistryCache().trimMaterials().byId(trim.material().id()); TrimPattern pattern = session.getRegistryCache().trimPatterns().byId(trim.pattern().id()); + // discard custom trim patterns/materials to prevent visual glitches on bedrock + if (!getNamespace(material.getMaterialId()).equals("minecraft") + || !getNamespace(pattern.getPatternId()).equals("minecraft")) { + return; + } + NbtMapBuilder trimBuilder = NbtMap.builder(); // bedrock has an uppercase first letter key, and the value is not namespaced trimBuilder.put("Material", material.getMaterialId()); @@ -71,4 +72,13 @@ public class ArmorItem extends Item { public boolean isValidRepairItem(Item other) { return material.getRepairIngredient() == other; } + + // TODO maybe some kind of namespace util? + private static String getNamespace(String identifier) { + int i = identifier.indexOf(':'); + if (i >= 0) { + return identifier.substring(0, i); + } + return "minecraft"; + } } From 627c2babe9380c64692728581339c0c60869eb6c Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 7 May 2024 19:26:31 -0400 Subject: [PATCH 130/897] Fix various mob attack animations (#4627) * Fix various mob attack animations * Fix error * Don't set piglin target unless attacking * Fix piglin and hoglin shaking effect * Fix piglin attack animation when switching weapons --- .../geyser/entity/EntityDefinitions.java | 7 ++- .../geyser/entity/type/LivingEntity.java | 9 +++ .../type/living/animal/HoglinEntity.java | 8 +++ .../monster/AbstractSkeletonEntity.java | 14 +++++ .../type/living/monster/BasePiglinEntity.java | 18 ++++++ .../type/living/monster/PiglinEntity.java | 56 ++++++++++++++++++- .../type/living/monster/ZoglinEntity.java | 7 +++ .../type/living/monster/ZombieEntity.java | 5 ++ .../living/monster/raid/PillagerEntity.java | 40 ++++++++++--- .../living/monster/raid/RavagerEntity.java | 54 ++++++++++++++++++ .../living/monster/raid/VindicatorEntity.java | 7 +++ .../inventory/item/StoredItemMappings.java | 2 + .../java/entity/JavaAnimateTranslator.java | 11 ++++ 13 files changed, 226 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RavagerEntity.java 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 2c5fe7a86..991b95571 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity; +import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; @@ -132,7 +133,7 @@ public final class EntityDefinitions { public static final EntityDefinition POTION; public static final EntityDefinition PUFFERFISH; public static final EntityDefinition RABBIT; - public static final EntityDefinition RAVAGER; + public static final EntityDefinition RAVAGER; public static final EntityDefinition SALMON; public static final EntityDefinition SHEEP; public static final EntityDefinition SHULKER; @@ -745,9 +746,9 @@ public final class EntityDefinitions { .type(EntityType.PILLAGER) .height(1.8f).width(0.6f) .offset(1.62f) - .addTranslator(null) // Charging; doesn't have an equivalent on Bedrock //TODO check + .addTranslator(MetadataType.BOOLEAN, PillagerEntity::setChargingCrossbow) .build(); - RAVAGER = EntityDefinition.inherited(raidParticipantEntityBase.factory(), raidParticipantEntityBase) + RAVAGER = EntityDefinition.inherited(RavagerEntity::new, raidParticipantEntityBase) .type(EntityType.RAVAGER) .height(1.9f).width(1.2f) .build(); 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 d27fa3cad..499084555 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 @@ -352,6 +352,15 @@ public class LivingEntity extends Entity { session.sendUpstreamPacket(offHandPacket); } + /** + * Called when a SWING_ARM animation packet is received + * + * @return true if an ATTACK_START event should be used instead + */ + public boolean useArmSwingAttack() { + return false; + } + /** * Attributes are properties of an entity that are generally more runtime-based instead of permanent properties. * Movement speed, current attack damage with a weapon, current knockback resistance. 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 46cafad02..74c937417 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.Nullable; 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.session.GeyserSession; @@ -40,6 +41,8 @@ public class HoglinEntity extends AnimalEntity { public HoglinEntity(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); + dirtyMetadata.put(EntityDataTypes.TARGET_EID, session.getPlayerEntity().getGeyserId()); + setFlag(EntityFlag.SHAKING, isShaking()); } public void setImmuneToZombification(BooleanEntityMetadata entityMetadata) { @@ -68,4 +71,9 @@ public class HoglinEntity extends AnimalEntity { protected boolean isEnemy() { return true; } + + @Override + public boolean useArmSwingAttack() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java index 3fbdda245..d08fff06a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java @@ -26,7 +26,9 @@ package org.geysermc.geyser.entity.type.living.monster; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; 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.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -45,5 +47,17 @@ public class AbstractSkeletonEntity extends MonsterEntity { byte xd = entityMetadata.getPrimitiveValue(); // A bit of a loophole so the hands get raised - set the target ID to its own ID dirtyMetadata.put(EntityDataTypes.TARGET_EID, ((xd & 4) == 4) ? geyserId : 0); + + if ((xd & 4) == 4) { + ItemDefinition bow = session.getItemMappings().getStoredItems().bow().getBedrockDefinition(); + setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, this.hand.getDefinition() == bow || this.offhand.getDefinition() == bow); + } else { + setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, false); + } + } + + @Override + public boolean useArmSwingAttack() { + return true; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java index 09bd28cd0..9258cd3b8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java @@ -26,10 +26,13 @@ package org.geysermc.geyser.entity.type.living.monster; 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.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import java.util.UUID; @@ -38,6 +41,16 @@ public class BasePiglinEntity extends MonsterEntity { public BasePiglinEntity(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); + // Both TARGET_EID and BLOCK are needed for melee attack animation + dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(1)); + setFlag(EntityFlag.SHAKING, isShaking()); + } + + @Override + public void setMobFlags(ByteEntityMetadata entityMetadata) { + super.setMobFlags(entityMetadata); + byte xd = entityMetadata.getPrimitiveValue(); + dirtyMetadata.put(EntityDataTypes.TARGET_EID, (xd & 4) == 4 ? session.getPlayerEntity().getGeyserId() : 0); } public void setImmuneToZombification(BooleanEntityMetadata entityMetadata) { @@ -50,4 +63,9 @@ public class BasePiglinEntity extends MonsterEntity { protected boolean isShaking() { return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking(); } + + @Override + public boolean useArmSwingAttack() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java index f0f01272f..19b6d8e69 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java @@ -27,16 +27,22 @@ package org.geysermc.geyser.entity.type.living.monster; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; 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.player.Hand; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.UUID; @@ -55,13 +61,61 @@ public class PiglinEntity extends BasePiglinEntity { } public void setChargingCrossbow(BooleanEntityMetadata entityMetadata) { - setFlag(EntityFlag.CHARGING, entityMetadata.getPrimitiveValue()); + boolean charging = entityMetadata.getPrimitiveValue(); + setFlag(EntityFlag.CHARGING, charging); + dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, charging ? (byte) 64 : (byte) 0); // TODO: gradually increase } public void setDancing(BooleanEntityMetadata entityMetadata) { setFlag(EntityFlag.DANCING, entityMetadata.getPrimitiveValue()); } + @Override + public void setHand(ItemStack stack) { + ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow(); + boolean toCrossbow = stack != null && stack.getId() == crossbow.getJavaItem().javaId(); + + if (toCrossbow ^ this.hand.getDefinition() == crossbow.getBedrockDefinition()) { // If switching to/from crossbow + dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(toCrossbow ? 0 : 1)); + dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0); + setFlag(EntityFlag.CHARGED, false); + setFlag(EntityFlag.USING_ITEM, false); + updateBedrockMetadata(); + + if (this.hand.isValid()) { + MobEquipmentPacket mobEquipmentPacket = new MobEquipmentPacket(); + mobEquipmentPacket.setRuntimeEntityId(geyserId); + mobEquipmentPacket.setContainerId(ContainerId.INVENTORY); + mobEquipmentPacket.setInventorySlot(0); + mobEquipmentPacket.setHotbarSlot(-1); + mobEquipmentPacket.setItem(ItemData.AIR); + session.sendUpstreamPacket(mobEquipmentPacket); + } + } + + super.setHand(stack); + } + + @Override + public void updateMainHand(GeyserSession session) { + super.updateMainHand(session); + + if (this.hand.getDefinition() == session.getItemMappings().getStoredItems().crossbow().getBedrockDefinition()) { + if (this.hand.getTag() != null && this.hand.getTag().containsKey("chargedItem")) { + dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE); + setFlag(EntityFlag.CHARGING, false); + setFlag(EntityFlag.CHARGED, true); + setFlag(EntityFlag.USING_ITEM, true); + } else if (getFlag(EntityFlag.CHARGED)) { + dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0); + setFlag(EntityFlag.CHARGED, false); + setFlag(EntityFlag.USING_ITEM, false); + } + } + + updateBedrockMetadata(); + } + @Override public void updateOffHand(GeyserSession session) { // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java index 7eb950e21..206746fb9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.monster; 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.session.GeyserSession; @@ -37,6 +38,7 @@ public class ZoglinEntity extends MonsterEntity { public ZoglinEntity(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); + dirtyMetadata.put(EntityDataTypes.TARGET_EID, session.getPlayerEntity().getGeyserId()); } public void setBaby(BooleanEntityMetadata entityMetadata) { @@ -64,4 +66,9 @@ public class ZoglinEntity extends MonsterEntity { protected boolean isEnemy() { return true; } + + @Override + public boolean useArmSwingAttack() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java index b8351089d..b07afd742 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java @@ -57,4 +57,9 @@ public class ZombieEntity extends MonsterEntity { protected boolean isShaking() { return convertingToDrowned || super.isShaking(); } + + @Override + public boolean useArmSwingAttack() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java index 1d2d9115b..fd7448e29 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java @@ -26,10 +26,13 @@ package org.geysermc.geyser.entity.type.living.monster.raid; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; @@ -39,16 +42,22 @@ public class PillagerEntity extends AbstractIllagerEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + public void setChargingCrossbow(BooleanEntityMetadata entityMetadata) { + boolean charging = entityMetadata.getPrimitiveValue(); + setFlag(EntityFlag.CHARGING, charging); + dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, charging ? (byte) 64 : (byte) 0); // TODO: gradually increase + } + @Override - public void updateMainHand(GeyserSession session) { //TODO - checkForCrossbow(); + public void updateMainHand(GeyserSession session) { + updateCrossbow(); super.updateMainHand(session); } @Override public void updateOffHand(GeyserSession session) { - checkForCrossbow(); + updateCrossbow(); super.updateOffHand(session); } @@ -56,12 +65,27 @@ public class PillagerEntity extends AbstractIllagerEntity { /** * Check for a crossbow in either the mainhand or offhand. If one exists, indicate that the pillager should be posing */ - protected void checkForCrossbow() { + protected void updateCrossbow() { ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow(); - boolean hasCrossbow = this.hand.getDefinition() == crossbow.getBedrockDefinition() - || this.offhand.getDefinition() == crossbow.getBedrockDefinition(); - setFlag(EntityFlag.USING_ITEM, hasCrossbow); - setFlag(EntityFlag.CHARGED, hasCrossbow); + ItemData activeCrossbow = null; + if (this.hand.getDefinition() == crossbow.getBedrockDefinition()) { + activeCrossbow = this.hand; + } else if (this.offhand.getDefinition() == crossbow.getBedrockDefinition()) { + activeCrossbow = this.offhand; + } + + if (activeCrossbow != null) { + if (activeCrossbow.getTag() != null && activeCrossbow.getTag().containsKey("chargedItem")) { + dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE); + setFlag(EntityFlag.CHARGING, false); + setFlag(EntityFlag.CHARGED, true); + setFlag(EntityFlag.USING_ITEM, true); + } else if (getFlag(EntityFlag.CHARGED)) { + dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0); + setFlag(EntityFlag.CHARGED, false); + setFlag(EntityFlag.USING_ITEM, false); + } + } updateBedrockMetadata(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RavagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RavagerEntity.java new file mode 100644 index 000000000..6190bae10 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RavagerEntity.java @@ -0,0 +1,54 @@ +/* + * 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.entity.type.living.monster.raid; + +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class RavagerEntity extends RaidParticipantEntity { + + public RavagerEntity(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 useArmSwingAttack() { + setFlag(EntityFlag.DELAYED_ATTACK, false); + updateBedrockMetadata(); + + session.scheduleInEventLoop(() -> { + setFlag(EntityFlag.DELAYED_ATTACK, true); + updateBedrockMetadata(); + }, 75, TimeUnit.MILLISECONDS); + + return true; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java index 04a58addd..a2557e75a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.monster.raid; 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.session.GeyserSession; @@ -37,6 +38,7 @@ public class VindicatorEntity extends AbstractIllagerEntity { public VindicatorEntity(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); + dirtyMetadata.put(EntityDataTypes.TARGET_EID, session.getPlayerEntity().getGeyserId()); } @Override @@ -46,4 +48,9 @@ public class VindicatorEntity extends AbstractIllagerEntity { byte xd = entityMetadata.getPrimitiveValue(); setFlag(EntityFlag.ANGRY, (xd & 4) == 4); } + + @Override + public boolean useArmSwingAttack() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java index 0305df685..05f6ba6cc 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java @@ -42,6 +42,7 @@ import java.util.Map; public class StoredItemMappings { private final ItemMapping banner; private final ItemMapping barrier; + private final ItemMapping bow; private final ItemMapping compass; private final ItemMapping crossbow; private final ItemMapping egg; @@ -57,6 +58,7 @@ public class StoredItemMappings { public StoredItemMappings(Map itemMappings) { this.banner = load(itemMappings, Items.WHITE_BANNER); // As of 1.17.10, all banners have the same Bedrock ID this.barrier = load(itemMappings, Items.BARRIER); + this.bow = load(itemMappings, Items.BOW); this.compass = load(itemMappings, Items.COMPASS); this.crossbow = load(itemMappings, Items.CROSSBOW); this.egg = load(itemMappings, Items.EGG); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAnimateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAnimateTranslator.java index 8bd4bad10..bf6dfe684 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAnimateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAnimateTranslator.java @@ -26,10 +26,13 @@ package org.geysermc.geyser.translator.protocol.java.entity; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.packet.AnimateEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; +import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.cloudburstmc.protocol.bedrock.packet.SpawnParticleEffectPacket; import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -57,6 +60,14 @@ public class JavaAnimateTranslator extends PacketTranslator { + if (entity instanceof LivingEntity livingEntity && livingEntity.useArmSwingAttack()) { + EntityEventPacket entityEventPacket = new EntityEventPacket(); + entityEventPacket.setRuntimeEntityId(entity.getGeyserId()); + entityEventPacket.setType(EntityEventType.ATTACK_START); + session.sendUpstreamPacket(entityEventPacket); + return; + } + animatePacket.setAction(AnimatePacket.Action.SWING_ARM); if (entity.getEntityId() == session.getPlayerEntity().getEntityId()) { session.activateArmAnimationTicking(); From e697eb3ae38bbda0b1b4803ea03a73067881dec2 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 10 May 2024 23:58:27 +0200 Subject: [PATCH 131/897] Feat: Make connection data exposed in api less prone to throw errors (#4604) * Feat: Make connection data exposed in api less prone to throw errors * address reviews * review --- .../connection/ConnectionRequestEvent.java | 26 +++++++++++++++++-- .../network/GeyserServerInitializer.java | 5 ---- .../geyser/network/UpstreamPacketHandler.java | 4 +++ .../geyser/session/GeyserSession.java | 12 +++++---- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java index 5c1f4ef51..b36ee8bfb 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java @@ -46,13 +46,35 @@ public final class ConnectionRequestEvent implements Event, Cancellable { this.proxyIp = proxyIp; } + /** + * The IP address of the client attempting to connect + * + * @return the IP address of the client attempting to connect + * @deprecated Use {@link #inetSocketAddress()} instead + */ + @NonNull @Deprecated(forRemoval = true) + public InetSocketAddress getInetSocketAddress() { + return ip; + } + + /** + * The IP address of the proxy handling the connection. It will return null if there is no proxy. + * + * @return the IP address of the proxy handling the connection + * @deprecated Use {@link #proxyIp()} instead + */ + @Nullable @Deprecated(forRemoval = true) + public InetSocketAddress getProxyIp() { + return proxyIp; + } + /** * The IP address of the client attempting to connect * * @return the IP address of the client attempting to connect */ @NonNull - public InetSocketAddress getInetSocketAddress() { + public InetSocketAddress inetSocketAddress() { return ip; } @@ -62,7 +84,7 @@ public final class ConnectionRequestEvent implements Event, Cancellable { * @return the IP address of the proxy handling the connection */ @Nullable - public InetSocketAddress getProxyIp() { + public InetSocketAddress proxyIp() { return proxyIp; } diff --git a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java index 662e2f4c7..5c83702ae 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java +++ b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java @@ -25,11 +25,8 @@ package org.geysermc.geyser.network; -import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; import io.netty.channel.DefaultEventLoopGroup; -import io.netty.channel.SimpleChannelInboundHandler; import io.netty.util.concurrent.DefaultThreadFactory; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.BedrockPeer; @@ -37,7 +34,6 @@ import org.cloudburstmc.protocol.bedrock.BedrockServerSession; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.cloudburstmc.protocol.bedrock.netty.initializer.BedrockServerInitializer; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.event.bedrock.SessionInitializeEvent; import org.geysermc.geyser.session.GeyserSession; import java.net.InetSocketAddress; @@ -72,7 +68,6 @@ public class GeyserServerInitializer extends BedrockServerInitializer { channel.pipeline().addAfter(BedrockPacketCodec.NAME, InvalidPacketHandler.NAME, new InvalidPacketHandler(session)); bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(this.geyser, session)); - this.geyser.eventBus().fire(new SessionInitializeEvent(session)); } catch (Throwable e) { // Error must be caught or it will be swallowed this.geyser.getLogger().error("Error occurred while initializing player!", e); 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 59485b2cd..23ab1697f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -54,6 +54,7 @@ import org.cloudburstmc.protocol.common.PacketSignal; import org.cloudburstmc.protocol.common.util.Zlib; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.event.bedrock.SessionInitializeEvent; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.pack.PackCodec; import org.geysermc.geyser.api.pack.ResourcePack; @@ -188,6 +189,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return PacketSignal.HANDLED; } + // Fire SessionInitializeEvent here as we now know the client data + geyser.eventBus().fire(new SessionInitializeEvent(session)); + PlayStatusPacket playStatus = new PlayStatusPacket(); playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS); session.sendUpstreamPacket(playStatus); 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 d10a20b3d..617087f71 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1077,9 +1077,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { if (!closed) { loggedIn = false; - // Fire SessionDisconnectEvent SessionDisconnectEvent disconnectEvent = new SessionDisconnectEvent(this, reason); - geyser.getEventBus().fire(disconnectEvent); + if (authData != null && clientData != null) { // can occur if player disconnects before Bedrock auth finishes + // Fire SessionDisconnectEvent + geyser.getEventBus().fire(disconnectEvent); + } // Disconnect downstream if necessary if (downstream != null) { @@ -1404,7 +1406,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public String name() { - return null; + return playerEntity != null ? javaUsername() : bedrockUsername(); } @Override @@ -1941,12 +1943,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public @MonotonicNonNull String javaUsername() { - return playerEntity.getUsername(); + return playerEntity != null ? playerEntity.getUsername() : null; } @Override public UUID javaUuid() { - return playerEntity.getUuid(); + return playerEntity != null ? playerEntity.getUuid() : null ; } @Override From 7801e357fb3c8e8ffecd9fb01c143d1c8343106c Mon Sep 17 00:00:00 2001 From: Teelair Date: Fri, 10 May 2024 17:20:52 -0600 Subject: [PATCH 132/897] Map new Mace enchantments for Bedrock clients (#4653) * Map new Mace enchantments for Bedrock clients * Move to using a map for Java-only enchantments. * Change to using null check for translationKey --- .../org/geysermc/geyser/item/type/Item.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) 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 bfcfb23d1..fc4fda07c 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 @@ -53,6 +53,16 @@ import java.util.List; import java.util.Map; public class Item { + /** + * This is a map from Java-only enchantments to their translation keys so that we can + * map these enchantments to Bedrock clients, since they don't actually exist there. + */ + private static final Map ENCHANTMENT_TRANSLATION_KEYS = Map.of( + Enchantment.JavaEnchantment.SWEEPING_EDGE, "enchantment.minecraft.sweeping", + Enchantment.JavaEnchantment.DENSITY, "enchantment.minecraft.density", + Enchantment.JavaEnchantment.BREACH, "enchantment.minecraft.breach", + Enchantment.JavaEnchantment.WIND_BURST, "enchantment.minecraft.wind_burst"); + private final String javaIdentifier; private int javaId = -1; private final int stackSize; @@ -227,8 +237,10 @@ public class Item { // TODO verify // TODO streamline Enchantment process Enchantment.JavaEnchantment enchantment = Enchantment.JavaEnchantment.of(enchantId); - if (enchantment == Enchantment.JavaEnchantment.SWEEPING_EDGE) { - addSweeping(session, builder, level); + String translationKey = ENCHANTMENT_TRANSLATION_KEYS.get(enchantment); + if (translationKey != null) { + String enchantmentTranslation = MinecraftLocale.getLocaleString(translationKey, session.locale()); + addJavaOnlyEnchantment(session, builder, enchantmentTranslation, level); return null; } if (enchantment == null) { @@ -242,11 +254,10 @@ public class Item { .build(); } - private void addSweeping(GeyserSession session, BedrockItemBuilder builder, int level) { - String sweepingTranslation = MinecraftLocale.getLocaleString("enchantment.minecraft.sweeping", session.locale()); + private void addJavaOnlyEnchantment(GeyserSession session, BedrockItemBuilder builder, String enchantmentName, int level) { String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale()); - builder.getOrCreateLore().add(ChatColor.RESET + ChatColor.GRAY + sweepingTranslation + " " + lvlTranslation); + builder.getOrCreateLore().add(ChatColor.RESET + ChatColor.GRAY + enchantmentName + " " + lvlTranslation); } /* Translation methods end */ From 86dafbc108fbc86a5d100b84804321a30f438883 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 12 May 2024 10:49:08 +0200 Subject: [PATCH 133/897] Ensure we load mod resources correctly on Geyser-NeoForge (#4651) * correctly load jar resource files on neoforge * also add support for neoforge-floodgate --- bootstrap/mod/neoforge/build.gradle.kts | 4 ++- .../neoforge/GeyserNeoForgeBootstrap.java | 5 ++-- .../neoforge/GeyserNeoForgePlatform.java | 25 ++++++++++++++++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts index ff77bcc5c..92ffae7e5 100644 --- a/bootstrap/mod/neoforge/build.gradle.kts +++ b/bootstrap/mod/neoforge/build.gradle.kts @@ -31,7 +31,9 @@ dependencies { // Let's shade in our own api shadow(projects.api) { isTransitive = false } - shadow(projects.common) { isTransitive = false } + + // cannot be shaded, since neoforge will complain if floodgate-neoforge tries to provide this + include(projects.common) // Include all transitive deps of core via JiJ includeTransitive(projects.core) 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 1655dea91..b97e42389 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.platform.neoforge; import net.minecraft.commands.CommandSourceStack; import net.minecraft.world.entity.player.Player; +import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; import net.neoforged.fml.loading.FMLLoader; import net.neoforged.neoforge.common.NeoForge; @@ -43,8 +44,8 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { private final GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler(); - public GeyserNeoForgeBootstrap() { - super(new GeyserNeoForgePlatform()); + public GeyserNeoForgeBootstrap(ModContainer container) { + super(new GeyserNeoForgePlatform(container)); if (isServer()) { // Set as an event so we can get the proper IP and port if needed diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePlatform.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePlatform.java index 63abe4a4a..41562baf3 100644 --- a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePlatform.java +++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePlatform.java @@ -26,20 +26,29 @@ package org.geysermc.geyser.platform.neoforge; import net.minecraft.server.MinecraftServer; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.ModList; import net.neoforged.fml.loading.FMLPaths; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.platform.mod.GeyserModBootstrap; import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform; +import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; import java.nio.file.Path; public class GeyserNeoForgePlatform implements GeyserModPlatform { + private final ModContainer container; + + public GeyserNeoForgePlatform(ModContainer container) { + this.container = container; + } + @Override public @NonNull PlatformType platformType() { return PlatformType.NEOFORGE; @@ -62,11 +71,21 @@ public class GeyserNeoForgePlatform implements GeyserModPlatform { @Override public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) { - return false; // No Floodgate mod for NeoForge yet + if (ModList.get().isLoaded("floodgate")) { + Path floodgateDataFolder = FMLPaths.CONFIGDIR.get().resolve("floodgate"); + bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder); + return true; + } + return false; } @Override public @Nullable InputStream resolveResource(@NonNull String resource) { - return GeyserBootstrap.class.getClassLoader().getResourceAsStream(resource); + try { + Path path = container.getModInfo().getOwningFile().getFile().findResource(resource); + return Files.newInputStream(path); + } catch (IOException e) { + return null; + } } } From b11a6d7176bb046dbc0b91a8d2faf251342978e5 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 14 May 2024 13:22:54 +0100 Subject: [PATCH 134/897] Remove unofficial skin sources and add skin event for extensions (#4507) * Remove ears and unoffical skin sources * Remove supplyEars * Cleanup and add SkinApplyEvent * Add failed back to skin * Accept suggestion on SkinGeometry Co-authored-by: chris * Add javadoc and update copyright * Remove old config options * Make SkinApplyEvent a ConnectionEvent * Add warning about third-party config options * Update warning message * Add javadoc to event * Fix javadoc * Ajust for review and bump version to 2.2.4 * Get rid of array and preserve original skin data * Add originalSkin method to event * Handle NonNull in SessionSkinApplyEvent * Revert default copyright change --------- Co-authored-by: chris --- .idea/copyright/Geyser.xml | 3 +- .../event/bedrock/SessionSkinApplyEvent.java | 144 +++++++ .../org/geysermc/geyser/api/skin/Cape.java | 40 ++ .../org/geysermc/geyser/api/skin/Skin.java | 39 ++ .../geysermc/geyser/api/skin/SkinData.java | 32 ++ .../geyser/api/skin/SkinGeometry.java | 48 +++ .../configuration/GeyserConfiguration.java | 4 +- .../geyser/pack/SkullResourcePackManager.java | 4 +- .../geyser/skin/FakeHeadProvider.java | 36 +- .../geysermc/geyser/skin/ProvidedSkins.java | 9 +- .../org/geysermc/geyser/skin/SkinManager.java | 42 +- .../geysermc/geyser/skin/SkinProvider.java | 406 ++++-------------- .../geyser/skin/SkullSkinManager.java | 14 +- .../bedrock/skin/geometry.humanoid.ears.json | 249 ----------- .../skin/geometry.humanoid.earsSlim.json | 249 ----------- core/src/main/resources/config.yml | 8 - gradle.properties | 2 +- 17 files changed, 444 insertions(+), 885 deletions(-) create mode 100644 api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSkinApplyEvent.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/skin/Cape.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/skin/Skin.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java delete mode 100644 core/src/main/resources/bedrock/skin/geometry.humanoid.ears.json delete mode 100644 core/src/main/resources/bedrock/skin/geometry.humanoid.earsSlim.json diff --git a/.idea/copyright/Geyser.xml b/.idea/copyright/Geyser.xml index c6b553aaf..758c31cbd 100644 --- a/.idea/copyright/Geyser.xml +++ b/.idea/copyright/Geyser.xml @@ -1,6 +1,7 @@ - \ No newline at end of file diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSkinApplyEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSkinApplyEvent.java new file mode 100644 index 000000000..f22241e41 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSkinApplyEvent.java @@ -0,0 +1,144 @@ +/* + * 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.api.event.bedrock; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.event.connection.ConnectionEvent; +import org.geysermc.geyser.api.skin.Cape; +import org.geysermc.geyser.api.skin.Skin; +import org.geysermc.geyser.api.skin.SkinData; +import org.geysermc.geyser.api.skin.SkinGeometry; + +import java.util.UUID; + +/** + * Called when a skin is applied to a player. + *

+ * Won't be called when a fake player is spawned for a player skull. + */ +public abstract class SessionSkinApplyEvent extends ConnectionEvent { + + private final String username; + private final UUID uuid; + private final boolean slim; + private final boolean bedrock; + private final SkinData originalSkinData; + + public SessionSkinApplyEvent(@NonNull GeyserConnection connection, String username, UUID uuid, boolean slim, boolean bedrock, SkinData skinData) { + super(connection); + this.username = username; + this.uuid = uuid; + this.slim = slim; + this.bedrock = bedrock; + this.originalSkinData = skinData; + } + + /** + * The username of the player. + * + * @return the username of the player + */ + public @NonNull String username() { + return username; + } + + /** + * The UUID of the player. + * + * @return the UUID of the player + */ + public @NonNull UUID uuid() { + return uuid; + } + + /** + * If the player is using a slim model. + * + * @return if the player is using a slim model + */ + public boolean slim() { + return slim; + } + + /** + * If the player is a Bedrock player. + * + * @return if the player is a Bedrock player + */ + public boolean bedrock() { + return bedrock; + } + + /** + * The original skin data of the player. + * + * @return the original skin data of the player + */ + public @NonNull SkinData originalSkin() { + return originalSkinData; + } + + /** + * The skin data of the player. + * + * @return the current skin data of the player + */ + public abstract @NonNull SkinData skinData(); + + /** + * Change the skin of the player. + * + * @param newSkin the new skin + */ + public abstract void skin(@NonNull Skin newSkin); + + /** + * Change the cape of the player. + * + * @param newCape the new cape + */ + public abstract void cape(@NonNull Cape newCape); + + /** + * Change the geometry of the player. + * + * @param newGeometry the new geometry + */ + public abstract void geometry(@NonNull SkinGeometry newGeometry); + + /** + * Change the geometry of the player. + *

+ * Constructs a generic {@link SkinGeometry} object with the given data. + * + * @param geometryName the name of the geometry + * @param geometryData the data of the geometry + */ + public void geometry(@NonNull String geometryName, @NonNull String geometryData) { + geometry(new SkinGeometry("{\"geometry\" :{\"default\" :\"" + geometryName + "\"}}", geometryData)); + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/skin/Cape.java b/api/src/main/java/org/geysermc/geyser/api/skin/Cape.java new file mode 100644 index 000000000..1e7341ae4 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/skin/Cape.java @@ -0,0 +1,40 @@ +/* + * 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.api.skin; + +/** + * Represents a cape. + * + * @param textureUrl The URL of the cape texture + * @param capeId The ID of the cape + * @param capeData The raw cape image data in ARGB format + * @param failed If the cape failed to load, this is for things like fallback capes + */ +public record Cape(String textureUrl, String capeId, byte[] capeData, boolean failed) { + public Cape(String textureUrl, String capeId, byte[] capeData) { + this(textureUrl, capeId, capeData, false); + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/skin/Skin.java b/api/src/main/java/org/geysermc/geyser/api/skin/Skin.java new file mode 100644 index 000000000..9b39ddfe8 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/skin/Skin.java @@ -0,0 +1,39 @@ +/* + * 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.api.skin; + +/** + * Represents a skin. + * + * @param textureUrl The URL/ID of the skin texture + * @param skinData The raw skin image data in ARGB + * @param failed If the skin failed to load, this is for things like fallback skins + */ +public record Skin(String textureUrl, byte[] skinData, boolean failed) { + public Skin(String textureUrl, byte[] skinData) { + this(textureUrl, skinData, false); + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java b/api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java new file mode 100644 index 000000000..9de4a3534 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java @@ -0,0 +1,32 @@ +/* + * 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.api.skin; + +/** + * Represents a full package of {@link Skin}, {@link Cape}, and {@link SkinGeometry}. + */ +public record SkinData(Skin skin, Cape cape, SkinGeometry geometry) { +} diff --git a/api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java b/api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java new file mode 100644 index 000000000..5b40d2022 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java @@ -0,0 +1,48 @@ +/* + * 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.api.skin; + +/** + * Represents geometry of a skin. + * + * @param geometryName The name of the geometry (JSON) + * @param geometryData The geometry data (JSON) + */ +public record SkinGeometry(String geometryName, String geometryData) { + + public static SkinGeometry WIDE = getLegacy(false); + public static SkinGeometry SLIM = getLegacy(true); + + /** + * Generate generic geometry + * + * @param isSlim if true, it will be the slimmer alex model + * @return The generic geometry object + */ + private static SkinGeometry getLegacy(boolean isSlim) { + return new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.custom" + (isSlim ? "Slim" : "") + "\"}}", ""); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java index d12ab79e9..88bb98171 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.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 @@ -72,8 +72,10 @@ public interface GeyserConfiguration { boolean isDebugMode(); + @Deprecated boolean isAllowThirdPartyCapes(); + @Deprecated boolean isAllowThirdPartyEars(); String getShowCooldown(); diff --git a/core/src/main/java/org/geysermc/geyser/pack/SkullResourcePackManager.java b/core/src/main/java/org/geysermc/geyser/pack/SkullResourcePackManager.java index f0faa4244..59651d139 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/SkullResourcePackManager.java +++ b/core/src/main/java/org/geysermc/geyser/pack/SkullResourcePackManager.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 @@ -118,7 +118,7 @@ public class SkullResourcePackManager { return; } - BufferedImage image = SkinProvider.requestImage(skinUrl, null); + BufferedImage image = SkinProvider.requestImage(skinUrl, false); // Resize skins to 48x16 to save on space and memory BufferedImage skullTexture = new BufferedImage(48, 16, image.getType()); // Reorder skin parts to fit into the space diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index d2a45b614..ef3ff3293 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.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 @@ -38,6 +38,10 @@ import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.skin.Cape; +import org.geysermc.geyser.api.skin.Skin; +import org.geysermc.geyser.api.skin.SkinData; +import org.geysermc.geyser.api.skin.SkinGeometry; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; @@ -59,27 +63,27 @@ import java.util.concurrent.TimeUnit; * Responsible for modifying a player's skin when wearing a player head */ public class FakeHeadProvider { - private static final LoadingCache MERGED_SKINS_LOADING_CACHE = CacheBuilder.newBuilder() + private static final LoadingCache MERGED_SKINS_LOADING_CACHE = CacheBuilder.newBuilder() .expireAfterAccess(1, TimeUnit.HOURS) .maximumSize(10000) .build(new CacheLoader<>() { @Override - public SkinProvider.SkinData load(@NonNull FakeHeadEntry fakeHeadEntry) throws Exception { - SkinProvider.SkinData skinData = SkinProvider.getOrDefault(SkinProvider.requestSkinData(fakeHeadEntry.getEntity()), null, 5); + public SkinData load(@NonNull FakeHeadEntry fakeHeadEntry) throws Exception { + SkinData skinData = SkinProvider.getOrDefault(SkinProvider.requestSkinData(fakeHeadEntry.getEntity(), fakeHeadEntry.getSession()), null, 5); if (skinData == null) { throw new Exception("Couldn't load player's original skin"); } - SkinProvider.Skin skin = skinData.skin(); - SkinProvider.Cape cape = skinData.cape(); - SkinProvider.SkinGeometry geometry = skinData.geometry().geometryName().equals("{\"geometry\" :{\"default\" :\"geometry.humanoid.customSlim\"}}") + Skin skin = skinData.skin(); + Cape cape = skinData.cape(); + SkinGeometry geometry = skinData.geometry().geometryName().equals("{\"geometry\" :{\"default\" :\"geometry.humanoid.customSlim\"}}") ? SkinProvider.WEARING_CUSTOM_SKULL_SLIM : SkinProvider.WEARING_CUSTOM_SKULL; - SkinProvider.Skin headSkin = SkinProvider.getOrDefault( + Skin headSkin = SkinProvider.getOrDefault( SkinProvider.requestSkin(fakeHeadEntry.getEntity().getUuid(), fakeHeadEntry.getFakeHeadSkinUrl(), false), SkinProvider.EMPTY_SKIN, 5); - BufferedImage originalSkinImage = SkinProvider.imageDataToBufferedImage(skin.getSkinData(), 64, skin.getSkinData().length / 4 / 64); - BufferedImage headSkinImage = SkinProvider.imageDataToBufferedImage(headSkin.getSkinData(), 64, headSkin.getSkinData().length / 4 / 64); + BufferedImage originalSkinImage = SkinProvider.imageDataToBufferedImage(skin.skinData(), 64, skin.skinData().length / 4 / 64); + BufferedImage headSkinImage = SkinProvider.imageDataToBufferedImage(headSkin.skinData(), 64, headSkin.skinData().length / 4 / 64); Graphics2D graphics2D = originalSkinImage.createGraphics(); graphics2D.setComposite(AlphaComposite.Clear); @@ -90,14 +94,15 @@ public class FakeHeadProvider { // Make the skin key a combination of the current skin data and the new skin data // Don't tie it to a player - that player *can* change skins in-game - String skinKey = "customPlayerHead_" + fakeHeadEntry.getFakeHeadSkinUrl() + "_" + skin.getTextureUrl(); + String skinKey = "customPlayerHead_" + fakeHeadEntry.getFakeHeadSkinUrl() + "_" + skin.textureUrl(); byte[] targetSkinData = SkinProvider.bufferedImageToImageData(originalSkinImage); - SkinProvider.Skin mergedSkin = new SkinProvider.Skin(fakeHeadEntry.getEntity().getUuid(), skinKey, targetSkinData, System.currentTimeMillis(), false, false); + Skin mergedSkin = new Skin(skinKey, targetSkinData); // Avoiding memory leak fakeHeadEntry.setEntity(null); + fakeHeadEntry.setSession(null); - return new SkinProvider.SkinData(mergedSkin, cape, geometry); + return new SkinData(mergedSkin, cape, geometry); } }); @@ -164,7 +169,7 @@ public class FakeHeadProvider { String texturesProperty = entity.getTexturesProperty(); SkinProvider.getExecutorService().execute(() -> { try { - SkinProvider.SkinData mergedSkinData = MERGED_SKINS_LOADING_CACHE.get(new FakeHeadEntry(texturesProperty, fakeHeadSkinUrl, entity)); + SkinData mergedSkinData = MERGED_SKINS_LOADING_CACHE.get(new FakeHeadEntry(texturesProperty, fakeHeadSkinUrl, entity, session)); SkinManager.sendSkinPacket(session, entity, mergedSkinData); } catch (ExecutionException e) { GeyserImpl.getInstance().getLogger().error("Couldn't merge skin of " + entity.getUsername() + " with head skin url " + fakeHeadSkinUrl, e); @@ -181,7 +186,7 @@ public class FakeHeadProvider { return; } - SkinProvider.requestSkinData(entity).whenCompleteAsync((skinData, throwable) -> { + SkinProvider.requestSkinData(entity, session).whenCompleteAsync((skinData, throwable) -> { if (throwable != null) { GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), throwable); return; @@ -198,6 +203,7 @@ public class FakeHeadProvider { private final String texturesProperty; private final String fakeHeadSkinUrl; private PlayerEntity entity; + private GeyserSession session; @Override public boolean equals(Object o) { diff --git a/core/src/main/java/org/geysermc/geyser/skin/ProvidedSkins.java b/core/src/main/java/org/geysermc/geyser/skin/ProvidedSkins.java index 58c8f0072..ba74fbb42 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/ProvidedSkins.java +++ b/core/src/main/java/org/geysermc/geyser/skin/ProvidedSkins.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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.skin; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.skin.Skin; import org.geysermc.geyser.util.AssetUtils; import javax.imageio.ImageIO; @@ -67,7 +68,7 @@ public final class ProvidedSkins { } public static final class ProvidedSkin { - private SkinProvider.Skin data; + private Skin data; private final boolean slim; ProvidedSkin(String asset, boolean slim) { @@ -94,14 +95,14 @@ public final class ProvidedSkins { image.flush(); String identifier = "geysermc:" + assetName + "_" + (slim ? "slim" : "wide"); - this.data = new SkinProvider.Skin(-1, identifier, byteData); + this.data = new Skin(identifier, byteData, true); } catch (IOException e) { e.printStackTrace(); } })); } - public SkinProvider.Skin getData() { + public Skin getData() { // Fall back to the default skin if we can't load our skins, or it's not loaded yet. return Objects.requireNonNullElse(data, SkinProvider.EMPTY_SKIN); } diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java index 4f3a94688..7b126c136 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.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 @@ -34,6 +34,10 @@ import org.cloudburstmc.protocol.bedrock.data.skin.SerializedSkin; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerSkinPacket; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.skin.Cape; +import org.geysermc.geyser.api.skin.Skin; +import org.geysermc.geyser.api.skin.SkinData; +import org.geysermc.geyser.api.skin.SkinGeometry; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; import org.geysermc.geyser.session.GeyserSession; @@ -56,21 +60,21 @@ public class SkinManager { public static PlayerListPacket.Entry buildCachedEntry(GeyserSession session, PlayerEntity playerEntity) { // First: see if we have the cached skin texture ID. GameProfileData data = GameProfileData.from(playerEntity); - SkinProvider.Skin skin = null; - SkinProvider.Cape cape = null; - SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.WIDE; + Skin skin = null; + Cape cape = null; + SkinGeometry geometry = SkinGeometry.WIDE; if (data != null) { // GameProfileData is not null = server provided us with textures data to work with. skin = SkinProvider.getCachedSkin(data.skinUrl()); cape = SkinProvider.getCachedCape(data.capeUrl()); - geometry = data.isAlex() ? SkinProvider.SkinGeometry.SLIM : SkinProvider.SkinGeometry.WIDE; + geometry = data.isAlex() ? SkinGeometry.SLIM : SkinGeometry.WIDE; } if (skin == null || cape == null) { // The server either didn't have a texture to send, or we didn't have the texture ID cached. // Let's see if this player is a Bedrock player, and if so, let's pull their skin. // Otherwise, grab the default player skin - SkinProvider.SkinData fallbackSkinData = SkinProvider.determineFallbackSkinData(playerEntity.getUuid()); + SkinData fallbackSkinData = SkinProvider.determineFallbackSkinData(playerEntity.getUuid()); if (skin == null) { skin = fallbackSkinData.skin(); geometry = fallbackSkinData.geometry(); @@ -95,10 +99,10 @@ public class SkinManager { * With all the information needed, build a Bedrock player entry with translated skin information. */ public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, UUID uuid, String username, long geyserId, - SkinProvider.Skin skin, - SkinProvider.Cape cape, - SkinProvider.SkinGeometry geometry) { - SerializedSkin serializedSkin = getSkin(skin.getTextureUrl(), skin, cape, geometry); + Skin skin, + Cape cape, + SkinGeometry geometry) { + SerializedSkin serializedSkin = getSkin(skin.textureUrl(), skin, cape, geometry); // This attempts to find the XUID of the player so profile images show up for Xbox accounts String xuid = ""; @@ -128,10 +132,10 @@ public class SkinManager { return entry; } - public static void sendSkinPacket(GeyserSession session, PlayerEntity entity, SkinProvider.SkinData skinData) { - SkinProvider.Skin skin = skinData.skin(); - SkinProvider.Cape cape = skinData.cape(); - SkinProvider.SkinGeometry geometry = skinData.geometry(); + public static void sendSkinPacket(GeyserSession session, PlayerEntity entity, SkinData skinData) { + Skin skin = skinData.skin(); + Cape cape = skinData.cape(); + SkinGeometry geometry = skinData.geometry(); if (entity.getUuid().equals(session.getPlayerEntity().getUuid())) { // TODO is this special behavior needed? @@ -153,23 +157,23 @@ public class SkinManager { PlayerSkinPacket packet = new PlayerSkinPacket(); packet.setUuid(entity.getUuid()); packet.setOldSkinName(""); - packet.setNewSkinName(skin.getTextureUrl()); - packet.setSkin(getSkin(skin.getTextureUrl(), skin, cape, geometry)); + packet.setNewSkinName(skin.textureUrl()); + packet.setSkin(getSkin(skin.textureUrl(), skin, cape, geometry)); packet.setTrustedSkin(true); session.sendUpstreamPacket(packet); } } - private static SerializedSkin getSkin(String skinId, SkinProvider.Skin skin, SkinProvider.Cape cape, SkinProvider.SkinGeometry geometry) { + private static SerializedSkin getSkin(String skinId, Skin skin, Cape cape, SkinGeometry geometry) { return SerializedSkin.of(skinId, "", geometry.geometryName(), - ImageData.of(skin.getSkinData()), Collections.emptyList(), + ImageData.of(skin.skinData()), Collections.emptyList(), ImageData.of(cape.capeData()), geometry.geometryData(), "", true, false, false, cape.capeId(), skinId); } public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSession session, Consumer skinAndCapeConsumer) { - SkinProvider.requestSkinData(entity).whenCompleteAsync((skinData, throwable) -> { + SkinProvider.requestSkinData(entity, session).whenCompleteAsync((skinData, throwable) -> { if (skinData == null) { if (skinAndCapeConsumer != null) { skinAndCapeConsumer.accept(null); diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index 683712c22..3b31dfff8 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java @@ -35,7 +35,12 @@ import lombok.NoArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.event.bedrock.SessionSkinApplyEvent; import org.geysermc.geyser.api.network.AuthType; +import org.geysermc.geyser.api.skin.Cape; +import org.geysermc.geyser.api.skin.Skin; +import org.geysermc.geyser.api.skin.SkinData; +import org.geysermc.geyser.api.skin.SkinGeometry; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -45,7 +50,6 @@ import org.geysermc.geyser.util.WebUtils; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -57,11 +61,10 @@ import java.util.concurrent.*; import java.util.function.Predicate; public class SkinProvider { - private static final boolean ALLOW_THIRD_PARTY_CAPES = GeyserImpl.getInstance().getConfig().isAllowThirdPartyCapes(); private static ExecutorService EXECUTOR_SERVICE; static final Skin EMPTY_SKIN; - static final Cape EMPTY_CAPE = new Cape("", "no-cape", ByteArrays.EMPTY_ARRAY, -1, true); + static final Cape EMPTY_CAPE = new Cape("", "no-cape", ByteArrays.EMPTY_ARRAY, true); private static final Cache CACHED_JAVA_CAPES = CacheBuilder.newBuilder() .expireAfterAccess(1, TimeUnit.HOURS) @@ -88,9 +91,6 @@ public class SkinProvider { */ private static final Predicate IS_NPC = uuid -> uuid.version() == 2; - private static final boolean ALLOW_THIRD_PARTY_EARS = GeyserImpl.getInstance().getConfig().isAllowThirdPartyEars(); - private static final String EARS_GEOMETRY; - private static final String EARS_GEOMETRY_SLIM; static final SkinGeometry SKULL_GEOMETRY; static final SkinGeometry WEARING_CUSTOM_SKULL; static final SkinGeometry WEARING_CUSTOM_SKULL_SLIM; @@ -114,28 +114,27 @@ public class SkinProvider { outputStream.write((rgba >> 24) & 0xFF); // Alpha } } - EMPTY_SKIN = new Skin(-1, "geysermc:empty", outputStream.toByteArray()); - - /* Load in the normal ears geometry */ - EARS_GEOMETRY = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.ears.json"), StandardCharsets.UTF_8); - - /* Load in the slim ears geometry */ - EARS_GEOMETRY_SLIM = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.earsSlim.json"), StandardCharsets.UTF_8); + EMPTY_SKIN = new Skin("geysermc:empty", outputStream.toByteArray(), true); /* Load in the custom skull geometry */ String skullData = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.customskull.json"), StandardCharsets.UTF_8); - SKULL_GEOMETRY = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.customskull\"}}", skullData, false); + SKULL_GEOMETRY = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.customskull\"}}", skullData); /* Load in the player head skull geometry */ String wearingCustomSkull = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.wearingCustomSkull.json"), StandardCharsets.UTF_8); - WEARING_CUSTOM_SKULL = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkull\"}}", wearingCustomSkull, false); + WEARING_CUSTOM_SKULL = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkull\"}}", wearingCustomSkull); String wearingCustomSkullSlim = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json"), StandardCharsets.UTF_8); - WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim, false); + WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim); + + GeyserImpl geyser = GeyserImpl.getInstance(); + if (geyser.getConfig().isAllowThirdPartyEars() || geyser.getConfig().isAllowThirdPartyCapes()) { + geyser.getLogger().warning("Third-party ears/capes have been removed from Geyser, if you still wish to have this functionality please use the extension: https://github.com/GeyserMC/ThirdPartyCosmetics"); + } } public static ExecutorService getExecutorService() { if (EXECUTOR_SERVICE == null) { - EXECUTOR_SERVICE = Executors.newFixedThreadPool(ALLOW_THIRD_PARTY_CAPES ? 21 : 14); + EXECUTOR_SERVICE = Executors.newFixedThreadPool(14); } return EXECUTOR_SERVICE; } @@ -204,7 +203,7 @@ public class SkinProvider { // We don't have a skin for the player right now. Fall back to a default. ProvidedSkins.ProvidedSkin providedSkin = ProvidedSkins.getDefaultPlayerSkin(uuid); skin = providedSkin.getData(); - geometry = providedSkin.isSlim() ? SkinProvider.SkinGeometry.SLIM : SkinProvider.SkinGeometry.WIDE; + geometry = providedSkin.isSlim() ? SkinGeometry.SLIM : SkinGeometry.WIDE; } if (cape == null) { @@ -238,7 +237,7 @@ public class SkinProvider { return CACHED_JAVA_CAPES.getIfPresent(capeUrl); } - static CompletableFuture requestSkinData(PlayerEntity entity) { + static CompletableFuture requestSkinData(PlayerEntity entity, GeyserSession session) { SkinManager.GameProfileData data = SkinManager.GameProfileData.from(entity); if (data == null) { // This player likely does not have a textures property @@ -260,42 +259,33 @@ public class SkinProvider { cape = getCachedBedrockCape(entity.getUuid()); } - if (cape.failed() && ALLOW_THIRD_PARTY_CAPES) { - cape = getOrDefault(requestUnofficialCape( - cape, entity.getUuid(), - entity.getUsername(), false - ), EMPTY_CAPE, CapeProvider.VALUES.length * 3); - } - - boolean isDeadmau5 = "deadmau5".equals(entity.getUsername()); - // Not a bedrock player check for ears - if (geometry.failed() && (ALLOW_THIRD_PARTY_EARS || isDeadmau5)) { - boolean isEars; - - // Its deadmau5, gotta support his skin :) - if (isDeadmau5) { - isEars = true; - } else { - // Get the ears texture for the player - skin = getOrDefault(requestUnofficialEars( - skin, entity.getUuid(), entity.getUsername(), false - ), skin, 3); - - isEars = skin.isEars(); + // Call event to allow extensions to modify the skin, cape and geo + boolean isBedrock = GeyserImpl.getInstance().connectionByUuid(entity.getUuid()) != null; + SkinData skinData = new SkinData(skin, cape, geometry); + final EventSkinData eventSkinData = new EventSkinData(skinData); + GeyserImpl.getInstance().eventBus().fire(new SessionSkinApplyEvent(session, entity.getUsername(), entity.getUuid(), data.isAlex(), isBedrock, skinData) { + @Override + public SkinData skinData() { + return eventSkinData.skinData(); } - // Does the skin have an ears texture - if (isEars) { - // Get the new geometry - geometry = SkinGeometry.getEars(data.isAlex()); - - // Store the skin and geometry for the ears - storeEarSkin(skin); - storeEarGeometry(entity.getUuid(), data.isAlex()); + @Override + public void skin(@NonNull Skin newSkin) { + eventSkinData.skinData(new SkinData(Objects.requireNonNull(newSkin), skinData.cape(), skinData.geometry())); } - } - return new SkinData(skin, cape, geometry); + @Override + public void cape(@NonNull Cape newCape) { + eventSkinData.skinData(new SkinData(skinData.skin(), Objects.requireNonNull(newCape), skinData.geometry())); + } + + @Override + public void geometry(@NonNull SkinGeometry newGeometry) { + eventSkinData.skinData(new SkinData(skinData.skin(), skinData.cape(), Objects.requireNonNull(newGeometry))); + } + }); + + return eventSkinData.skinData(); } catch (Exception e) { GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), e); } @@ -308,10 +298,9 @@ public class SkinProvider { return CompletableFuture.supplyAsync(() -> { long time = System.currentTimeMillis(); - CapeProvider provider = capeUrl != null ? CapeProvider.MINECRAFT : null; SkinAndCape skinAndCape = new SkinAndCape( getOrDefault(requestSkin(playerId, skinUrl, false), EMPTY_SKIN, 5), - getOrDefault(requestCape(capeUrl, provider, false), EMPTY_CAPE, 5) + getOrDefault(requestCape(capeUrl, false), EMPTY_CAPE, 5) ); GeyserImpl.getInstance().getLogger().debug("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId); @@ -336,7 +325,6 @@ public class SkinProvider { if (newThread) { future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), getExecutorService()) .whenCompleteAsync((skin, throwable) -> { - skin.updated = true; CACHED_JAVA_SKINS.put(textureUrl, skin); requestedSkins.remove(textureUrl); }); @@ -349,7 +337,7 @@ public class SkinProvider { return future; } - private static CompletableFuture requestCape(String capeUrl, CapeProvider provider, boolean newThread) { + private static CompletableFuture requestCape(String capeUrl, boolean newThread) { if (capeUrl == null || capeUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_CAPE); CompletableFuture requestedCape = requestedCapes.get(capeUrl); if (requestedCape != null) { @@ -363,128 +351,48 @@ public class SkinProvider { CompletableFuture future; if (newThread) { - future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl, provider), getExecutorService()) + future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl), getExecutorService()) .whenCompleteAsync((cape, throwable) -> { CACHED_JAVA_CAPES.put(capeUrl, cape); requestedCapes.remove(capeUrl); }); requestedCapes.put(capeUrl, future); } else { - Cape cape = supplyCape(capeUrl, provider); // blocking + Cape cape = supplyCape(capeUrl); // blocking future = CompletableFuture.completedFuture(cape); CACHED_JAVA_CAPES.put(capeUrl, cape); } return future; } - private static CompletableFuture requestUnofficialCape(Cape officialCape, UUID playerId, - String username, boolean newThread) { - if (officialCape.failed() && ALLOW_THIRD_PARTY_CAPES) { - for (CapeProvider provider : CapeProvider.VALUES) { - if (provider.type != CapeUrlType.USERNAME && IS_NPC.test(playerId)) { - continue; - } - - Cape cape1 = getOrDefault( - requestCape(provider.getUrlFor(playerId, username), provider, newThread), - EMPTY_CAPE, 4 - ); - if (!cape1.failed()) { - return CompletableFuture.completedFuture(cape1); - } - } - } - return CompletableFuture.completedFuture(officialCape); - } - - private static CompletableFuture requestEars(String earsUrl, boolean newThread, Skin skin) { - if (earsUrl == null || earsUrl.isEmpty()) return CompletableFuture.completedFuture(skin); - - CompletableFuture future; - if (newThread) { - future = CompletableFuture.supplyAsync(() -> supplyEars(skin, earsUrl), getExecutorService()) - .whenCompleteAsync((outSkin, throwable) -> { }); - } else { - Skin ears = supplyEars(skin, earsUrl); // blocking - future = CompletableFuture.completedFuture(ears); - } - return future; - } - - /** - * Try and find an ear texture for a Java player - * - * @param officialSkin The current players skin - * @param playerId The players UUID - * @param username The players username - * @param newThread Should we start in a new thread - * @return The updated skin with ears - */ - private static CompletableFuture requestUnofficialEars(Skin officialSkin, UUID playerId, String username, boolean newThread) { - for (EarsProvider provider : EarsProvider.VALUES) { - if (provider.type != CapeUrlType.USERNAME && IS_NPC.test(playerId)) { - continue; - } - - Skin skin1 = getOrDefault( - requestEars(provider.getUrlFor(playerId, username), newThread, officialSkin), - officialSkin, 4 - ); - if (skin1.isEars()) { - return CompletableFuture.completedFuture(skin1); - } - } - - return CompletableFuture.completedFuture(officialSkin); - } - static void storeBedrockSkin(UUID playerID, String skinId, byte[] skinData) { - Skin skin = new Skin(playerID, skinId, skinData, System.currentTimeMillis(), true, false); - CACHED_BEDROCK_SKINS.put(skin.getTextureUrl(), skin); + Skin skin = new Skin(skinId, skinData); + CACHED_BEDROCK_SKINS.put(skin.textureUrl(), skin); } static void storeBedrockCape(String capeId, byte[] capeData) { - Cape cape = new Cape(capeId, capeId, capeData, System.currentTimeMillis(), false); + Cape cape = new Cape(capeId, capeId, capeData); CACHED_BEDROCK_CAPES.put(capeId, cape); } static void storeBedrockGeometry(UUID playerID, byte[] geometryName, byte[] geometryData) { - SkinGeometry geometry = new SkinGeometry(new String(geometryName), new String(geometryData), false); + SkinGeometry geometry = new SkinGeometry(new String(geometryName), new String(geometryData)); cachedGeometry.put(playerID, geometry); } - /** - * Stores the adjusted skin with the ear texture to the cache - * - * @param skin The skin to cache - */ - public static void storeEarSkin(Skin skin) { - CACHED_JAVA_SKINS.put(skin.getTextureUrl(), skin); - } - - /** - * Stores the geometry for a Java player with ears - * - * @param playerID The UUID to cache it against - * @param isSlim If the player is using an slim base - */ - private static void storeEarGeometry(UUID playerID, boolean isSlim) { - cachedGeometry.put(playerID, SkinGeometry.getEars(isSlim)); - } - private static Skin supplySkin(UUID uuid, String textureUrl) { try { - byte[] skin = requestImageData(textureUrl, null); - return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false, false); + byte[] skin = requestImageData(textureUrl, false); + return new Skin(textureUrl, skin); } catch (Exception ignored) {} // just ignore I guess - return new Skin(uuid, "empty", EMPTY_SKIN.getSkinData(), System.currentTimeMillis(), false, false); + return new Skin("empty", EMPTY_SKIN.skinData(), true); } - private static Cape supplyCape(String capeUrl, CapeProvider provider) { + private static Cape supplyCape(String capeUrl) { byte[] cape = EMPTY_CAPE.capeData(); try { - cape = requestImageData(capeUrl, provider); + cape = requestImageData(capeUrl, true); } catch (Exception ignored) { } // just ignore I guess @@ -494,54 +402,12 @@ public class SkinProvider { capeUrl, urlSection[urlSection.length - 1], // get the texture id and use it as cape id cape, - System.currentTimeMillis(), cape.length == 0 ); } - /** - * Get the ears texture and place it on the skin from the given URL - * - * @param existingSkin The players current skin - * @param earsUrl The URL to get the ears texture from - * @return The updated skin with ears - */ - private static Skin supplyEars(Skin existingSkin, String earsUrl) { - try { - // Get the ears texture - BufferedImage ears = ImageIO.read(new URL(earsUrl)); - if (ears == null) throw new NullPointerException(); - - // Convert the skin data to a BufferedImage - int height = (existingSkin.getSkinData().length / 4 / 64); - BufferedImage skinImage = imageDataToBufferedImage(existingSkin.getSkinData(), 64, height); - - // Create a new image with the ears texture over it - BufferedImage newSkin = new BufferedImage(skinImage.getWidth(), skinImage.getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D g = (Graphics2D) newSkin.getGraphics(); - g.drawImage(skinImage, 0, 0, null); - g.drawImage(ears, 24, 0, null); - - // Turn the buffered image back into an array of bytes - byte[] data = bufferedImageToImageData(newSkin); - skinImage.flush(); - - // Create a new skin object with the new infomation - return new Skin( - existingSkin.getSkinOwner(), - existingSkin.getTextureUrl(), - data, - System.currentTimeMillis(), - true, - true - ); - } catch (Exception ignored) {} // just ignore I guess - - return existingSkin; - } - @SuppressWarnings("ResultOfMethodCallIgnored") - public static BufferedImage requestImage(String imageUrl, CapeProvider provider) throws IOException { + public static BufferedImage requestImage(String imageUrl, boolean isCape) throws IOException { BufferedImage image = null; // First see if we have a cached file. We also update the modification stamp so we know when the file was last used @@ -556,7 +422,7 @@ public class SkinProvider { // If no image we download it if (image == null) { - image = downloadImage(imageUrl, provider); + image = downloadImage(imageUrl); GeyserImpl.getInstance().getLogger().debug("Downloaded " + imageUrl); // Write to cache if we are allowed @@ -572,7 +438,7 @@ public class SkinProvider { } // if the requested image is a cape - if (provider != null) { + if (isCape) { if (image.getWidth() > 64 || image.getHeight() > 32) { // Prevent weirdly-scaled capes from being cut off BufferedImage newImage = new BufferedImage(128, 64, BufferedImage.TYPE_INT_ARGB); @@ -604,8 +470,8 @@ public class SkinProvider { return image; } - private static byte[] requestImageData(String imageUrl, CapeProvider provider) throws Exception { - BufferedImage image = requestImage(imageUrl, provider); + private static byte[] requestImageData(String imageUrl, boolean isCape) throws Exception { + BufferedImage image = requestImage(imageUrl, isCape); byte[] data = bufferedImageToImageData(image); image.flush(); return data; @@ -668,35 +534,20 @@ public class SkinProvider { }); } - private static BufferedImage downloadImage(String imageUrl, CapeProvider provider) throws IOException { - BufferedImage image; - if (provider == CapeProvider.FIVEZIG) { - image = readFiveZigCape(imageUrl); - } else { - HttpURLConnection con = (HttpURLConnection) new URL(imageUrl).openConnection(); - con.setRequestProperty("User-Agent", WebUtils.getUserAgent()); - con.setConnectTimeout(10000); - con.setReadTimeout(10000); + private static BufferedImage downloadImage(String imageUrl) throws IOException { + HttpURLConnection con = (HttpURLConnection) new URL(imageUrl).openConnection(); + con.setRequestProperty("User-Agent", WebUtils.getUserAgent()); + con.setConnectTimeout(10000); + con.setReadTimeout(10000); - image = ImageIO.read(con.getInputStream()); - } + BufferedImage image = ImageIO.read(con.getInputStream()); if (image == null) { - throw new IllegalArgumentException("Failed to read image from: %s (cape provider=%s)".formatted(imageUrl, provider)); + throw new IllegalArgumentException("Failed to read image from: %s".formatted(imageUrl)); } return image; } - private static @Nullable BufferedImage readFiveZigCape(String url) throws IOException { - JsonNode element = GeyserImpl.JSON_MAPPER.readTree(WebUtils.getBody(url)); - if (element != null && element.isObject()) { - JsonNode capeElement = element.get("d"); - if (capeElement == null || capeElement.isNull()) return null; - return ImageIO.read(new ByteArrayInputStream(Base64.getDecoder().decode(capeElement.textValue()))); - } - return null; - } - public static BufferedImage scale(BufferedImage bufferedImage, int newWidth, int newHeight) { BufferedImage resized = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = resized.createGraphics(); @@ -770,124 +621,19 @@ public class SkinProvider { public record SkinAndCape(Skin skin, Cape cape) { } - /** - * Represents a full package of skin, cape, and geometry. - */ - public record SkinData(Skin skin, Cape cape, SkinGeometry geometry) { - } + public static class EventSkinData { + private SkinData skinData; - @AllArgsConstructor - @Getter - public static class Skin { - private UUID skinOwner; - private final String textureUrl; - private final byte[] skinData; - private final long requestedOn; - private boolean updated; - private boolean ears; + public EventSkinData(SkinData skinData) { + this.skinData = skinData; + } - Skin(long requestedOn, String textureUrl, byte[] skinData) { - this.requestedOn = requestedOn; - this.textureUrl = textureUrl; + public SkinData skinData() { + return skinData; + } + + public void skinData(SkinData skinData) { this.skinData = skinData; } } - - public record Cape(String textureUrl, String capeId, byte[] capeData, long requestedOn, boolean failed) { - } - - public record SkinGeometry(String geometryName, String geometryData, boolean failed) { - public static SkinGeometry WIDE = getLegacy(false); - public static SkinGeometry SLIM = getLegacy(true); - - /** - * Generate generic geometry - * - * @param isSlim Should it be the alex model - * @return The generic geometry object - */ - private static SkinGeometry getLegacy(boolean isSlim) { - return new SkinProvider.SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.custom" + (isSlim ? "Slim" : "") + "\"}}", "", true); - } - - /** - * Generate basic geometry with ears - * - * @param isSlim Should it be the alex model - * @return The generated geometry for the ears model - */ - private static SkinGeometry getEars(boolean isSlim) { - return new SkinProvider.SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.ears" + (isSlim ? "Slim" : "") + "\"}}", (isSlim ? EARS_GEOMETRY_SLIM : EARS_GEOMETRY), false); - } - } - - /* - * Sorted by 'priority' - */ - @AllArgsConstructor - @NoArgsConstructor - @Getter - public enum CapeProvider { - MINECRAFT, - OPTIFINE("https://optifine.net/capes/%s.png", CapeUrlType.USERNAME), - LABYMOD("https://dl.labymod.net/capes/%s", CapeUrlType.UUID_DASHED), - FIVEZIG("https://textures.5zigreborn.eu/profile/%s", CapeUrlType.UUID_DASHED), - MINECRAFTCAPES("https://api.minecraftcapes.net/profile/%s/cape", CapeUrlType.UUID); - - public static final CapeProvider[] VALUES = Arrays.copyOfRange(values(), 1, 5); - private String url; - private CapeUrlType type; - - public String getUrlFor(String type) { - return String.format(url, type); - } - - public String getUrlFor(UUID uuid, String username) { - return getUrlFor(toRequestedType(type, uuid, username)); - } - - public static String toRequestedType(CapeUrlType type, UUID uuid, String username) { - return switch (type) { - case UUID -> uuid.toString().replace("-", ""); - case UUID_DASHED -> uuid.toString(); - default -> username; - }; - } - } - - public enum CapeUrlType { - USERNAME, - UUID, - UUID_DASHED - } - - /* - * Sorted by 'priority' - */ - @AllArgsConstructor - @NoArgsConstructor - @Getter - public enum EarsProvider { - MINECRAFTCAPES("https://api.minecraftcapes.net/profile/%s/ears", CapeUrlType.UUID); - - public static final EarsProvider[] VALUES = values(); - private String url; - private CapeUrlType type; - - public String getUrlFor(String type) { - return String.format(url, type); - } - - public String getUrlFor(UUID uuid, String username) { - return getUrlFor(toRequestedType(type, uuid, username)); - } - - public static String toRequestedType(CapeUrlType type, UUID uuid, String username) { - return switch (type) { - case UUID -> uuid.toString().replace("-", ""); - case UUID_DASHED -> uuid.toString(); - default -> username; - }; - } - } } diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java index 18edc8079..e3f00d3b7 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.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 @@ -29,6 +29,8 @@ import org.cloudburstmc.protocol.bedrock.data.skin.ImageData; import org.cloudburstmc.protocol.bedrock.data.skin.SerializedSkin; import org.cloudburstmc.protocol.bedrock.packet.PlayerSkinPacket; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.skin.Skin; +import org.geysermc.geyser.api.skin.SkinData; import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -50,14 +52,14 @@ public class SkullSkinManager extends SkinManager { } public static void requestAndHandleSkin(SkullPlayerEntity entity, GeyserSession session, - Consumer skinConsumer) { - BiConsumer applySkin = (skin, throwable) -> { + Consumer skinConsumer) { + BiConsumer applySkin = (skin, throwable) -> { try { PlayerSkinPacket packet = new PlayerSkinPacket(); packet.setUuid(entity.getUuid()); packet.setOldSkinName(""); - packet.setNewSkinName(skin.getTextureUrl()); - packet.setSkin(buildSkullEntryManually(skin.getTextureUrl(), skin.getSkinData())); + packet.setNewSkinName(skin.textureUrl()); + packet.setSkin(buildSkullEntryManually(skin.textureUrl(), skin.skinData())); packet.setTrustedSkin(true); session.sendUpstreamPacket(packet); } catch (Exception e) { @@ -74,7 +76,7 @@ public class SkullSkinManager extends SkinManager { GeyserImpl.getInstance().getLogger().debug("Using fallback skin for skull at " + entity.getSkullPosition() + " with texture value: " + entity.getTexturesProperty() + " and UUID: " + entity.getSkullUUID()); // No texture available, fallback using the UUID - SkinProvider.SkinData fallback = SkinProvider.determineFallbackSkinData(entity.getSkullUUID()); + SkinData fallback = SkinProvider.determineFallbackSkinData(entity.getSkullUUID()); applySkin.accept(fallback.skin(), null); } else { SkinProvider.requestSkin(entity.getUuid(), data.skinUrl(), true) diff --git a/core/src/main/resources/bedrock/skin/geometry.humanoid.ears.json b/core/src/main/resources/bedrock/skin/geometry.humanoid.ears.json deleted file mode 100644 index 5571655b8..000000000 --- a/core/src/main/resources/bedrock/skin/geometry.humanoid.ears.json +++ /dev/null @@ -1,249 +0,0 @@ -{ - "format_version": "1.14.0", - "minecraft:geometry": [ - { - "bones": [ - { - "name" : "root", - "pivot" : [ 0.0, 0.0, 0.0 ] - }, - - { - "name" : "waist", - "parent" : "root", - "pivot" : [ 0.0, 12.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes" : [] - }, - - - { - "name": "body", - "parent" : "waist", - "pivot": [ 0.0, 24.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -4.0, 12.0, -2.0 ], - "size": [ 8, 12, 4 ], - "uv": [ 16, 16 ] - } - ] - }, - - { - "name": "jacket", - "parent" : "body", - "pivot": [ 0.0, 24.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -4.0, 12.0, -2.0 ], - "size": [ 8, 12, 4 ], - "uv": [ 16, 32 ], - "inflate": 0.25 - } - ] - }, - - - { - "name": "head", - "parent" : "body", - "pivot": [ 0.0, 24.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -4.0, 24.0, -4.0 ], - "size": [ 8, 8, 8 ], - "uv": [ 0, 0 ] - } - ] - }, - - { - "name": "hat", - "parent" : "head", - "pivot": [ 0.0, 24.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -4.0, 24.0, -4.0 ], - "size": [ 8, 8, 8 ], - "uv": [ 32, 0 ], - "inflate": 0.5 - } - ] - }, - - - { - "name": "leftArm", - "parent" : "body", - "pivot": [ 5.0, 22.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ 4.0, 12.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 32, 48 ] - } - ] - }, - { - "name": "rightArm", - "parent" : "body", - "pivot": [ -5.0, 22.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -8.0, 12.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 40, 16 ] - } - ] - }, - - { - "name": "leftSleeve", - "parent" : "leftArm", - "pivot": [ 5.0, 22.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ 4.0, 12.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 48, 48 ], - "inflate": 0.25 - } - ] - }, - - { - "name": "rightSleeve", - "parent" : "rightArm", - "pivot": [ -5.0, 22.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -8.0, 12.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 40, 32 ], - "inflate": 0.25 - } - ] - }, - - - { - "name": "leftLeg", - "parent" : "root", - "pivot": [ 1.9, 12.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -0.1, 0.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 0, 16 ] - } - ] - }, - - { - "name": "rightLeg", - "parent" : "root", - "pivot": [ -1.9, 12.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -3.9, 0.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 0, 16 ] - } - ] - }, - - { - "name": "leftPants", - "parent" : "leftLeg", - "pivot": [1.9, 12.0, 0.0], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -0.1, 0.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 0, 48 ], - "inflate": 0.25 - } - ] - }, - - { - "name": "rightPants", - "parent" : "rightLeg", - "pivot": [ -1.9, 12.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -3.9, 0.0, -2.0] , - "size": [ 4, 12, 4 ], - "uv": [ 0, 32], - "inflate": 0.25 - } - ] - }, - - - { - "name" : "rightItem", - "parent" : "rightArm", - "pivot" : [ -6.0, 15.0, 1.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes" : [] - }, - - { - "name" : "leftItem", - "parent" : "leftArm", - "pivot" : [ 6.0, 15.0, 1.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes" : [] - }, - - - { - "name": "leftEar", - "parent" : "head", - "pivot": [ -1.9, 12.0, 0.0 ], - "cubes": [ - { - "origin": [ 3.0, 31.0, -0.5 ], - "size": [ 6, 6, 1 ], - "uv": [ 24, 0 ], - "inflate": 0.5 - } - ] - }, - - { - "name": "rightEar", - "parent" : "head", - "pivot": [ -1.9, 12.0, 0.0 ], - "cubes": [ - { - "origin": [ -9.0, 31.0, -0.5 ], - "size": [ 6, 6, 1 ], - "uv": [ 24, 0 ], - "inflate": 0.5 - } - ] - } - ], - "description": { - "identifier": "geometry.humanoid.ears", - "texture_height": 64, - "texture_width": 64 - } - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/skin/geometry.humanoid.earsSlim.json b/core/src/main/resources/bedrock/skin/geometry.humanoid.earsSlim.json deleted file mode 100644 index 70c44f854..000000000 --- a/core/src/main/resources/bedrock/skin/geometry.humanoid.earsSlim.json +++ /dev/null @@ -1,249 +0,0 @@ -{ - "format_version": "1.14.0", - "minecraft:geometry": [ - { - "bones": [ - { - "name" : "root", - "pivot" : [ 0.0, 0.0, 0.0 ] - }, - - { - "name" : "waist", - "parent" : "root", - "pivot" : [ 0.0, 12.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes" : [] - }, - - - { - "name": "body", - "parent" : "waist", - "pivot": [ 0.0, 24.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -4.0, 12.0, -2.0 ], - "size": [ 8, 12, 4 ], - "uv": [ 16, 16 ] - } - ] - }, - - { - "name": "jacket", - "parent" : "body", - "pivot": [ 0.0, 24.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -4.0, 12.0, -2.0 ], - "size": [ 8, 12, 4 ], - "uv": [ 16, 32 ], - "inflate": 0.25 - } - ] - }, - - - { - "name": "head", - "parent" : "body", - "pivot": [ 0.0, 24.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -4.0, 24.0, -4.0 ], - "size": [ 8, 8, 8 ], - "uv": [ 0, 0 ] - } - ] - }, - - { - "name": "hat", - "parent" : "head", - "pivot": [ 0.0, 24.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -4.0, 24.0, -4.0 ], - "size": [ 8, 8, 8 ], - "uv": [ 32, 0 ], - "inflate": 0.5 - } - ] - }, - - - { - "name": "leftArm", - "parent" : "body", - "pivot": [ 5.0, 21.5, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ 4.0, 12, -2.0 ], - "size": [ 3, 12, 4 ], - "uv": [ 32, 48 ] - } - ] - }, - { - "name": "rightArm", - "parent" : "body", - "pivot": [ -5.0, 21.5, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -7.0, 12, -2.0 ], - "size": [ 3, 12, 4 ], - "uv": [ 40, 16 ] - } - ] - }, - - { - "name": "leftSleeve", - "parent" : "leftArm", - "pivot": [ 5.0, 21.5, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ 4.0, 11.5, -2.0 ], - "size": [ 3, 12, 4 ], - "uv": [ 48, 48 ], - "inflate": 0.25 - } - ] - }, - - { - "name": "rightSleeve", - "parent" : "rightArm", - "pivot": [ -5.0, 21.5, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -7.0, 11.5, -2.0 ], - "size": [ 3, 12, 4 ], - "uv": [ 40, 32 ], - "inflate": 0.25 - } - ] - }, - - - { - "name": "leftLeg", - "parent" : "root", - "pivot": [ 1.9, 12.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -0.1, 0.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 0, 16 ] - } - ] - }, - - { - "name": "rightLeg", - "parent" : "root", - "pivot": [ -1.9, 12.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -3.9, 0.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 0, 16 ] - } - ] - }, - - { - "name": "leftPants", - "parent" : "leftLeg", - "pivot": [1.9, 12.0, 0.0], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -0.1, 0.0, -2.0 ], - "size": [ 4, 12, 4 ], - "uv": [ 0, 48 ], - "inflate": 0.25 - } - ] - }, - - { - "name": "rightPants", - "parent" : "rightLeg", - "pivot": [ -1.9, 12.0, 0.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes": [ - { - "origin": [ -3.9, 0.0, -2.0] , - "size": [ 4, 12, 4 ], - "uv": [ 0, 32], - "inflate": 0.25 - } - ] - }, - - - { - "name" : "rightItem", - "parent" : "rightArm", - "pivot" : [ -6.0, 15.0, 1.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes" : [] - }, - - { - "name" : "leftItem", - "parent" : "leftArm", - "pivot" : [ 6.0, 15.0, 1.0 ], - "rotation" : [ 0.0, 0.0, 0.0 ], - "cubes" : [] - }, - - - { - "name": "leftEar", - "parent" : "head", - "pivot": [ -1.9, 12.0, 0.0 ], - "cubes": [ - { - "origin": [ 3.0, 31.0, -0.5 ], - "size": [ 6, 6, 1 ], - "uv": [ 24, 0 ], - "inflate": 0.5 - } - ] - }, - - { - "name": "rightEar", - "parent" : "head", - "pivot": [ -1.9, 12.0, 0.0 ], - "cubes": [ - { - "origin": [ -9.0, 31.0, -0.5 ], - "size": [ 6, 6, 1 ], - "uv": [ 24, 0 ], - "inflate": 0.5 - } - ] - } - ], - "description": { - "identifier": "geometry.humanoid.earsSlim", - "texture_height": 64, - "texture_width": 64 - } - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index c70b0d7ab..fc0cd83f1 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -113,14 +113,6 @@ max-players: 100 # If debug messages should be sent through console debug-mode: false -# Allow third party capes to be visible. Currently allowing: -# OptiFine capes, LabyMod capes, 5Zig capes and MinecraftCapes -allow-third-party-capes: false - -# Allow third party deadmau5 ears to be visible. Currently allowing: -# MinecraftCapes -allow-third-party-ears: false - # Allow a fake cooldown indicator to be sent. Bedrock players otherwise do not see a cooldown as they still use 1.8 combat. # Please note: if the cooldown is enabled, some users may see a black box during the cooldown sequence, like below: # https://cdn.discordapp.com/attachments/613170125696270357/957075682230419466/Screenshot_from_2022-03-25_20-35-08.png diff --git a/gradle.properties b/gradle.properties index dd61d2556..40d8a36db 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.3.0-SNAPSHOT +version=2.3.1-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From 4d61766d0adf17849ecd66538c3889f76a763b3f Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 14 May 2024 16:38:51 +0100 Subject: [PATCH 135/897] Fix SessionSkinApplyEvent not keeping altered skin data (#4663) --- .../main/java/org/geysermc/geyser/skin/SkinProvider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index 3b31dfff8..5b16bc3a3 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java @@ -271,17 +271,17 @@ public class SkinProvider { @Override public void skin(@NonNull Skin newSkin) { - eventSkinData.skinData(new SkinData(Objects.requireNonNull(newSkin), skinData.cape(), skinData.geometry())); + eventSkinData.skinData(new SkinData(Objects.requireNonNull(newSkin), eventSkinData.skinData().cape(), eventSkinData.skinData().geometry())); } @Override public void cape(@NonNull Cape newCape) { - eventSkinData.skinData(new SkinData(skinData.skin(), Objects.requireNonNull(newCape), skinData.geometry())); + eventSkinData.skinData(new SkinData(eventSkinData.skinData().skin(), Objects.requireNonNull(newCape), eventSkinData.skinData().geometry())); } @Override public void geometry(@NonNull SkinGeometry newGeometry) { - eventSkinData.skinData(new SkinData(skinData.skin(), skinData.cape(), Objects.requireNonNull(newGeometry))); + eventSkinData.skinData(new SkinData(eventSkinData.skinData().skin(), eventSkinData.skinData().cape(), Objects.requireNonNull(newGeometry))); } }); From 6c4b2cb173bb5e36396a3ee031286ee2ab3f8ed4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 15 May 2024 13:40:57 -0400 Subject: [PATCH 136/897] Don't create a property manager if an entity has no properties --- .../geysermc/geyser/entity/type/Entity.java | 4 +- .../java/JavaSelectKnownPacksTranslator.java | 62 +++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java 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 fecd72f67..da9a28451 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 @@ -134,7 +134,7 @@ public class Entity implements GeyserEntity { this.valid = false; - this.propertyManager = new GeyserEntityPropertyManager(definition.registeredProperties()); + this.propertyManager = definition.registeredProperties() == null ? null : new GeyserEntityPropertyManager(definition.registeredProperties()); setPosition(position); setAirSupply(getMaxAir()); @@ -361,7 +361,7 @@ public class Entity implements GeyserEntity { return; } - if (propertyManager.hasProperties()) { + if (propertyManager != null && propertyManager.hasProperties()) { SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); entityDataPacket.setRuntimeEntityId(geyserId); propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java new file mode 100644 index 000000000..6b1c8c645 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java @@ -0,0 +1,62 @@ +/* + * 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.java; + +import org.geysermc.geyser.network.GameProtocol; +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.KnownPack; +import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundSelectKnownPacks; +import org.geysermc.mcprotocollib.protocol.packet.configuration.serverbound.ServerboundSelectKnownPacks; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@Translator(packet = ClientboundSelectKnownPacks.class) +public class JavaSelectKnownPacksTranslator extends PacketTranslator { + // todo: dump from client? + private static final Set KNOWN_PACK_IDS = Set.of("core", "update_1_21", "bundle", "trade_rebalance"); + + @Override + public void translate(GeyserSession session, ClientboundSelectKnownPacks packet) { + List knownPacks = new ArrayList<>(1); + for (KnownPack pack : packet.getKnownPacks()) { + if ("minecraft".equals(pack.getNamespace()) && GameProtocol.getJavaMinecraftVersion().equals(pack.getVersion())) { + // Implementation note: these won't always necessarily be equal. + // 1.20.5 versus 1.20.6 for example - same protocol version. A vanilla server for either version will gracefully accept either. + // If the versions mismatch, the registry will be sent over the network, though. + // For vanilla compliancy, to minimize network traffic, and for potential future behavior, + // We'll implement how the Java client does it. + if (KNOWN_PACK_IDS.contains(pack.getId())) { + knownPacks.add(pack); + } + } + } + session.sendDownstreamPacket(new ServerboundSelectKnownPacks(knownPacks)); + } +} From 423d2e3a362ccd0cbf5dc0eafaed4b67d3728757 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 15 May 2024 13:41:31 -0400 Subject: [PATCH 137/897] Emulate vanilla behavior with existing registries --- .../geyser/session/GeyserSession.java | 88 ++++++++++++------- .../geyser/session/cache/RegistryCache.java | 37 +++++++- 2 files changed, 90 insertions(+), 35 deletions(-) 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 617087f71..c0ff1fb71 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -28,35 +28,6 @@ package org.geysermc.geyser.session; import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.auth.service.MsaAuthenticationService; -import org.geysermc.mcprotocollib.protocol.MinecraftConstants; -import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; -import org.geysermc.mcprotocollib.protocol.data.ProtocolState; -import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; -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.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.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.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.player.ServerboundPlayerAbilitiesPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; -import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; -import org.geysermc.mcprotocollib.network.BuiltinFlags; -import org.geysermc.mcprotocollib.network.Session; -import org.geysermc.mcprotocollib.network.event.session.*; -import org.geysermc.mcprotocollib.network.packet.Packet; -import org.geysermc.mcprotocollib.network.tcp.TcpClientSession; -import org.geysermc.mcprotocollib.network.tcp.TcpSession; import io.netty.channel.Channel; import io.netty.channel.EventLoop; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -145,6 +116,38 @@ import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.LoginEncryptionUtils; +import org.geysermc.mcprotocollib.network.BuiltinFlags; +import org.geysermc.mcprotocollib.network.Session; +import org.geysermc.mcprotocollib.network.event.session.*; +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; +import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +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.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.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.player.ServerboundPlayerAbilitiesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; +import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; import java.net.ConnectException; import java.net.InetSocketAddress; @@ -646,9 +649,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { sentSpawnPacket = true; syncEntityProperties(); - // Set the hardcoded shield ID to the ID we just defined in StartGamePacket - // upstream.getSession().getHardcodedBlockingId().set(this.itemMappings.getStoredItems().shield().getBedrockId()); - if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) { ItemComponentPacket componentPacket = new ItemComponentPacket(); componentPacket.getItems().addAll(itemMappings.getComponentItemData()); @@ -875,6 +875,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Start ticking tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); + this.protocol.setUseDefaultListeners(false); + TcpSession downstream; if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP @@ -904,6 +906,25 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Let Geyser handle sending the keep alive downstream.setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false); } + // We'll handle this since we have the registry data on hand + downstream.setFlag(MinecraftConstants.SEND_BLANK_KNOWN_PACKS_RESPONSE, false); + + // This isn't a great solution, but... we want to make sure the finish configuration packet cannot be sent + // before the KnownPacks packet. + this.downstream.getSession().addListener(new ClientListener(ProtocolState.LOGIN, loginEvent.transferring()) { + @Override + public void packetReceived(Session session, Packet packet) { + if (protocol.getState() == ProtocolState.CONFIGURATION) { + if (packet instanceof ClientboundFinishConfigurationPacket) { + // Prevent + GeyserSession.this.ensureInEventLoop(() -> GeyserSession.this.sendDownstreamPacket(new ServerboundFinishConfigurationPacket())); + return; + } + } + super.packetReceived(session, packet); + } + }); + downstream.addListener(new SessionAdapter() { @Override public void packetSending(PacketSendingEvent event) { @@ -1543,8 +1564,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setEnchantmentSeed(0); startGamePacket.setMultiplayerCorrelationId(""); - startGamePacket.setItemDefinitions(this.itemMappings.getItemDefinitions().values().stream().toList()); // TODO - // startGamePacket.setBlockPalette(this.blockMappings.getBedrockBlockPalette()); + startGamePacket.getItemDefinitions().addAll(this.itemMappings.getItemDefinitions().values()); // Needed for custom block mappings and custom skulls system startGamePacket.getBlockProperties().addAll(this.blockMappings.getBlockProperties()); 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 9581df253..fa4503635 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 @@ -30,6 +30,8 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import lombok.AccessLevel; import lombok.Getter; import lombok.experimental.Accessors; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; @@ -42,6 +44,7 @@ import org.geysermc.geyser.session.cache.registry.JavaRegistry; import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; +import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; @@ -63,6 +66,7 @@ import java.util.function.ToIntFunction; @Accessors(fluent = true) @Getter public final class RegistryCache { + private static final Map> DEFAULTS; private static final Map>> REGISTRIES = new HashMap<>(); static { @@ -73,6 +77,24 @@ public final class RegistryCache { register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId())); + + // Load from MCProtocolLib's classloader + NbtMap tag = MinecraftProtocol.loadNetworkCodec(); + 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) + .getList("value", NbtType.COMPOUND); + Map values = new HashMap<>(); + for (NbtMap value : rawValues) { + String name = value.getString("name"); + values.put(name, value.getCompound("element")); + } + // Can make these maps immutable and as efficient as possible after initialization + defaults.put(key, Map.copyOf(values)); + }); + + DEFAULTS = Map.copyOf(defaults); } @Getter(AccessLevel.NONE) @@ -116,13 +138,22 @@ public final class RegistryCache { * @param the class that represents these entries. */ private static void register(String registry, Function> localCacheFunction, BiFunction reader) { - REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> { + String key = "minecraft:" + registry; + REGISTRIES.put(key, (registryCache, entries) -> { + Map localRegistry = null; JavaRegistry localCache = localCacheFunction.apply(registryCache); // Clear each local cache every time a new registry entry is given to us // (e.g. proxy server switches) List builder = new ArrayList<>(entries.size()); for (int i = 0; i < entries.size(); i++) { RegistryEntry entry = entries.get(i); + // 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(key); + } + entry = new RegistryEntry(entry.getId(), localRegistry.get(entry.getId())); + } // This is what Geyser wants to keep as a value for this registry. T cacheEntry = reader.apply(registryCache.session, entry); builder.add(i, cacheEntry); @@ -156,4 +187,8 @@ public final class RegistryCache { localCacheFunction.accept(registryCache, array); }); } + + public static void init() { + // no-op + } } From 9bca012194211b34583e1688bc9e925e138c77f1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 15 May 2024 15:31:02 -0400 Subject: [PATCH 138/897] Bump Erosion --- bootstrap/spigot/build.gradle.kts | 6 +++++ .../manager/GeyserSpigotWorldManager.java | 17 ++++++------ .../java/org/geysermc/geyser/GeyserImpl.java | 6 ++++- .../erosion/GeyserboundPacketHandlerImpl.java | 16 +++--------- .../geyser/level/GeyserWorldManager.java | 5 ++-- .../geysermc/geyser/level/WorldManager.java | 26 +++++++++++++++++++ .../protocol/java/JavaLoginTranslator.java | 4 +++ gradle/libs.versions.toml | 7 ++--- 8 files changed, 61 insertions(+), 26 deletions(-) diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 8143d96a1..7ccb50484 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -4,6 +4,12 @@ dependencies { isTransitive = false } + implementation(libs.erosion.bukkit.nms) { + attributes { + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) + } + } + implementation(variantOf(libs.adapters.spigot) { classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations }) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 8a0e0b70d..47086d36c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -25,9 +25,7 @@ package org.geysermc.geyser.platform.spigot.world.manager; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -39,6 +37,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.geysermc.erosion.bukkit.BukkitLecterns; import org.geysermc.erosion.bukkit.BukkitUtils; +import org.geysermc.erosion.bukkit.PickBlockUtils; import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.GameRule; @@ -47,6 +46,9 @@ import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import java.util.List; import java.util.Objects; @@ -205,17 +207,16 @@ public class GeyserSpigotWorldManager extends WorldManager { @Override public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { - CompletableFuture<@Nullable DataComponents> future = new CompletableFuture<>(); Player bukkitPlayer; if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { - future.complete(null); - return future; + return CompletableFuture.completedFuture(null); } + CompletableFuture> future = new CompletableFuture<>(); Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); // Paper 1.19.3 complains about async access otherwise. // java.lang.IllegalStateException: Tile is null, asynchronous access? - SchedulerUtils.runTask(this.plugin, () -> future.complete(/*PickBlockUtils.pickBlock(block)*/ null), block); // TODO fix erosion once clear how to handle this - return future; + SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block); + return future.thenApply(RAW_TRANSFORMER); } /** diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index d5635acf9..a60a14ea0 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -45,6 +45,7 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.geysermc.api.Geyser; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; +import org.geysermc.erosion.packet.Packets; import org.geysermc.floodgate.crypto.AesCipher; import org.geysermc.floodgate.crypto.AesKeyProducer; import org.geysermc.floodgate.crypto.Base64Topping; @@ -77,6 +78,7 @@ import org.geysermc.geyser.scoreboard.ScoreboardUpdater; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.PendingMicrosoftAuthentication; import org.geysermc.geyser.session.SessionManager; +import org.geysermc.geyser.session.cache.RegistryCache; import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.skin.ProvidedSkins; import org.geysermc.geyser.skin.SkinProvider; @@ -211,6 +213,8 @@ public class GeyserImpl implements GeyserApi { Registries.init(); BlockRegistries.init(); + RegistryCache.init(); + /* Initialize translators */ EntityDefinitions.init(); MessageTranslator.init(); @@ -383,7 +387,7 @@ public class GeyserImpl implements GeyserApi { this.newsHandler = new NewsHandler(BRANCH, this.buildNumber()); - //Packets.initGeyser(); + Packets.initGeyser(); if (Epoll.isAvailable()) { this.erosionUnixListener = new UnixSocketClientListener(); diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index a62f9ec49..7d5bba1e8 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.erosion; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import io.netty.channel.Channel; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; @@ -43,14 +41,7 @@ import org.geysermc.erosion.packet.ErosionPacketHandler; import org.geysermc.erosion.packet.ErosionPacketSender; import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket; import org.geysermc.erosion.packet.backendbound.BackendboundPacket; -import org.geysermc.erosion.packet.geyserbound.GeyserboundBatchBlockIdPacket; -import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockEntityPacket; -import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockIdPacket; -import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockLookupFailPacket; -import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockPlacePacket; -import org.geysermc.erosion.packet.geyserbound.GeyserboundHandshakePacket; -import org.geysermc.erosion.packet.geyserbound.GeyserboundPickBlockPacket; -import org.geysermc.erosion.packet.geyserbound.GeyserboundPistonEventPacket; +import org.geysermc.erosion.packet.geyserbound.*; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.network.GameProtocol; @@ -58,6 +49,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; @@ -71,7 +63,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke @Setter private CompletableFuture pendingBatchLookup = null; @Setter - private CompletableFuture pickBlockLookup = null; + private CompletableFuture> pickBlockLookup = null; private final AtomicInteger nextTransactionId = new AtomicInteger(1); @@ -147,7 +139,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke @Override public void handlePickBlock(GeyserboundPickBlockPacket packet) { if (this.pickBlockLookup != null) { - //this.pickBlockLookup.complete(packet.getTag()); // TODO 1.20.5 + this.pickBlockLookup.complete(packet.getComponents()); } } diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 08611a5e1..3144f0cb2 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.level; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -179,9 +180,9 @@ public class GeyserWorldManager extends WorldManager { if (erosionHandler == null) { return super.getPickItemComponents(session, x, y, z, addNbtData); } - CompletableFuture future = new CompletableFuture<>(); + CompletableFuture> future = new CompletableFuture<>(); erosionHandler.setPickBlockLookup(future); erosionHandler.sendPacket(new BackendboundPickBlockPacket(Vector3i.from(x, y, z))); - return future; + return future.thenApply(RAW_TRANSFORMER); } } diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index a1b16a1d5..cd6c9e824 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -25,19 +25,29 @@ package org.geysermc.geyser.level; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; +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.ItemCodecHelper; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.function.Function; /** * Class that manages or retrieves various information @@ -223,4 +233,20 @@ public abstract class WorldManager { public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addExtraData) { return CompletableFuture.completedFuture(null); } + + protected static final Function, DataComponents> RAW_TRANSFORMER = map -> { + try { + Map, DataComponent> components = new HashMap<>(); + Int2ObjectMaps.fastForEach(map, entry -> { + DataComponentType type = DataComponentType.from(entry.getIntKey()); + ByteBuf buf = Unpooled.wrappedBuffer(entry.getValue()); + DataComponent value = type.readDataComponent(ItemCodecHelper.INSTANCE, buf); + components.put(type, value); + }); + return new DataComponents(components); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + }; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index fe4401dca..33d5a88b9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; +import org.geysermc.erosion.Constants; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket; @@ -45,6 +46,8 @@ import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.EntityUtils; +import java.nio.charset.StandardCharsets; + @Translator(packet = ClientboundLoginPacket.class) public class JavaLoginTranslator extends PacketTranslator { @@ -134,6 +137,7 @@ public class JavaLoginTranslator extends PacketTranslator Date: Thu, 16 May 2024 23:12:06 -0400 Subject: [PATCH 139/897] Block refactory --- .../world/GeyserSpigotBlockPlaceListener.java | 3 +- .../GeyserSpigotNativeWorldManager.java | 3 +- .../manager/GeyserSpigotWorldManager.java | 8 +- .../java/org/geysermc/geyser/GeyserImpl.java | 13 + .../geyser/entity/type/FishingHookEntity.java | 3 +- .../erosion/GeyserboundPacketHandlerImpl.java | 3 +- .../geyser/level/block/BlockStateValues.java | 21 +- .../geysermc/geyser/level/block/Blocks.java | 2820 +++++++++++++++++ .../level/block/property/ChestType.java | 34 + .../level/block/property/Properties.java | 146 + .../geyser/level/block/property/Property.java | 43 + .../geyser/level/block/type/BannerBlock.java | 39 + .../geyser/level/block/type/BedBlock.java | 39 + .../geyser/level/block/type/Block.java | 152 + .../geyser/level/block/type/BlockState.java | 64 + .../geyser/registry/BlockRegistries.java | 12 +- .../geyser/registry/ListRegistry.java | 103 + .../populator/BlockRegistryPopulator.java | 2 - .../geyser/session/GeyserSession.java | 3 - .../geyser/session/cache/ChunkCache.java | 13 +- .../inventory/ShulkerInventoryTranslator.java | 3 +- .../chest/DoubleChestInventoryTranslator.java | 7 +- .../entity/BannerBlockEntityTranslator.java | 10 +- .../entity/BeaconBlockEntityTranslator.java | 3 +- .../entity/BedBlockEntityTranslator.java | 12 +- .../block/entity/BedrockOnlyBlockEntity.java | 3 +- .../block/entity/BlockEntityTranslator.java | 5 +- .../BrushableBlockEntityTranslator.java | 7 +- .../entity/CampfireBlockEntityTranslator.java | 3 +- .../CommandBlockBlockEntityTranslator.java | 7 +- .../DecoratedPotBlockEntityTranslator.java | 3 +- .../DoubleChestBlockEntityTranslator.java | 46 +- .../entity/EmptyBlockEntityTranslator.java | 3 +- .../EndGatewayBlockEntityTranslator.java | 3 +- .../FlowerPotBlockEntityTranslator.java | 7 +- .../JigsawBlockBlockEntityTranslator.java | 5 +- .../level/block/entity/PistonBlockEntity.java | 15 +- .../ShulkerBoxBlockEntityTranslator.java | 12 +- .../entity/SignBlockEntityTranslator.java | 3 +- .../entity/SkullBlockEntityTranslator.java | 15 +- .../entity/SpawnerBlockEntityTranslator.java | 5 +- .../StructureBlockBlockEntityTranslator.java | 5 +- .../TrialSpawnerBlockEntityTranslator.java | 3 +- .../BedrockBlockPickRequestTranslator.java | 3 +- ...BedrockInventoryTransactionTranslator.java | 3 +- .../player/BedrockActionTranslator.java | 3 +- .../level/JavaBlockEntityDataTranslator.java | 11 +- .../java/level/JavaBlockEventTranslator.java | 3 +- .../java/level/JavaExplodeTranslator.java | 3 +- .../JavaLevelChunkWithLightTranslator.java | 13 +- .../org/geysermc/geyser/util/ChunkUtils.java | 14 +- .../org/geysermc/geyser/util/SoundUtils.java | 3 +- .../geysermc/geyser/util/StatisticsUtils.java | 9 +- gradle/libs.versions.toml | 3 +- 54 files changed, 3620 insertions(+), 157 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/Blocks.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/property/ChestType.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/property/Property.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/BannerBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/BedBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/Block.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java index 71aba11f9..b5f4bd4f9 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java @@ -34,6 +34,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; @@ -59,7 +60,7 @@ public class GeyserSpigotBlockPlaceListener implements Listener { event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()))); } else { String javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); - placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID))); + placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, Block.JAVA_AIR_ID))); } placeBlockSoundPacket.setIdentifier(":"); session.sendUpstreamPacket(placeBlockSoundPacket); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java index 45e84d254..c99ca4e78 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java @@ -34,6 +34,7 @@ import org.geysermc.geyser.adapters.WorldAdapter; import org.geysermc.geyser.adapters.paper.PaperAdapters; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { @@ -52,7 +53,7 @@ public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { public int getBlockAt(GeyserSession session, int x, int y, int z) { Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); if (player == null) { - return BlockStateValues.JAVA_AIR_ID; + return Block.JAVA_AIR_ID; } return adapter.getBlockAt(player.getWorld(), x, y, z); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 47086d36c..a04c60126 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -70,12 +70,12 @@ public class GeyserSpigotWorldManager extends WorldManager { public int getBlockAt(GeyserSession session, int x, int y, int z) { Player bukkitPlayer; if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { - return BlockStateValues.JAVA_AIR_ID; + return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID; } World world = bukkitPlayer.getWorld(); if (!world.isChunkLoaded(x >> 4, z >> 4)) { // If the chunk isn't loaded, how could we even be here? - return BlockStateValues.JAVA_AIR_ID; + return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID; } return getBlockNetworkId(world.getBlockAt(x, y, z)); @@ -86,9 +86,9 @@ public class GeyserSpigotWorldManager extends WorldManager { // Terrible behavior, but this is basically what's always been happening behind the scenes anyway. CompletableFuture blockData = new CompletableFuture<>(); Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString())); - return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID); + return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); } - return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID); + return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index a60a14ea0..4f572ef63 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -69,6 +69,7 @@ import org.geysermc.geyser.event.GeyserEventBus; import org.geysermc.geyser.extension.GeyserExtensionManager; import org.geysermc.geyser.impl.MinecraftVersionImpl; import org.geysermc.geyser.level.WorldManager; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.GeyserServer; import org.geysermc.geyser.registry.BlockRegistries; @@ -256,6 +257,18 @@ public class GeyserImpl implements GeyserApi { } VersionCheckUtils.checkForOutdatedJava(logger); + + Blocks.VAULT.javaId(); + for (int i = 0; i < BlockRegistries.JAVA_BLOCKS.get().length; i++) { + String cleanIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getCleanJavaIdentifier(); + String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier(); + if (!cleanIdentifier.equals(newIdentifier)) { + System.out.println("Check block " + BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier()); + break; + } + } + System.out.println(BlockRegistries.JAVA_BLOCKS.get().length); + System.out.println(BlockRegistries.BLOCK_STATES.get().size()); } private void startInstance() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java index f4c0cea36..26a64bcae 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java @@ -33,6 +33,7 @@ import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.collision.BlockCollision; @@ -162,7 +163,7 @@ public class FishingHookEntity extends ThrowableEntity { */ protected boolean isInAir() { int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt()); - return block == BlockStateValues.JAVA_AIR_ID; + return block == Block.JAVA_AIR_ID; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index 7d5bba1e8..b76dc0b85 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -43,6 +43,7 @@ import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket; import org.geysermc.erosion.packet.backendbound.BackendboundPacket; import org.geysermc.erosion.packet.geyserbound.*; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; @@ -119,7 +120,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke } CompletableFuture future = this.asyncPendingLookups.remove(transactionId); if (future != null) { - future.complete(BlockStateValues.JAVA_AIR_ID); + future.complete(Block.JAVA_AIR_ID); } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 52759c709..205486ced 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.JsonNode; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; @@ -48,7 +49,6 @@ public final class BlockStateValues { private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap(); private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap(); private static final Int2IntMap BRUSH_PROGRESS = new Int2IntOpenHashMap(); - private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap(); private static final Int2ObjectMap DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>(); private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet(); @@ -110,11 +110,6 @@ public final class BlockStateValues { } } - if (javaId.contains("command_block")) { - COMMAND_BLOCK_VALUES.put(javaBlockState, javaId.contains("conditional=true") ? (byte) 1 : (byte) 0); - return; - } - if (blockData.get("double_chest_position") != null) { boolean isX = (blockData.get("x") != null); boolean isDirectionPositive = ((blockData.get("x") != null && blockData.get("x").asBoolean()) || @@ -277,16 +272,6 @@ public final class BlockStateValues { return ALL_CAULDRONS.contains(state); } - /** - * The block state in Java and Bedrock both contain the conditional bit, however command block block entity tags - * in Bedrock need the conditional information. - * - * @return the list of all command blocks and if they are conditional (1 or 0) - */ - public static Int2ByteMap getCommandBlockValues() { - return COMMAND_BLOCK_VALUES; - } - /** * All double chest values are part of the block state in Java and part of the block entity tag in Bedrock. * This gives the DoubleChestValue that can be calculated into the final tag. @@ -356,7 +341,7 @@ public final class BlockStateValues { * @return Block state for the piston head */ public static int getPistonHead(Direction direction) { - return PISTON_HEADS.getOrDefault(direction, BlockStateValues.JAVA_AIR_ID); + return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID); } /** @@ -420,7 +405,7 @@ public final class BlockStateValues { } public static boolean canPistonMoveBlock(int javaId, boolean isPushing) { - if (javaId == JAVA_AIR_ID) { + if (javaId == Block.JAVA_AIR_ID) { return true; } // Pistons can only be moved if they aren't extended 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 new file mode 100644 index 000000000..426895269 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java @@ -0,0 +1,2820 @@ +/* + * 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.level.block; + +import org.geysermc.geyser.level.block.type.BannerBlock; +import org.geysermc.geyser.level.block.type.BedBlock; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.physics.Axis; +import org.geysermc.geyser.level.physics.Direction; +import org.geysermc.geyser.registry.BlockRegistries; + +import static org.geysermc.geyser.level.block.property.Properties.*; +import static org.geysermc.geyser.level.block.type.Block.builder; + +@SuppressWarnings("unused") +public final class Blocks { + public static final Block AIR = register(new Block("air", builder())); + public static final Block STONE = register(new Block("stone", builder())); + public static final Block GRANITE = register(new Block("granite", builder())); + public static final Block POLISHED_GRANITE = register(new Block("polished_granite", builder())); + public static final Block DIORITE = register(new Block("diorite", builder())); + public static final Block POLISHED_DIORITE = register(new Block("polished_diorite", builder())); + public static final Block ANDESITE = register(new Block("andesite", builder())); + public static final Block POLISHED_ANDESITE = register(new Block("polished_andesite", builder())); + public static final Block GRASS_BLOCK = register(new Block("grass_block", builder() + .booleanState(SNOWY))); + public static final Block DIRT = register(new Block("dirt", builder())); + public static final Block COARSE_DIRT = register(new Block("coarse_dirt", builder())); + public static final Block PODZOL = register(new Block("podzol", builder() + .booleanState(SNOWY))); + public static final Block COBBLESTONE = register(new Block("cobblestone", builder())); + public static final Block OAK_PLANKS = register(new Block("oak_planks", builder())); + public static final Block SPRUCE_PLANKS = register(new Block("spruce_planks", builder())); + public static final Block BIRCH_PLANKS = register(new Block("birch_planks", builder())); + public static final Block JUNGLE_PLANKS = register(new Block("jungle_planks", builder())); + public static final Block ACACIA_PLANKS = register(new Block("acacia_planks", builder())); + public static final Block CHERRY_PLANKS = register(new Block("cherry_planks", builder())); + public static final Block DARK_OAK_PLANKS = register(new Block("dark_oak_planks", builder())); + public static final Block MANGROVE_PLANKS = register(new Block("mangrove_planks", builder())); + public static final Block BAMBOO_PLANKS = register(new Block("bamboo_planks", builder())); + public static final Block BAMBOO_MOSAIC = register(new Block("bamboo_mosaic", builder())); + public static final Block OAK_SAPLING = register(new Block("oak_sapling", builder() + .intState(STAGE, 0, 1))); + public static final Block SPRUCE_SAPLING = register(new Block("spruce_sapling", builder() + .intState(STAGE, 0, 1))); + public static final Block BIRCH_SAPLING = register(new Block("birch_sapling", builder() + .intState(STAGE, 0, 1))); + public static final Block JUNGLE_SAPLING = register(new Block("jungle_sapling", builder() + .intState(STAGE, 0, 1))); + public static final Block ACACIA_SAPLING = register(new Block("acacia_sapling", builder() + .intState(STAGE, 0, 1))); + public static final Block CHERRY_SAPLING = register(new Block("cherry_sapling", builder() + .intState(STAGE, 0, 1))); + public static final Block DARK_OAK_SAPLING = register(new Block("dark_oak_sapling", builder() + .intState(STAGE, 0, 1))); + public static final Block MANGROVE_PROPAGULE = register(new Block("mangrove_propagule", builder() + .intState(AGE_4, 0, 4) + .booleanState(HANGING) + .intState(STAGE, 0, 1) + .booleanState(WATERLOGGED))); + public static final Block BEDROCK = register(new Block("bedrock", builder())); + public static final Block WATER = register(new Block("water", builder() + .intState(LEVEL, 0, 15))); + public static final Block LAVA = register(new Block("lava", builder() + .intState(LEVEL, 0, 15))); + public static final Block SAND = register(new Block("sand", builder())); + public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder() + .intState(DUSTED, 0, 3))); + public static final Block RED_SAND = register(new Block("red_sand", builder())); + public static final Block GRAVEL = register(new Block("gravel", builder())); + public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder() + .intState(DUSTED, 0, 3))); + public static final Block GOLD_ORE = register(new Block("gold_ore", builder())); + public static final Block DEEPSLATE_GOLD_ORE = register(new Block("deepslate_gold_ore", builder())); + public static final Block IRON_ORE = register(new Block("iron_ore", builder())); + public static final Block DEEPSLATE_IRON_ORE = register(new Block("deepslate_iron_ore", builder())); + public static final Block COAL_ORE = register(new Block("coal_ore", builder())); + public static final Block DEEPSLATE_COAL_ORE = register(new Block("deepslate_coal_ore", builder())); + public static final Block NETHER_GOLD_ORE = register(new Block("nether_gold_ore", builder())); + public static final Block OAK_LOG = register(new Block("oak_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block SPRUCE_LOG = register(new Block("spruce_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block BIRCH_LOG = register(new Block("birch_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block JUNGLE_LOG = register(new Block("jungle_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block ACACIA_LOG = register(new Block("acacia_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block CHERRY_LOG = register(new Block("cherry_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block DARK_OAK_LOG = register(new Block("dark_oak_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block MANGROVE_LOG = register(new Block("mangrove_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block MANGROVE_ROOTS = register(new Block("mangrove_roots", builder() + .booleanState(WATERLOGGED))); + public static final Block MUDDY_MANGROVE_ROOTS = register(new Block("muddy_mangrove_roots", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block BAMBOO_BLOCK = register(new Block("bamboo_block", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_SPRUCE_LOG = register(new Block("stripped_spruce_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_BIRCH_LOG = register(new Block("stripped_birch_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_JUNGLE_LOG = register(new Block("stripped_jungle_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_ACACIA_LOG = register(new Block("stripped_acacia_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_CHERRY_LOG = register(new Block("stripped_cherry_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_DARK_OAK_LOG = register(new Block("stripped_dark_oak_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_OAK_LOG = register(new Block("stripped_oak_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_MANGROVE_LOG = register(new Block("stripped_mangrove_log", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_BAMBOO_BLOCK = register(new Block("stripped_bamboo_block", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block OAK_WOOD = register(new Block("oak_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block SPRUCE_WOOD = register(new Block("spruce_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block BIRCH_WOOD = register(new Block("birch_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block JUNGLE_WOOD = register(new Block("jungle_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block ACACIA_WOOD = register(new Block("acacia_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block CHERRY_WOOD = register(new Block("cherry_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block DARK_OAK_WOOD = register(new Block("dark_oak_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block MANGROVE_WOOD = register(new Block("mangrove_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_OAK_WOOD = register(new Block("stripped_oak_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_SPRUCE_WOOD = register(new Block("stripped_spruce_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_BIRCH_WOOD = register(new Block("stripped_birch_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_JUNGLE_WOOD = register(new Block("stripped_jungle_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_ACACIA_WOOD = register(new Block("stripped_acacia_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_CHERRY_WOOD = register(new Block("stripped_cherry_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_DARK_OAK_WOOD = register(new Block("stripped_dark_oak_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_MANGROVE_WOOD = register(new Block("stripped_mangrove_wood", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block SPRUCE_LEAVES = register(new Block("spruce_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block BIRCH_LEAVES = register(new Block("birch_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block JUNGLE_LEAVES = register(new Block("jungle_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block ACACIA_LEAVES = register(new Block("acacia_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block CHERRY_LEAVES = register(new Block("cherry_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block DARK_OAK_LEAVES = register(new Block("dark_oak_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block MANGROVE_LEAVES = register(new Block("mangrove_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block AZALEA_LEAVES = register(new Block("azalea_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block FLOWERING_AZALEA_LEAVES = register(new Block("flowering_azalea_leaves", builder() + .intState(DISTANCE, 1, 7) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block SPONGE = register(new Block("sponge", builder())); + public static final Block WET_SPONGE = register(new Block("wet_sponge", builder())); + public static final Block GLASS = register(new Block("glass", builder())); + public static final Block LAPIS_ORE = register(new Block("lapis_ore", builder())); + public static final Block DEEPSLATE_LAPIS_ORE = register(new Block("deepslate_lapis_ore", builder())); + public static final Block LAPIS_BLOCK = register(new Block("lapis_block", builder())); + public static final Block DISPENSER = register(new Block("dispenser", builder() + .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())); + public static final Block CHISELED_SANDSTONE = register(new Block("chiseled_sandstone", builder())); + public static final Block CUT_SANDSTONE = register(new Block("cut_sandstone", builder())); + public static final Block NOTE_BLOCK = register(new Block("note_block", builder() + .enumState(NOTEBLOCK_INSTRUMENT, "harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling", "zombie", "skeleton", "creeper", "dragon", "wither_skeleton", "piglin", "custom_head") + .intState(NOTE, 0, 24) + .booleanState(POWERED))); + public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART, "head", "foot"))); + public static final Block POWERED_RAIL = register(new Block("powered_rail", builder() + .booleanState(POWERED) + .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") + .booleanState(WATERLOGGED))); + public static final Block DETECTOR_RAIL = register(new Block("detector_rail", builder() + .booleanState(POWERED) + .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") + .booleanState(WATERLOGGED))); + public static final Block STICKY_PISTON = register(new Block("sticky_piston", builder() + .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())); + public static final Block SHORT_GRASS = register(new Block("short_grass", builder())); + public static final Block FERN = register(new Block("fern", builder())); + public static final Block DEAD_BUSH = register(new Block("dead_bush", builder())); + public static final Block SEAGRASS = register(new Block("seagrass", builder())); + public static final Block TALL_SEAGRASS = register(new Block("tall_seagrass", builder() + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block PISTON = register(new Block("piston", builder() + .booleanState(EXTENDED) + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + public static final Block PISTON_HEAD = register(new Block("piston_head", builder() + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(SHORT) + .enumState(PISTON_TYPE, "normal", "sticky"))); + public static final Block WHITE_WOOL = register(new Block("white_wool", builder())); + public static final Block ORANGE_WOOL = register(new Block("orange_wool", builder())); + public static final Block MAGENTA_WOOL = register(new Block("magenta_wool", builder())); + public static final Block LIGHT_BLUE_WOOL = register(new Block("light_blue_wool", builder())); + public static final Block YELLOW_WOOL = register(new Block("yellow_wool", builder())); + public static final Block LIME_WOOL = register(new Block("lime_wool", builder())); + public static final Block PINK_WOOL = register(new Block("pink_wool", builder())); + public static final Block GRAY_WOOL = register(new Block("gray_wool", builder())); + public static final Block LIGHT_GRAY_WOOL = register(new Block("light_gray_wool", builder())); + public static final Block CYAN_WOOL = register(new Block("cyan_wool", builder())); + public static final Block PURPLE_WOOL = register(new Block("purple_wool", builder())); + public static final Block BLUE_WOOL = register(new Block("blue_wool", builder())); + public static final Block BROWN_WOOL = register(new Block("brown_wool", builder())); + public static final Block GREEN_WOOL = register(new Block("green_wool", builder())); + public static final Block RED_WOOL = register(new Block("red_wool", builder())); + public static final Block BLACK_WOOL = register(new Block("black_wool", builder())); + public static final Block MOVING_PISTON = register(new Block("moving_piston", builder() + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .enumState(PISTON_TYPE, "normal", "sticky"))); + public static final Block DANDELION = register(new Block("dandelion", builder())); + public static final Block TORCHFLOWER = register(new Block("torchflower", builder())); + public static final Block POPPY = register(new Block("poppy", builder())); + public static final Block BLUE_ORCHID = register(new Block("blue_orchid", builder())); + public static final Block ALLIUM = register(new Block("allium", builder())); + public static final Block AZURE_BLUET = register(new Block("azure_bluet", builder())); + public static final Block RED_TULIP = register(new Block("red_tulip", builder())); + public static final Block ORANGE_TULIP = register(new Block("orange_tulip", builder())); + public static final Block WHITE_TULIP = register(new Block("white_tulip", builder())); + public static final Block PINK_TULIP = register(new Block("pink_tulip", builder())); + public static final Block OXEYE_DAISY = register(new Block("oxeye_daisy", builder())); + public static final Block CORNFLOWER = register(new Block("cornflower", builder())); + public static final Block WITHER_ROSE = register(new Block("wither_rose", builder())); + public static final Block LILY_OF_THE_VALLEY = register(new Block("lily_of_the_valley", builder())); + public static final Block BROWN_MUSHROOM = register(new Block("brown_mushroom", builder())); + public static final Block RED_MUSHROOM = register(new Block("red_mushroom", builder())); + public static final Block GOLD_BLOCK = register(new Block("gold_block", builder())); + public static final Block IRON_BLOCK = register(new Block("iron_block", builder())); + public static final Block BRICKS = register(new Block("bricks", builder())); + public static final Block TNT = register(new Block("tnt", builder() + .booleanState(UNSTABLE))); + public static final Block BOOKSHELF = register(new Block("bookshelf", builder())); + public static final Block CHISELED_BOOKSHELF = register(new Block("chiseled_bookshelf", builder() + .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())); + public static final Block OBSIDIAN = register(new Block("obsidian", builder())); + public static final Block TORCH = register(new Block("torch", builder())); + public static final Block WALL_TORCH = register(new Block("wall_torch", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block FIRE = register(new Block("fire", builder() + .intState(AGE_15, 0, 15) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); + public static final Block SOUL_FIRE = register(new Block("soul_fire", builder())); + public static final Block SPAWNER = register(new Block("spawner", builder())); + public static final Block OAK_STAIRS = register(new Block("oak_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block CHEST = register(new Block("chest", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(CHEST_TYPE, "single", "left", "right") + .booleanState(WATERLOGGED))); + public static final Block REDSTONE_WIRE = register(new Block("redstone_wire", builder() + .enumState(EAST_REDSTONE, "up", "side", "none") + .enumState(NORTH_REDSTONE, "up", "side", "none") + .intState(POWER, 0, 15) + .enumState(SOUTH_REDSTONE, "up", "side", "none") + .enumState(WEST_REDSTONE, "up", "side", "none"))); + public static final Block DIAMOND_ORE = register(new Block("diamond_ore", builder())); + public static final Block DEEPSLATE_DIAMOND_ORE = register(new Block("deepslate_diamond_ore", builder())); + public static final Block DIAMOND_BLOCK = register(new Block("diamond_block", builder())); + public static final Block CRAFTING_TABLE = register(new Block("crafting_table", builder())); + public static final Block WHEAT = register(new Block("wheat", builder() + .intState(AGE_7, 0, 7))); + public static final Block FARMLAND = register(new Block("farmland", builder() + .intState(MOISTURE, 0, 7))); + public static final Block FURNACE = register(new Block("furnace", builder() + .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() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block DARK_OAK_SIGN = register(new Block("dark_oak_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block OAK_DOOR = register(new Block("oak_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block LADDER = register(new Block("ladder", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); + public static final Block RAIL = register(new Block("rail", builder() + .enumState(RAIL_SHAPE, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south", "south_east", "south_west", "north_west", "north_east") + .booleanState(WATERLOGGED))); + public static final Block COBBLESTONE_STAIRS = register(new Block("cobblestone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block OAK_WALL_SIGN = register(new Block("oak_wall_sign", builder() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block SPRUCE_HANGING_SIGN = register(new Block("spruce_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block BIRCH_HANGING_SIGN = register(new Block("birch_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block ACACIA_HANGING_SIGN = register(new Block("acacia_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block CHERRY_HANGING_SIGN = register(new Block("cherry_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block JUNGLE_HANGING_SIGN = register(new Block("jungle_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block DARK_OAK_HANGING_SIGN = register(new Block("dark_oak_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block CRIMSON_HANGING_SIGN = register(new Block("crimson_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block WARPED_HANGING_SIGN = register(new Block("warped_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block MANGROVE_HANGING_SIGN = register(new Block("mangrove_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block BAMBOO_HANGING_SIGN = register(new Block("bamboo_hanging_sign", builder() + .booleanState(ATTACHED) + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block OAK_WALL_HANGING_SIGN = register(new Block("oak_wall_hanging_sign", builder() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); + public static final Block LEVER = register(new Block("lever", builder() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .booleanState(POWERED))); + public static final Block IRON_DOOR = register(new Block("iron_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block OAK_PRESSURE_PLATE = register(new Block("oak_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block SPRUCE_PRESSURE_PLATE = register(new Block("spruce_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block BIRCH_PRESSURE_PLATE = register(new Block("birch_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block JUNGLE_PRESSURE_PLATE = register(new Block("jungle_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block ACACIA_PRESSURE_PLATE = register(new Block("acacia_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block CHERRY_PRESSURE_PLATE = register(new Block("cherry_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block DARK_OAK_PRESSURE_PLATE = register(new Block("dark_oak_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block MANGROVE_PRESSURE_PLATE = register(new Block("mangrove_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block BAMBOO_PRESSURE_PLATE = register(new Block("bamboo_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block REDSTONE_ORE = register(new Block("redstone_ore", builder() + .booleanState(LIT))); + public static final Block DEEPSLATE_REDSTONE_ORE = register(new Block("deepslate_redstone_ore", builder() + .booleanState(LIT))); + public static final Block REDSTONE_TORCH = register(new Block("redstone_torch", builder() + .booleanState(LIT))); + public static final Block REDSTONE_WALL_TORCH = register(new Block("redstone_wall_torch", builder() + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block SNOW = register(new Block("snow", builder() + .intState(LAYERS, 1, 8))); + public static final Block ICE = register(new Block("ice", builder())); + public static final Block SNOW_BLOCK = register(new Block("snow_block", builder())); + public static final Block CACTUS = register(new Block("cactus", builder() + .intState(AGE_15, 0, 15))); + public static final Block CLAY = register(new Block("clay", builder())); + public static final Block SUGAR_CANE = register(new Block("sugar_cane", builder() + .intState(AGE_15, 0, 15))); + public static final Block JUKEBOX = register(new Block("jukebox", builder() + .booleanState(HAS_RECORD))); + public static final Block OAK_FENCE = register(new Block("oak_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block NETHERRACK = register(new Block("netherrack", builder())); + public static final Block SOUL_SAND = register(new Block("soul_sand", builder())); + public static final Block SOUL_SOIL = register(new Block("soul_soil", builder())); + public static final Block BASALT = register(new Block("basalt", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block POLISHED_BASALT = register(new Block("polished_basalt", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block SOUL_TORCH = register(new Block("soul_torch", builder())); + public static final Block SOUL_WALL_TORCH = register(new Block("soul_wall_torch", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block GLOWSTONE = register(new Block("glowstone", builder())); + public static final Block NETHER_PORTAL = register(new Block("nether_portal", builder() + .enumState(HORIZONTAL_AXIS, Axis.X, Axis.Z))); + public static final Block CARVED_PUMPKIN = register(new Block("carved_pumpkin", builder() + .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() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block CAKE = register(new Block("cake", builder() + .intState(BITES, 0, 6))); + public static final Block REPEATER = register(new Block("repeater", builder() + .intState(DELAY, 1, 4) + .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())); + public static final Block ORANGE_STAINED_GLASS = register(new Block("orange_stained_glass", builder())); + public static final Block MAGENTA_STAINED_GLASS = register(new Block("magenta_stained_glass", builder())); + public static final Block LIGHT_BLUE_STAINED_GLASS = register(new Block("light_blue_stained_glass", builder())); + public static final Block YELLOW_STAINED_GLASS = register(new Block("yellow_stained_glass", builder())); + public static final Block LIME_STAINED_GLASS = register(new Block("lime_stained_glass", builder())); + public static final Block PINK_STAINED_GLASS = register(new Block("pink_stained_glass", builder())); + public static final Block GRAY_STAINED_GLASS = register(new Block("gray_stained_glass", builder())); + public static final Block LIGHT_GRAY_STAINED_GLASS = register(new Block("light_gray_stained_glass", builder())); + public static final Block CYAN_STAINED_GLASS = register(new Block("cyan_stained_glass", builder())); + public static final Block PURPLE_STAINED_GLASS = register(new Block("purple_stained_glass", builder())); + public static final Block BLUE_STAINED_GLASS = register(new Block("blue_stained_glass", builder())); + public static final Block BROWN_STAINED_GLASS = register(new Block("brown_stained_glass", builder())); + public static final Block GREEN_STAINED_GLASS = register(new Block("green_stained_glass", builder())); + public static final Block RED_STAINED_GLASS = register(new Block("red_stained_glass", builder())); + public static final Block BLACK_STAINED_GLASS = register(new Block("black_stained_glass", builder())); + public static final Block OAK_TRAPDOOR = register(new Block("oak_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block SPRUCE_TRAPDOOR = register(new Block("spruce_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block BIRCH_TRAPDOOR = register(new Block("birch_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block JUNGLE_TRAPDOOR = register(new Block("jungle_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block ACACIA_TRAPDOOR = register(new Block("acacia_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block CHERRY_TRAPDOOR = register(new Block("cherry_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block DARK_OAK_TRAPDOOR = register(new Block("dark_oak_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block MANGROVE_TRAPDOOR = register(new Block("mangrove_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block BAMBOO_TRAPDOOR = register(new Block("bamboo_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block STONE_BRICKS = register(new Block("stone_bricks", builder())); + public static final Block MOSSY_STONE_BRICKS = register(new Block("mossy_stone_bricks", builder())); + public static final Block CRACKED_STONE_BRICKS = register(new Block("cracked_stone_bricks", builder())); + public static final Block CHISELED_STONE_BRICKS = register(new Block("chiseled_stone_bricks", builder())); + public static final Block PACKED_MUD = register(new Block("packed_mud", builder())); + public static final Block MUD_BRICKS = register(new Block("mud_bricks", builder())); + public static final Block INFESTED_STONE = register(new Block("infested_stone", builder())); + public static final Block INFESTED_COBBLESTONE = register(new Block("infested_cobblestone", builder())); + public static final Block INFESTED_STONE_BRICKS = register(new Block("infested_stone_bricks", builder())); + public static final Block INFESTED_MOSSY_STONE_BRICKS = register(new Block("infested_mossy_stone_bricks", builder())); + public static final Block INFESTED_CRACKED_STONE_BRICKS = register(new Block("infested_cracked_stone_bricks", builder())); + public static final Block INFESTED_CHISELED_STONE_BRICKS = register(new Block("infested_chiseled_stone_bricks", builder())); + public static final Block BROWN_MUSHROOM_BLOCK = register(new Block("brown_mushroom_block", builder() + .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() + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); + public static final Block MUSHROOM_STEM = register(new Block("mushroom_stem", builder() + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); + public static final Block IRON_BARS = register(new Block("iron_bars", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block CHAIN = register(new Block("chain", builder() + .enumState(AXIS, Axis.VALUES) + .booleanState(WATERLOGGED))); + public static final Block GLASS_PANE = register(new Block("glass_pane", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block PUMPKIN = register(new Block("pumpkin", builder())); + public static final Block MELON = register(new Block("melon", builder())); + public static final Block ATTACHED_PUMPKIN_STEM = register(new Block("attached_pumpkin_stem", builder() + .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() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block PUMPKIN_STEM = register(new Block("pumpkin_stem", builder() + .intState(AGE_7, 0, 7))); + public static final Block MELON_STEM = register(new Block("melon_stem", builder() + .intState(AGE_7, 0, 7))); + public static final Block VINE = register(new Block("vine", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); + public static final Block GLOW_LICHEN = register(new Block("glow_lichen", builder() + .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() + .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() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block STONE_BRICK_STAIRS = register(new Block("stone_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block MUD_BRICK_STAIRS = register(new Block("mud_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block MYCELIUM = register(new Block("mycelium", builder() + .booleanState(SNOWY))); + public static final Block LILY_PAD = register(new Block("lily_pad", builder())); + public static final Block NETHER_BRICKS = register(new Block("nether_bricks", builder())); + public static final Block NETHER_BRICK_FENCE = register(new Block("nether_brick_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block NETHER_BRICK_STAIRS = register(new Block("nether_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block NETHER_WART = register(new Block("nether_wart", builder() + .intState(AGE_3, 0, 3))); + public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder())); + public static final Block BREWING_STAND = register(new Block("brewing_stand", builder() + .booleanState(HAS_BOTTLE_0) + .booleanState(HAS_BOTTLE_1) + .booleanState(HAS_BOTTLE_2))); + public static final Block CAULDRON = register(new Block("cauldron", builder())); + public static final Block WATER_CAULDRON = register(new Block("water_cauldron", builder() + .intState(LEVEL_CAULDRON, 1, 3))); + public static final Block LAVA_CAULDRON = register(new Block("lava_cauldron", builder())); + public static final Block POWDER_SNOW_CAULDRON = register(new Block("powder_snow_cauldron", builder() + .intState(LEVEL_CAULDRON, 1, 3))); + public static final Block END_PORTAL = register(new Block("end_portal", builder())); + public static final Block END_PORTAL_FRAME = register(new Block("end_portal_frame", builder() + .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())); + public static final Block DRAGON_EGG = register(new Block("dragon_egg", builder())); + public static final Block REDSTONE_LAMP = register(new Block("redstone_lamp", builder() + .booleanState(LIT))); + public static final Block COCOA = register(new Block("cocoa", builder() + .intState(AGE_2, 0, 2) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block SANDSTONE_STAIRS = register(new Block("sandstone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block EMERALD_ORE = register(new Block("emerald_ore", builder())); + public static final Block DEEPSLATE_EMERALD_ORE = register(new Block("deepslate_emerald_ore", builder())); + public static final Block ENDER_CHEST = register(new Block("ender_chest", builder() + .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() + .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() + .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())); + public static final Block SPRUCE_STAIRS = register(new Block("spruce_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block BIRCH_STAIRS = register(new Block("birch_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block JUNGLE_STAIRS = register(new Block("jungle_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block COMMAND_BLOCK = register(new Block("command_block", builder() + .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())); + public static final Block COBBLESTONE_WALL = register(new Block("cobblestone_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block MOSSY_COBBLESTONE_WALL = register(new Block("mossy_cobblestone_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block FLOWER_POT = register(new Block("flower_pot", builder())); + public static final Block POTTED_TORCHFLOWER = register(new Block("potted_torchflower", builder())); + public static final Block POTTED_OAK_SAPLING = register(new Block("potted_oak_sapling", builder())); + public static final Block POTTED_SPRUCE_SAPLING = register(new Block("potted_spruce_sapling", builder())); + public static final Block POTTED_BIRCH_SAPLING = register(new Block("potted_birch_sapling", builder())); + public static final Block POTTED_JUNGLE_SAPLING = register(new Block("potted_jungle_sapling", builder())); + public static final Block POTTED_ACACIA_SAPLING = register(new Block("potted_acacia_sapling", builder())); + public static final Block POTTED_CHERRY_SAPLING = register(new Block("potted_cherry_sapling", builder())); + public static final Block POTTED_DARK_OAK_SAPLING = register(new Block("potted_dark_oak_sapling", builder())); + public static final Block POTTED_MANGROVE_PROPAGULE = register(new Block("potted_mangrove_propagule", builder())); + public static final Block POTTED_FERN = register(new Block("potted_fern", builder())); + public static final Block POTTED_DANDELION = register(new Block("potted_dandelion", builder())); + public static final Block POTTED_POPPY = register(new Block("potted_poppy", builder())); + public static final Block POTTED_BLUE_ORCHID = register(new Block("potted_blue_orchid", builder())); + public static final Block POTTED_ALLIUM = register(new Block("potted_allium", builder())); + public static final Block POTTED_AZURE_BLUET = register(new Block("potted_azure_bluet", builder())); + public static final Block POTTED_RED_TULIP = register(new Block("potted_red_tulip", builder())); + public static final Block POTTED_ORANGE_TULIP = register(new Block("potted_orange_tulip", builder())); + public static final Block POTTED_WHITE_TULIP = register(new Block("potted_white_tulip", builder())); + public static final Block POTTED_PINK_TULIP = register(new Block("potted_pink_tulip", builder())); + public static final Block POTTED_OXEYE_DAISY = register(new Block("potted_oxeye_daisy", builder())); + public static final Block POTTED_CORNFLOWER = register(new Block("potted_cornflower", builder())); + public static final Block POTTED_LILY_OF_THE_VALLEY = register(new Block("potted_lily_of_the_valley", builder())); + public static final Block POTTED_WITHER_ROSE = register(new Block("potted_wither_rose", builder())); + public static final Block POTTED_RED_MUSHROOM = register(new Block("potted_red_mushroom", builder())); + public static final Block POTTED_BROWN_MUSHROOM = register(new Block("potted_brown_mushroom", builder())); + public static final Block POTTED_DEAD_BUSH = register(new Block("potted_dead_bush", builder())); + public static final Block POTTED_CACTUS = register(new Block("potted_cactus", builder())); + public static final Block CARROTS = register(new Block("carrots", builder() + .intState(AGE_7, 0, 7))); + public static final Block POTATOES = register(new Block("potatoes", builder() + .intState(AGE_7, 0, 7))); + public static final Block OAK_BUTTON = register(new Block("oak_button", builder() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block SKELETON_SKULL = register(new Block("skeleton_skull", builder() + .booleanState(POWERED) + .intState(ROTATION_16, 0, 15))); + public static final Block SKELETON_WALL_SKULL = register(new Block("skeleton_wall_skull", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block WITHER_SKELETON_SKULL = register(new Block("wither_skeleton_skull", builder() + .booleanState(POWERED) + .intState(ROTATION_16, 0, 15))); + public static final Block WITHER_SKELETON_WALL_SKULL = register(new Block("wither_skeleton_wall_skull", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block ZOMBIE_HEAD = register(new Block("zombie_head", builder() + .booleanState(POWERED) + .intState(ROTATION_16, 0, 15))); + public static final Block ZOMBIE_WALL_HEAD = register(new Block("zombie_wall_head", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block PLAYER_HEAD = register(new Block("player_head", builder() + .booleanState(POWERED) + .intState(ROTATION_16, 0, 15))); + public static final Block PLAYER_WALL_HEAD = register(new Block("player_wall_head", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block CREEPER_HEAD = register(new Block("creeper_head", builder() + .booleanState(POWERED) + .intState(ROTATION_16, 0, 15))); + public static final Block CREEPER_WALL_HEAD = register(new Block("creeper_wall_head", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block DRAGON_HEAD = register(new Block("dragon_head", builder() + .booleanState(POWERED) + .intState(ROTATION_16, 0, 15))); + public static final Block DRAGON_WALL_HEAD = register(new Block("dragon_wall_head", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block PIGLIN_HEAD = register(new Block("piglin_head", builder() + .booleanState(POWERED) + .intState(ROTATION_16, 0, 15))); + public static final Block PIGLIN_WALL_HEAD = register(new Block("piglin_wall_head", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block ANVIL = register(new Block("anvil", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block CHIPPED_ANVIL = register(new Block("chipped_anvil", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block DAMAGED_ANVIL = register(new Block("damaged_anvil", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block TRAPPED_CHEST = register(new Block("trapped_chest", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(CHEST_TYPE, "single", "left", "right") + .booleanState(WATERLOGGED))); + public static final Block LIGHT_WEIGHTED_PRESSURE_PLATE = register(new Block("light_weighted_pressure_plate", builder() + .intState(POWER, 0, 15))); + public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder() + .intState(POWER, 0, 15))); + public static final Block COMPARATOR = register(new Block("comparator", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(MODE_COMPARATOR, "compare", "subtract") + .booleanState(POWERED))); + public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder() + .booleanState(INVERTED) + .intState(POWER, 0, 15))); + public static final Block REDSTONE_BLOCK = register(new Block("redstone_block", builder())); + public static final Block NETHER_QUARTZ_ORE = register(new Block("nether_quartz_ore", builder())); + public static final Block HOPPER = register(new Block("hopper", builder() + .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())); + public static final Block CHISELED_QUARTZ_BLOCK = register(new Block("chiseled_quartz_block", builder())); + public static final Block QUARTZ_PILLAR = register(new Block("quartz_pillar", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block QUARTZ_STAIRS = register(new Block("quartz_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block ACTIVATOR_RAIL = register(new Block("activator_rail", builder() + .booleanState(POWERED) + .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") + .booleanState(WATERLOGGED))); + public static final Block DROPPER = register(new Block("dropper", builder() + .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())); + public static final Block ORANGE_TERRACOTTA = register(new Block("orange_terracotta", builder())); + public static final Block MAGENTA_TERRACOTTA = register(new Block("magenta_terracotta", builder())); + public static final Block LIGHT_BLUE_TERRACOTTA = register(new Block("light_blue_terracotta", builder())); + public static final Block YELLOW_TERRACOTTA = register(new Block("yellow_terracotta", builder())); + public static final Block LIME_TERRACOTTA = register(new Block("lime_terracotta", builder())); + public static final Block PINK_TERRACOTTA = register(new Block("pink_terracotta", builder())); + public static final Block GRAY_TERRACOTTA = register(new Block("gray_terracotta", builder())); + public static final Block LIGHT_GRAY_TERRACOTTA = register(new Block("light_gray_terracotta", builder())); + public static final Block CYAN_TERRACOTTA = register(new Block("cyan_terracotta", builder())); + public static final Block PURPLE_TERRACOTTA = register(new Block("purple_terracotta", builder())); + public static final Block BLUE_TERRACOTTA = register(new Block("blue_terracotta", builder())); + public static final Block BROWN_TERRACOTTA = register(new Block("brown_terracotta", builder())); + public static final Block GREEN_TERRACOTTA = register(new Block("green_terracotta", builder())); + public static final Block RED_TERRACOTTA = register(new Block("red_terracotta", builder())); + public static final Block BLACK_TERRACOTTA = register(new Block("black_terracotta", builder())); + public static final Block WHITE_STAINED_GLASS_PANE = register(new Block("white_stained_glass_pane", builder() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block ACACIA_STAIRS = register(new Block("acacia_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block CHERRY_STAIRS = register(new Block("cherry_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block DARK_OAK_STAIRS = register(new Block("dark_oak_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block MANGROVE_STAIRS = register(new Block("mangrove_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block BAMBOO_STAIRS = register(new Block("bamboo_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block BAMBOO_MOSAIC_STAIRS = register(new Block("bamboo_mosaic_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block SLIME_BLOCK = register(new Block("slime_block", builder())); + public static final Block BARRIER = register(new Block("barrier", builder() + .booleanState(WATERLOGGED))); + public static final Block LIGHT = register(new Block("light", builder() + .intState(LEVEL, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block IRON_TRAPDOOR = register(new Block("iron_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block PRISMARINE = register(new Block("prismarine", builder())); + public static final Block PRISMARINE_BRICKS = register(new Block("prismarine_bricks", builder())); + public static final Block DARK_PRISMARINE = register(new Block("dark_prismarine", builder())); + public static final Block PRISMARINE_STAIRS = register(new Block("prismarine_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block PRISMARINE_BRICK_STAIRS = register(new Block("prismarine_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block DARK_PRISMARINE_STAIRS = register(new Block("dark_prismarine_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block PRISMARINE_SLAB = register(new Block("prismarine_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block PRISMARINE_BRICK_SLAB = register(new Block("prismarine_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block DARK_PRISMARINE_SLAB = register(new Block("dark_prismarine_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block SEA_LANTERN = register(new Block("sea_lantern", builder())); + public static final Block HAY_BLOCK = register(new Block("hay_block", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block WHITE_CARPET = register(new Block("white_carpet", builder())); + public static final Block ORANGE_CARPET = register(new Block("orange_carpet", builder())); + public static final Block MAGENTA_CARPET = register(new Block("magenta_carpet", builder())); + public static final Block LIGHT_BLUE_CARPET = register(new Block("light_blue_carpet", builder())); + public static final Block YELLOW_CARPET = register(new Block("yellow_carpet", builder())); + public static final Block LIME_CARPET = register(new Block("lime_carpet", builder())); + public static final Block PINK_CARPET = register(new Block("pink_carpet", builder())); + public static final Block GRAY_CARPET = register(new Block("gray_carpet", builder())); + public static final Block LIGHT_GRAY_CARPET = register(new Block("light_gray_carpet", builder())); + public static final Block CYAN_CARPET = register(new Block("cyan_carpet", builder())); + public static final Block PURPLE_CARPET = register(new Block("purple_carpet", builder())); + public static final Block BLUE_CARPET = register(new Block("blue_carpet", builder())); + public static final Block BROWN_CARPET = register(new Block("brown_carpet", builder())); + public static final Block GREEN_CARPET = register(new Block("green_carpet", builder())); + public static final Block RED_CARPET = register(new Block("red_carpet", builder())); + public static final Block BLACK_CARPET = register(new Block("black_carpet", builder())); + public static final Block TERRACOTTA = register(new Block("terracotta", builder())); + public static final Block COAL_BLOCK = register(new Block("coal_block", builder())); + public static final Block PACKED_ICE = register(new Block("packed_ice", builder())); + public static final Block SUNFLOWER = register(new Block("sunflower", builder() + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block LILAC = register(new Block("lilac", builder() + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block ROSE_BUSH = register(new Block("rose_bush", builder() + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block PEONY = register(new Block("peony", builder() + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block TALL_GRASS = register(new Block("tall_grass", builder() + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block LARGE_FERN = register(new Block("large_fern", builder() + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder() + .intState(ROTATION_16, 0, 15))); + public static final Block WHITE_WALL_BANNER = register(new BannerBlock("white_wall_banner", 0, builder() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block RED_SANDSTONE = register(new Block("red_sandstone", builder())); + public static final Block CHISELED_RED_SANDSTONE = register(new Block("chiseled_red_sandstone", builder())); + public static final Block CUT_RED_SANDSTONE = register(new Block("cut_red_sandstone", builder())); + public static final Block RED_SANDSTONE_STAIRS = register(new Block("red_sandstone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block OAK_SLAB = register(new Block("oak_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block SPRUCE_SLAB = register(new Block("spruce_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block BIRCH_SLAB = register(new Block("birch_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block JUNGLE_SLAB = register(new Block("jungle_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block ACACIA_SLAB = register(new Block("acacia_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block CHERRY_SLAB = register(new Block("cherry_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block DARK_OAK_SLAB = register(new Block("dark_oak_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block MANGROVE_SLAB = register(new Block("mangrove_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block BAMBOO_SLAB = register(new Block("bamboo_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block BAMBOO_MOSAIC_SLAB = register(new Block("bamboo_mosaic_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block STONE_SLAB = register(new Block("stone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block SMOOTH_STONE_SLAB = register(new Block("smooth_stone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block SANDSTONE_SLAB = register(new Block("sandstone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block CUT_SANDSTONE_SLAB = register(new Block("cut_sandstone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block PETRIFIED_OAK_SLAB = register(new Block("petrified_oak_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block COBBLESTONE_SLAB = register(new Block("cobblestone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block BRICK_SLAB = register(new Block("brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block STONE_BRICK_SLAB = register(new Block("stone_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block MUD_BRICK_SLAB = register(new Block("mud_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block NETHER_BRICK_SLAB = register(new Block("nether_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block QUARTZ_SLAB = register(new Block("quartz_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block RED_SANDSTONE_SLAB = register(new Block("red_sandstone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block CUT_RED_SANDSTONE_SLAB = register(new Block("cut_red_sandstone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block PURPUR_SLAB = register(new Block("purpur_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block SMOOTH_STONE = register(new Block("smooth_stone", builder())); + public static final Block SMOOTH_SANDSTONE = register(new Block("smooth_sandstone", builder())); + public static final Block SMOOTH_QUARTZ = register(new Block("smooth_quartz", builder())); + public static final Block SMOOTH_RED_SANDSTONE = register(new Block("smooth_red_sandstone", builder())); + public static final Block SPRUCE_FENCE_GATE = register(new Block("spruce_fence_gate", builder() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block BIRCH_FENCE = register(new Block("birch_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block JUNGLE_FENCE = register(new Block("jungle_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block ACACIA_FENCE = register(new Block("acacia_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block CHERRY_FENCE = register(new Block("cherry_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block DARK_OAK_FENCE = register(new Block("dark_oak_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block MANGROVE_FENCE = register(new Block("mangrove_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block BAMBOO_FENCE = register(new Block("bamboo_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block SPRUCE_DOOR = register(new Block("spruce_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block BIRCH_DOOR = register(new Block("birch_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block JUNGLE_DOOR = register(new Block("jungle_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block ACACIA_DOOR = register(new Block("acacia_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block CHERRY_DOOR = register(new Block("cherry_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block DARK_OAK_DOOR = register(new Block("dark_oak_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block MANGROVE_DOOR = register(new Block("mangrove_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block BAMBOO_DOOR = register(new Block("bamboo_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .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))); + public static final Block CHORUS_PLANT = register(new Block("chorus_plant", builder() + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); + public static final Block CHORUS_FLOWER = register(new Block("chorus_flower", builder() + .intState(AGE_5, 0, 5))); + public static final Block PURPUR_BLOCK = register(new Block("purpur_block", builder())); + public static final Block PURPUR_PILLAR = register(new Block("purpur_pillar", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block PURPUR_STAIRS = register(new Block("purpur_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block END_STONE_BRICKS = register(new Block("end_stone_bricks", builder())); + public static final Block TORCHFLOWER_CROP = register(new Block("torchflower_crop", builder() + .intState(AGE_1, 0, 1))); + public static final Block PITCHER_CROP = register(new Block("pitcher_crop", builder() + .intState(AGE_4, 0, 4) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block PITCHER_PLANT = register(new Block("pitcher_plant", builder() + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + public static final Block BEETROOTS = register(new Block("beetroots", builder() + .intState(AGE_3, 0, 3))); + public static final Block DIRT_PATH = register(new Block("dirt_path", builder())); + public static final Block END_GATEWAY = register(new Block("end_gateway", builder())); + public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder() + .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() + .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() + .intState(AGE_3, 0, 3))); + public static final Block MAGMA_BLOCK = register(new Block("magma_block", builder())); + public static final Block NETHER_WART_BLOCK = register(new Block("nether_wart_block", builder())); + public static final Block RED_NETHER_BRICKS = register(new Block("red_nether_bricks", builder())); + public static final Block BONE_BLOCK = register(new Block("bone_block", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRUCTURE_VOID = register(new Block("structure_void", builder())); + public static final Block OBSERVER = register(new Block("observer", builder() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block WHITE_CONCRETE = register(new Block("white_concrete", builder())); + public static final Block ORANGE_CONCRETE = register(new Block("orange_concrete", builder())); + public static final Block MAGENTA_CONCRETE = register(new Block("magenta_concrete", builder())); + public static final Block LIGHT_BLUE_CONCRETE = register(new Block("light_blue_concrete", builder())); + public static final Block YELLOW_CONCRETE = register(new Block("yellow_concrete", builder())); + public static final Block LIME_CONCRETE = register(new Block("lime_concrete", builder())); + public static final Block PINK_CONCRETE = register(new Block("pink_concrete", builder())); + public static final Block GRAY_CONCRETE = register(new Block("gray_concrete", builder())); + public static final Block LIGHT_GRAY_CONCRETE = register(new Block("light_gray_concrete", builder())); + public static final Block CYAN_CONCRETE = register(new Block("cyan_concrete", builder())); + public static final Block PURPLE_CONCRETE = register(new Block("purple_concrete", builder())); + public static final Block BLUE_CONCRETE = register(new Block("blue_concrete", builder())); + public static final Block BROWN_CONCRETE = register(new Block("brown_concrete", builder())); + public static final Block GREEN_CONCRETE = register(new Block("green_concrete", builder())); + public static final Block RED_CONCRETE = register(new Block("red_concrete", builder())); + public static final Block BLACK_CONCRETE = register(new Block("black_concrete", builder())); + public static final Block WHITE_CONCRETE_POWDER = register(new Block("white_concrete_powder", builder())); + public static final Block ORANGE_CONCRETE_POWDER = register(new Block("orange_concrete_powder", builder())); + public static final Block MAGENTA_CONCRETE_POWDER = register(new Block("magenta_concrete_powder", builder())); + public static final Block LIGHT_BLUE_CONCRETE_POWDER = register(new Block("light_blue_concrete_powder", builder())); + public static final Block YELLOW_CONCRETE_POWDER = register(new Block("yellow_concrete_powder", builder())); + public static final Block LIME_CONCRETE_POWDER = register(new Block("lime_concrete_powder", builder())); + public static final Block PINK_CONCRETE_POWDER = register(new Block("pink_concrete_powder", builder())); + public static final Block GRAY_CONCRETE_POWDER = register(new Block("gray_concrete_powder", builder())); + public static final Block LIGHT_GRAY_CONCRETE_POWDER = register(new Block("light_gray_concrete_powder", builder())); + public static final Block CYAN_CONCRETE_POWDER = register(new Block("cyan_concrete_powder", builder())); + public static final Block PURPLE_CONCRETE_POWDER = register(new Block("purple_concrete_powder", builder())); + public static final Block BLUE_CONCRETE_POWDER = register(new Block("blue_concrete_powder", builder())); + public static final Block BROWN_CONCRETE_POWDER = register(new Block("brown_concrete_powder", builder())); + public static final Block GREEN_CONCRETE_POWDER = register(new Block("green_concrete_powder", builder())); + public static final Block RED_CONCRETE_POWDER = register(new Block("red_concrete_powder", builder())); + public static final Block BLACK_CONCRETE_POWDER = register(new Block("black_concrete_powder", builder())); + public static final Block KELP = register(new Block("kelp", builder() + .intState(AGE_25, 0, 25))); + public static final Block KELP_PLANT = register(new Block("kelp_plant", builder())); + public static final Block DRIED_KELP_BLOCK = register(new Block("dried_kelp_block", builder())); + public static final Block TURTLE_EGG = register(new Block("turtle_egg", builder() + .intState(EGGS, 1, 4) + .intState(HATCH, 0, 2))); + public static final Block SNIFFER_EGG = register(new Block("sniffer_egg", builder() + .intState(HATCH, 0, 2))); + public static final Block DEAD_TUBE_CORAL_BLOCK = register(new Block("dead_tube_coral_block", builder())); + public static final Block DEAD_BRAIN_CORAL_BLOCK = register(new Block("dead_brain_coral_block", builder())); + public static final Block DEAD_BUBBLE_CORAL_BLOCK = register(new Block("dead_bubble_coral_block", builder())); + public static final Block DEAD_FIRE_CORAL_BLOCK = register(new Block("dead_fire_coral_block", builder())); + public static final Block DEAD_HORN_CORAL_BLOCK = register(new Block("dead_horn_coral_block", builder())); + public static final Block TUBE_CORAL_BLOCK = register(new Block("tube_coral_block", builder())); + public static final Block BRAIN_CORAL_BLOCK = register(new Block("brain_coral_block", builder())); + public static final Block BUBBLE_CORAL_BLOCK = register(new Block("bubble_coral_block", builder())); + public static final Block FIRE_CORAL_BLOCK = register(new Block("fire_coral_block", builder())); + public static final Block HORN_CORAL_BLOCK = register(new Block("horn_coral_block", builder())); + public static final Block DEAD_TUBE_CORAL = register(new Block("dead_tube_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_BRAIN_CORAL = register(new Block("dead_brain_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_BUBBLE_CORAL = register(new Block("dead_bubble_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_FIRE_CORAL = register(new Block("dead_fire_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_HORN_CORAL = register(new Block("dead_horn_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block TUBE_CORAL = register(new Block("tube_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block BRAIN_CORAL = register(new Block("brain_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block BUBBLE_CORAL = register(new Block("bubble_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block FIRE_CORAL = register(new Block("fire_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block HORN_CORAL = register(new Block("horn_coral", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_TUBE_CORAL_FAN = register(new Block("dead_tube_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_BRAIN_CORAL_FAN = register(new Block("dead_brain_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_BUBBLE_CORAL_FAN = register(new Block("dead_bubble_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_FIRE_CORAL_FAN = register(new Block("dead_fire_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_HORN_CORAL_FAN = register(new Block("dead_horn_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block TUBE_CORAL_FAN = register(new Block("tube_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block BRAIN_CORAL_FAN = register(new Block("brain_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block BUBBLE_CORAL_FAN = register(new Block("bubble_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block FIRE_CORAL_FAN = register(new Block("fire_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block HORN_CORAL_FAN = register(new Block("horn_coral_fan", builder() + .booleanState(WATERLOGGED))); + public static final Block DEAD_TUBE_CORAL_WALL_FAN = register(new Block("dead_tube_coral_wall_fan", builder() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .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() + .intState(PICKLES, 1, 4) + .booleanState(WATERLOGGED))); + public static final Block BLUE_ICE = register(new Block("blue_ice", builder())); + public static final Block CONDUIT = register(new Block("conduit", builder() + .booleanState(WATERLOGGED))); + public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder())); + public static final Block BAMBOO = register(new Block("bamboo", builder() + .intState(AGE_1, 0, 1) + .enumState(BAMBOO_LEAVES, "none", "small", "large") + .intState(STAGE, 0, 1))); + public static final Block POTTED_BAMBOO = register(new Block("potted_bamboo", builder())); + 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() + .booleanState(DRAG))); + public static final Block POLISHED_GRANITE_STAIRS = register(new Block("polished_granite_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block SMOOTH_RED_SANDSTONE_STAIRS = register(new Block("smooth_red_sandstone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block MOSSY_STONE_BRICK_STAIRS = register(new Block("mossy_stone_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_DIORITE_STAIRS = register(new Block("polished_diorite_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block MOSSY_COBBLESTONE_STAIRS = register(new Block("mossy_cobblestone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block END_STONE_BRICK_STAIRS = register(new Block("end_stone_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block STONE_STAIRS = register(new Block("stone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block SMOOTH_SANDSTONE_STAIRS = register(new Block("smooth_sandstone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block SMOOTH_QUARTZ_STAIRS = register(new Block("smooth_quartz_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block GRANITE_STAIRS = register(new Block("granite_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block ANDESITE_STAIRS = register(new Block("andesite_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block RED_NETHER_BRICK_STAIRS = register(new Block("red_nether_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_ANDESITE_STAIRS = register(new Block("polished_andesite_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block DIORITE_STAIRS = register(new Block("diorite_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_GRANITE_SLAB = register(new Block("polished_granite_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block SMOOTH_RED_SANDSTONE_SLAB = register(new Block("smooth_red_sandstone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block MOSSY_STONE_BRICK_SLAB = register(new Block("mossy_stone_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_DIORITE_SLAB = register(new Block("polished_diorite_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block MOSSY_COBBLESTONE_SLAB = register(new Block("mossy_cobblestone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block END_STONE_BRICK_SLAB = register(new Block("end_stone_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block SMOOTH_SANDSTONE_SLAB = register(new Block("smooth_sandstone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block SMOOTH_QUARTZ_SLAB = register(new Block("smooth_quartz_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block GRANITE_SLAB = register(new Block("granite_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block ANDESITE_SLAB = register(new Block("andesite_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block RED_NETHER_BRICK_SLAB = register(new Block("red_nether_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_ANDESITE_SLAB = register(new Block("polished_andesite_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block DIORITE_SLAB = register(new Block("diorite_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block BRICK_WALL = register(new Block("brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block PRISMARINE_WALL = register(new Block("prismarine_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block RED_SANDSTONE_WALL = register(new Block("red_sandstone_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block MOSSY_STONE_BRICK_WALL = register(new Block("mossy_stone_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block GRANITE_WALL = register(new Block("granite_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block STONE_BRICK_WALL = register(new Block("stone_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block MUD_BRICK_WALL = register(new Block("mud_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block NETHER_BRICK_WALL = register(new Block("nether_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block ANDESITE_WALL = register(new Block("andesite_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block RED_NETHER_BRICK_WALL = register(new Block("red_nether_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block SANDSTONE_WALL = register(new Block("sandstone_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block END_STONE_BRICK_WALL = register(new Block("end_stone_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block DIORITE_WALL = register(new Block("diorite_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block SCAFFOLDING = register(new Block("scaffolding", builder() + .booleanState(BOTTOM) + .intState(STABILITY_DISTANCE, 0, 7) + .booleanState(WATERLOGGED))); + public static final Block LOOM = register(new Block("loom", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block BARREL = register(new Block("barrel", builder() + .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() + .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() + .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())); + public static final Block FLETCHING_TABLE = register(new Block("fletching_table", builder())); + public static final Block GRINDSTONE = register(new Block("grindstone", builder() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block LECTERN = register(new Block("lectern", builder() + .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())); + public static final Block STONECUTTER = register(new Block("stonecutter", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + public static final Block BELL = register(new Block("bell", builder() + .enumState(BELL_ATTACHMENT, "floor", "ceiling", "single_wall", "double_wall") + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block LANTERN = register(new Block("lantern", builder() + .booleanState(HANGING) + .booleanState(WATERLOGGED))); + public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder() + .booleanState(HANGING) + .booleanState(WATERLOGGED))); + public static final Block CAMPFIRE = register(new Block("campfire", builder() + .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() + .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() + .intState(AGE_3, 0, 3))); + public static final Block WARPED_STEM = register(new Block("warped_stem", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_WARPED_STEM = register(new Block("stripped_warped_stem", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block WARPED_HYPHAE = register(new Block("warped_hyphae", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_WARPED_HYPHAE = register(new Block("stripped_warped_hyphae", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block WARPED_NYLIUM = register(new Block("warped_nylium", builder())); + public static final Block WARPED_FUNGUS = register(new Block("warped_fungus", builder())); + public static final Block WARPED_WART_BLOCK = register(new Block("warped_wart_block", builder())); + public static final Block WARPED_ROOTS = register(new Block("warped_roots", builder())); + public static final Block NETHER_SPROUTS = register(new Block("nether_sprouts", builder())); + public static final Block CRIMSON_STEM = register(new Block("crimson_stem", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_CRIMSON_STEM = register(new Block("stripped_crimson_stem", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block CRIMSON_HYPHAE = register(new Block("crimson_hyphae", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_CRIMSON_HYPHAE = register(new Block("stripped_crimson_hyphae", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block CRIMSON_NYLIUM = register(new Block("crimson_nylium", builder())); + public static final Block CRIMSON_FUNGUS = register(new Block("crimson_fungus", builder())); + public static final Block SHROOMLIGHT = register(new Block("shroomlight", builder())); + public static final Block WEEPING_VINES = register(new Block("weeping_vines", builder() + .intState(AGE_25, 0, 25))); + public static final Block WEEPING_VINES_PLANT = register(new Block("weeping_vines_plant", builder())); + public static final Block TWISTING_VINES = register(new Block("twisting_vines", builder() + .intState(AGE_25, 0, 25))); + public static final Block TWISTING_VINES_PLANT = register(new Block("twisting_vines_plant", builder())); + public static final Block CRIMSON_ROOTS = register(new Block("crimson_roots", builder())); + public static final Block CRIMSON_PLANKS = register(new Block("crimson_planks", builder())); + public static final Block WARPED_PLANKS = register(new Block("warped_planks", builder())); + public static final Block CRIMSON_SLAB = register(new Block("crimson_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block WARPED_SLAB = register(new Block("warped_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block CRIMSON_PRESSURE_PLATE = register(new Block("crimson_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block WARPED_PRESSURE_PLATE = register(new Block("warped_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block CRIMSON_FENCE = register(new Block("crimson_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block WARPED_FENCE = register(new Block("warped_fence", builder() + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block CRIMSON_TRAPDOOR = register(new Block("crimson_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block WARPED_TRAPDOOR = register(new Block("warped_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block CRIMSON_FENCE_GATE = register(new Block("crimson_fence_gate", builder() + .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() + .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() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block WARPED_STAIRS = register(new Block("warped_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block CRIMSON_DOOR = register(new Block("crimson_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block WARPED_DOOR = register(new Block("warped_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block WARPED_SIGN = register(new Block("warped_sign", builder() + .intState(ROTATION_16, 0, 15) + .booleanState(WATERLOGGED))); + public static final Block CRIMSON_WALL_SIGN = register(new Block("crimson_wall_sign", builder() + .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() + .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() + .enumState(STRUCTUREBLOCK_MODE, "save", "load", "corner", "data"))); + public static final Block JIGSAW = register(new Block("jigsaw", builder() + .enumState(ORIENTATION, "down_east", "down_north", "down_south", "down_west", "up_east", "up_north", "up_south", "up_west", "west_up", "east_up", "north_up", "south_up"))); + public static final Block COMPOSTER = register(new Block("composter", builder() + .intState(LEVEL_COMPOSTER, 0, 8))); + public static final Block TARGET = register(new Block("target", builder() + .intState(POWER, 0, 15))); + public static final Block BEE_NEST = register(new Block("bee_nest", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(LEVEL_HONEY, 0, 5))); + public static final Block BEEHIVE = register(new Block("beehive", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(LEVEL_HONEY, 0, 5))); + public static final Block HONEY_BLOCK = register(new Block("honey_block", builder())); + public static final Block HONEYCOMB_BLOCK = register(new Block("honeycomb_block", builder())); + public static final Block NETHERITE_BLOCK = register(new Block("netherite_block", builder())); + public static final Block ANCIENT_DEBRIS = register(new Block("ancient_debris", builder())); + public static final Block CRYING_OBSIDIAN = register(new Block("crying_obsidian", builder())); + public static final Block RESPAWN_ANCHOR = register(new Block("respawn_anchor", builder() + .intState(RESPAWN_ANCHOR_CHARGES, 0, 4))); + public static final Block POTTED_CRIMSON_FUNGUS = register(new Block("potted_crimson_fungus", builder())); + public static final Block POTTED_WARPED_FUNGUS = register(new Block("potted_warped_fungus", builder())); + public static final Block POTTED_CRIMSON_ROOTS = register(new Block("potted_crimson_roots", builder())); + public static final Block POTTED_WARPED_ROOTS = register(new Block("potted_warped_roots", builder())); + public static final Block LODESTONE = register(new Block("lodestone", builder())); + public static final Block BLACKSTONE = register(new Block("blackstone", builder())); + public static final Block BLACKSTONE_STAIRS = register(new Block("blackstone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block BLACKSTONE_WALL = register(new Block("blackstone_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block BLACKSTONE_SLAB = register(new Block("blackstone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_BLACKSTONE = register(new Block("polished_blackstone", builder())); + public static final Block POLISHED_BLACKSTONE_BRICKS = register(new Block("polished_blackstone_bricks", builder())); + public static final Block CRACKED_POLISHED_BLACKSTONE_BRICKS = register(new Block("cracked_polished_blackstone_bricks", builder())); + public static final Block CHISELED_POLISHED_BLACKSTONE = register(new Block("chiseled_polished_blackstone", builder())); + public static final Block POLISHED_BLACKSTONE_BRICK_SLAB = register(new Block("polished_blackstone_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_BLACKSTONE_BRICK_STAIRS = register(new Block("polished_blackstone_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_BLACKSTONE_BRICK_WALL = register(new Block("polished_blackstone_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block GILDED_BLACKSTONE = register(new Block("gilded_blackstone", builder())); + public static final Block POLISHED_BLACKSTONE_STAIRS = register(new Block("polished_blackstone_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_BLACKSTONE_SLAB = register(new Block("polished_blackstone_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder() + .booleanState(POWERED))); + public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder() + .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block CHISELED_NETHER_BRICKS = register(new Block("chiseled_nether_bricks", builder())); + public static final Block CRACKED_NETHER_BRICKS = register(new Block("cracked_nether_bricks", builder())); + public static final Block QUARTZ_BRICKS = register(new Block("quartz_bricks", builder())); + public static final Block CANDLE = register(new Block("candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block WHITE_CANDLE = register(new Block("white_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block ORANGE_CANDLE = register(new Block("orange_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block MAGENTA_CANDLE = register(new Block("magenta_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block LIGHT_BLUE_CANDLE = register(new Block("light_blue_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block YELLOW_CANDLE = register(new Block("yellow_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block LIME_CANDLE = register(new Block("lime_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block PINK_CANDLE = register(new Block("pink_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block GRAY_CANDLE = register(new Block("gray_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block LIGHT_GRAY_CANDLE = register(new Block("light_gray_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block CYAN_CANDLE = register(new Block("cyan_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block PURPLE_CANDLE = register(new Block("purple_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block BLUE_CANDLE = register(new Block("blue_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block BROWN_CANDLE = register(new Block("brown_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block GREEN_CANDLE = register(new Block("green_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block RED_CANDLE = register(new Block("red_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block BLACK_CANDLE = register(new Block("black_candle", builder() + .intState(CANDLES, 1, 4) + .booleanState(LIT) + .booleanState(WATERLOGGED))); + public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder() + .booleanState(LIT))); + public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder() + .booleanState(LIT))); + public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder() + .booleanState(LIT))); + public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder() + .booleanState(LIT))); + public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder() + .booleanState(LIT))); + public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder() + .booleanState(LIT))); + public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder() + .booleanState(LIT))); + public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder() + .booleanState(LIT))); + public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder() + .booleanState(LIT))); + public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder() + .booleanState(LIT))); + public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder() + .booleanState(LIT))); + public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder() + .booleanState(LIT))); + public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder() + .booleanState(LIT))); + public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder() + .booleanState(LIT))); + public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder() + .booleanState(LIT))); + public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder() + .booleanState(LIT))); + public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder() + .booleanState(LIT))); + public static final Block AMETHYST_BLOCK = register(new Block("amethyst_block", builder())); + public static final Block BUDDING_AMETHYST = register(new Block("budding_amethyst", builder())); + public static final Block AMETHYST_CLUSTER = register(new Block("amethyst_cluster", builder() + .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() + .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() + .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() + .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())); + public static final Block TUFF_SLAB = register(new Block("tuff_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block TUFF_STAIRS = register(new Block("tuff_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block TUFF_WALL = register(new Block("tuff_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block POLISHED_TUFF = register(new Block("polished_tuff", builder())); + public static final Block POLISHED_TUFF_SLAB = register(new Block("polished_tuff_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_TUFF_STAIRS = register(new Block("polished_tuff_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_TUFF_WALL = register(new Block("polished_tuff_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block CHISELED_TUFF = register(new Block("chiseled_tuff", builder())); + public static final Block TUFF_BRICKS = register(new Block("tuff_bricks", builder())); + public static final Block TUFF_BRICK_SLAB = register(new Block("tuff_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block TUFF_BRICK_STAIRS = register(new Block("tuff_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block TUFF_BRICK_WALL = register(new Block("tuff_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block CHISELED_TUFF_BRICKS = register(new Block("chiseled_tuff_bricks", builder())); + public static final Block CALCITE = register(new Block("calcite", builder())); + public static final Block TINTED_GLASS = register(new Block("tinted_glass", builder())); + public static final Block POWDER_SNOW = register(new Block("powder_snow", builder())); + public static final Block SCULK_SENSOR = register(new Block("sculk_sensor", builder() + .intState(POWER, 0, 15) + .enumState(SCULK_SENSOR_PHASE, "inactive", "active", "cooldown") + .booleanState(WATERLOGGED))); + public static final Block CALIBRATED_SCULK_SENSOR = register(new Block("calibrated_sculk_sensor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(POWER, 0, 15) + .enumState(SCULK_SENSOR_PHASE, "inactive", "active", "cooldown") + .booleanState(WATERLOGGED))); + public static final Block SCULK = register(new Block("sculk", builder())); + public static final Block SCULK_VEIN = register(new Block("sculk_vein", builder() + .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() + .booleanState(BLOOM))); + public static final Block SCULK_SHRIEKER = register(new Block("sculk_shrieker", builder() + .booleanState(CAN_SUMMON) + .booleanState(SHRIEKING) + .booleanState(WATERLOGGED))); + public static final Block COPPER_BLOCK = register(new Block("copper_block", builder())); + public static final Block EXPOSED_COPPER = register(new Block("exposed_copper", builder())); + public static final Block WEATHERED_COPPER = register(new Block("weathered_copper", builder())); + public static final Block OXIDIZED_COPPER = register(new Block("oxidized_copper", builder())); + public static final Block COPPER_ORE = register(new Block("copper_ore", builder())); + public static final Block DEEPSLATE_COPPER_ORE = register(new Block("deepslate_copper_ore", builder())); + public static final Block OXIDIZED_CUT_COPPER = register(new Block("oxidized_cut_copper", builder())); + public static final Block WEATHERED_CUT_COPPER = register(new Block("weathered_cut_copper", builder())); + public static final Block EXPOSED_CUT_COPPER = register(new Block("exposed_cut_copper", builder())); + public static final Block CUT_COPPER = register(new Block("cut_copper", builder())); + public static final Block OXIDIZED_CHISELED_COPPER = register(new Block("oxidized_chiseled_copper", builder())); + public static final Block WEATHERED_CHISELED_COPPER = register(new Block("weathered_chiseled_copper", builder())); + public static final Block EXPOSED_CHISELED_COPPER = register(new Block("exposed_chiseled_copper", builder())); + public static final Block CHISELED_COPPER = register(new Block("chiseled_copper", builder())); + public static final Block WAXED_OXIDIZED_CHISELED_COPPER = register(new Block("waxed_oxidized_chiseled_copper", builder())); + public static final Block WAXED_WEATHERED_CHISELED_COPPER = register(new Block("waxed_weathered_chiseled_copper", builder())); + public static final Block WAXED_EXPOSED_CHISELED_COPPER = register(new Block("waxed_exposed_chiseled_copper", builder())); + public static final Block WAXED_CHISELED_COPPER = register(new Block("waxed_chiseled_copper", builder())); + public static final Block OXIDIZED_CUT_COPPER_STAIRS = register(new Block("oxidized_cut_copper_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block WEATHERED_CUT_COPPER_STAIRS = register(new Block("weathered_cut_copper_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block EXPOSED_CUT_COPPER_STAIRS = register(new Block("exposed_cut_copper_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block CUT_COPPER_STAIRS = register(new Block("cut_copper_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block OXIDIZED_CUT_COPPER_SLAB = register(new Block("oxidized_cut_copper_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block WEATHERED_CUT_COPPER_SLAB = register(new Block("weathered_cut_copper_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block EXPOSED_CUT_COPPER_SLAB = register(new Block("exposed_cut_copper_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block CUT_COPPER_SLAB = register(new Block("cut_copper_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block WAXED_COPPER_BLOCK = register(new Block("waxed_copper_block", builder())); + public static final Block WAXED_WEATHERED_COPPER = register(new Block("waxed_weathered_copper", builder())); + public static final Block WAXED_EXPOSED_COPPER = register(new Block("waxed_exposed_copper", builder())); + public static final Block WAXED_OXIDIZED_COPPER = register(new Block("waxed_oxidized_copper", builder())); + public static final Block WAXED_OXIDIZED_CUT_COPPER = register(new Block("waxed_oxidized_cut_copper", builder())); + public static final Block WAXED_WEATHERED_CUT_COPPER = register(new Block("waxed_weathered_cut_copper", builder())); + public static final Block WAXED_EXPOSED_CUT_COPPER = register(new Block("waxed_exposed_cut_copper", builder())); + public static final Block WAXED_CUT_COPPER = register(new Block("waxed_cut_copper", builder())); + public static final Block WAXED_OXIDIZED_CUT_COPPER_STAIRS = register(new Block("waxed_oxidized_cut_copper_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block WAXED_WEATHERED_CUT_COPPER_STAIRS = register(new Block("waxed_weathered_cut_copper_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block WAXED_EXPOSED_CUT_COPPER_STAIRS = register(new Block("waxed_exposed_cut_copper_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block WAXED_CUT_COPPER_STAIRS = register(new Block("waxed_cut_copper_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block WAXED_OXIDIZED_CUT_COPPER_SLAB = register(new Block("waxed_oxidized_cut_copper_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block WAXED_WEATHERED_CUT_COPPER_SLAB = register(new Block("waxed_weathered_cut_copper_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block WAXED_EXPOSED_CUT_COPPER_SLAB = register(new Block("waxed_exposed_cut_copper_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block WAXED_CUT_COPPER_SLAB = register(new Block("waxed_cut_copper_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block COPPER_DOOR = register(new Block("copper_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block EXPOSED_COPPER_DOOR = register(new Block("exposed_copper_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block OXIDIZED_COPPER_DOOR = register(new Block("oxidized_copper_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block WEATHERED_COPPER_DOOR = register(new Block("weathered_copper_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block WAXED_COPPER_DOOR = register(new Block("waxed_copper_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block WAXED_EXPOSED_COPPER_DOOR = register(new Block("waxed_exposed_copper_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block WAXED_OXIDIZED_COPPER_DOOR = register(new Block("waxed_oxidized_copper_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block WAXED_WEATHERED_COPPER_DOOR = register(new Block("waxed_weathered_copper_door", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .enumState(DOOR_HINGE, "left", "right") + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block COPPER_TRAPDOOR = register(new Block("copper_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block EXPOSED_COPPER_TRAPDOOR = register(new Block("exposed_copper_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block OXIDIZED_COPPER_TRAPDOOR = register(new Block("oxidized_copper_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block WEATHERED_COPPER_TRAPDOOR = register(new Block("weathered_copper_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block WAXED_COPPER_TRAPDOOR = register(new Block("waxed_copper_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block WAXED_EXPOSED_COPPER_TRAPDOOR = register(new Block("waxed_exposed_copper_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new Block("waxed_oxidized_copper_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block WAXED_WEATHERED_COPPER_TRAPDOOR = register(new Block("waxed_weathered_copper_trapdoor", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block COPPER_GRATE = register(new Block("copper_grate", builder() + .booleanState(WATERLOGGED))); + public static final Block EXPOSED_COPPER_GRATE = register(new Block("exposed_copper_grate", builder() + .booleanState(WATERLOGGED))); + public static final Block WEATHERED_COPPER_GRATE = register(new Block("weathered_copper_grate", builder() + .booleanState(WATERLOGGED))); + public static final Block OXIDIZED_COPPER_GRATE = register(new Block("oxidized_copper_grate", builder() + .booleanState(WATERLOGGED))); + public static final Block WAXED_COPPER_GRATE = register(new Block("waxed_copper_grate", builder() + .booleanState(WATERLOGGED))); + public static final Block WAXED_EXPOSED_COPPER_GRATE = register(new Block("waxed_exposed_copper_grate", builder() + .booleanState(WATERLOGGED))); + public static final Block WAXED_WEATHERED_COPPER_GRATE = register(new Block("waxed_weathered_copper_grate", builder() + .booleanState(WATERLOGGED))); + public static final Block WAXED_OXIDIZED_COPPER_GRATE = register(new Block("waxed_oxidized_copper_grate", builder() + .booleanState(WATERLOGGED))); + public static final Block COPPER_BULB = register(new Block("copper_bulb", builder() + .booleanState(LIT) + .booleanState(POWERED))); + public static final Block EXPOSED_COPPER_BULB = register(new Block("exposed_copper_bulb", builder() + .booleanState(LIT) + .booleanState(POWERED))); + public static final Block WEATHERED_COPPER_BULB = register(new Block("weathered_copper_bulb", builder() + .booleanState(LIT) + .booleanState(POWERED))); + public static final Block OXIDIZED_COPPER_BULB = register(new Block("oxidized_copper_bulb", builder() + .booleanState(LIT) + .booleanState(POWERED))); + public static final Block WAXED_COPPER_BULB = register(new Block("waxed_copper_bulb", builder() + .booleanState(LIT) + .booleanState(POWERED))); + public static final Block WAXED_EXPOSED_COPPER_BULB = register(new Block("waxed_exposed_copper_bulb", builder() + .booleanState(LIT) + .booleanState(POWERED))); + public static final Block WAXED_WEATHERED_COPPER_BULB = register(new Block("waxed_weathered_copper_bulb", builder() + .booleanState(LIT) + .booleanState(POWERED))); + public static final Block WAXED_OXIDIZED_COPPER_BULB = register(new Block("waxed_oxidized_copper_bulb", builder() + .booleanState(LIT) + .booleanState(POWERED))); + public static final Block LIGHTNING_ROD = register(new Block("lightning_rod", builder() + .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() + .enumState(DRIPSTONE_THICKNESS, "tip_merge", "tip", "frustum", "middle", "base") + .enumState(VERTICAL_DIRECTION, Direction.UP, Direction.DOWN) + .booleanState(WATERLOGGED))); + public static final Block DRIPSTONE_BLOCK = register(new Block("dripstone_block", builder())); + public static final Block CAVE_VINES = register(new Block("cave_vines", builder() + .intState(AGE_25, 0, 25) + .booleanState(BERRIES))); + public static final Block CAVE_VINES_PLANT = register(new Block("cave_vines_plant", builder() + .booleanState(BERRIES))); + public static final Block SPORE_BLOSSOM = register(new Block("spore_blossom", builder())); + public static final Block AZALEA = register(new Block("azalea", builder())); + public static final Block FLOWERING_AZALEA = register(new Block("flowering_azalea", builder())); + public static final Block MOSS_CARPET = register(new Block("moss_carpet", builder())); + public static final Block PINK_PETALS = register(new Block("pink_petals", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(FLOWER_AMOUNT, 1, 4))); + public static final Block MOSS_BLOCK = register(new Block("moss_block", builder())); + public static final Block BIG_DRIPLEAF = register(new Block("big_dripleaf", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(TILT, "none", "unstable", "partial", "full") + .booleanState(WATERLOGGED))); + public static final Block BIG_DRIPLEAF_STEM = register(new Block("big_dripleaf_stem", builder() + .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() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") + .booleanState(WATERLOGGED))); + public static final Block HANGING_ROOTS = register(new Block("hanging_roots", builder() + .booleanState(WATERLOGGED))); + public static final Block ROOTED_DIRT = register(new Block("rooted_dirt", builder())); + public static final Block MUD = register(new Block("mud", builder())); + public static final Block DEEPSLATE = register(new Block("deepslate", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block COBBLED_DEEPSLATE = register(new Block("cobbled_deepslate", builder())); + public static final Block COBBLED_DEEPSLATE_STAIRS = register(new Block("cobbled_deepslate_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block COBBLED_DEEPSLATE_SLAB = register(new Block("cobbled_deepslate_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block COBBLED_DEEPSLATE_WALL = register(new Block("cobbled_deepslate_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block POLISHED_DEEPSLATE = register(new Block("polished_deepslate", builder())); + public static final Block POLISHED_DEEPSLATE_STAIRS = register(new Block("polished_deepslate_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_DEEPSLATE_SLAB = register(new Block("polished_deepslate_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block POLISHED_DEEPSLATE_WALL = register(new Block("polished_deepslate_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block DEEPSLATE_TILES = register(new Block("deepslate_tiles", builder())); + public static final Block DEEPSLATE_TILE_STAIRS = register(new Block("deepslate_tile_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block DEEPSLATE_TILE_SLAB = register(new Block("deepslate_tile_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block DEEPSLATE_TILE_WALL = register(new Block("deepslate_tile_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block DEEPSLATE_BRICKS = register(new Block("deepslate_bricks", builder())); + public static final Block DEEPSLATE_BRICK_STAIRS = register(new Block("deepslate_brick_stairs", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF, "top", "bottom") + .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .booleanState(WATERLOGGED))); + public static final Block DEEPSLATE_BRICK_SLAB = register(new Block("deepslate_brick_slab", builder() + .enumState(SLAB_TYPE, "top", "bottom", "double") + .booleanState(WATERLOGGED))); + public static final Block DEEPSLATE_BRICK_WALL = register(new Block("deepslate_brick_wall", builder() + .enumState(EAST_WALL, "none", "low", "tall") + .enumState(NORTH_WALL, "none", "low", "tall") + .enumState(SOUTH_WALL, "none", "low", "tall") + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL, "none", "low", "tall"))); + public static final Block CHISELED_DEEPSLATE = register(new Block("chiseled_deepslate", builder())); + public static final Block CRACKED_DEEPSLATE_BRICKS = register(new Block("cracked_deepslate_bricks", builder())); + public static final Block CRACKED_DEEPSLATE_TILES = register(new Block("cracked_deepslate_tiles", builder())); + public static final Block INFESTED_DEEPSLATE = register(new Block("infested_deepslate", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block SMOOTH_BASALT = register(new Block("smooth_basalt", builder())); + public static final Block RAW_IRON_BLOCK = register(new Block("raw_iron_block", builder())); + public static final Block RAW_COPPER_BLOCK = register(new Block("raw_copper_block", builder())); + public static final Block RAW_GOLD_BLOCK = register(new Block("raw_gold_block", builder())); + public static final Block POTTED_AZALEA_BUSH = register(new Block("potted_azalea_bush", builder())); + public static final Block POTTED_FLOWERING_AZALEA_BUSH = register(new Block("potted_flowering_azalea_bush", builder())); + public static final Block OCHRE_FROGLIGHT = register(new Block("ochre_froglight", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block VERDANT_FROGLIGHT = register(new Block("verdant_froglight", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block PEARLESCENT_FROGLIGHT = register(new Block("pearlescent_froglight", builder() + .enumState(AXIS, Axis.VALUES))); + public static final Block FROGSPAWN = register(new Block("frogspawn", builder())); + public static final Block REINFORCED_DEEPSLATE = register(new Block("reinforced_deepslate", builder())); + public static final Block DECORATED_POT = register(new Block("decorated_pot", builder() + .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() + .booleanState(CRAFTING) + .enumState(ORIENTATION, "down_east", "down_north", "down_south", "down_west", "up_east", "up_north", "up_south", "up_west", "west_up", "east_up", "north_up", "south_up") + .booleanState(TRIGGERED))); + public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder() + .booleanState(OMINOUS) + .enumState(TRIAL_SPAWNER_STATE, "inactive", "waiting_for_players", "active", "waiting_for_reward_ejection", "ejecting_reward", "cooldown"))); + public static final Block VAULT = register(new Block("vault", builder() + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OMINOUS) + .enumState(VAULT_STATE, "inactive", "active", "unlocking", "ejecting"))); + public static final Block HEAVY_CORE = register(new Block("heavy_core", builder() + .booleanState(WATERLOGGED))); + + private static T register(T block) { + BlockRegistries.JAVA_BLOCKS_TO_RENAME.get().add(block); + return block; + } + + private Blocks() { + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/ChestType.java b/core/src/main/java/org/geysermc/geyser/level/block/property/ChestType.java new file mode 100644 index 000000000..c206f127c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/ChestType.java @@ -0,0 +1,34 @@ +/* + * 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.level.block.property; + +public enum ChestType { + SINGLE, + LEFT, + RIGHT; + + public static final ChestType[] VALUES = values(); +} 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 new file mode 100644 index 000000000..bbb6f8fe3 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java @@ -0,0 +1,146 @@ +/* + * 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.level.block.property; + +import org.geysermc.geyser.level.physics.Axis; +import org.geysermc.geyser.level.physics.Direction; + +public final class Properties { + public static final Property ATTACHED = Property.create("attached"); + public static final Property BOTTOM = Property.create("bottom"); + public static final Property CONDITIONAL = Property.create("conditional"); + public static final Property DISARMED = Property.create("disarmed"); + public static final Property DRAG = Property.create("drag"); + public static final Property ENABLED = Property.create("enabled"); + public static final Property EXTENDED = Property.create("extended"); + public static final Property EYE = Property.create("eye"); + public static final Property FALLING = Property.create("falling"); + public static final Property HANGING = Property.create("hanging"); + public static final Property HAS_BOTTLE_0 = Property.create("has_bottle_0"); + public static final Property HAS_BOTTLE_1 = Property.create("has_bottle_1"); + public static final Property HAS_BOTTLE_2 = Property.create("has_bottle_2"); + public static final Property HAS_RECORD = Property.create("has_record"); + public static final Property HAS_BOOK = Property.create("has_book"); + public static final Property INVERTED = Property.create("inverted"); + public static final Property IN_WALL = Property.create("in_wall"); + public static final Property LIT = Property.create("lit"); + public static final Property LOCKED = Property.create("locked"); + public static final Property OCCUPIED = Property.create("occupied"); + public static final Property OPEN = Property.create("open"); + public static final Property PERSISTENT = Property.create("persistent"); + public static final Property POWERED = Property.create("powered"); + public static final Property SHORT = Property.create("short"); + public static final Property SIGNAL_FIRE = Property.create("signal_fire"); + public static final Property SNOWY = Property.create("snowy"); + public static final Property TRIGGERED = Property.create("triggered"); + public static final Property UNSTABLE = Property.create("unstable"); + public static final Property WATERLOGGED = Property.create("waterlogged"); + public static final Property BERRIES = Property.create("berries"); + public static final Property BLOOM = Property.create("bloom"); + public static final Property SHRIEKING = Property.create("shrieking"); + public static final Property CAN_SUMMON = Property.create("can_summon"); + public static final Property HORIZONTAL_AXIS = Property.create("axis"); + public static final Property AXIS = Property.create("axis"); + public static final Property UP = Property.create("up"); + public static final Property DOWN = Property.create("down"); + public static final Property NORTH = Property.create("north"); + public static final Property EAST = Property.create("east"); + public static final Property SOUTH = Property.create("south"); + public static final Property WEST = Property.create("west"); + public static final Property FACING = Property.create("facing"); + public static final Property FACING_HOPPER = Property.create("facing"); + public static final Property HORIZONTAL_FACING = Property.create("facing"); + public static final Property FLOWER_AMOUNT = Property.create("flower_amount"); + public static final Property ORIENTATION = Property.create("orientation"); + public static final Property ATTACH_FACE = Property.create("face"); + public static final Property BELL_ATTACHMENT = Property.create("attachment"); + public static final Property EAST_WALL = Property.create("east"); + public static final Property NORTH_WALL = Property.create("north"); + public static final Property SOUTH_WALL = Property.create("south"); + public static final Property WEST_WALL = Property.create("west"); + public static final Property EAST_REDSTONE = Property.create("east"); + public static final Property NORTH_REDSTONE = Property.create("north"); + public static final Property SOUTH_REDSTONE = Property.create("south"); + public static final Property WEST_REDSTONE = Property.create("west"); + public static final Property DOUBLE_BLOCK_HALF = Property.create("half"); + public static final Property HALF = Property.create("half"); + public static final Property RAIL_SHAPE = Property.create("shape"); + public static final Property RAIL_SHAPE_STRAIGHT = Property.create("shape"); + public static final Property AGE_1 = Property.create("age"); + public static final Property AGE_2 = Property.create("age"); + public static final Property AGE_3 = Property.create("age"); + public static final Property AGE_4 = Property.create("age"); + public static final Property AGE_5 = Property.create("age"); + public static final Property AGE_7 = Property.create("age"); + public static final Property AGE_15 = Property.create("age"); + public static final Property AGE_25 = Property.create("age"); + public static final Property BITES = Property.create("bites"); + public static final Property CANDLES = Property.create("candles"); + public static final Property DELAY = Property.create("delay"); + public static final Property DISTANCE = Property.create("distance"); + public static final Property EGGS = Property.create("eggs"); + public static final Property HATCH = Property.create("hatch"); + public static final Property LAYERS = Property.create("layers"); + public static final Property LEVEL_CAULDRON = Property.create("level"); + public static final Property LEVEL_COMPOSTER = Property.create("level"); + public static final Property LEVEL_FLOWING = Property.create("level"); + public static final Property LEVEL_HONEY = Property.create("honey_level"); + public static final Property LEVEL = Property.create("level"); + public static final Property MOISTURE = Property.create("moisture"); + public static final Property NOTE = Property.create("note"); + public static final Property PICKLES = Property.create("pickles"); + public static final Property POWER = Property.create("power"); + public static final Property STAGE = Property.create("stage"); + public static final Property STABILITY_DISTANCE = Property.create("distance"); + public static final Property RESPAWN_ANCHOR_CHARGES = Property.create("charges"); + public static final Property ROTATION_16 = Property.create("rotation"); + public static final Property BED_PART = Property.create("part"); + public static final Property CHEST_TYPE = Property.create("type"); + public static final Property MODE_COMPARATOR = Property.create("mode"); + public static final Property DOOR_HINGE = Property.create("hinge"); + public static final Property NOTEBLOCK_INSTRUMENT = Property.create("instrument"); + public static final Property PISTON_TYPE = Property.create("type"); + public static final Property SLAB_TYPE = Property.create("type"); + public static final Property STAIRS_SHAPE = Property.create("shape"); + public static final Property STRUCTUREBLOCK_MODE = Property.create("mode"); + public static final Property BAMBOO_LEAVES = Property.create("leaves"); + public static final Property TILT = Property.create("tilt"); + public static final Property VERTICAL_DIRECTION = Property.create("vertical_direction"); + public static final Property DRIPSTONE_THICKNESS = Property.create("thickness"); + public static final Property SCULK_SENSOR_PHASE = Property.create("sculk_sensor_phase"); + public static final Property CHISELED_BOOKSHELF_SLOT_0_OCCUPIED = Property.create("slot_0_occupied"); + public static final Property CHISELED_BOOKSHELF_SLOT_1_OCCUPIED = Property.create("slot_1_occupied"); + public static final Property CHISELED_BOOKSHELF_SLOT_2_OCCUPIED = Property.create("slot_2_occupied"); + public static final Property CHISELED_BOOKSHELF_SLOT_3_OCCUPIED = Property.create("slot_3_occupied"); + public static final Property CHISELED_BOOKSHELF_SLOT_4_OCCUPIED = Property.create("slot_4_occupied"); + public static final Property CHISELED_BOOKSHELF_SLOT_5_OCCUPIED = Property.create("slot_5_occupied"); + public static final Property DUSTED = Property.create("dusted"); + public static final Property CRACKED = Property.create("cracked"); + public static final Property CRAFTING = Property.create("crafting"); + public static final Property TRIAL_SPAWNER_STATE = Property.create("trial_spawner_state"); + public static final Property VAULT_STATE = Property.create("vault_state"); + public static final Property OMINOUS = Property.create("ominous"); +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java b/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java new file mode 100644 index 000000000..da68c54e4 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/Property.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.level.block.property; + +public class Property> { + private final String name; + + public Property(String name) { + this.name = name; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + name + "]"; + } + + public static > Property create(String name) { + return new Property<>(name); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BannerBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BannerBlock.java new file mode 100644 index 000000000..481004baa --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BannerBlock.java @@ -0,0 +1,39 @@ +/* + * 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.level.block.type; + +public class BannerBlock extends Block { + private final int dyeColor; + + public BannerBlock(String javaIdentifier, int dyeColor, Builder builder) { + super(javaIdentifier, builder); + this.dyeColor = dyeColor; + } + + public int dyeColor() { + return dyeColor; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BedBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BedBlock.java new file mode 100644 index 000000000..e72dbdafa --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BedBlock.java @@ -0,0 +1,39 @@ +/* + * 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.level.block.type; + +public class BedBlock extends Block { + private final int dyeColor; + + public BedBlock(String javaIdentifier, int dyeColor, Builder builder) { + super(javaIdentifier, builder); + this.dyeColor = dyeColor; + } + + public int dyeColor() { + return dyeColor; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java new file mode 100644 index 000000000..459f4a5af --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -0,0 +1,152 @@ +/* + * 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.level.block.type; + +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; +import org.geysermc.geyser.level.block.property.Property; +import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.mcprotocollib.protocol.data.game.Identifier; + +import java.util.*; +import java.util.stream.Stream; + +public class Block { + public static final int JAVA_AIR_ID = 0; + + private final String javaIdentifier; + private int javaId = -1; + + public Block(String javaIdentifier, Builder builder) { + this.javaIdentifier = Identifier.formalize(javaIdentifier).intern(); + builder.build(this); + } + + public String javaIdentifier() { + return javaIdentifier; + } + + public int javaId() { + return javaId; + } + + public void setJavaId(int javaId) { + if (this.javaId != -1) { + throw new RuntimeException("Block ID has already been set!"); + } + this.javaId = javaId; + } + + @Override + public String toString() { + return "Item{" + + "javaIdentifier='" + javaIdentifier + '\'' + + ", javaId=" + javaId + + '}'; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private final Map, List>> states = new LinkedHashMap<>(); + + /** + * For states that we're just tracking for mirroring Java states. + */ + public Builder enumState(Property property, String... values) { + states.put(property, List.of(values)); + return this; + } + + @SafeVarargs + public final > Builder enumState(Property property, T... enums) { + states.put(property, List.of(enums)); + return this; + } + + public Builder booleanState(Property property) { + states.put(property, List.of(Boolean.TRUE, Boolean.FALSE)); // Make this list a static constant if it'll survive past initialization + return this; + } + + public Builder intState(Property property, int low, int high) { + IntList list = new IntArrayList(); + // There is a state for every number between the low and high. + for (int i = low; i <= high; i++) { + list.add(i); + } + states.put(property, List.copyOf(list)); // Boxing reasons for that copy I guess. + return this; + } + + private void build(Block block) { + if (states.isEmpty()) { + BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size())); + } else { + // Think of this stream as another list containing, at the start, one empty list. + // It's two collections. Not a stream from the empty list. + Stream, Comparable>>> stream = Stream.of(Collections.emptyList()); + for (var state : this.states.entrySet()) { + // OK, so here's how I understand this works. Because this was staring at vanilla Java code trying + // to figure out exactly how it works so we don't have any discrepencies. + // For each existing pair in the list, a new list is created, adding one of the new values. + // Property up [true/false] would exist as true and false + // Both entries will get duplicated, adding down, true and false. + stream = stream.flatMap(aPreviousPropertiesList -> + // So the above is a list. It may be empty if this is the first property, + // or it may be populated if this is not the first property. + // We're about to create a new stream, each with a new list, + // for every previous property + state.getValue().stream().map(value -> { + var newProperties = new ArrayList<>(aPreviousPropertiesList); + newProperties.add(Pair.of(state.getKey(), value)); + return newProperties; + })); + } + + // Now we have a list of Pairs. Each list is a block state! + // If we have two boolean properties: up [true/false] and down [true/false], + // We'll see [up=true,down=true], [up=false,down=true], [up=true,down=false], [up=false,down=false] + stream.forEach(properties -> { + Reference2ObjectMap, Comparable> propertyMap = new Reference2ObjectArrayMap<>(properties.size()); + for (int i = 0; i < properties.size(); i++) { + Pair, Comparable> property = properties.get(i); + propertyMap.put(property.key(), property.value()); + } + BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap)); + }); + } + } + + private Builder() { + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java new file mode 100644 index 000000000..936b711e4 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -0,0 +1,64 @@ +/* + * 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.level.block.type; + +import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; +import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps; +import org.geysermc.geyser.level.block.property.Property; +import org.geysermc.geyser.registry.BlockRegistries; + +public final class BlockState { + private final Block block; + private final int javaId; + private final Reference2ObjectMap, Comparable> states; + + BlockState(Block block, int javaId) { + this(block, javaId, Reference2ObjectMaps.emptyMap()); + } + + BlockState(Block block, int javaId, Reference2ObjectMap, Comparable> states) { + this.block = block; + this.javaId = javaId; + this.states = states; + } + + public > T getValue(Property property) { + //noinspection unchecked + return (T) states.get(property); + } + + public Block block() { + return block; + } + + public int javaId() { + return javaId; + } + + public static BlockState of(int javaId) { + return BlockRegistries.BLOCK_STATES.get(javaId); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index aa9d6fc36..54a36dc12 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -34,6 +34,8 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.loader.CollisionRegistryLoader; import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.registry.populator.BlockRegistryPopulator; @@ -44,8 +46,8 @@ import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.CustomSkull; import org.geysermc.geyser.translator.collision.BlockCollision; +import java.util.ArrayList; import java.util.BitSet; - import java.util.Set; /** @@ -58,6 +60,14 @@ public class BlockRegistries { */ public static final VersionedRegistry BLOCKS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + /** + * A registry which stores Java IDs to Java {@link BlockState}s, each with their specific state differences and a link + * to the overarching block. + */ + public static final ListRegistry BLOCK_STATES = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); + + public static final ListRegistry JAVA_BLOCKS_TO_RENAME = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); + /** * A mapped registry which stores Java to Bedrock block identifiers. */ diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java new file mode 100644 index 000000000..bb5d2538c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java @@ -0,0 +1,103 @@ +/* + * 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; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.List; + +public class ListRegistry extends Registry> { + /** + * Creates a new instance of this class with the given input and + * {@link RegistryLoader}. The input specified is what the registry + * loader needs to take in. + * + * @param input the input + * @param registryLoader the registry loader + */ + protected ListRegistry(I input, RegistryLoader> registryLoader) { + super(input, registryLoader); + } + + /** + * Returns the value registered by the given index. + * + * @param index the index + * @return the value registered by the given index. + */ + @Nullable + public M get(int index) { + if (index >= this.mappings.size()) { + return null; + } + + return this.mappings.get(index); + } + + /** + * Returns the value registered by the given index or the default value + * specified if null. + * + * @param index the index + * @param defaultValue the default value + * @return the value registered by the given key or the default value + * specified if null. + */ + public M getOrDefault(int index, M defaultValue) { + M value = this.get(index); + if (value == null) { + return defaultValue; + } + + return value; + } + + /** + * Registers a new value into this registry with the given index. + * + * @param index the index + * @param value the value + * @return a new value into this registry with the given index. + */ + public M register(int index, M value) { + return this.mappings.set(index, value); + } + + /** + * Creates a new array registry with the given {@link RegistryLoader}. The + * input type is not specified here, meaning the loader return type is either + * predefined, or the registry is populated at a later point. + * + * @param registryLoader the registry loader + * @param the input type + * @param the returned mappings type + * @return a new registry with the given RegistryLoader supplier + */ + public static ListRegistry create(RegistryLoader> registryLoader) { + return new ListRegistry(null, registryLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index e76edc059..ace110f78 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -582,8 +582,6 @@ public final class BlockRegistryPopulator { } } - BlockRegistries.CLEAN_JAVA_IDENTIFIERS.set(cleanIdentifiers.toArray(new String[0])); - BLOCKS_JSON = blocksJson; JsonNode blockInteractionsJson; 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 c0ff1fb71..144cd9f27 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1592,9 +1592,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setRewindHistorySize(0); startGamePacket.setServerAuthoritativeBlockBreaking(false); - // Entity properties for older versions - startGamePacket.getExperiments().add(new ExperimentData("upcoming_creator_features", true)); - upstream.sendPacket(startGamePacket); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java index e3a9cba89..7b279857a 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.session.cache; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -92,11 +93,11 @@ public class ChunkCache { DataPalette palette = chunk.sections()[(y - minY) >> 4]; if (palette == null) { - if (block != BlockStateValues.JAVA_AIR_ID) { + if (block != Block.JAVA_AIR_ID) { // A previously empty chunk, which is no longer empty as a block has been added to it palette = DataPalette.createForChunk(); // Fixes the chunk assuming that all blocks is the `block` variable we are updating. /shrug - palette.getPalette().stateToId(BlockStateValues.JAVA_AIR_ID); + palette.getPalette().stateToId(Block.JAVA_AIR_ID); chunk.sections()[(y - minY) >> 4] = palette; } else { // Nothing to update @@ -109,17 +110,17 @@ public class ChunkCache { public int getBlockAt(int x, int y, int z) { if (!cache) { - return BlockStateValues.JAVA_AIR_ID; + return Block.JAVA_AIR_ID; } GeyserChunk column = this.getChunk(x >> 4, z >> 4); if (column == null) { - return BlockStateValues.JAVA_AIR_ID; + return Block.JAVA_AIR_ID; } if (y < minY || ((y - minY) >> 4) > column.sections().length - 1) { // Y likely goes above or below the height limit of this world - return BlockStateValues.JAVA_AIR_ID; + return Block.JAVA_AIR_ID; } DataPalette chunk = column.sections()[(y - minY) >> 4]; @@ -127,7 +128,7 @@ public class ChunkCache { return chunk.get(x & 0xF, y & 0xF, z & 0xF); } - return BlockStateValues.JAVA_AIR_ID; + return Block.JAVA_AIR_ID; } public void removeChunk(int chunkX, int chunkZ) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java index f9879499a..795eba101 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java @@ -35,6 +35,7 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; @@ -58,7 +59,7 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator .putInt("z", position.getZ()) .putString("CustomName", inventory.getTitle()); // Don't reset facing property - shulkerBoxTranslator.translateTag(session, tag, null, javaBlockState); + shulkerBoxTranslator.translateTag(session, tag, null, BlockState.of(javaBlockState)); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag.build()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index 498bd418b..cb973fa18 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -36,8 +36,7 @@ import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.level.block.DoubleChestValue; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.session.GeyserSession; @@ -72,8 +71,8 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { .putString("CustomName", inventory.getTitle()) .putString("id", "Chest"); - DoubleChestValue chestValue = BlockStateValues.getDoubleChestValues().get(javaBlockId); - DoubleChestBlockEntityTranslator.translateChestValue(tag, chestValue, + BlockState blockState = BlockState.of(javaBlockId); + DoubleChestBlockEntityTranslator.translateChestValue(tag, blockState, session.getLastInteractionBlockPosition().getX(), session.getLastInteractionBlockPosition().getZ()); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java index 81f58214c..8b6f627e1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java @@ -30,7 +30,8 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.item.type.BannerItem; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BannerBlock; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -39,10 +40,9 @@ import java.util.List; @BlockEntity(type = BlockEntityType.BANNER) public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { - int bannerColor = BlockStateValues.getBannerColor(blockState); - if (bannerColor != -1) { - bedrockNbt.putInt("Base", 15 - bannerColor); + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) { + if (blockState.block() instanceof BannerBlock banner) { + bedrockNbt.putInt("Base", 15 - banner.dyeColor()); } if (javaNbt == null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java index f7dee2864..9b5248785 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java @@ -27,13 +27,14 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.BEACON) public class BeaconBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { int primary = javaNbt.getInt("primary"); // The effects here generally map one-to-one Java <-> Bedrock. Only the newer ones get more complicated bedrockNbt.putInt("primary", primary == -1 ? 0 : primary); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java index 720ffea3c..7622e6d28 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java @@ -27,19 +27,15 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BedBlock; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.BED) public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { - byte bedcolor = BlockStateValues.getBedColor(blockState); - // Just in case... - if (bedcolor == -1) { - bedcolor = 0; - } - bedrockNbt.putByte("color", bedcolor); + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { + bedrockNbt.putByte("color", (byte) (blockState.block() instanceof BedBlock bed ? bed.dyeColor() : 0)); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java index 051986473..01e2d3e74 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java @@ -31,6 +31,7 @@ import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; /** @@ -50,7 +51,7 @@ public interface BedrockOnlyBlockEntity extends RequiresBlockState { * @param blockState The Java block state. * @param position The Bedrock block position. */ - void updateBlock(GeyserSession session, int blockState, Vector3i position); + void updateBlock(GeyserSession session, BlockState blockState, Vector3i position); /** * Get the tag of the Bedrock-only block entity diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java index 6df7781be..5def51e01 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -39,9 +40,9 @@ public abstract class BlockEntityTranslator { protected BlockEntityTranslator() { } - public abstract void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState); + public abstract void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState); - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) { NbtMapBuilder tagBuilder = getConstantBedrockTag(type, x, y, z); if (javaNbt != null || this instanceof RequiresBlockState) { // Always process tags if the block state is part of the tag. diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java index b4012236b..f0d632041 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java @@ -29,7 +29,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -38,7 +39,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class BrushableBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { return; } @@ -70,6 +71,6 @@ public class BrushableBlockEntityTranslator extends BlockEntityTranslator implem // controls which side the item protrudes from bedrockNbt.putByte("brush_direction", hitDirection); // controls how much the item protrudes - bedrockNbt.putInt("brush_count", BlockStateValues.getBrushProgress(blockState)); + bedrockNbt.putInt("brush_count", blockState.getValue(Properties.DUSTED)); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java index 699319bb6..fb71a84cc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -38,7 +39,7 @@ import java.util.List; @BlockEntity(type = BlockEntityType.CAMPFIRE) public class CampfireBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { List items = javaNbt.getList("Items", NbtType.COMPOUND); if (items != null) { int i = 1; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java index 0e00a19a8..b363de530 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java @@ -27,7 +27,8 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.level.block.BlockStateValues; +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.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -35,12 +36,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType @BlockEntity(type = BlockEntityType.COMMAND_BLOCK) public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { if (javaNbt == null || javaNbt.size() < 5) { return; // These values aren't here } // Java infers from the block state, but Bedrock needs it in the tag - bedrockNbt.putByte("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0)); + bedrockNbt.putBoolean("conditionalMode", blockState.getValue(Properties.CONDITIONAL)); // Java and Bedrock values bedrockNbt.putByte("conditionMet", javaNbt.getByte("conditionMet")); bedrockNbt.putByte("auto", javaNbt.getByte("auto")); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java index b24558b45..33c884c55 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -35,7 +36,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index dcb39d22c..63c5f71f3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -29,7 +29,9 @@ import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.level.block.DoubleChestValue; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -45,52 +47,40 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl } @Override - public void updateBlock(GeyserSession session, int blockState, Vector3i position) { + public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockEntityType.CHEST), position.getX(), position.getY(), position.getZ()); translateTag(session, tagBuilder, null, blockState); BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); } @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { - DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().get(blockState); - if (chestValues != null) { - int x = (int) bedrockNbt.get("x"); - int z = (int) bedrockNbt.get("z"); - translateChestValue(bedrockNbt, chestValues, x, z); - } + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { + int x = (int) bedrockNbt.get("x"); + int z = (int) bedrockNbt.get("z"); + translateChestValue(bedrockNbt, blockState, x, z); } /** * Add Bedrock block entity tags to a NbtMap based on Java properties * * @param builder the NbtMapBuilder to apply properties to - * @param chestValues the position properties of this double chest + * @param state the BlockState of this double chest * @param x the x position of this chest pair * @param z the z position of this chest pair */ - public static void translateChestValue(NbtMapBuilder builder, DoubleChestValue chestValues, int x, int z) { + public static void translateChestValue(NbtMapBuilder builder, BlockState state, int x, int z) { // Calculate the position of the other chest based on the Java block state - if (chestValues.isFacingEast()) { - if (chestValues.isDirectionPositive()) { - // East - z = z + (chestValues.isLeft() ? 1 : -1); - } else { - // West - z = z + (chestValues.isLeft() ? -1 : 1); - } - } else { - if (chestValues.isDirectionPositive()) { - // South - x = x + (chestValues.isLeft() ? -1 : 1); - } else { - // North - x = x + (chestValues.isLeft() ? 1 : -1); - } + Direction facing = state.getValue(Properties.HORIZONTAL_FACING); + boolean isLeft = state.getValue(Properties.CHEST_TYPE).equals("left"); //TODO enum + switch (facing) { + case EAST -> z = z + (isLeft ? 1 : -1); + case WEST -> z = z + (isLeft ? -1 : 1); + case SOUTH -> x = x + (isLeft ? -1 : 1); + case NORTH -> x = x + (isLeft ? 1 : -1); } builder.putInt("pairx", x); builder.putInt("pairz", z); - if (!chestValues.isLeft()) { + if (!isLeft) { builder.putInt("pairlead", (byte) 1); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java index 9ce0aff0a..88029dc2d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java @@ -27,10 +27,11 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; public class EmptyBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java index 97428eec1..36731bdff 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java @@ -31,13 +31,14 @@ import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.END_GATEWAY) public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { bedrockNbt.putInt("Age", (int) javaNbt.getLong("Age")); // Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist // Linked coordinates diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java index 074fff6ef..0a60b0f32 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java @@ -30,6 +30,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; @@ -75,12 +76,12 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity { } @Override - public void updateBlock(GeyserSession session, int blockState, Vector3i position) { - NbtMap tag = getTag(session, blockState, position); + public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { + NbtMap tag = getTag(session, blockState.javaId(), position); BlockEntityUtils.updateBlockEntity(session, tag, position); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); - updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState)); + updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState.javaId())); updateBlockPacket.setBlockPosition(position); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java index 53f32682c..51f5565b7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java @@ -29,13 +29,14 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.JIGSAW) public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { return; } @@ -46,7 +47,7 @@ public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator impl } else { // Tag is not present in at least 1.14.4 Paper // Minecraft 1.18.1 deliberately has a fallback here, but not for any other value - bedrockNbt.putString("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState) ? "aligned" : "rollable"); + bedrockNbt.putString("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState.javaId()) ? "aligned" : "rollable"); // TODO } bedrockNbt.putString("name", javaNbt.getString("name")); bedrockNbt.putString("target_pool", javaNbt.getString("target_pool")); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index 78e71000a..e09f6ae42 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; @@ -222,10 +223,10 @@ public class PistonBlockEntity { Vector3i blockInFront = position.add(orientation.getUnitVector()); int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockInFront); if (BlockStateValues.isPistonHead(blockId)) { - ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront); - } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == BlockStateValues.JAVA_AIR_ID) { + ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront); + } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == Block.JAVA_AIR_ID) { // Spigot removes the piston head from the cache, but we need to send the block update ourselves - ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront); + ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront); } } @@ -255,7 +256,7 @@ public class PistonBlockEntity { continue; } int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockPos); - if (blockId == BlockStateValues.JAVA_AIR_ID) { + if (blockId == Block.JAVA_AIR_ID) { continue; } if (BlockStateValues.canPistonMoveBlock(blockId, action == PistonValueType.PUSHING)) { @@ -278,7 +279,7 @@ public class PistonBlockEntity { continue; } int adjacentBlockId = session.getGeyser().getWorldManager().getBlockAt(session, adjacentPos); - if (adjacentBlockId != BlockStateValues.JAVA_AIR_ID && BlockStateValues.isBlockAttached(blockId, adjacentBlockId) && BlockStateValues.canPistonMoveBlock(adjacentBlockId, false)) { + if (adjacentBlockId != Block.JAVA_AIR_ID && BlockStateValues.isBlockAttached(blockId, adjacentBlockId) && BlockStateValues.canPistonMoveBlock(adjacentBlockId, false)) { // If it is another slime/honey block we need to check its adjacent blocks if (BlockStateValues.isBlockSticky(adjacentBlockId)) { blocksToCheck.add(adjacentPos); @@ -322,7 +323,7 @@ public class PistonBlockEntity { */ private void removeBlocks() { for (Vector3i blockPos : attachedBlocks.keySet()) { - ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockPos); + ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockPos); } if (action != PistonValueType.PUSHING) { removePistonHead(); @@ -560,7 +561,7 @@ public class PistonBlockEntity { if (blockPos.equals(getPistonHeadPos())) { return BlockStateValues.getPistonHead(orientation); } else { - return attachedBlocks.getOrDefault(blockPos, BlockStateValues.JAVA_AIR_ID); + return attachedBlocks.getOrDefault(blockPos, Block.JAVA_AIR_ID); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java index ba2ddd815..e6d19e492 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -28,7 +28,8 @@ package org.geysermc.geyser.translator.level.block.entity; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.level.block.BlockStateValues; +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.inventory.ShulkerInventoryTranslator; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -40,12 +41,7 @@ public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator imple * where {@code tag} is passed as null. */ @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { - byte direction = BlockStateValues.getShulkerBoxDirection(blockState); - // Just in case... - if (direction == -1) { - direction = 1; - } - bedrockNbt.putByte("facing", direction); + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) { + bedrockNbt.putByte("facing", (byte) blockState.getValue(Properties.FACING).ordinal()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java index bbf0dbcb3..2a1ccb639 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -73,7 +74,7 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator { } @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { bedrockNbt.putCompound("FrontText", translateSide(javaNbt.getCompound("front_text"))); bedrockNbt.putCompound("BackText", translateSide(javaNbt.getCompound("back_text"))); bedrockNbt.putBoolean("IsWaxed", javaNbt.getBoolean("is_waxed")); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index b1ab017e8..c03ae8ef0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -34,6 +34,8 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.BlockStateValues; +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.session.cache.SkullCache; import org.geysermc.geyser.skin.SkinProvider; @@ -50,16 +52,19 @@ import java.util.concurrent.ExecutionException; public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { - byte skullVariant = BlockStateValues.getSkullVariant(blockState); - float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f; + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { + byte skullVariant = BlockStateValues.getSkullVariant(blockState.javaId()); // TODO // Just in case... if (skullVariant == -1) { skullVariant = 0; } - bedrockNbt.putFloat("Rotation", rotation); + Integer rotation = blockState.getValue(Properties.ROTATION_16); + if (rotation != null) { + // Could be a wall skull block + bedrockNbt.putFloat("Rotation", rotation * 22.5f); + } bedrockNbt.putByte("SkullType", skullVariant); - if (BlockStateValues.isSkullPowered(blockState)) { + if (blockState.getValue(Properties.POWERED)) { bedrockNbt.putBoolean("MouthMoving", true); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index edf71d384..4b6a630ba 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -40,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { @Override - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState); } @@ -70,7 +71,7 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { } @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { Object current; // TODO use primitive get and put methods diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java index 4bb9c5676..79fb3da6b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java @@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror; import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.StructureBlockUtils; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -40,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { @Override - public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState); } @@ -73,7 +74,7 @@ public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { } @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { if (javaNbt.size() < 5) { return; // These values aren't here } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java index ff3f89f3f..a4c158a15 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -34,7 +35,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator { @Override - public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 35c46ffd2..9cb3fb455 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket; @@ -48,7 +49,7 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator> 4) - yOffset]; - int blockState = section.get(x, y & 0xF, z); + BlockState blockState = BlockRegistries.BLOCK_STATES.get(section.get(x, y & 0xF, z)); - if (type == BlockEntityType.LECTERN && BlockStateValues.getLecternBookStates().get(blockState)) { + if (type == BlockEntityType.LECTERN && blockState.getValue(Properties.HAS_BOOK)) { // If getLecternBookStates is false, let's just treat it like a normal block entity // Fill in tag with a default value NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x + chunkBlockX, y, z + chunkBlockZ, 1); @@ -419,7 +422,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4) - (bedrockDimension.minY() >> 4); int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4); diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index 379162540..a1e956ace 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -41,6 +41,8 @@ import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.GeyserChunkSection; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; @@ -50,8 +52,6 @@ import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; -import static org.geysermc.geyser.level.block.BlockStateValues.JAVA_AIR_ID; - @UtilityClass public class ChunkUtils { @@ -130,7 +130,7 @@ public class ChunkUtils { // Checks for item frames so they aren't tripped up and removed ItemFrameEntity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, position); if (itemFrameEntity != null) { - if (blockState == JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it + if (blockState == Block.JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it itemFrameEntity.updateBlock(true); // Still update the chunk cache with the new block if updateBlock is called return; @@ -180,21 +180,21 @@ public class ChunkUtils { BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(blockState); int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ()); BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock); - if (belowBedrockExtendedCollisionDefinition != null && blockState == BlockStateValues.JAVA_AIR_ID) { + if (belowBedrockExtendedCollisionDefinition != null && blockState == Block.JAVA_AIR_ID) { UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); updateBlockPacket.setBlockPosition(position); updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); session.sendUpstreamPacket(updateBlockPacket); - } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == BlockStateValues.JAVA_AIR_ID) { + } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) { UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); session.sendUpstreamPacket(updateBlockPacket); - } else if (aboveBlock == BlockStateValues.JAVA_AIR_ID) { + } else if (aboveBlock == Block.JAVA_AIR_ID) { UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); @@ -211,7 +211,7 @@ public class ChunkUtils { for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityUtils.BEDROCK_ONLY_BLOCK_ENTITIES) { if (bedrockOnlyBlockEntity.isBlock(blockState)) { // Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks - bedrockOnlyBlockEntity.updateBlock(session, blockState, position); + bedrockOnlyBlockEntity.updateBlock(session, BlockState.of(blockState), position); //TODO blockState break; //No block will be a part of two classes } } 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 85f8fc704..7559347e9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -34,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.SoundMapping; @@ -147,7 +148,7 @@ public final class SoundUtils { soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12); } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { if (!soundMapping.getIdentifier().equals(":")) { - int javaId = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID); + int javaId = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(soundMapping.getIdentifier(), Block.JAVA_AIR_ID); soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(javaId)); } else { session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + soundMapping); diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index 96328bcdd..8f9be0b98 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.cumulus.util.FormImage; 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.Registries; import org.geysermc.geyser.session.GeyserSession; @@ -93,10 +94,10 @@ public class StatisticsUtils { for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof BreakBlockStatistic statistic) { - String identifier = BlockRegistries.CLEAN_JAVA_IDENTIFIERS.get(statistic.getId()); - if (identifier != null) { - String block = identifier.replace("minecraft:", "block.minecraft."); - content.add(block + ": " + entry.getIntValue()); + Block block = BlockRegistries.JAVA_BLOCKS_TO_RENAME.get(statistic.getId()); + if (block != null) { + String identifier = block.javaIdentifier().replace("minecraft:", "block.minecraft."); + content.add(identifier + ": " + entry.getIntValue()); } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0500a31be..0f0845137 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -65,6 +65,7 @@ fastutil-int-byte-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int- fastutil-int-boolean-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-boolean-maps", version.ref = "fastutil" } fastutil-object-int-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-int-maps", version.ref = "fastutil" } fastutil-object-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-object-maps", version.ref = "fastutil" } +fastutil-reference-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-reference-object-maps", version.ref = "fastutil" } adventure-text-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" } # Remove when we remove our Adventure bump adventure-text-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" } @@ -142,7 +143,7 @@ blossom = { id = "net.kyori.blossom", version.ref = "blossom" } [bundles] jackson = [ "jackson-annotations", "jackson-core", "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" ] +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", "fastutil-reference-object-maps" ] adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ] log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl" ] jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ] From a46332ace19aadf2d09f258f7c9ef456cf0af965 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 17 May 2024 14:50:21 -0400 Subject: [PATCH 140/897] Move block breaking to new system --- .../geysermc/geyser/level/block/Blocks.java | 1834 ++++++++--------- .../geyser/level/block/type/Block.java | 36 + .../populator/BlockRegistryPopulator.java | 10 + .../geyser/session/cache/TagCache.java | 14 +- .../player/BedrockActionTranslator.java | 5 +- .../level/JavaBlockDestructionTranslator.java | 7 +- .../org/geysermc/geyser/util/BlockUtils.java | 44 +- 7 files changed, 1005 insertions(+), 945 deletions(-) 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 426895269..1f9c9c162 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 @@ -38,30 +38,30 @@ import static org.geysermc.geyser.level.block.type.Block.builder; @SuppressWarnings("unused") public final class Blocks { public static final Block AIR = register(new Block("air", builder())); - public static final Block STONE = register(new Block("stone", builder())); - public static final Block GRANITE = register(new Block("granite", builder())); - public static final Block POLISHED_GRANITE = register(new Block("polished_granite", builder())); - public static final Block DIORITE = register(new Block("diorite", builder())); - public static final Block POLISHED_DIORITE = register(new Block("polished_diorite", builder())); - public static final Block ANDESITE = register(new Block("andesite", builder())); - public static final Block POLISHED_ANDESITE = register(new Block("polished_andesite", builder())); - public static final Block GRASS_BLOCK = register(new Block("grass_block", builder() + public static final Block STONE = register(new Block("stone", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block GRANITE = register(new Block("granite", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block POLISHED_GRANITE = register(new Block("polished_granite", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block DIORITE = register(new Block("diorite", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block POLISHED_DIORITE = register(new Block("polished_diorite", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + 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))); - public static final Block DIRT = register(new Block("dirt", builder())); - public static final Block COARSE_DIRT = register(new Block("coarse_dirt", builder())); - public static final Block PODZOL = register(new Block("podzol", builder() + 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))); - public static final Block COBBLESTONE = register(new Block("cobblestone", builder())); - public static final Block OAK_PLANKS = register(new Block("oak_planks", builder())); - public static final Block SPRUCE_PLANKS = register(new Block("spruce_planks", builder())); - public static final Block BIRCH_PLANKS = register(new Block("birch_planks", builder())); - public static final Block JUNGLE_PLANKS = register(new Block("jungle_planks", builder())); - public static final Block ACACIA_PLANKS = register(new Block("acacia_planks", builder())); - public static final Block CHERRY_PLANKS = register(new Block("cherry_planks", builder())); - public static final Block DARK_OAK_PLANKS = register(new Block("dark_oak_planks", builder())); - public static final Block MANGROVE_PLANKS = register(new Block("mangrove_planks", builder())); - public static final Block BAMBOO_PLANKS = register(new Block("bamboo_planks", builder())); - public static final Block BAMBOO_MOSAIC = register(new Block("bamboo_mosaic", builder())); + 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))); + public static final Block BIRCH_PLANKS = register(new Block("birch_planks", builder().destroyTime(2.0f))); + public static final Block JUNGLE_PLANKS = register(new Block("jungle_planks", builder().destroyTime(2.0f))); + 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 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() .intState(STAGE, 0, 1))); public static final Block SPRUCE_SAPLING = register(new Block("spruce_sapling", builder() @@ -81,259 +81,259 @@ public final class Blocks { .booleanState(HANGING) .intState(STAGE, 0, 1) .booleanState(WATERLOGGED))); - public static final Block BEDROCK = register(new Block("bedrock", builder())); - public static final Block WATER = register(new Block("water", builder() + public static final Block BEDROCK = register(new Block("bedrock", builder().destroyTime(-1.0f))); + public static final Block WATER = register(new Block("water", builder().destroyTime(100.0f) .intState(LEVEL, 0, 15))); - public static final Block LAVA = register(new Block("lava", builder() + public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f) .intState(LEVEL, 0, 15))); - public static final Block SAND = register(new Block("sand", builder())); - public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder() + 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().destroyTime(0.25f) .intState(DUSTED, 0, 3))); - public static final Block RED_SAND = register(new Block("red_sand", builder())); - public static final Block GRAVEL = register(new Block("gravel", builder())); - public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder() + 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().destroyTime(0.25f) .intState(DUSTED, 0, 3))); - public static final Block GOLD_ORE = register(new Block("gold_ore", builder())); - public static final Block DEEPSLATE_GOLD_ORE = register(new Block("deepslate_gold_ore", builder())); - public static final Block IRON_ORE = register(new Block("iron_ore", builder())); - public static final Block DEEPSLATE_IRON_ORE = register(new Block("deepslate_iron_ore", builder())); - public static final Block COAL_ORE = register(new Block("coal_ore", builder())); - public static final Block DEEPSLATE_COAL_ORE = register(new Block("deepslate_coal_ore", builder())); - public static final Block NETHER_GOLD_ORE = register(new Block("nether_gold_ore", builder())); - public static final Block OAK_LOG = register(new Block("oak_log", builder() + 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))); + public static final Block DEEPSLATE_IRON_ORE = register(new Block("deepslate_iron_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); + public static final Block COAL_ORE = register(new Block("coal_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + 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))); - public static final Block SPRUCE_LOG = register(new Block("spruce_log", builder() + public static final Block SPRUCE_LOG = register(new Block("spruce_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block BIRCH_LOG = register(new Block("birch_log", builder() + public static final Block BIRCH_LOG = register(new Block("birch_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block JUNGLE_LOG = register(new Block("jungle_log", builder() + public static final Block JUNGLE_LOG = register(new Block("jungle_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block ACACIA_LOG = register(new Block("acacia_log", builder() + public static final Block ACACIA_LOG = register(new Block("acacia_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block CHERRY_LOG = register(new Block("cherry_log", builder() + public static final Block CHERRY_LOG = register(new Block("cherry_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block DARK_OAK_LOG = register(new Block("dark_oak_log", builder() + public static final Block DARK_OAK_LOG = register(new Block("dark_oak_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block MANGROVE_LOG = register(new Block("mangrove_log", builder() + public static final Block MANGROVE_LOG = register(new Block("mangrove_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block MANGROVE_ROOTS = register(new Block("mangrove_roots", builder() + public static final Block MANGROVE_ROOTS = register(new Block("mangrove_roots", builder().destroyTime(0.7f) .booleanState(WATERLOGGED))); - public static final Block MUDDY_MANGROVE_ROOTS = register(new Block("muddy_mangrove_roots", builder() + public static final Block MUDDY_MANGROVE_ROOTS = register(new Block("muddy_mangrove_roots", builder().destroyTime(0.7f) .enumState(AXIS, Axis.VALUES))); - public static final Block BAMBOO_BLOCK = register(new Block("bamboo_block", builder() + public static final Block BAMBOO_BLOCK = register(new Block("bamboo_block", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_SPRUCE_LOG = register(new Block("stripped_spruce_log", builder() + public static final Block STRIPPED_SPRUCE_LOG = register(new Block("stripped_spruce_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_BIRCH_LOG = register(new Block("stripped_birch_log", builder() + public static final Block STRIPPED_BIRCH_LOG = register(new Block("stripped_birch_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_JUNGLE_LOG = register(new Block("stripped_jungle_log", builder() + public static final Block STRIPPED_JUNGLE_LOG = register(new Block("stripped_jungle_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_ACACIA_LOG = register(new Block("stripped_acacia_log", builder() + public static final Block STRIPPED_ACACIA_LOG = register(new Block("stripped_acacia_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_CHERRY_LOG = register(new Block("stripped_cherry_log", builder() + public static final Block STRIPPED_CHERRY_LOG = register(new Block("stripped_cherry_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_DARK_OAK_LOG = register(new Block("stripped_dark_oak_log", builder() + public static final Block STRIPPED_DARK_OAK_LOG = register(new Block("stripped_dark_oak_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_OAK_LOG = register(new Block("stripped_oak_log", builder() + public static final Block STRIPPED_OAK_LOG = register(new Block("stripped_oak_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_MANGROVE_LOG = register(new Block("stripped_mangrove_log", builder() + public static final Block STRIPPED_MANGROVE_LOG = register(new Block("stripped_mangrove_log", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_BAMBOO_BLOCK = register(new Block("stripped_bamboo_block", builder() + public static final Block STRIPPED_BAMBOO_BLOCK = register(new Block("stripped_bamboo_block", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block OAK_WOOD = register(new Block("oak_wood", builder() + public static final Block OAK_WOOD = register(new Block("oak_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block SPRUCE_WOOD = register(new Block("spruce_wood", builder() + public static final Block SPRUCE_WOOD = register(new Block("spruce_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block BIRCH_WOOD = register(new Block("birch_wood", builder() + public static final Block BIRCH_WOOD = register(new Block("birch_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block JUNGLE_WOOD = register(new Block("jungle_wood", builder() + public static final Block JUNGLE_WOOD = register(new Block("jungle_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block ACACIA_WOOD = register(new Block("acacia_wood", builder() + public static final Block ACACIA_WOOD = register(new Block("acacia_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block CHERRY_WOOD = register(new Block("cherry_wood", builder() + public static final Block CHERRY_WOOD = register(new Block("cherry_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block DARK_OAK_WOOD = register(new Block("dark_oak_wood", builder() + public static final Block DARK_OAK_WOOD = register(new Block("dark_oak_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block MANGROVE_WOOD = register(new Block("mangrove_wood", builder() + public static final Block MANGROVE_WOOD = register(new Block("mangrove_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_OAK_WOOD = register(new Block("stripped_oak_wood", builder() + public static final Block STRIPPED_OAK_WOOD = register(new Block("stripped_oak_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_SPRUCE_WOOD = register(new Block("stripped_spruce_wood", builder() + public static final Block STRIPPED_SPRUCE_WOOD = register(new Block("stripped_spruce_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_BIRCH_WOOD = register(new Block("stripped_birch_wood", builder() + public static final Block STRIPPED_BIRCH_WOOD = register(new Block("stripped_birch_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_JUNGLE_WOOD = register(new Block("stripped_jungle_wood", builder() + public static final Block STRIPPED_JUNGLE_WOOD = register(new Block("stripped_jungle_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_ACACIA_WOOD = register(new Block("stripped_acacia_wood", builder() + public static final Block STRIPPED_ACACIA_WOOD = register(new Block("stripped_acacia_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_CHERRY_WOOD = register(new Block("stripped_cherry_wood", builder() + public static final Block STRIPPED_CHERRY_WOOD = register(new Block("stripped_cherry_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_DARK_OAK_WOOD = register(new Block("stripped_dark_oak_wood", builder() + public static final Block STRIPPED_DARK_OAK_WOOD = register(new Block("stripped_dark_oak_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_MANGROVE_WOOD = register(new Block("stripped_mangrove_wood", builder() + public static final Block STRIPPED_MANGROVE_WOOD = register(new Block("stripped_mangrove_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder() + public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block SPRUCE_LEAVES = register(new Block("spruce_leaves", builder() + public static final Block SPRUCE_LEAVES = register(new Block("spruce_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block BIRCH_LEAVES = register(new Block("birch_leaves", builder() + public static final Block BIRCH_LEAVES = register(new Block("birch_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block JUNGLE_LEAVES = register(new Block("jungle_leaves", builder() + public static final Block JUNGLE_LEAVES = register(new Block("jungle_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block ACACIA_LEAVES = register(new Block("acacia_leaves", builder() + public static final Block ACACIA_LEAVES = register(new Block("acacia_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block CHERRY_LEAVES = register(new Block("cherry_leaves", builder() + public static final Block CHERRY_LEAVES = register(new Block("cherry_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_LEAVES = register(new Block("dark_oak_leaves", builder() + public static final Block DARK_OAK_LEAVES = register(new Block("dark_oak_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block MANGROVE_LEAVES = register(new Block("mangrove_leaves", builder() + public static final Block MANGROVE_LEAVES = register(new Block("mangrove_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block AZALEA_LEAVES = register(new Block("azalea_leaves", builder() + public static final Block AZALEA_LEAVES = register(new Block("azalea_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block FLOWERING_AZALEA_LEAVES = register(new Block("flowering_azalea_leaves", builder() + public static final Block FLOWERING_AZALEA_LEAVES = register(new Block("flowering_azalea_leaves", builder().destroyTime(0.2f) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block SPONGE = register(new Block("sponge", builder())); - public static final Block WET_SPONGE = register(new Block("wet_sponge", builder())); - public static final Block GLASS = register(new Block("glass", builder())); - public static final Block LAPIS_ORE = register(new Block("lapis_ore", builder())); - public static final Block DEEPSLATE_LAPIS_ORE = register(new Block("deepslate_lapis_ore", builder())); - public static final Block LAPIS_BLOCK = register(new Block("lapis_block", builder())); - public static final Block DISPENSER = register(new Block("dispenser", builder() + 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))); + public static final Block LAPIS_ORE = register(new Block("lapis_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + 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().requiresCorrectToolForDrops().destroyTime(3.5f) .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())); - public static final Block CHISELED_SANDSTONE = register(new Block("chiseled_sandstone", builder())); - public static final Block CUT_SANDSTONE = register(new Block("cut_sandstone", builder())); - public static final Block NOTE_BLOCK = register(new Block("note_block", builder() + 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, "harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling", "zombie", "skeleton", "creeper", "dragon", "wither_skeleton", "piglin", "custom_head") .intState(NOTE, 0, 24) .booleanState(POWERED))); - public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder() + public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder() + public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder() + public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder() + public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder() + public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder() + public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder() + public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder() + public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder() + public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder() + public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder() + public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder() + public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder() + public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder() + public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder() + public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder() + public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity().destroyTime(0.2f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block POWERED_RAIL = register(new Block("powered_rail", builder() + public static final Block POWERED_RAIL = register(new Block("powered_rail", builder().destroyTime(0.7f) .booleanState(POWERED) .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") .booleanState(WATERLOGGED))); - public static final Block DETECTOR_RAIL = register(new Block("detector_rail", builder() + public static final Block DETECTOR_RAIL = register(new Block("detector_rail", builder().destroyTime(0.7f) .booleanState(POWERED) .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") .booleanState(WATERLOGGED))); - public static final Block STICKY_PISTON = register(new Block("sticky_piston", builder() + public static final Block STICKY_PISTON = register(new Block("sticky_piston", builder().destroyTime(1.5f) .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())); + public static final Block COBWEB = register(new Block("cobweb", builder().requiresCorrectToolForDrops().destroyTime(4.0f))); public static final Block SHORT_GRASS = register(new Block("short_grass", builder())); public static final Block FERN = register(new Block("fern", builder())); public static final Block DEAD_BUSH = register(new Block("dead_bush", builder())); public static final Block SEAGRASS = register(new Block("seagrass", builder())); public static final Block TALL_SEAGRASS = register(new Block("tall_seagrass", builder() .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block PISTON = register(new Block("piston", builder() + public static final Block PISTON = register(new Block("piston", builder().destroyTime(1.5f) .booleanState(EXTENDED) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block PISTON_HEAD = register(new Block("piston_head", builder() + public static final Block PISTON_HEAD = register(new Block("piston_head", builder().destroyTime(1.5f) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .booleanState(SHORT) .enumState(PISTON_TYPE, "normal", "sticky"))); - public static final Block WHITE_WOOL = register(new Block("white_wool", builder())); - public static final Block ORANGE_WOOL = register(new Block("orange_wool", builder())); - public static final Block MAGENTA_WOOL = register(new Block("magenta_wool", builder())); - public static final Block LIGHT_BLUE_WOOL = register(new Block("light_blue_wool", builder())); - public static final Block YELLOW_WOOL = register(new Block("yellow_wool", builder())); - public static final Block LIME_WOOL = register(new Block("lime_wool", builder())); - public static final Block PINK_WOOL = register(new Block("pink_wool", builder())); - public static final Block GRAY_WOOL = register(new Block("gray_wool", builder())); - public static final Block LIGHT_GRAY_WOOL = register(new Block("light_gray_wool", builder())); - public static final Block CYAN_WOOL = register(new Block("cyan_wool", builder())); - public static final Block PURPLE_WOOL = register(new Block("purple_wool", builder())); - public static final Block BLUE_WOOL = register(new Block("blue_wool", builder())); - public static final Block BROWN_WOOL = register(new Block("brown_wool", builder())); - public static final Block GREEN_WOOL = register(new Block("green_wool", builder())); - public static final Block RED_WOOL = register(new Block("red_wool", builder())); - public static final Block BLACK_WOOL = register(new Block("black_wool", builder())); - public static final Block MOVING_PISTON = register(new Block("moving_piston", builder() + 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))); + public static final Block LIGHT_BLUE_WOOL = register(new Block("light_blue_wool", builder().destroyTime(0.8f))); + public static final Block YELLOW_WOOL = register(new Block("yellow_wool", builder().destroyTime(0.8f))); + public static final Block LIME_WOOL = register(new Block("lime_wool", builder().destroyTime(0.8f))); + public static final Block PINK_WOOL = register(new Block("pink_wool", builder().destroyTime(0.8f))); + public static final Block GRAY_WOOL = register(new Block("gray_wool", builder().destroyTime(0.8f))); + public static final Block LIGHT_GRAY_WOOL = register(new Block("light_gray_wool", builder().destroyTime(0.8f))); + public static final Block CYAN_WOOL = register(new Block("cyan_wool", builder().destroyTime(0.8f))); + public static final Block PURPLE_WOOL = register(new Block("purple_wool", builder().destroyTime(0.8f))); + public static final Block BLUE_WOOL = register(new Block("blue_wool", builder().destroyTime(0.8f))); + public static final Block BROWN_WOOL = register(new Block("brown_wool", builder().destroyTime(0.8f))); + public static final Block GREEN_WOOL = register(new Block("green_wool", builder().destroyTime(0.8f))); + 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 Block("moving_piston", builder().setBlockEntity().destroyTime(-1.0f) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .enumState(PISTON_TYPE, "normal", "sticky"))); public static final Block DANDELION = register(new Block("dandelion", builder())); @@ -352,13 +352,13 @@ public final class Blocks { public static final Block LILY_OF_THE_VALLEY = register(new Block("lily_of_the_valley", builder())); public static final Block BROWN_MUSHROOM = register(new Block("brown_mushroom", builder())); public static final Block RED_MUSHROOM = register(new Block("red_mushroom", builder())); - public static final Block GOLD_BLOCK = register(new Block("gold_block", builder())); - public static final Block IRON_BLOCK = register(new Block("iron_block", builder())); - public static final Block BRICKS = register(new Block("bricks", builder())); + public static final Block GOLD_BLOCK = register(new Block("gold_block", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + 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))); - public static final Block BOOKSHELF = register(new Block("bookshelf", builder())); - public static final Block CHISELED_BOOKSHELF = register(new Block("chiseled_bookshelf", builder() + 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().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) @@ -366,8 +366,8 @@ public final class Blocks { .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())); - public static final Block OBSIDIAN = register(new Block("obsidian", builder())); + 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())); public static final Block WALL_TORCH = register(new Block("wall_torch", builder() .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); @@ -379,13 +379,13 @@ public final class Blocks { .booleanState(UP) .booleanState(WEST))); public static final Block SOUL_FIRE = register(new Block("soul_fire", builder())); - public static final Block SPAWNER = register(new Block("spawner", builder())); - public static final Block OAK_STAIRS = register(new Block("oak_stairs", builder() + public static final Block SPAWNER = register(new Block("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block CHEST = register(new Block("chest", builder() + public static final Block CHEST = register(new Block("chest", builder().setBlockEntity().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(CHEST_TYPE, "single", "left", "right") .booleanState(WATERLOGGED))); @@ -395,369 +395,369 @@ public final class Blocks { .intState(POWER, 0, 15) .enumState(SOUTH_REDSTONE, "up", "side", "none") .enumState(WEST_REDSTONE, "up", "side", "none"))); - public static final Block DIAMOND_ORE = register(new Block("diamond_ore", builder())); - public static final Block DEEPSLATE_DIAMOND_ORE = register(new Block("deepslate_diamond_ore", builder())); - public static final Block DIAMOND_BLOCK = register(new Block("diamond_block", builder())); - public static final Block CRAFTING_TABLE = register(new Block("crafting_table", builder())); + 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() .intState(AGE_7, 0, 7))); - public static final Block FARMLAND = register(new Block("farmland", builder() + public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f) .intState(MOISTURE, 0, 7))); - public static final Block FURNACE = register(new Block("furnace", builder() + public static final Block FURNACE = register(new Block("furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) .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() + public static final Block OAK_SIGN = register(new Block("oak_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder() + public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder() + public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder() + public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder() + public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder() + public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_SIGN = register(new Block("dark_oak_sign", builder() + public static final Block DARK_OAK_SIGN = register(new Block("dark_oak_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder() + public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder() + public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block OAK_DOOR = register(new Block("oak_door", builder() + public static final Block OAK_DOOR = register(new Block("oak_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block LADDER = register(new Block("ladder", builder() + public static final Block LADDER = register(new Block("ladder", builder().destroyTime(0.4f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block RAIL = register(new Block("rail", builder() + public static final Block RAIL = register(new Block("rail", builder().destroyTime(0.7f) .enumState(RAIL_SHAPE, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south", "south_east", "south_west", "north_west", "north_east") .booleanState(WATERLOGGED))); - public static final Block COBBLESTONE_STAIRS = register(new Block("cobblestone_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block OAK_WALL_SIGN = register(new Block("oak_wall_sign", builder() + public static final Block OAK_WALL_SIGN = register(new Block("oak_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block SPRUCE_WALL_SIGN = register(new Block("spruce_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block BIRCH_WALL_SIGN = register(new Block("birch_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block ACACIA_WALL_SIGN = register(new Block("acacia_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block CHERRY_WALL_SIGN = register(new Block("cherry_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block JUNGLE_WALL_SIGN = register(new Block("jungle_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block DARK_OAK_WALL_SIGN = register(new Block("dark_oak_wall_sign", builder().setBlockEntity().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() + public static final Block MANGROVE_WALL_SIGN = register(new Block("mangrove_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block BAMBOO_WALL_SIGN = register(new Block("bamboo_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block OAK_HANGING_SIGN = register(new Block("oak_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block SPRUCE_HANGING_SIGN = register(new Block("spruce_hanging_sign", builder() + public static final Block SPRUCE_HANGING_SIGN = register(new Block("spruce_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block BIRCH_HANGING_SIGN = register(new Block("birch_hanging_sign", builder() + public static final Block BIRCH_HANGING_SIGN = register(new Block("birch_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block ACACIA_HANGING_SIGN = register(new Block("acacia_hanging_sign", builder() + public static final Block ACACIA_HANGING_SIGN = register(new Block("acacia_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block CHERRY_HANGING_SIGN = register(new Block("cherry_hanging_sign", builder() + public static final Block CHERRY_HANGING_SIGN = register(new Block("cherry_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block JUNGLE_HANGING_SIGN = register(new Block("jungle_hanging_sign", builder() + public static final Block JUNGLE_HANGING_SIGN = register(new Block("jungle_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_HANGING_SIGN = register(new Block("dark_oak_hanging_sign", builder() + public static final Block DARK_OAK_HANGING_SIGN = register(new Block("dark_oak_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block CRIMSON_HANGING_SIGN = register(new Block("crimson_hanging_sign", builder() + public static final Block CRIMSON_HANGING_SIGN = register(new Block("crimson_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block WARPED_HANGING_SIGN = register(new Block("warped_hanging_sign", builder() + public static final Block WARPED_HANGING_SIGN = register(new Block("warped_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block MANGROVE_HANGING_SIGN = register(new Block("mangrove_hanging_sign", builder() + public static final Block MANGROVE_HANGING_SIGN = register(new Block("mangrove_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_HANGING_SIGN = register(new Block("bamboo_hanging_sign", builder() + public static final Block BAMBOO_HANGING_SIGN = register(new Block("bamboo_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block OAK_WALL_HANGING_SIGN = register(new Block("oak_wall_hanging_sign", builder() + public static final Block OAK_WALL_HANGING_SIGN = register(new Block("oak_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block SPRUCE_WALL_HANGING_SIGN = register(new Block("spruce_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block BIRCH_WALL_HANGING_SIGN = register(new Block("birch_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block ACACIA_WALL_HANGING_SIGN = register(new Block("acacia_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block CHERRY_WALL_HANGING_SIGN = register(new Block("cherry_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block JUNGLE_WALL_HANGING_SIGN = register(new Block("jungle_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block DARK_OAK_WALL_HANGING_SIGN = register(new Block("dark_oak_wall_hanging_sign", builder().setBlockEntity().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() + public static final Block MANGROVE_WALL_HANGING_SIGN = register(new Block("mangrove_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block CRIMSON_WALL_HANGING_SIGN = register(new Block("crimson_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block WARPED_WALL_HANGING_SIGN = register(new Block("warped_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block BAMBOO_WALL_HANGING_SIGN = register(new Block("bamboo_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block LEVER = register(new Block("lever", builder() + public static final Block LEVER = register(new Block("lever", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block STONE_PRESSURE_PLATE = register(new Block("stone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block IRON_DOOR = register(new Block("iron_door", builder() + public static final Block IRON_DOOR = register(new Block("iron_door", builder().requiresCorrectToolForDrops().destroyTime(5.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block OAK_PRESSURE_PLATE = register(new Block("oak_pressure_plate", builder() + public static final Block OAK_PRESSURE_PLATE = register(new Block("oak_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block SPRUCE_PRESSURE_PLATE = register(new Block("spruce_pressure_plate", builder() + public static final Block SPRUCE_PRESSURE_PLATE = register(new Block("spruce_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block BIRCH_PRESSURE_PLATE = register(new Block("birch_pressure_plate", builder() + public static final Block BIRCH_PRESSURE_PLATE = register(new Block("birch_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block JUNGLE_PRESSURE_PLATE = register(new Block("jungle_pressure_plate", builder() + public static final Block JUNGLE_PRESSURE_PLATE = register(new Block("jungle_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block ACACIA_PRESSURE_PLATE = register(new Block("acacia_pressure_plate", builder() + public static final Block ACACIA_PRESSURE_PLATE = register(new Block("acacia_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block CHERRY_PRESSURE_PLATE = register(new Block("cherry_pressure_plate", builder() + public static final Block CHERRY_PRESSURE_PLATE = register(new Block("cherry_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block DARK_OAK_PRESSURE_PLATE = register(new Block("dark_oak_pressure_plate", builder() + public static final Block DARK_OAK_PRESSURE_PLATE = register(new Block("dark_oak_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block MANGROVE_PRESSURE_PLATE = register(new Block("mangrove_pressure_plate", builder() + public static final Block MANGROVE_PRESSURE_PLATE = register(new Block("mangrove_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block BAMBOO_PRESSURE_PLATE = register(new Block("bamboo_pressure_plate", builder() + public static final Block BAMBOO_PRESSURE_PLATE = register(new Block("bamboo_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block REDSTONE_ORE = register(new Block("redstone_ore", builder() + public static final Block REDSTONE_ORE = register(new Block("redstone_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT))); - public static final Block DEEPSLATE_REDSTONE_ORE = register(new Block("deepslate_redstone_ore", builder() + public static final Block DEEPSLATE_REDSTONE_ORE = register(new Block("deepslate_redstone_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f) .booleanState(LIT))); public static final Block REDSTONE_TORCH = register(new Block("redstone_torch", builder() .booleanState(LIT))); public static final Block REDSTONE_WALL_TORCH = register(new Block("redstone_wall_torch", builder() .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() + public static final Block STONE_BUTTON = register(new Block("stone_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block SNOW = register(new Block("snow", builder() + public static final Block SNOW = register(new Block("snow", builder().requiresCorrectToolForDrops().destroyTime(0.1f) .intState(LAYERS, 1, 8))); - public static final Block ICE = register(new Block("ice", builder())); - public static final Block SNOW_BLOCK = register(new Block("snow_block", builder())); - public static final Block CACTUS = register(new Block("cactus", builder() + 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) .intState(AGE_15, 0, 15))); - public static final Block CLAY = register(new Block("clay", builder())); + 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() .intState(AGE_15, 0, 15))); - public static final Block JUKEBOX = register(new Block("jukebox", builder() + public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity().destroyTime(2.0f) .booleanState(HAS_RECORD))); - public static final Block OAK_FENCE = register(new Block("oak_fence", builder() + 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))); - public static final Block NETHERRACK = register(new Block("netherrack", builder())); - public static final Block SOUL_SAND = register(new Block("soul_sand", builder())); - public static final Block SOUL_SOIL = register(new Block("soul_soil", builder())); - public static final Block BASALT = register(new Block("basalt", builder() + 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))); - public static final Block POLISHED_BASALT = register(new Block("polished_basalt", builder() + public static final Block POLISHED_BASALT = register(new Block("polished_basalt", builder().requiresCorrectToolForDrops().destroyTime(1.25f) .enumState(AXIS, Axis.VALUES))); public static final Block SOUL_TORCH = register(new Block("soul_torch", builder())); public static final Block SOUL_WALL_TORCH = register(new Block("soul_wall_torch", builder() .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block GLOWSTONE = register(new Block("glowstone", builder())); - public static final Block NETHER_PORTAL = register(new Block("nether_portal", builder() + 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) .enumState(HORIZONTAL_AXIS, Axis.X, Axis.Z))); - public static final Block CARVED_PUMPKIN = register(new Block("carved_pumpkin", builder() + public static final Block CARVED_PUMPKIN = register(new Block("carved_pumpkin", builder().destroyTime(1.0f) .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() + public static final Block JACK_O_LANTERN = register(new Block("jack_o_lantern", builder().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block CAKE = register(new Block("cake", builder() + public static final Block CAKE = register(new Block("cake", builder().destroyTime(0.5f) .intState(BITES, 0, 6))); public static final Block REPEATER = register(new Block("repeater", builder() .intState(DELAY, 1, 4) .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())); - public static final Block ORANGE_STAINED_GLASS = register(new Block("orange_stained_glass", builder())); - public static final Block MAGENTA_STAINED_GLASS = register(new Block("magenta_stained_glass", builder())); - public static final Block LIGHT_BLUE_STAINED_GLASS = register(new Block("light_blue_stained_glass", builder())); - public static final Block YELLOW_STAINED_GLASS = register(new Block("yellow_stained_glass", builder())); - public static final Block LIME_STAINED_GLASS = register(new Block("lime_stained_glass", builder())); - public static final Block PINK_STAINED_GLASS = register(new Block("pink_stained_glass", builder())); - public static final Block GRAY_STAINED_GLASS = register(new Block("gray_stained_glass", builder())); - public static final Block LIGHT_GRAY_STAINED_GLASS = register(new Block("light_gray_stained_glass", builder())); - public static final Block CYAN_STAINED_GLASS = register(new Block("cyan_stained_glass", builder())); - public static final Block PURPLE_STAINED_GLASS = register(new Block("purple_stained_glass", builder())); - public static final Block BLUE_STAINED_GLASS = register(new Block("blue_stained_glass", builder())); - public static final Block BROWN_STAINED_GLASS = register(new Block("brown_stained_glass", builder())); - public static final Block GREEN_STAINED_GLASS = register(new Block("green_stained_glass", builder())); - public static final Block RED_STAINED_GLASS = register(new Block("red_stained_glass", builder())); - public static final Block BLACK_STAINED_GLASS = register(new Block("black_stained_glass", builder())); - public static final Block OAK_TRAPDOOR = register(new Block("oak_trapdoor", builder() + 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))); + public static final Block LIGHT_BLUE_STAINED_GLASS = register(new Block("light_blue_stained_glass", builder().destroyTime(0.3f))); + public static final Block YELLOW_STAINED_GLASS = register(new Block("yellow_stained_glass", builder().destroyTime(0.3f))); + public static final Block LIME_STAINED_GLASS = register(new Block("lime_stained_glass", builder().destroyTime(0.3f))); + public static final Block PINK_STAINED_GLASS = register(new Block("pink_stained_glass", builder().destroyTime(0.3f))); + public static final Block GRAY_STAINED_GLASS = register(new Block("gray_stained_glass", builder().destroyTime(0.3f))); + public static final Block LIGHT_GRAY_STAINED_GLASS = register(new Block("light_gray_stained_glass", builder().destroyTime(0.3f))); + public static final Block CYAN_STAINED_GLASS = register(new Block("cyan_stained_glass", builder().destroyTime(0.3f))); + public static final Block PURPLE_STAINED_GLASS = register(new Block("purple_stained_glass", builder().destroyTime(0.3f))); + public static final Block BLUE_STAINED_GLASS = register(new Block("blue_stained_glass", builder().destroyTime(0.3f))); + public static final Block BROWN_STAINED_GLASS = register(new Block("brown_stained_glass", builder().destroyTime(0.3f))); + public static final Block GREEN_STAINED_GLASS = register(new Block("green_stained_glass", builder().destroyTime(0.3f))); + 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 Block("oak_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block SPRUCE_TRAPDOOR = register(new Block("spruce_trapdoor", builder() + public static final Block SPRUCE_TRAPDOOR = register(new Block("spruce_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block BIRCH_TRAPDOOR = register(new Block("birch_trapdoor", builder() + public static final Block BIRCH_TRAPDOOR = register(new Block("birch_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block JUNGLE_TRAPDOOR = register(new Block("jungle_trapdoor", builder() + public static final Block JUNGLE_TRAPDOOR = register(new Block("jungle_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block ACACIA_TRAPDOOR = register(new Block("acacia_trapdoor", builder() + public static final Block ACACIA_TRAPDOOR = register(new Block("acacia_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block CHERRY_TRAPDOOR = register(new Block("cherry_trapdoor", builder() + public static final Block CHERRY_TRAPDOOR = register(new Block("cherry_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_TRAPDOOR = register(new Block("dark_oak_trapdoor", builder() + public static final Block DARK_OAK_TRAPDOOR = register(new Block("dark_oak_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block MANGROVE_TRAPDOOR = register(new Block("mangrove_trapdoor", builder() + public static final Block MANGROVE_TRAPDOOR = register(new Block("mangrove_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_TRAPDOOR = register(new Block("bamboo_trapdoor", builder() + public static final Block BAMBOO_TRAPDOOR = register(new Block("bamboo_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block STONE_BRICKS = register(new Block("stone_bricks", builder())); - public static final Block MOSSY_STONE_BRICKS = register(new Block("mossy_stone_bricks", builder())); - public static final Block CRACKED_STONE_BRICKS = register(new Block("cracked_stone_bricks", builder())); - public static final Block CHISELED_STONE_BRICKS = register(new Block("chiseled_stone_bricks", builder())); - public static final Block PACKED_MUD = register(new Block("packed_mud", builder())); - public static final Block MUD_BRICKS = register(new Block("mud_bricks", builder())); - public static final Block INFESTED_STONE = register(new Block("infested_stone", builder())); - public static final Block INFESTED_COBBLESTONE = register(new Block("infested_cobblestone", builder())); - public static final Block INFESTED_STONE_BRICKS = register(new Block("infested_stone_bricks", builder())); - public static final Block INFESTED_MOSSY_STONE_BRICKS = register(new Block("infested_mossy_stone_bricks", builder())); - public static final Block INFESTED_CRACKED_STONE_BRICKS = register(new Block("infested_cracked_stone_bricks", builder())); - public static final Block INFESTED_CHISELED_STONE_BRICKS = register(new Block("infested_chiseled_stone_bricks", builder())); - public static final Block BROWN_MUSHROOM_BLOCK = register(new Block("brown_mushroom_block", builder() + 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))); + public static final Block CHISELED_STONE_BRICKS = register(new Block("chiseled_stone_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block PACKED_MUD = register(new Block("packed_mud", builder().destroyTime(1.0f))); + public static final Block MUD_BRICKS = register(new Block("mud_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block INFESTED_STONE = register(new Block("infested_stone", builder().destroyTime(0.75f))); + public static final Block INFESTED_COBBLESTONE = register(new Block("infested_cobblestone", builder().destroyTime(1.0f))); + public static final Block INFESTED_STONE_BRICKS = register(new Block("infested_stone_bricks", builder().destroyTime(0.75f))); + public static final Block INFESTED_MOSSY_STONE_BRICKS = register(new Block("infested_mossy_stone_bricks", builder().destroyTime(0.75f))); + 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))); - public static final Block RED_MUSHROOM_BLOCK = register(new Block("red_mushroom_block", builder() + 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))); - public static final Block MUSHROOM_STEM = register(new Block("mushroom_stem", builder() + 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))); - public static final Block IRON_BARS = register(new Block("iron_bars", builder() + 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))); - public static final Block CHAIN = register(new Block("chain", builder() + public static final Block CHAIN = register(new Block("chain", builder().requiresCorrectToolForDrops().destroyTime(5.0f) .enumState(AXIS, Axis.VALUES) .booleanState(WATERLOGGED))); - public static final Block GLASS_PANE = register(new Block("glass_pane", builder() + 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))); - public static final Block PUMPKIN = register(new Block("pumpkin", builder())); - public static final Block MELON = register(new Block("melon", builder())); + public static final Block PUMPKIN = register(new Block("pumpkin", builder().destroyTime(1.0f))); + public static final Block MELON = register(new Block("melon", builder().destroyTime(1.0f))); public static final Block ATTACHED_PUMPKIN_STEM = register(new Block("attached_pumpkin_stem", builder() .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() @@ -766,13 +766,13 @@ public final class Blocks { .intState(AGE_7, 0, 7))); public static final Block MELON_STEM = register(new Block("melon_stem", builder() .intState(AGE_7, 0, 7))); - public static final Block VINE = register(new Block("vine", builder() + public static final Block VINE = register(new Block("vine", builder().destroyTime(0.2f) .booleanState(EAST) .booleanState(NORTH) .booleanState(SOUTH) .booleanState(UP) .booleanState(WEST))); - public static final Block GLOW_LICHEN = register(new Block("glow_lichen", builder() + public static final Block GLOW_LICHEN = register(new Block("glow_lichen", builder().destroyTime(0.2f) .booleanState(DOWN) .booleanState(EAST) .booleanState(NORTH) @@ -780,73 +780,73 @@ public final class Blocks { .booleanState(UP) .booleanState(WATERLOGGED) .booleanState(WEST))); - public static final Block OAK_FENCE_GATE = register(new Block("oak_fence_gate", builder() + 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))); - public static final Block BRICK_STAIRS = register(new Block("brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block STONE_BRICK_STAIRS = register(new Block("stone_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block MUD_BRICK_STAIRS = register(new Block("mud_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block MYCELIUM = register(new Block("mycelium", builder() + public static final Block MYCELIUM = register(new Block("mycelium", builder().destroyTime(0.6f) .booleanState(SNOWY))); public static final Block LILY_PAD = register(new Block("lily_pad", builder())); - public static final Block NETHER_BRICKS = register(new Block("nether_bricks", builder())); - public static final Block NETHER_BRICK_FENCE = register(new Block("nether_brick_fence", builder() + 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))); - public static final Block NETHER_BRICK_STAIRS = register(new Block("nether_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); public static final Block NETHER_WART = register(new Block("nether_wart", builder() .intState(AGE_3, 0, 3))); - public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder())); - public static final Block BREWING_STAND = register(new Block("brewing_stand", builder() + public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); + public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(0.5f) .booleanState(HAS_BOTTLE_0) .booleanState(HAS_BOTTLE_1) .booleanState(HAS_BOTTLE_2))); - public static final Block CAULDRON = register(new Block("cauldron", builder())); - public static final Block WATER_CAULDRON = register(new Block("water_cauldron", builder() + public static final Block CAULDRON = register(new Block("cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); + public static final Block WATER_CAULDRON = register(new Block("water_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .intState(LEVEL_CAULDRON, 1, 3))); - public static final Block LAVA_CAULDRON = register(new Block("lava_cauldron", builder())); - public static final Block POWDER_SNOW_CAULDRON = register(new Block("powder_snow_cauldron", builder() + public static final Block LAVA_CAULDRON = register(new Block("lava_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); + public static final Block POWDER_SNOW_CAULDRON = register(new Block("powder_snow_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .intState(LEVEL_CAULDRON, 1, 3))); - public static final Block END_PORTAL = register(new Block("end_portal", builder())); - public static final Block END_PORTAL_FRAME = register(new Block("end_portal_frame", builder() + public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().destroyTime(-1.0f))); + 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))); - public static final Block END_STONE = register(new Block("end_stone", builder())); - public static final Block DRAGON_EGG = register(new Block("dragon_egg", builder())); - public static final Block REDSTONE_LAMP = register(new Block("redstone_lamp", builder() + 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))); + public static final Block REDSTONE_LAMP = register(new Block("redstone_lamp", builder().destroyTime(0.3f) .booleanState(LIT))); - public static final Block COCOA = register(new Block("cocoa", builder() + public static final Block COCOA = register(new Block("cocoa", builder().destroyTime(0.2f) .intState(AGE_2, 0, 2) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block SANDSTONE_STAIRS = register(new Block("sandstone_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block EMERALD_ORE = register(new Block("emerald_ore", builder())); - public static final Block DEEPSLATE_EMERALD_ORE = register(new Block("deepslate_emerald_ore", builder())); - public static final Block ENDER_CHEST = register(new Block("ender_chest", builder() + 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().requiresCorrectToolForDrops().destroyTime(22.5f) .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() @@ -861,34 +861,34 @@ public final class Blocks { .booleanState(POWERED) .booleanState(SOUTH) .booleanState(WEST))); - public static final Block EMERALD_BLOCK = register(new Block("emerald_block", builder())); - public static final Block SPRUCE_STAIRS = register(new Block("spruce_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block BIRCH_STAIRS = register(new Block("birch_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block JUNGLE_STAIRS = register(new Block("jungle_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block COMMAND_BLOCK = register(new Block("command_block", builder() + public static final Block COMMAND_BLOCK = register(new Block("command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .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())); - public static final Block COBBLESTONE_WALL = register(new Block("cobblestone_wall", builder() + public static final Block BEACON = register(new Block("beacon", builder().setBlockEntity().destroyTime(3.0f))); + public static final Block COBBLESTONE_WALL = register(new Block("cobblestone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block MOSSY_COBBLESTONE_WALL = register(new Block("mossy_cobblestone_wall", builder() + public static final Block MOSSY_COBBLESTONE_WALL = register(new Block("mossy_cobblestone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") @@ -927,329 +927,329 @@ public final class Blocks { .intState(AGE_7, 0, 7))); public static final Block POTATOES = register(new Block("potatoes", builder() .intState(AGE_7, 0, 7))); - public static final Block OAK_BUTTON = register(new Block("oak_button", builder() + public static final Block OAK_BUTTON = register(new Block("oak_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block SPRUCE_BUTTON = register(new Block("spruce_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block BIRCH_BUTTON = register(new Block("birch_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block JUNGLE_BUTTON = register(new Block("jungle_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block ACACIA_BUTTON = register(new Block("acacia_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block CHERRY_BUTTON = register(new Block("cherry_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block DARK_OAK_BUTTON = register(new Block("dark_oak_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block MANGROVE_BUTTON = register(new Block("mangrove_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block BAMBOO_BUTTON = register(new Block("bamboo_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block SKELETON_SKULL = register(new Block("skeleton_skull", builder() + public static final Block SKELETON_SKULL = register(new Block("skeleton_skull", builder().setBlockEntity().destroyTime(1.0f) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block SKELETON_WALL_SKULL = register(new Block("skeleton_wall_skull", builder() + public static final Block SKELETON_WALL_SKULL = register(new Block("skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block WITHER_SKELETON_SKULL = register(new Block("wither_skeleton_skull", builder() + public static final Block WITHER_SKELETON_SKULL = register(new Block("wither_skeleton_skull", builder().setBlockEntity().destroyTime(1.0f) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block WITHER_SKELETON_WALL_SKULL = register(new Block("wither_skeleton_wall_skull", builder() + public static final Block WITHER_SKELETON_WALL_SKULL = register(new Block("wither_skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block ZOMBIE_HEAD = register(new Block("zombie_head", builder() + public static final Block ZOMBIE_HEAD = register(new Block("zombie_head", builder().setBlockEntity().destroyTime(1.0f) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block ZOMBIE_WALL_HEAD = register(new Block("zombie_wall_head", builder() + public static final Block ZOMBIE_WALL_HEAD = register(new Block("zombie_wall_head", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block PLAYER_HEAD = register(new Block("player_head", builder() + public static final Block PLAYER_HEAD = register(new Block("player_head", builder().setBlockEntity().destroyTime(1.0f) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block PLAYER_WALL_HEAD = register(new Block("player_wall_head", builder() + public static final Block PLAYER_WALL_HEAD = register(new Block("player_wall_head", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block CREEPER_HEAD = register(new Block("creeper_head", builder() + public static final Block CREEPER_HEAD = register(new Block("creeper_head", builder().setBlockEntity().destroyTime(1.0f) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block CREEPER_WALL_HEAD = register(new Block("creeper_wall_head", builder() + public static final Block CREEPER_WALL_HEAD = register(new Block("creeper_wall_head", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block DRAGON_HEAD = register(new Block("dragon_head", builder() + public static final Block DRAGON_HEAD = register(new Block("dragon_head", builder().setBlockEntity().destroyTime(1.0f) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block DRAGON_WALL_HEAD = register(new Block("dragon_wall_head", builder() + public static final Block DRAGON_WALL_HEAD = register(new Block("dragon_wall_head", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block PIGLIN_HEAD = register(new Block("piglin_head", builder() + public static final Block PIGLIN_HEAD = register(new Block("piglin_head", builder().setBlockEntity().destroyTime(1.0f) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block PIGLIN_WALL_HEAD = register(new Block("piglin_wall_head", builder() + public static final Block PIGLIN_WALL_HEAD = register(new Block("piglin_wall_head", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block ANVIL = register(new Block("anvil", builder() + public static final Block ANVIL = register(new Block("anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block CHIPPED_ANVIL = register(new Block("chipped_anvil", builder() + public static final Block CHIPPED_ANVIL = register(new Block("chipped_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block DAMAGED_ANVIL = register(new Block("damaged_anvil", builder() + public static final Block DAMAGED_ANVIL = register(new Block("damaged_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block TRAPPED_CHEST = register(new Block("trapped_chest", builder() + public static final Block TRAPPED_CHEST = register(new Block("trapped_chest", builder().setBlockEntity().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(CHEST_TYPE, "single", "left", "right") .booleanState(WATERLOGGED))); - public static final Block LIGHT_WEIGHTED_PRESSURE_PLATE = register(new Block("light_weighted_pressure_plate", builder() + public static final Block LIGHT_WEIGHTED_PRESSURE_PLATE = register(new Block("light_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) .intState(POWER, 0, 15))); - public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder() + public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) .intState(POWER, 0, 15))); - public static final Block COMPARATOR = register(new Block("comparator", builder() + public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity() .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(MODE_COMPARATOR, "compare", "subtract") .booleanState(POWERED))); - public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder() + public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder().setBlockEntity().destroyTime(0.2f) .booleanState(INVERTED) .intState(POWER, 0, 15))); - public static final Block REDSTONE_BLOCK = register(new Block("redstone_block", builder())); - public static final Block NETHER_QUARTZ_ORE = register(new Block("nether_quartz_ore", builder())); - public static final Block HOPPER = register(new Block("hopper", builder() + 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().requiresCorrectToolForDrops().destroyTime(3.0f) .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())); - public static final Block CHISELED_QUARTZ_BLOCK = register(new Block("chiseled_quartz_block", builder())); - public static final Block QUARTZ_PILLAR = register(new Block("quartz_pillar", builder() + 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))); - public static final Block QUARTZ_STAIRS = register(new Block("quartz_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block ACTIVATOR_RAIL = register(new Block("activator_rail", builder() + public static final Block ACTIVATOR_RAIL = register(new Block("activator_rail", builder().destroyTime(0.7f) .booleanState(POWERED) .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") .booleanState(WATERLOGGED))); - public static final Block DROPPER = register(new Block("dropper", builder() + public static final Block DROPPER = register(new Block("dropper", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) .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())); - public static final Block ORANGE_TERRACOTTA = register(new Block("orange_terracotta", builder())); - public static final Block MAGENTA_TERRACOTTA = register(new Block("magenta_terracotta", builder())); - public static final Block LIGHT_BLUE_TERRACOTTA = register(new Block("light_blue_terracotta", builder())); - public static final Block YELLOW_TERRACOTTA = register(new Block("yellow_terracotta", builder())); - public static final Block LIME_TERRACOTTA = register(new Block("lime_terracotta", builder())); - public static final Block PINK_TERRACOTTA = register(new Block("pink_terracotta", builder())); - public static final Block GRAY_TERRACOTTA = register(new Block("gray_terracotta", builder())); - public static final Block LIGHT_GRAY_TERRACOTTA = register(new Block("light_gray_terracotta", builder())); - public static final Block CYAN_TERRACOTTA = register(new Block("cyan_terracotta", builder())); - public static final Block PURPLE_TERRACOTTA = register(new Block("purple_terracotta", builder())); - public static final Block BLUE_TERRACOTTA = register(new Block("blue_terracotta", builder())); - public static final Block BROWN_TERRACOTTA = register(new Block("brown_terracotta", builder())); - public static final Block GREEN_TERRACOTTA = register(new Block("green_terracotta", builder())); - public static final Block RED_TERRACOTTA = register(new Block("red_terracotta", builder())); - public static final Block BLACK_TERRACOTTA = register(new Block("black_terracotta", builder())); - public static final Block WHITE_STAINED_GLASS_PANE = register(new Block("white_stained_glass_pane", builder() + 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))); + public static final Block LIGHT_BLUE_TERRACOTTA = register(new Block("light_blue_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block YELLOW_TERRACOTTA = register(new Block("yellow_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block LIME_TERRACOTTA = register(new Block("lime_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block PINK_TERRACOTTA = register(new Block("pink_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block GRAY_TERRACOTTA = register(new Block("gray_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block LIGHT_GRAY_TERRACOTTA = register(new Block("light_gray_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block CYAN_TERRACOTTA = register(new Block("cyan_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block PURPLE_TERRACOTTA = register(new Block("purple_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block BLUE_TERRACOTTA = register(new Block("blue_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block BROWN_TERRACOTTA = register(new Block("brown_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + public static final Block GREEN_TERRACOTTA = register(new Block("green_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + 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))); - public static final Block ORANGE_STAINED_GLASS_PANE = register(new Block("orange_stained_glass_pane", builder() + 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))); - public static final Block MAGENTA_STAINED_GLASS_PANE = register(new Block("magenta_stained_glass_pane", builder() + 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))); - public static final Block LIGHT_BLUE_STAINED_GLASS_PANE = register(new Block("light_blue_stained_glass_pane", builder() + 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))); - public static final Block YELLOW_STAINED_GLASS_PANE = register(new Block("yellow_stained_glass_pane", builder() + 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))); - public static final Block LIME_STAINED_GLASS_PANE = register(new Block("lime_stained_glass_pane", builder() + 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))); - public static final Block PINK_STAINED_GLASS_PANE = register(new Block("pink_stained_glass_pane", builder() + 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))); - public static final Block GRAY_STAINED_GLASS_PANE = register(new Block("gray_stained_glass_pane", builder() + 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))); - public static final Block LIGHT_GRAY_STAINED_GLASS_PANE = register(new Block("light_gray_stained_glass_pane", builder() + 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))); - public static final Block CYAN_STAINED_GLASS_PANE = register(new Block("cyan_stained_glass_pane", builder() + 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))); - public static final Block PURPLE_STAINED_GLASS_PANE = register(new Block("purple_stained_glass_pane", builder() + 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))); - public static final Block BLUE_STAINED_GLASS_PANE = register(new Block("blue_stained_glass_pane", builder() + 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))); - public static final Block BROWN_STAINED_GLASS_PANE = register(new Block("brown_stained_glass_pane", builder() + 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))); - public static final Block GREEN_STAINED_GLASS_PANE = register(new Block("green_stained_glass_pane", builder() + 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))); - public static final Block RED_STAINED_GLASS_PANE = register(new Block("red_stained_glass_pane", builder() + 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))); - public static final Block BLACK_STAINED_GLASS_PANE = register(new Block("black_stained_glass_pane", builder() + 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))); - public static final Block ACACIA_STAIRS = register(new Block("acacia_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block CHERRY_STAIRS = register(new Block("cherry_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_STAIRS = register(new Block("dark_oak_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block MANGROVE_STAIRS = register(new Block("mangrove_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block BAMBOO_STAIRS = register(new Block("bamboo_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block BAMBOO_MOSAIC_STAIRS = register(new Block("bamboo_mosaic_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); public static final Block SLIME_BLOCK = register(new Block("slime_block", builder())); - public static final Block BARRIER = register(new Block("barrier", builder() + public static final Block BARRIER = register(new Block("barrier", builder().destroyTime(-1.0f) .booleanState(WATERLOGGED))); - public static final Block LIGHT = register(new Block("light", builder() + public static final Block LIGHT = register(new Block("light", builder().destroyTime(-1.0f) .intState(LEVEL, 0, 15) .booleanState(WATERLOGGED))); - public static final Block IRON_TRAPDOOR = register(new Block("iron_trapdoor", builder() + public static final Block IRON_TRAPDOOR = register(new Block("iron_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(5.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block PRISMARINE = register(new Block("prismarine", builder())); - public static final Block PRISMARINE_BRICKS = register(new Block("prismarine_bricks", builder())); - public static final Block DARK_PRISMARINE = register(new Block("dark_prismarine", builder())); - public static final Block PRISMARINE_STAIRS = register(new Block("prismarine_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block PRISMARINE_BRICK_STAIRS = register(new Block("prismarine_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block DARK_PRISMARINE_STAIRS = register(new Block("dark_prismarine_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block PRISMARINE_SLAB = register(new Block("prismarine_slab", builder() + public static final Block PRISMARINE_SLAB = register(new Block("prismarine_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block PRISMARINE_BRICK_SLAB = register(new Block("prismarine_brick_slab", builder() + public static final Block PRISMARINE_BRICK_SLAB = register(new Block("prismarine_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block DARK_PRISMARINE_SLAB = register(new Block("dark_prismarine_slab", builder() + public static final Block DARK_PRISMARINE_SLAB = register(new Block("dark_prismarine_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block SEA_LANTERN = register(new Block("sea_lantern", builder())); - public static final Block HAY_BLOCK = register(new Block("hay_block", builder() + 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))); - public static final Block WHITE_CARPET = register(new Block("white_carpet", builder())); - public static final Block ORANGE_CARPET = register(new Block("orange_carpet", builder())); - public static final Block MAGENTA_CARPET = register(new Block("magenta_carpet", builder())); - public static final Block LIGHT_BLUE_CARPET = register(new Block("light_blue_carpet", builder())); - public static final Block YELLOW_CARPET = register(new Block("yellow_carpet", builder())); - public static final Block LIME_CARPET = register(new Block("lime_carpet", builder())); - public static final Block PINK_CARPET = register(new Block("pink_carpet", builder())); - public static final Block GRAY_CARPET = register(new Block("gray_carpet", builder())); - public static final Block LIGHT_GRAY_CARPET = register(new Block("light_gray_carpet", builder())); - public static final Block CYAN_CARPET = register(new Block("cyan_carpet", builder())); - public static final Block PURPLE_CARPET = register(new Block("purple_carpet", builder())); - public static final Block BLUE_CARPET = register(new Block("blue_carpet", builder())); - public static final Block BROWN_CARPET = register(new Block("brown_carpet", builder())); - public static final Block GREEN_CARPET = register(new Block("green_carpet", builder())); - public static final Block RED_CARPET = register(new Block("red_carpet", builder())); - public static final Block BLACK_CARPET = register(new Block("black_carpet", builder())); - public static final Block TERRACOTTA = register(new Block("terracotta", builder())); - public static final Block COAL_BLOCK = register(new Block("coal_block", builder())); - public static final Block PACKED_ICE = register(new Block("packed_ice", builder())); + 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))); + public static final Block LIGHT_BLUE_CARPET = register(new Block("light_blue_carpet", builder().destroyTime(0.1f))); + public static final Block YELLOW_CARPET = register(new Block("yellow_carpet", builder().destroyTime(0.1f))); + public static final Block LIME_CARPET = register(new Block("lime_carpet", builder().destroyTime(0.1f))); + public static final Block PINK_CARPET = register(new Block("pink_carpet", builder().destroyTime(0.1f))); + public static final Block GRAY_CARPET = register(new Block("gray_carpet", builder().destroyTime(0.1f))); + public static final Block LIGHT_GRAY_CARPET = register(new Block("light_gray_carpet", builder().destroyTime(0.1f))); + public static final Block CYAN_CARPET = register(new Block("cyan_carpet", builder().destroyTime(0.1f))); + public static final Block PURPLE_CARPET = register(new Block("purple_carpet", builder().destroyTime(0.1f))); + public static final Block BLUE_CARPET = register(new Block("blue_carpet", builder().destroyTime(0.1f))); + public static final Block BROWN_CARPET = register(new Block("brown_carpet", builder().destroyTime(0.1f))); + public static final Block GREEN_CARPET = register(new Block("green_carpet", builder().destroyTime(0.1f))); + public static final Block RED_CARPET = register(new Block("red_carpet", builder().destroyTime(0.1f))); + public static final Block BLACK_CARPET = register(new Block("black_carpet", builder().destroyTime(0.1f))); + public static final Block TERRACOTTA = register(new Block("terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); + 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() .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); public static final Block LILAC = register(new Block("lilac", builder() @@ -1262,285 +1262,285 @@ public final class Blocks { .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); public static final Block LARGE_FERN = register(new Block("large_fern", builder() .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder() + public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder() + public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder() + public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder() + public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder() + public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder() + public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder() + public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder() + public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder() + public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder() + public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder() + public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder() + public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder() + public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder() + public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder() + public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder() + public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); - public static final Block WHITE_WALL_BANNER = register(new BannerBlock("white_wall_banner", 0, builder() + public static final Block WHITE_WALL_BANNER = register(new BannerBlock("white_wall_banner", 0, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block ORANGE_WALL_BANNER = register(new BannerBlock("orange_wall_banner", 1, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block MAGENTA_WALL_BANNER = register(new BannerBlock("magenta_wall_banner", 2, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block LIGHT_BLUE_WALL_BANNER = register(new BannerBlock("light_blue_wall_banner", 3, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block YELLOW_WALL_BANNER = register(new BannerBlock("yellow_wall_banner", 4, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block LIME_WALL_BANNER = register(new BannerBlock("lime_wall_banner", 5, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block PINK_WALL_BANNER = register(new BannerBlock("pink_wall_banner", 6, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block GRAY_WALL_BANNER = register(new BannerBlock("gray_wall_banner", 7, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block LIGHT_GRAY_WALL_BANNER = register(new BannerBlock("light_gray_wall_banner", 8, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block CYAN_WALL_BANNER = register(new BannerBlock("cyan_wall_banner", 9, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block PURPLE_WALL_BANNER = register(new BannerBlock("purple_wall_banner", 10, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block BLUE_WALL_BANNER = register(new BannerBlock("blue_wall_banner", 11, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block BROWN_WALL_BANNER = register(new BannerBlock("brown_wall_banner", 12, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block GREEN_WALL_BANNER = register(new BannerBlock("green_wall_banner", 13, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block RED_WALL_BANNER = register(new BannerBlock("red_wall_banner", 14, builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block BLACK_WALL_BANNER = register(new BannerBlock("black_wall_banner", 15, builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block RED_SANDSTONE = register(new Block("red_sandstone", builder())); - public static final Block CHISELED_RED_SANDSTONE = register(new Block("chiseled_red_sandstone", builder())); - public static final Block CUT_RED_SANDSTONE = register(new Block("cut_red_sandstone", builder())); - public static final Block RED_SANDSTONE_STAIRS = register(new Block("red_sandstone_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block OAK_SLAB = register(new Block("oak_slab", builder() + public static final Block OAK_SLAB = register(new Block("oak_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block SPRUCE_SLAB = register(new Block("spruce_slab", builder() + public static final Block SPRUCE_SLAB = register(new Block("spruce_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block BIRCH_SLAB = register(new Block("birch_slab", builder() + public static final Block BIRCH_SLAB = register(new Block("birch_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block JUNGLE_SLAB = register(new Block("jungle_slab", builder() + public static final Block JUNGLE_SLAB = register(new Block("jungle_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block ACACIA_SLAB = register(new Block("acacia_slab", builder() + public static final Block ACACIA_SLAB = register(new Block("acacia_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block CHERRY_SLAB = register(new Block("cherry_slab", builder() + public static final Block CHERRY_SLAB = register(new Block("cherry_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_SLAB = register(new Block("dark_oak_slab", builder() + public static final Block DARK_OAK_SLAB = register(new Block("dark_oak_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block MANGROVE_SLAB = register(new Block("mangrove_slab", builder() + public static final Block MANGROVE_SLAB = register(new Block("mangrove_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block BAMBOO_SLAB = register(new Block("bamboo_slab", builder() + public static final Block BAMBOO_SLAB = register(new Block("bamboo_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block BAMBOO_MOSAIC_SLAB = register(new Block("bamboo_mosaic_slab", builder() + public static final Block BAMBOO_MOSAIC_SLAB = register(new Block("bamboo_mosaic_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block STONE_SLAB = register(new Block("stone_slab", builder() + public static final Block STONE_SLAB = register(new Block("stone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block SMOOTH_STONE_SLAB = register(new Block("smooth_stone_slab", builder() + public static final Block SMOOTH_STONE_SLAB = register(new Block("smooth_stone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block SANDSTONE_SLAB = register(new Block("sandstone_slab", builder() + public static final Block SANDSTONE_SLAB = register(new Block("sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block CUT_SANDSTONE_SLAB = register(new Block("cut_sandstone_slab", builder() + public static final Block CUT_SANDSTONE_SLAB = register(new Block("cut_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block PETRIFIED_OAK_SLAB = register(new Block("petrified_oak_slab", builder() + public static final Block PETRIFIED_OAK_SLAB = register(new Block("petrified_oak_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block COBBLESTONE_SLAB = register(new Block("cobblestone_slab", builder() + public static final Block COBBLESTONE_SLAB = register(new Block("cobblestone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block BRICK_SLAB = register(new Block("brick_slab", builder() + public static final Block BRICK_SLAB = register(new Block("brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block STONE_BRICK_SLAB = register(new Block("stone_brick_slab", builder() + public static final Block STONE_BRICK_SLAB = register(new Block("stone_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block MUD_BRICK_SLAB = register(new Block("mud_brick_slab", builder() + public static final Block MUD_BRICK_SLAB = register(new Block("mud_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block NETHER_BRICK_SLAB = register(new Block("nether_brick_slab", builder() + public static final Block NETHER_BRICK_SLAB = register(new Block("nether_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block QUARTZ_SLAB = register(new Block("quartz_slab", builder() + public static final Block QUARTZ_SLAB = register(new Block("quartz_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block RED_SANDSTONE_SLAB = register(new Block("red_sandstone_slab", builder() + public static final Block RED_SANDSTONE_SLAB = register(new Block("red_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block CUT_RED_SANDSTONE_SLAB = register(new Block("cut_red_sandstone_slab", builder() + public static final Block CUT_RED_SANDSTONE_SLAB = register(new Block("cut_red_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block PURPUR_SLAB = register(new Block("purpur_slab", builder() + public static final Block PURPUR_SLAB = register(new Block("purpur_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block SMOOTH_STONE = register(new Block("smooth_stone", builder())); - public static final Block SMOOTH_SANDSTONE = register(new Block("smooth_sandstone", builder())); - public static final Block SMOOTH_QUARTZ = register(new Block("smooth_quartz", builder())); - public static final Block SMOOTH_RED_SANDSTONE = register(new Block("smooth_red_sandstone", builder())); - public static final Block SPRUCE_FENCE_GATE = register(new Block("spruce_fence_gate", builder() + 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))); - public static final Block BIRCH_FENCE_GATE = register(new Block("birch_fence_gate", builder() + 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))); - public static final Block JUNGLE_FENCE_GATE = register(new Block("jungle_fence_gate", builder() + 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))); - public static final Block ACACIA_FENCE_GATE = register(new Block("acacia_fence_gate", builder() + 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))); - public static final Block CHERRY_FENCE_GATE = register(new Block("cherry_fence_gate", builder() + 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))); - public static final Block DARK_OAK_FENCE_GATE = register(new Block("dark_oak_fence_gate", builder() + 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))); - public static final Block MANGROVE_FENCE_GATE = register(new Block("mangrove_fence_gate", builder() + 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))); - public static final Block BAMBOO_FENCE_GATE = register(new Block("bamboo_fence_gate", builder() + 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))); - public static final Block SPRUCE_FENCE = register(new Block("spruce_fence", builder() + 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))); - public static final Block BIRCH_FENCE = register(new Block("birch_fence", builder() + 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))); - public static final Block JUNGLE_FENCE = register(new Block("jungle_fence", builder() + 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))); - public static final Block ACACIA_FENCE = register(new Block("acacia_fence", builder() + 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))); - public static final Block CHERRY_FENCE = register(new Block("cherry_fence", builder() + 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))); - public static final Block DARK_OAK_FENCE = register(new Block("dark_oak_fence", builder() + 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))); - public static final Block MANGROVE_FENCE = register(new Block("mangrove_fence", builder() + 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))); - public static final Block BAMBOO_FENCE = register(new Block("bamboo_fence", builder() + 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))); - public static final Block SPRUCE_DOOR = register(new Block("spruce_door", builder() + public static final Block SPRUCE_DOOR = register(new Block("spruce_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block BIRCH_DOOR = register(new Block("birch_door", builder() + public static final Block BIRCH_DOOR = register(new Block("birch_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block JUNGLE_DOOR = register(new Block("jungle_door", builder() + public static final Block JUNGLE_DOOR = register(new Block("jungle_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block ACACIA_DOOR = register(new Block("acacia_door", builder() + public static final Block ACACIA_DOOR = register(new Block("acacia_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block CHERRY_DOOR = register(new Block("cherry_door", builder() + public static final Block CHERRY_DOOR = register(new Block("cherry_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block DARK_OAK_DOOR = register(new Block("dark_oak_door", builder() + public static final Block DARK_OAK_DOOR = register(new Block("dark_oak_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block MANGROVE_DOOR = register(new Block("mangrove_door", builder() + public static final Block MANGROVE_DOOR = register(new Block("mangrove_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block BAMBOO_DOOR = register(new Block("bamboo_door", builder() + public static final Block BAMBOO_DOOR = register(new Block("bamboo_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") @@ -1548,24 +1548,24 @@ public final class Blocks { .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))); - public static final Block CHORUS_PLANT = register(new Block("chorus_plant", builder() + public static final Block CHORUS_PLANT = register(new Block("chorus_plant", builder().destroyTime(0.4f) .booleanState(DOWN) .booleanState(EAST) .booleanState(NORTH) .booleanState(SOUTH) .booleanState(UP) .booleanState(WEST))); - public static final Block CHORUS_FLOWER = register(new Block("chorus_flower", builder() + public static final Block CHORUS_FLOWER = register(new Block("chorus_flower", builder().destroyTime(0.4f) .intState(AGE_5, 0, 5))); - public static final Block PURPUR_BLOCK = register(new Block("purpur_block", builder())); - public static final Block PURPUR_PILLAR = register(new Block("purpur_pillar", builder() + 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))); - public static final Block PURPUR_STAIRS = register(new Block("purpur_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block END_STONE_BRICKS = register(new Block("end_stone_bricks", builder())); + 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() .intState(AGE_1, 0, 1))); public static final Block PITCHER_CROP = register(new Block("pitcher_crop", builder() @@ -1575,151 +1575,151 @@ public final class Blocks { .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); public static final Block BEETROOTS = register(new Block("beetroots", builder() .intState(AGE_3, 0, 3))); - public static final Block DIRT_PATH = register(new Block("dirt_path", builder())); - public static final Block END_GATEWAY = register(new Block("end_gateway", builder())); - public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder() + 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().destroyTime(-1.0f))); + public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .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() + public static final Block CHAIN_COMMAND_BLOCK = register(new Block("chain_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .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() + public static final Block FROSTED_ICE = register(new Block("frosted_ice", builder().destroyTime(0.5f) .intState(AGE_3, 0, 3))); - public static final Block MAGMA_BLOCK = register(new Block("magma_block", builder())); - public static final Block NETHER_WART_BLOCK = register(new Block("nether_wart_block", builder())); - public static final Block RED_NETHER_BRICKS = register(new Block("red_nether_bricks", builder())); - public static final Block BONE_BLOCK = register(new Block("bone_block", builder() + 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))); public static final Block STRUCTURE_VOID = register(new Block("structure_void", builder())); - public static final Block OBSERVER = register(new Block("observer", builder() + 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))); - public static final Block SHULKER_BOX = register(new Block("shulker_box", builder() + public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block WHITE_SHULKER_BOX = register(new Block("white_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block ORANGE_SHULKER_BOX = register(new Block("orange_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block MAGENTA_SHULKER_BOX = register(new Block("magenta_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block LIGHT_BLUE_SHULKER_BOX = register(new Block("light_blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block YELLOW_SHULKER_BOX = register(new Block("yellow_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block LIME_SHULKER_BOX = register(new Block("lime_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block PINK_SHULKER_BOX = register(new Block("pink_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block GRAY_SHULKER_BOX = register(new Block("gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block LIGHT_GRAY_SHULKER_BOX = register(new Block("light_gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block CYAN_SHULKER_BOX = register(new Block("cyan_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block PURPLE_SHULKER_BOX = register(new Block("purple_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block BLUE_SHULKER_BOX = register(new Block("blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block BROWN_SHULKER_BOX = register(new Block("brown_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block GREEN_SHULKER_BOX = register(new Block("green_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block RED_SHULKER_BOX = register(new Block("red_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block BLACK_SHULKER_BOX = register(new Block("black_shulker_box", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block WHITE_GLAZED_TERRACOTTA = register(new Block("white_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block ORANGE_GLAZED_TERRACOTTA = register(new Block("orange_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block MAGENTA_GLAZED_TERRACOTTA = register(new Block("magenta_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block LIGHT_BLUE_GLAZED_TERRACOTTA = register(new Block("light_blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block YELLOW_GLAZED_TERRACOTTA = register(new Block("yellow_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block LIME_GLAZED_TERRACOTTA = register(new Block("lime_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block PINK_GLAZED_TERRACOTTA = register(new Block("pink_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block GRAY_GLAZED_TERRACOTTA = register(new Block("gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block LIGHT_GRAY_GLAZED_TERRACOTTA = register(new Block("light_gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block CYAN_GLAZED_TERRACOTTA = register(new Block("cyan_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block PURPLE_GLAZED_TERRACOTTA = register(new Block("purple_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block BLUE_GLAZED_TERRACOTTA = register(new Block("blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block BROWN_GLAZED_TERRACOTTA = register(new Block("brown_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block GREEN_GLAZED_TERRACOTTA = register(new Block("green_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block RED_GLAZED_TERRACOTTA = register(new Block("red_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .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() + public static final Block BLACK_GLAZED_TERRACOTTA = register(new Block("black_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block WHITE_CONCRETE = register(new Block("white_concrete", builder())); - public static final Block ORANGE_CONCRETE = register(new Block("orange_concrete", builder())); - public static final Block MAGENTA_CONCRETE = register(new Block("magenta_concrete", builder())); - public static final Block LIGHT_BLUE_CONCRETE = register(new Block("light_blue_concrete", builder())); - public static final Block YELLOW_CONCRETE = register(new Block("yellow_concrete", builder())); - public static final Block LIME_CONCRETE = register(new Block("lime_concrete", builder())); - public static final Block PINK_CONCRETE = register(new Block("pink_concrete", builder())); - public static final Block GRAY_CONCRETE = register(new Block("gray_concrete", builder())); - public static final Block LIGHT_GRAY_CONCRETE = register(new Block("light_gray_concrete", builder())); - public static final Block CYAN_CONCRETE = register(new Block("cyan_concrete", builder())); - public static final Block PURPLE_CONCRETE = register(new Block("purple_concrete", builder())); - public static final Block BLUE_CONCRETE = register(new Block("blue_concrete", builder())); - public static final Block BROWN_CONCRETE = register(new Block("brown_concrete", builder())); - public static final Block GREEN_CONCRETE = register(new Block("green_concrete", builder())); - public static final Block RED_CONCRETE = register(new Block("red_concrete", builder())); - public static final Block BLACK_CONCRETE = register(new Block("black_concrete", builder())); - public static final Block WHITE_CONCRETE_POWDER = register(new Block("white_concrete_powder", builder())); - public static final Block ORANGE_CONCRETE_POWDER = register(new Block("orange_concrete_powder", builder())); - public static final Block MAGENTA_CONCRETE_POWDER = register(new Block("magenta_concrete_powder", builder())); - public static final Block LIGHT_BLUE_CONCRETE_POWDER = register(new Block("light_blue_concrete_powder", builder())); - public static final Block YELLOW_CONCRETE_POWDER = register(new Block("yellow_concrete_powder", builder())); - public static final Block LIME_CONCRETE_POWDER = register(new Block("lime_concrete_powder", builder())); - public static final Block PINK_CONCRETE_POWDER = register(new Block("pink_concrete_powder", builder())); - public static final Block GRAY_CONCRETE_POWDER = register(new Block("gray_concrete_powder", builder())); - public static final Block LIGHT_GRAY_CONCRETE_POWDER = register(new Block("light_gray_concrete_powder", builder())); - public static final Block CYAN_CONCRETE_POWDER = register(new Block("cyan_concrete_powder", builder())); - public static final Block PURPLE_CONCRETE_POWDER = register(new Block("purple_concrete_powder", builder())); - public static final Block BLUE_CONCRETE_POWDER = register(new Block("blue_concrete_powder", builder())); - public static final Block BROWN_CONCRETE_POWDER = register(new Block("brown_concrete_powder", builder())); - public static final Block GREEN_CONCRETE_POWDER = register(new Block("green_concrete_powder", builder())); - public static final Block RED_CONCRETE_POWDER = register(new Block("red_concrete_powder", builder())); - public static final Block BLACK_CONCRETE_POWDER = register(new Block("black_concrete_powder", builder())); + 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))); + public static final Block LIGHT_BLUE_CONCRETE = register(new Block("light_blue_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block YELLOW_CONCRETE = register(new Block("yellow_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block LIME_CONCRETE = register(new Block("lime_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block PINK_CONCRETE = register(new Block("pink_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block GRAY_CONCRETE = register(new Block("gray_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block LIGHT_GRAY_CONCRETE = register(new Block("light_gray_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block CYAN_CONCRETE = register(new Block("cyan_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block PURPLE_CONCRETE = register(new Block("purple_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block BLUE_CONCRETE = register(new Block("blue_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block BROWN_CONCRETE = register(new Block("brown_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block GREEN_CONCRETE = register(new Block("green_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block RED_CONCRETE = register(new Block("red_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block BLACK_CONCRETE = register(new Block("black_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); + public static final Block WHITE_CONCRETE_POWDER = register(new Block("white_concrete_powder", builder().destroyTime(0.5f))); + public static final Block ORANGE_CONCRETE_POWDER = register(new Block("orange_concrete_powder", builder().destroyTime(0.5f))); + public static final Block MAGENTA_CONCRETE_POWDER = register(new Block("magenta_concrete_powder", builder().destroyTime(0.5f))); + public static final Block LIGHT_BLUE_CONCRETE_POWDER = register(new Block("light_blue_concrete_powder", builder().destroyTime(0.5f))); + public static final Block YELLOW_CONCRETE_POWDER = register(new Block("yellow_concrete_powder", builder().destroyTime(0.5f))); + public static final Block LIME_CONCRETE_POWDER = register(new Block("lime_concrete_powder", builder().destroyTime(0.5f))); + public static final Block PINK_CONCRETE_POWDER = register(new Block("pink_concrete_powder", builder().destroyTime(0.5f))); + public static final Block GRAY_CONCRETE_POWDER = register(new Block("gray_concrete_powder", builder().destroyTime(0.5f))); + public static final Block LIGHT_GRAY_CONCRETE_POWDER = register(new Block("light_gray_concrete_powder", builder().destroyTime(0.5f))); + public static final Block CYAN_CONCRETE_POWDER = register(new Block("cyan_concrete_powder", builder().destroyTime(0.5f))); + public static final Block PURPLE_CONCRETE_POWDER = register(new Block("purple_concrete_powder", builder().destroyTime(0.5f))); + public static final Block BLUE_CONCRETE_POWDER = register(new Block("blue_concrete_powder", builder().destroyTime(0.5f))); + public static final Block BROWN_CONCRETE_POWDER = register(new Block("brown_concrete_powder", builder().destroyTime(0.5f))); + public static final Block GREEN_CONCRETE_POWDER = register(new Block("green_concrete_powder", builder().destroyTime(0.5f))); + 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() .intState(AGE_25, 0, 25))); public static final Block KELP_PLANT = register(new Block("kelp_plant", builder())); - public static final Block DRIED_KELP_BLOCK = register(new Block("dried_kelp_block", builder())); - public static final Block TURTLE_EGG = register(new Block("turtle_egg", builder() + 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) .intState(EGGS, 1, 4) .intState(HATCH, 0, 2))); - public static final Block SNIFFER_EGG = register(new Block("sniffer_egg", builder() + public static final Block SNIFFER_EGG = register(new Block("sniffer_egg", builder().destroyTime(0.5f) .intState(HATCH, 0, 2))); - public static final Block DEAD_TUBE_CORAL_BLOCK = register(new Block("dead_tube_coral_block", builder())); - public static final Block DEAD_BRAIN_CORAL_BLOCK = register(new Block("dead_brain_coral_block", builder())); - public static final Block DEAD_BUBBLE_CORAL_BLOCK = register(new Block("dead_bubble_coral_block", builder())); - public static final Block DEAD_FIRE_CORAL_BLOCK = register(new Block("dead_fire_coral_block", builder())); - public static final Block DEAD_HORN_CORAL_BLOCK = register(new Block("dead_horn_coral_block", builder())); - public static final Block TUBE_CORAL_BLOCK = register(new Block("tube_coral_block", builder())); - public static final Block BRAIN_CORAL_BLOCK = register(new Block("brain_coral_block", builder())); - public static final Block BUBBLE_CORAL_BLOCK = register(new Block("bubble_coral_block", builder())); - public static final Block FIRE_CORAL_BLOCK = register(new Block("fire_coral_block", builder())); - public static final Block HORN_CORAL_BLOCK = register(new Block("horn_coral_block", builder())); - public static final Block DEAD_TUBE_CORAL = register(new Block("dead_tube_coral", builder() + 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))); + public static final Block DEAD_FIRE_CORAL_BLOCK = register(new Block("dead_fire_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block DEAD_HORN_CORAL_BLOCK = register(new Block("dead_horn_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block TUBE_CORAL_BLOCK = register(new Block("tube_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block BRAIN_CORAL_BLOCK = register(new Block("brain_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block BUBBLE_CORAL_BLOCK = register(new Block("bubble_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + 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))); - public static final Block DEAD_BRAIN_CORAL = register(new Block("dead_brain_coral", builder() + public static final Block DEAD_BRAIN_CORAL = register(new Block("dead_brain_coral", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block DEAD_BUBBLE_CORAL = register(new Block("dead_bubble_coral", builder() + public static final Block DEAD_BUBBLE_CORAL = register(new Block("dead_bubble_coral", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block DEAD_FIRE_CORAL = register(new Block("dead_fire_coral", builder() + public static final Block DEAD_FIRE_CORAL = register(new Block("dead_fire_coral", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block DEAD_HORN_CORAL = register(new Block("dead_horn_coral", builder() + public static final Block DEAD_HORN_CORAL = register(new Block("dead_horn_coral", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); public static final Block TUBE_CORAL = register(new Block("tube_coral", builder() .booleanState(WATERLOGGED))); @@ -1731,15 +1731,15 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block HORN_CORAL = register(new Block("horn_coral", builder() .booleanState(WATERLOGGED))); - public static final Block DEAD_TUBE_CORAL_FAN = register(new Block("dead_tube_coral_fan", builder() + public static final Block DEAD_TUBE_CORAL_FAN = register(new Block("dead_tube_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block DEAD_BRAIN_CORAL_FAN = register(new Block("dead_brain_coral_fan", builder() + public static final Block DEAD_BRAIN_CORAL_FAN = register(new Block("dead_brain_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block DEAD_BUBBLE_CORAL_FAN = register(new Block("dead_bubble_coral_fan", builder() + public static final Block DEAD_BUBBLE_CORAL_FAN = register(new Block("dead_bubble_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block DEAD_FIRE_CORAL_FAN = register(new Block("dead_fire_coral_fan", builder() + public static final Block DEAD_FIRE_CORAL_FAN = register(new Block("dead_fire_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block DEAD_HORN_CORAL_FAN = register(new Block("dead_horn_coral_fan", builder() + public static final Block DEAD_HORN_CORAL_FAN = register(new Block("dead_horn_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); public static final Block TUBE_CORAL_FAN = register(new Block("tube_coral_fan", builder() .booleanState(WATERLOGGED))); @@ -1751,19 +1751,19 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block HORN_CORAL_FAN = register(new Block("horn_coral_fan", builder() .booleanState(WATERLOGGED))); - public static final Block DEAD_TUBE_CORAL_WALL_FAN = register(new Block("dead_tube_coral_wall_fan", builder() + 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))); - public static final Block DEAD_BRAIN_CORAL_WALL_FAN = register(new Block("dead_brain_coral_wall_fan", builder() + 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))); - public static final Block DEAD_BUBBLE_CORAL_WALL_FAN = register(new Block("dead_bubble_coral_wall_fan", builder() + 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))); - public static final Block DEAD_FIRE_CORAL_WALL_FAN = register(new Block("dead_fire_coral_wall_fan", builder() + 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))); - public static final Block DEAD_HORN_CORAL_WALL_FAN = register(new Block("dead_horn_coral_wall_fan", builder() + 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))); public static final Block TUBE_CORAL_WALL_FAN = register(new Block("tube_coral_wall_fan", builder() @@ -1784,11 +1784,11 @@ public final class Blocks { public static final Block SEA_PICKLE = register(new Block("sea_pickle", builder() .intState(PICKLES, 1, 4) .booleanState(WATERLOGGED))); - public static final Block BLUE_ICE = register(new Block("blue_ice", builder())); - public static final Block CONDUIT = register(new Block("conduit", builder() + 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().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder())); - public static final Block BAMBOO = register(new Block("bamboo", builder() + public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder().destroyTime(1.0f))); + public static final Block BAMBOO = register(new Block("bamboo", builder().destroyTime(1.0f) .intState(AGE_1, 0, 1) .enumState(BAMBOO_LEAVES, "none", "small", "large") .intState(STAGE, 0, 1))); @@ -1797,200 +1797,200 @@ public final class Blocks { public static final Block CAVE_AIR = register(new Block("cave_air", builder())); public static final Block BUBBLE_COLUMN = register(new Block("bubble_column", builder() .booleanState(DRAG))); - public static final Block POLISHED_GRANITE_STAIRS = register(new Block("polished_granite_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block SMOOTH_RED_SANDSTONE_STAIRS = register(new Block("smooth_red_sandstone_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block MOSSY_STONE_BRICK_STAIRS = register(new Block("mossy_stone_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block POLISHED_DIORITE_STAIRS = register(new Block("polished_diorite_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block MOSSY_COBBLESTONE_STAIRS = register(new Block("mossy_cobblestone_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block END_STONE_BRICK_STAIRS = register(new Block("end_stone_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block STONE_STAIRS = register(new Block("stone_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block SMOOTH_SANDSTONE_STAIRS = register(new Block("smooth_sandstone_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block SMOOTH_QUARTZ_STAIRS = register(new Block("smooth_quartz_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block GRANITE_STAIRS = register(new Block("granite_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block ANDESITE_STAIRS = register(new Block("andesite_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block RED_NETHER_BRICK_STAIRS = register(new Block("red_nether_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block POLISHED_ANDESITE_STAIRS = register(new Block("polished_andesite_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block DIORITE_STAIRS = register(new Block("diorite_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block POLISHED_GRANITE_SLAB = register(new Block("polished_granite_slab", builder() + public static final Block POLISHED_GRANITE_SLAB = register(new Block("polished_granite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block SMOOTH_RED_SANDSTONE_SLAB = register(new Block("smooth_red_sandstone_slab", builder() + public static final Block SMOOTH_RED_SANDSTONE_SLAB = register(new Block("smooth_red_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block MOSSY_STONE_BRICK_SLAB = register(new Block("mossy_stone_brick_slab", builder() + public static final Block MOSSY_STONE_BRICK_SLAB = register(new Block("mossy_stone_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_DIORITE_SLAB = register(new Block("polished_diorite_slab", builder() + public static final Block POLISHED_DIORITE_SLAB = register(new Block("polished_diorite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block MOSSY_COBBLESTONE_SLAB = register(new Block("mossy_cobblestone_slab", builder() + public static final Block MOSSY_COBBLESTONE_SLAB = register(new Block("mossy_cobblestone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block END_STONE_BRICK_SLAB = register(new Block("end_stone_brick_slab", builder() + public static final Block END_STONE_BRICK_SLAB = register(new Block("end_stone_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block SMOOTH_SANDSTONE_SLAB = register(new Block("smooth_sandstone_slab", builder() + public static final Block SMOOTH_SANDSTONE_SLAB = register(new Block("smooth_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block SMOOTH_QUARTZ_SLAB = register(new Block("smooth_quartz_slab", builder() + public static final Block SMOOTH_QUARTZ_SLAB = register(new Block("smooth_quartz_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block GRANITE_SLAB = register(new Block("granite_slab", builder() + public static final Block GRANITE_SLAB = register(new Block("granite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block ANDESITE_SLAB = register(new Block("andesite_slab", builder() + public static final Block ANDESITE_SLAB = register(new Block("andesite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block RED_NETHER_BRICK_SLAB = register(new Block("red_nether_brick_slab", builder() + public static final Block RED_NETHER_BRICK_SLAB = register(new Block("red_nether_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_ANDESITE_SLAB = register(new Block("polished_andesite_slab", builder() + public static final Block POLISHED_ANDESITE_SLAB = register(new Block("polished_andesite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block DIORITE_SLAB = register(new Block("diorite_slab", builder() + public static final Block DIORITE_SLAB = register(new Block("diorite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block BRICK_WALL = register(new Block("brick_wall", builder() + public static final Block BRICK_WALL = register(new Block("brick_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block PRISMARINE_WALL = register(new Block("prismarine_wall", builder() + public static final Block PRISMARINE_WALL = register(new Block("prismarine_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block RED_SANDSTONE_WALL = register(new Block("red_sandstone_wall", builder() + public static final Block RED_SANDSTONE_WALL = register(new Block("red_sandstone_wall", builder().requiresCorrectToolForDrops().destroyTime(0.8f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block MOSSY_STONE_BRICK_WALL = register(new Block("mossy_stone_brick_wall", builder() + public static final Block MOSSY_STONE_BRICK_WALL = register(new Block("mossy_stone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block GRANITE_WALL = register(new Block("granite_wall", builder() + public static final Block GRANITE_WALL = register(new Block("granite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block STONE_BRICK_WALL = register(new Block("stone_brick_wall", builder() + public static final Block STONE_BRICK_WALL = register(new Block("stone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block MUD_BRICK_WALL = register(new Block("mud_brick_wall", builder() + public static final Block MUD_BRICK_WALL = register(new Block("mud_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block NETHER_BRICK_WALL = register(new Block("nether_brick_wall", builder() + public static final Block NETHER_BRICK_WALL = register(new Block("nether_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block ANDESITE_WALL = register(new Block("andesite_wall", builder() + public static final Block ANDESITE_WALL = register(new Block("andesite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block RED_NETHER_BRICK_WALL = register(new Block("red_nether_brick_wall", builder() + public static final Block RED_NETHER_BRICK_WALL = register(new Block("red_nether_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block SANDSTONE_WALL = register(new Block("sandstone_wall", builder() + public static final Block SANDSTONE_WALL = register(new Block("sandstone_wall", builder().requiresCorrectToolForDrops().destroyTime(0.8f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block END_STONE_BRICK_WALL = register(new Block("end_stone_brick_wall", builder() + public static final Block END_STONE_BRICK_WALL = register(new Block("end_stone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block DIORITE_WALL = register(new Block("diorite_wall", builder() + public static final Block DIORITE_WALL = register(new Block("diorite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") @@ -2001,75 +2001,75 @@ public final class Blocks { .booleanState(BOTTOM) .intState(STABILITY_DISTANCE, 0, 7) .booleanState(WATERLOGGED))); - public static final Block LOOM = register(new Block("loom", builder() + public static final Block LOOM = register(new Block("loom", builder().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block BARREL = register(new Block("barrel", builder() + public static final Block BARREL = register(new Block("barrel", builder().setBlockEntity().destroyTime(2.5f) .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() + public static final Block SMOKER = register(new Block("smoker", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) .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() + public static final Block BLAST_FURNACE = register(new Block("blast_furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) .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())); - public static final Block FLETCHING_TABLE = register(new Block("fletching_table", builder())); - public static final Block GRINDSTONE = register(new Block("grindstone", builder() + 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) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block LECTERN = register(new Block("lectern", builder() + public static final Block LECTERN = register(new Block("lectern", builder().setBlockEntity().destroyTime(2.5f) .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())); - public static final Block STONECUTTER = register(new Block("stonecutter", builder() + 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))); - public static final Block BELL = register(new Block("bell", builder() + public static final Block BELL = register(new Block("bell", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f) .enumState(BELL_ATTACHMENT, "floor", "ceiling", "single_wall", "double_wall") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block LANTERN = register(new Block("lantern", builder() + public static final Block LANTERN = register(new Block("lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .booleanState(HANGING) .booleanState(WATERLOGGED))); - public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder() + public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .booleanState(HANGING) .booleanState(WATERLOGGED))); - public static final Block CAMPFIRE = register(new Block("campfire", builder() + public static final Block CAMPFIRE = register(new Block("campfire", builder().setBlockEntity().destroyTime(2.0f) .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() + public static final Block SOUL_CAMPFIRE = register(new Block("soul_campfire", builder().setBlockEntity().destroyTime(2.0f) .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() .intState(AGE_3, 0, 3))); - public static final Block WARPED_STEM = register(new Block("warped_stem", builder() + public static final Block WARPED_STEM = register(new Block("warped_stem", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_WARPED_STEM = register(new Block("stripped_warped_stem", builder() + public static final Block STRIPPED_WARPED_STEM = register(new Block("stripped_warped_stem", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block WARPED_HYPHAE = register(new Block("warped_hyphae", builder() + public static final Block WARPED_HYPHAE = register(new Block("warped_hyphae", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_WARPED_HYPHAE = register(new Block("stripped_warped_hyphae", builder() + public static final Block STRIPPED_WARPED_HYPHAE = register(new Block("stripped_warped_hyphae", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block WARPED_NYLIUM = register(new Block("warped_nylium", builder())); + 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())); - public static final Block WARPED_WART_BLOCK = register(new Block("warped_wart_block", builder())); + 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())); public static final Block NETHER_SPROUTS = register(new Block("nether_sprouts", builder())); - public static final Block CRIMSON_STEM = register(new Block("crimson_stem", builder() + public static final Block CRIMSON_STEM = register(new Block("crimson_stem", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_CRIMSON_STEM = register(new Block("stripped_crimson_stem", builder() + public static final Block STRIPPED_CRIMSON_STEM = register(new Block("stripped_crimson_stem", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block CRIMSON_HYPHAE = register(new Block("crimson_hyphae", builder() + public static final Block CRIMSON_HYPHAE = register(new Block("crimson_hyphae", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRIPPED_CRIMSON_HYPHAE = register(new Block("stripped_crimson_hyphae", builder() + public static final Block STRIPPED_CRIMSON_HYPHAE = register(new Block("stripped_crimson_hyphae", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block CRIMSON_NYLIUM = register(new Block("crimson_nylium", builder())); + 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())); - public static final Block SHROOMLIGHT = register(new Block("shroomlight", builder())); + 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() .intState(AGE_25, 0, 25))); public static final Block WEEPING_VINES_PLANT = register(new Block("weeping_vines_plant", builder())); @@ -2077,360 +2077,360 @@ public final class Blocks { .intState(AGE_25, 0, 25))); public static final Block TWISTING_VINES_PLANT = register(new Block("twisting_vines_plant", builder())); public static final Block CRIMSON_ROOTS = register(new Block("crimson_roots", builder())); - public static final Block CRIMSON_PLANKS = register(new Block("crimson_planks", builder())); - public static final Block WARPED_PLANKS = register(new Block("warped_planks", builder())); - public static final Block CRIMSON_SLAB = register(new Block("crimson_slab", builder() + 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, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block WARPED_SLAB = register(new Block("warped_slab", builder() + public static final Block WARPED_SLAB = register(new Block("warped_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block CRIMSON_PRESSURE_PLATE = register(new Block("crimson_pressure_plate", builder() + public static final Block CRIMSON_PRESSURE_PLATE = register(new Block("crimson_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block WARPED_PRESSURE_PLATE = register(new Block("warped_pressure_plate", builder() + public static final Block WARPED_PRESSURE_PLATE = register(new Block("warped_pressure_plate", builder().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block CRIMSON_FENCE = register(new Block("crimson_fence", builder() + 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))); - public static final Block WARPED_FENCE = register(new Block("warped_fence", builder() + 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))); - public static final Block CRIMSON_TRAPDOOR = register(new Block("crimson_trapdoor", builder() + public static final Block CRIMSON_TRAPDOOR = register(new Block("crimson_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WARPED_TRAPDOOR = register(new Block("warped_trapdoor", builder() + public static final Block WARPED_TRAPDOOR = register(new Block("warped_trapdoor", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block CRIMSON_FENCE_GATE = register(new Block("crimson_fence_gate", builder() + 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))); - public static final Block WARPED_FENCE_GATE = register(new Block("warped_fence_gate", builder() + 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))); - public static final Block CRIMSON_STAIRS = register(new Block("crimson_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block WARPED_STAIRS = register(new Block("warped_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder() + public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block WARPED_BUTTON = register(new Block("warped_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block CRIMSON_DOOR = register(new Block("crimson_door", builder() + public static final Block CRIMSON_DOOR = register(new Block("crimson_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WARPED_DOOR = register(new Block("warped_door", builder() + public static final Block WARPED_DOOR = register(new Block("warped_door", builder().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder() + public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block WARPED_SIGN = register(new Block("warped_sign", builder() + public static final Block WARPED_SIGN = register(new Block("warped_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block CRIMSON_WALL_SIGN = register(new Block("crimson_wall_sign", builder() + public static final Block CRIMSON_WALL_SIGN = register(new Block("crimson_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block WARPED_WALL_SIGN = register(new Block("warped_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .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() + public static final Block STRUCTURE_BLOCK = register(new Block("structure_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .enumState(STRUCTUREBLOCK_MODE, "save", "load", "corner", "data"))); - public static final Block JIGSAW = register(new Block("jigsaw", builder() + public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .enumState(ORIENTATION, "down_east", "down_north", "down_south", "down_west", "up_east", "up_north", "up_south", "up_west", "west_up", "east_up", "north_up", "south_up"))); - public static final Block COMPOSTER = register(new Block("composter", builder() + public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f) .intState(LEVEL_COMPOSTER, 0, 8))); - public static final Block TARGET = register(new Block("target", builder() + public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f) .intState(POWER, 0, 15))); - public static final Block BEE_NEST = register(new Block("bee_nest", builder() + public static final Block BEE_NEST = register(new Block("bee_nest", builder().setBlockEntity().destroyTime(0.3f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .intState(LEVEL_HONEY, 0, 5))); - public static final Block BEEHIVE = register(new Block("beehive", builder() + public static final Block BEEHIVE = register(new Block("beehive", builder().setBlockEntity().destroyTime(0.6f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .intState(LEVEL_HONEY, 0, 5))); public static final Block HONEY_BLOCK = register(new Block("honey_block", builder())); - public static final Block HONEYCOMB_BLOCK = register(new Block("honeycomb_block", builder())); - public static final Block NETHERITE_BLOCK = register(new Block("netherite_block", builder())); - public static final Block ANCIENT_DEBRIS = register(new Block("ancient_debris", builder())); - public static final Block CRYING_OBSIDIAN = register(new Block("crying_obsidian", builder())); - public static final Block RESPAWN_ANCHOR = register(new Block("respawn_anchor", 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, 0, 4))); public static final Block POTTED_CRIMSON_FUNGUS = register(new Block("potted_crimson_fungus", builder())); public static final Block POTTED_WARPED_FUNGUS = register(new Block("potted_warped_fungus", builder())); public static final Block POTTED_CRIMSON_ROOTS = register(new Block("potted_crimson_roots", builder())); public static final Block POTTED_WARPED_ROOTS = register(new Block("potted_warped_roots", builder())); - public static final Block LODESTONE = register(new Block("lodestone", builder())); - public static final Block BLACKSTONE = register(new Block("blackstone", builder())); - public static final Block BLACKSTONE_STAIRS = register(new Block("blackstone_stairs", builder() + public static final Block LODESTONE = register(new Block("lodestone", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block BLACKSTONE_WALL = register(new Block("blackstone_wall", builder() + public static final Block BLACKSTONE_WALL = register(new Block("blackstone_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block BLACKSTONE_SLAB = register(new Block("blackstone_slab", builder() + public static final Block BLACKSTONE_SLAB = register(new Block("blackstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_BLACKSTONE = register(new Block("polished_blackstone", builder())); - public static final Block POLISHED_BLACKSTONE_BRICKS = register(new Block("polished_blackstone_bricks", builder())); - public static final Block CRACKED_POLISHED_BLACKSTONE_BRICKS = register(new Block("cracked_polished_blackstone_bricks", builder())); - public static final Block CHISELED_POLISHED_BLACKSTONE = register(new Block("chiseled_polished_blackstone", builder())); - public static final Block POLISHED_BLACKSTONE_BRICK_SLAB = register(new Block("polished_blackstone_brick_slab", builder() + 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, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_BLACKSTONE_BRICK_STAIRS = register(new Block("polished_blackstone_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block POLISHED_BLACKSTONE_BRICK_WALL = register(new Block("polished_blackstone_brick_wall", builder() + public static final Block POLISHED_BLACKSTONE_BRICK_WALL = register(new Block("polished_blackstone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block GILDED_BLACKSTONE = register(new Block("gilded_blackstone", builder())); - public static final Block POLISHED_BLACKSTONE_STAIRS = register(new Block("polished_blackstone_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block POLISHED_BLACKSTONE_SLAB = register(new Block("polished_blackstone_slab", builder() + public static final Block POLISHED_BLACKSTONE_SLAB = register(new Block("polished_blackstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder() + public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) .booleanState(POWERED))); - public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder() + public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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() + public static final Block POLISHED_BLACKSTONE_WALL = register(new Block("polished_blackstone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block CHISELED_NETHER_BRICKS = register(new Block("chiseled_nether_bricks", builder())); - public static final Block CRACKED_NETHER_BRICKS = register(new Block("cracked_nether_bricks", builder())); - public static final Block QUARTZ_BRICKS = register(new Block("quartz_bricks", builder())); - public static final Block CANDLE = register(new Block("candle", builder() + 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) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block WHITE_CANDLE = register(new Block("white_candle", builder() + public static final Block WHITE_CANDLE = register(new Block("white_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block ORANGE_CANDLE = register(new Block("orange_candle", builder() + public static final Block ORANGE_CANDLE = register(new Block("orange_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block MAGENTA_CANDLE = register(new Block("magenta_candle", builder() + public static final Block MAGENTA_CANDLE = register(new Block("magenta_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIGHT_BLUE_CANDLE = register(new Block("light_blue_candle", builder() + public static final Block LIGHT_BLUE_CANDLE = register(new Block("light_blue_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block YELLOW_CANDLE = register(new Block("yellow_candle", builder() + public static final Block YELLOW_CANDLE = register(new Block("yellow_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIME_CANDLE = register(new Block("lime_candle", builder() + public static final Block LIME_CANDLE = register(new Block("lime_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block PINK_CANDLE = register(new Block("pink_candle", builder() + public static final Block PINK_CANDLE = register(new Block("pink_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block GRAY_CANDLE = register(new Block("gray_candle", builder() + public static final Block GRAY_CANDLE = register(new Block("gray_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIGHT_GRAY_CANDLE = register(new Block("light_gray_candle", builder() + public static final Block LIGHT_GRAY_CANDLE = register(new Block("light_gray_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block CYAN_CANDLE = register(new Block("cyan_candle", builder() + public static final Block CYAN_CANDLE = register(new Block("cyan_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block PURPLE_CANDLE = register(new Block("purple_candle", builder() + public static final Block PURPLE_CANDLE = register(new Block("purple_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BLUE_CANDLE = register(new Block("blue_candle", builder() + public static final Block BLUE_CANDLE = register(new Block("blue_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BROWN_CANDLE = register(new Block("brown_candle", builder() + public static final Block BROWN_CANDLE = register(new Block("brown_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block GREEN_CANDLE = register(new Block("green_candle", builder() + public static final Block GREEN_CANDLE = register(new Block("green_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block RED_CANDLE = register(new Block("red_candle", builder() + public static final Block RED_CANDLE = register(new Block("red_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BLACK_CANDLE = register(new Block("black_candle", builder() + public static final Block BLACK_CANDLE = register(new Block("black_candle", builder().destroyTime(0.1f) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder() + public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder() + public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder() + public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder() + public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder() + public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder() + public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder() + public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder() + public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder() + public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder() + public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder() + public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder() + public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder() + public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder() + public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder() + public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder() + public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder() + public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder().destroyTime(0.5f) .booleanState(LIT))); - public static final Block AMETHYST_BLOCK = register(new Block("amethyst_block", builder())); - public static final Block BUDDING_AMETHYST = register(new Block("budding_amethyst", builder())); - public static final Block AMETHYST_CLUSTER = register(new Block("amethyst_cluster", builder() + 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))); + public static final Block AMETHYST_CLUSTER = register(new Block("amethyst_cluster", builder().destroyTime(1.5f) .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() + public static final Block LARGE_AMETHYST_BUD = register(new Block("large_amethyst_bud", builder().destroyTime(1.5f) .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() + public static final Block MEDIUM_AMETHYST_BUD = register(new Block("medium_amethyst_bud", builder().destroyTime(1.5f) .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() + public static final Block SMALL_AMETHYST_BUD = register(new Block("small_amethyst_bud", builder().destroyTime(1.5f) .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())); - public static final Block TUFF_SLAB = register(new Block("tuff_slab", builder() + 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, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block TUFF_STAIRS = register(new Block("tuff_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block TUFF_WALL = register(new Block("tuff_wall", builder() + public static final Block TUFF_WALL = register(new Block("tuff_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block POLISHED_TUFF = register(new Block("polished_tuff", builder())); - public static final Block POLISHED_TUFF_SLAB = register(new Block("polished_tuff_slab", builder() + 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, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_TUFF_STAIRS = register(new Block("polished_tuff_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block POLISHED_TUFF_WALL = register(new Block("polished_tuff_wall", builder() + public static final Block POLISHED_TUFF_WALL = register(new Block("polished_tuff_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block CHISELED_TUFF = register(new Block("chiseled_tuff", builder())); - public static final Block TUFF_BRICKS = register(new Block("tuff_bricks", builder())); - public static final Block TUFF_BRICK_SLAB = register(new Block("tuff_brick_slab", builder() + 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, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block TUFF_BRICK_STAIRS = register(new Block("tuff_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block TUFF_BRICK_WALL = register(new Block("tuff_brick_wall", builder() + public static final Block TUFF_BRICK_WALL = register(new Block("tuff_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block CHISELED_TUFF_BRICKS = register(new Block("chiseled_tuff_bricks", builder())); - public static final Block CALCITE = register(new Block("calcite", builder())); - public static final Block TINTED_GLASS = register(new Block("tinted_glass", builder())); - public static final Block POWDER_SNOW = register(new Block("powder_snow", builder())); - public static final Block SCULK_SENSOR = register(new Block("sculk_sensor", builder() + 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().destroyTime(1.5f) .intState(POWER, 0, 15) .enumState(SCULK_SENSOR_PHASE, "inactive", "active", "cooldown") .booleanState(WATERLOGGED))); - public static final Block CALIBRATED_SCULK_SENSOR = register(new Block("calibrated_sculk_sensor", builder() + public static final Block CALIBRATED_SCULK_SENSOR = register(new Block("calibrated_sculk_sensor", builder().setBlockEntity().destroyTime(1.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .intState(POWER, 0, 15) .enumState(SCULK_SENSOR_PHASE, "inactive", "active", "cooldown") .booleanState(WATERLOGGED))); - public static final Block SCULK = register(new Block("sculk", builder())); - public static final Block SCULK_VEIN = register(new Block("sculk_vein", builder() + 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) .booleanState(DOWN) .booleanState(EAST) .booleanState(NORTH) @@ -2438,247 +2438,247 @@ public final class Blocks { .booleanState(UP) .booleanState(WATERLOGGED) .booleanState(WEST))); - public static final Block SCULK_CATALYST = register(new Block("sculk_catalyst", builder() + public static final Block SCULK_CATALYST = register(new Block("sculk_catalyst", builder().setBlockEntity().destroyTime(3.0f) .booleanState(BLOOM))); - public static final Block SCULK_SHRIEKER = register(new Block("sculk_shrieker", builder() + public static final Block SCULK_SHRIEKER = register(new Block("sculk_shrieker", builder().setBlockEntity().destroyTime(3.0f) .booleanState(CAN_SUMMON) .booleanState(SHRIEKING) .booleanState(WATERLOGGED))); - public static final Block COPPER_BLOCK = register(new Block("copper_block", builder())); - public static final Block EXPOSED_COPPER = register(new Block("exposed_copper", builder())); - public static final Block WEATHERED_COPPER = register(new Block("weathered_copper", builder())); - public static final Block OXIDIZED_COPPER = register(new Block("oxidized_copper", builder())); - public static final Block COPPER_ORE = register(new Block("copper_ore", builder())); - public static final Block DEEPSLATE_COPPER_ORE = register(new Block("deepslate_copper_ore", builder())); - public static final Block OXIDIZED_CUT_COPPER = register(new Block("oxidized_cut_copper", builder())); - public static final Block WEATHERED_CUT_COPPER = register(new Block("weathered_cut_copper", builder())); - public static final Block EXPOSED_CUT_COPPER = register(new Block("exposed_cut_copper", builder())); - public static final Block CUT_COPPER = register(new Block("cut_copper", builder())); - public static final Block OXIDIZED_CHISELED_COPPER = register(new Block("oxidized_chiseled_copper", builder())); - public static final Block WEATHERED_CHISELED_COPPER = register(new Block("weathered_chiseled_copper", builder())); - public static final Block EXPOSED_CHISELED_COPPER = register(new Block("exposed_chiseled_copper", builder())); - public static final Block CHISELED_COPPER = register(new Block("chiseled_copper", builder())); - public static final Block WAXED_OXIDIZED_CHISELED_COPPER = register(new Block("waxed_oxidized_chiseled_copper", builder())); - public static final Block WAXED_WEATHERED_CHISELED_COPPER = register(new Block("waxed_weathered_chiseled_copper", builder())); - public static final Block WAXED_EXPOSED_CHISELED_COPPER = register(new Block("waxed_exposed_chiseled_copper", builder())); - public static final Block WAXED_CHISELED_COPPER = register(new Block("waxed_chiseled_copper", builder())); - public static final Block OXIDIZED_CUT_COPPER_STAIRS = register(new Block("oxidized_cut_copper_stairs", builder() + 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))); + public static final Block OXIDIZED_COPPER = register(new Block("oxidized_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block COPPER_ORE = register(new Block("copper_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block DEEPSLATE_COPPER_ORE = register(new Block("deepslate_copper_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); + public static final Block OXIDIZED_CUT_COPPER = register(new Block("oxidized_cut_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block WEATHERED_CUT_COPPER = register(new Block("weathered_cut_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block EXPOSED_CUT_COPPER = register(new Block("exposed_cut_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block CUT_COPPER = register(new Block("cut_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block OXIDIZED_CHISELED_COPPER = register(new Block("oxidized_chiseled_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block WEATHERED_CHISELED_COPPER = register(new Block("weathered_chiseled_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block EXPOSED_CHISELED_COPPER = register(new Block("exposed_chiseled_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block CHISELED_COPPER = register(new Block("chiseled_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block WAXED_OXIDIZED_CHISELED_COPPER = register(new Block("waxed_oxidized_chiseled_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block WAXED_WEATHERED_CHISELED_COPPER = register(new Block("waxed_weathered_chiseled_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block WEATHERED_CUT_COPPER_STAIRS = register(new Block("weathered_cut_copper_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block EXPOSED_CUT_COPPER_STAIRS = register(new Block("exposed_cut_copper_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block CUT_COPPER_STAIRS = register(new Block("cut_copper_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block OXIDIZED_CUT_COPPER_SLAB = register(new Block("oxidized_cut_copper_slab", builder() + public static final Block OXIDIZED_CUT_COPPER_SLAB = register(new Block("oxidized_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block WEATHERED_CUT_COPPER_SLAB = register(new Block("weathered_cut_copper_slab", builder() + public static final Block WEATHERED_CUT_COPPER_SLAB = register(new Block("weathered_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block EXPOSED_CUT_COPPER_SLAB = register(new Block("exposed_cut_copper_slab", builder() + public static final Block EXPOSED_CUT_COPPER_SLAB = register(new Block("exposed_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block CUT_COPPER_SLAB = register(new Block("cut_copper_slab", builder() + public static final Block CUT_COPPER_SLAB = register(new Block("cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block WAXED_COPPER_BLOCK = register(new Block("waxed_copper_block", builder())); - public static final Block WAXED_WEATHERED_COPPER = register(new Block("waxed_weathered_copper", builder())); - public static final Block WAXED_EXPOSED_COPPER = register(new Block("waxed_exposed_copper", builder())); - public static final Block WAXED_OXIDIZED_COPPER = register(new Block("waxed_oxidized_copper", builder())); - public static final Block WAXED_OXIDIZED_CUT_COPPER = register(new Block("waxed_oxidized_cut_copper", builder())); - public static final Block WAXED_WEATHERED_CUT_COPPER = register(new Block("waxed_weathered_cut_copper", builder())); - public static final Block WAXED_EXPOSED_CUT_COPPER = register(new Block("waxed_exposed_cut_copper", builder())); - public static final Block WAXED_CUT_COPPER = register(new Block("waxed_cut_copper", builder())); - public static final Block WAXED_OXIDIZED_CUT_COPPER_STAIRS = register(new Block("waxed_oxidized_cut_copper_stairs", builder() + 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))); + public static final Block WAXED_OXIDIZED_COPPER = register(new Block("waxed_oxidized_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block WAXED_OXIDIZED_CUT_COPPER = register(new Block("waxed_oxidized_cut_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + public static final Block WAXED_WEATHERED_CUT_COPPER = register(new Block("waxed_weathered_cut_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block WAXED_WEATHERED_CUT_COPPER_STAIRS = register(new Block("waxed_weathered_cut_copper_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block WAXED_EXPOSED_CUT_COPPER_STAIRS = register(new Block("waxed_exposed_cut_copper_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block WAXED_CUT_COPPER_STAIRS = register(new Block("waxed_cut_copper_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block WAXED_OXIDIZED_CUT_COPPER_SLAB = register(new Block("waxed_oxidized_cut_copper_slab", builder() + 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, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block WAXED_WEATHERED_CUT_COPPER_SLAB = register(new Block("waxed_weathered_cut_copper_slab", builder() + 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, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block WAXED_EXPOSED_CUT_COPPER_SLAB = register(new Block("waxed_exposed_cut_copper_slab", builder() + 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, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block WAXED_CUT_COPPER_SLAB = register(new Block("waxed_cut_copper_slab", builder() + public static final Block WAXED_CUT_COPPER_SLAB = register(new Block("waxed_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block COPPER_DOOR = register(new Block("copper_door", builder() + public static final Block COPPER_DOOR = register(new Block("copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block EXPOSED_COPPER_DOOR = register(new Block("exposed_copper_door", builder() + public static final Block EXPOSED_COPPER_DOOR = register(new Block("exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block OXIDIZED_COPPER_DOOR = register(new Block("oxidized_copper_door", builder() + public static final Block OXIDIZED_COPPER_DOOR = register(new Block("oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WEATHERED_COPPER_DOOR = register(new Block("weathered_copper_door", builder() + public static final Block WEATHERED_COPPER_DOOR = register(new Block("weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_COPPER_DOOR = register(new Block("waxed_copper_door", builder() + public static final Block WAXED_COPPER_DOOR = register(new Block("waxed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_EXPOSED_COPPER_DOOR = register(new Block("waxed_exposed_copper_door", builder() + public static final Block WAXED_EXPOSED_COPPER_DOOR = register(new Block("waxed_exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_OXIDIZED_COPPER_DOOR = register(new Block("waxed_oxidized_copper_door", builder() + public static final Block WAXED_OXIDIZED_COPPER_DOOR = register(new Block("waxed_oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_WEATHERED_COPPER_DOOR = register(new Block("waxed_weathered_copper_door", builder() + public static final Block WAXED_WEATHERED_COPPER_DOOR = register(new Block("waxed_weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block COPPER_TRAPDOOR = register(new Block("copper_trapdoor", builder() + public static final Block COPPER_TRAPDOOR = register(new Block("copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block EXPOSED_COPPER_TRAPDOOR = register(new Block("exposed_copper_trapdoor", builder() + public static final Block EXPOSED_COPPER_TRAPDOOR = register(new Block("exposed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block OXIDIZED_COPPER_TRAPDOOR = register(new Block("oxidized_copper_trapdoor", builder() + public static final Block OXIDIZED_COPPER_TRAPDOOR = register(new Block("oxidized_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WEATHERED_COPPER_TRAPDOOR = register(new Block("weathered_copper_trapdoor", builder() + public static final Block WEATHERED_COPPER_TRAPDOOR = register(new Block("weathered_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WAXED_COPPER_TRAPDOOR = register(new Block("waxed_copper_trapdoor", builder() + public static final Block WAXED_COPPER_TRAPDOOR = register(new Block("waxed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WAXED_EXPOSED_COPPER_TRAPDOOR = register(new Block("waxed_exposed_copper_trapdoor", builder() + public static final Block WAXED_EXPOSED_COPPER_TRAPDOOR = register(new Block("waxed_exposed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new Block("waxed_oxidized_copper_trapdoor", builder() + public static final Block WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new Block("waxed_oxidized_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WAXED_WEATHERED_COPPER_TRAPDOOR = register(new Block("waxed_weathered_copper_trapdoor", builder() + public static final Block WAXED_WEATHERED_COPPER_TRAPDOOR = register(new Block("waxed_weathered_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block COPPER_GRATE = register(new Block("copper_grate", builder() + public static final Block COPPER_GRATE = register(new Block("copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block EXPOSED_COPPER_GRATE = register(new Block("exposed_copper_grate", builder() + public static final Block EXPOSED_COPPER_GRATE = register(new Block("exposed_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block WEATHERED_COPPER_GRATE = register(new Block("weathered_copper_grate", builder() + public static final Block WEATHERED_COPPER_GRATE = register(new Block("weathered_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block OXIDIZED_COPPER_GRATE = register(new Block("oxidized_copper_grate", builder() + public static final Block OXIDIZED_COPPER_GRATE = register(new Block("oxidized_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block WAXED_COPPER_GRATE = register(new Block("waxed_copper_grate", builder() + public static final Block WAXED_COPPER_GRATE = register(new Block("waxed_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block WAXED_EXPOSED_COPPER_GRATE = register(new Block("waxed_exposed_copper_grate", builder() + public static final Block WAXED_EXPOSED_COPPER_GRATE = register(new Block("waxed_exposed_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block WAXED_WEATHERED_COPPER_GRATE = register(new Block("waxed_weathered_copper_grate", builder() + public static final Block WAXED_WEATHERED_COPPER_GRATE = register(new Block("waxed_weathered_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block WAXED_OXIDIZED_COPPER_GRATE = register(new Block("waxed_oxidized_copper_grate", builder() + public static final Block WAXED_OXIDIZED_COPPER_GRATE = register(new Block("waxed_oxidized_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block COPPER_BULB = register(new Block("copper_bulb", builder() + public static final Block COPPER_BULB = register(new Block("copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT) .booleanState(POWERED))); - public static final Block EXPOSED_COPPER_BULB = register(new Block("exposed_copper_bulb", builder() + public static final Block EXPOSED_COPPER_BULB = register(new Block("exposed_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT) .booleanState(POWERED))); - public static final Block WEATHERED_COPPER_BULB = register(new Block("weathered_copper_bulb", builder() + public static final Block WEATHERED_COPPER_BULB = register(new Block("weathered_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT) .booleanState(POWERED))); - public static final Block OXIDIZED_COPPER_BULB = register(new Block("oxidized_copper_bulb", builder() + public static final Block OXIDIZED_COPPER_BULB = register(new Block("oxidized_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT) .booleanState(POWERED))); - public static final Block WAXED_COPPER_BULB = register(new Block("waxed_copper_bulb", builder() + public static final Block WAXED_COPPER_BULB = register(new Block("waxed_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT) .booleanState(POWERED))); - public static final Block WAXED_EXPOSED_COPPER_BULB = register(new Block("waxed_exposed_copper_bulb", builder() + public static final Block WAXED_EXPOSED_COPPER_BULB = register(new Block("waxed_exposed_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT) .booleanState(POWERED))); - public static final Block WAXED_WEATHERED_COPPER_BULB = register(new Block("waxed_weathered_copper_bulb", builder() + public static final Block WAXED_WEATHERED_COPPER_BULB = register(new Block("waxed_weathered_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT) .booleanState(POWERED))); - public static final Block WAXED_OXIDIZED_COPPER_BULB = register(new Block("waxed_oxidized_copper_bulb", builder() + public static final Block WAXED_OXIDIZED_COPPER_BULB = register(new Block("waxed_oxidized_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT) .booleanState(POWERED))); - public static final Block LIGHTNING_ROD = register(new Block("lightning_rod", builder() + 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))); - public static final Block POINTED_DRIPSTONE = register(new Block("pointed_dripstone", builder() + public static final Block POINTED_DRIPSTONE = register(new Block("pointed_dripstone", builder().destroyTime(1.5f) .enumState(DRIPSTONE_THICKNESS, "tip_merge", "tip", "frustum", "middle", "base") .enumState(VERTICAL_DIRECTION, Direction.UP, Direction.DOWN) .booleanState(WATERLOGGED))); - public static final Block DRIPSTONE_BLOCK = register(new Block("dripstone_block", builder())); + 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() .intState(AGE_25, 0, 25) .booleanState(BERRIES))); @@ -2687,16 +2687,16 @@ public final class Blocks { public static final Block SPORE_BLOSSOM = register(new Block("spore_blossom", builder())); public static final Block AZALEA = register(new Block("azalea", builder())); public static final Block FLOWERING_AZALEA = register(new Block("flowering_azalea", builder())); - public static final Block MOSS_CARPET = register(new Block("moss_carpet", builder())); + public static final Block MOSS_CARPET = register(new Block("moss_carpet", builder().destroyTime(0.1f))); public static final Block PINK_PETALS = register(new Block("pink_petals", builder() .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .intState(FLOWER_AMOUNT, 1, 4))); - public static final Block MOSS_BLOCK = register(new Block("moss_block", builder())); - public static final Block BIG_DRIPLEAF = register(new Block("big_dripleaf", builder() + public static final Block MOSS_BLOCK = register(new Block("moss_block", builder().destroyTime(0.1f))); + public static final Block BIG_DRIPLEAF = register(new Block("big_dripleaf", builder().destroyTime(0.1f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(TILT, "none", "unstable", "partial", "full") .booleanState(WATERLOGGED))); - public static final Block BIG_DRIPLEAF_STEM = register(new Block("big_dripleaf_stem", builder() + public static final Block BIG_DRIPLEAF_STEM = register(new Block("big_dripleaf_stem", builder().destroyTime(0.1f) .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() @@ -2705,109 +2705,109 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block HANGING_ROOTS = register(new Block("hanging_roots", builder() .booleanState(WATERLOGGED))); - public static final Block ROOTED_DIRT = register(new Block("rooted_dirt", builder())); - public static final Block MUD = register(new Block("mud", builder())); - public static final Block DEEPSLATE = register(new Block("deepslate", builder() + 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))); - public static final Block COBBLED_DEEPSLATE = register(new Block("cobbled_deepslate", builder())); - public static final Block COBBLED_DEEPSLATE_STAIRS = register(new Block("cobbled_deepslate_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block COBBLED_DEEPSLATE_SLAB = register(new Block("cobbled_deepslate_slab", builder() + public static final Block COBBLED_DEEPSLATE_SLAB = register(new Block("cobbled_deepslate_slab", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block COBBLED_DEEPSLATE_WALL = register(new Block("cobbled_deepslate_wall", builder() + public static final Block COBBLED_DEEPSLATE_WALL = register(new Block("cobbled_deepslate_wall", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block POLISHED_DEEPSLATE = register(new Block("polished_deepslate", builder())); - public static final Block POLISHED_DEEPSLATE_STAIRS = register(new Block("polished_deepslate_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block POLISHED_DEEPSLATE_SLAB = register(new Block("polished_deepslate_slab", builder() + public static final Block POLISHED_DEEPSLATE_SLAB = register(new Block("polished_deepslate_slab", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_DEEPSLATE_WALL = register(new Block("polished_deepslate_wall", builder() + public static final Block POLISHED_DEEPSLATE_WALL = register(new Block("polished_deepslate_wall", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block DEEPSLATE_TILES = register(new Block("deepslate_tiles", builder())); - public static final Block DEEPSLATE_TILE_STAIRS = register(new Block("deepslate_tile_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block DEEPSLATE_TILE_SLAB = register(new Block("deepslate_tile_slab", builder() + public static final Block DEEPSLATE_TILE_SLAB = register(new Block("deepslate_tile_slab", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block DEEPSLATE_TILE_WALL = register(new Block("deepslate_tile_wall", builder() + public static final Block DEEPSLATE_TILE_WALL = register(new Block("deepslate_tile_wall", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block DEEPSLATE_BRICKS = register(new Block("deepslate_bricks", builder())); - public static final Block DEEPSLATE_BRICK_STAIRS = register(new Block("deepslate_brick_stairs", builder() + 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block DEEPSLATE_BRICK_SLAB = register(new Block("deepslate_brick_slab", builder() + public static final Block DEEPSLATE_BRICK_SLAB = register(new Block("deepslate_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block DEEPSLATE_BRICK_WALL = register(new Block("deepslate_brick_wall", builder() + public static final Block DEEPSLATE_BRICK_WALL = register(new Block("deepslate_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(EAST_WALL, "none", "low", "tall") .enumState(NORTH_WALL, "none", "low", "tall") .enumState(SOUTH_WALL, "none", "low", "tall") .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block CHISELED_DEEPSLATE = register(new Block("chiseled_deepslate", builder())); - public static final Block CRACKED_DEEPSLATE_BRICKS = register(new Block("cracked_deepslate_bricks", builder())); - public static final Block CRACKED_DEEPSLATE_TILES = register(new Block("cracked_deepslate_tiles", builder())); - public static final Block INFESTED_DEEPSLATE = register(new Block("infested_deepslate", builder() + 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))); - public static final Block SMOOTH_BASALT = register(new Block("smooth_basalt", builder())); - public static final Block RAW_IRON_BLOCK = register(new Block("raw_iron_block", builder())); - public static final Block RAW_COPPER_BLOCK = register(new Block("raw_copper_block", builder())); - public static final Block RAW_GOLD_BLOCK = register(new Block("raw_gold_block", builder())); + 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))); + public static final Block RAW_GOLD_BLOCK = register(new Block("raw_gold_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block POTTED_AZALEA_BUSH = register(new Block("potted_azalea_bush", builder())); public static final Block POTTED_FLOWERING_AZALEA_BUSH = register(new Block("potted_flowering_azalea_bush", builder())); - public static final Block OCHRE_FROGLIGHT = register(new Block("ochre_froglight", builder() + public static final Block OCHRE_FROGLIGHT = register(new Block("ochre_froglight", builder().destroyTime(0.3f) .enumState(AXIS, Axis.VALUES))); - public static final Block VERDANT_FROGLIGHT = register(new Block("verdant_froglight", builder() + public static final Block VERDANT_FROGLIGHT = register(new Block("verdant_froglight", builder().destroyTime(0.3f) .enumState(AXIS, Axis.VALUES))); - public static final Block PEARLESCENT_FROGLIGHT = register(new Block("pearlescent_froglight", builder() + public static final Block PEARLESCENT_FROGLIGHT = register(new Block("pearlescent_froglight", builder().destroyTime(0.3f) .enumState(AXIS, Axis.VALUES))); public static final Block FROGSPAWN = register(new Block("frogspawn", builder())); - public static final Block REINFORCED_DEEPSLATE = register(new Block("reinforced_deepslate", builder())); - public static final Block DECORATED_POT = register(new Block("decorated_pot", builder() + 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() .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() + public static final Block CRAFTER = register(new Block("crafter", builder().setBlockEntity().destroyTime(1.5f) .booleanState(CRAFTING) .enumState(ORIENTATION, "down_east", "down_north", "down_south", "down_west", "up_east", "up_north", "up_south", "up_west", "west_up", "east_up", "north_up", "south_up") .booleanState(TRIGGERED))); - public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder() + public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f) .booleanState(OMINOUS) .enumState(TRIAL_SPAWNER_STATE, "inactive", "waiting_for_players", "active", "waiting_for_reward_ejection", "ejecting_reward", "cooldown"))); - public static final Block VAULT = register(new Block("vault", builder() + public static final Block VAULT = register(new Block("vault", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OMINOUS) .enumState(VAULT_STATE, "inactive", "active", "unlocking", "ejecting"))); - public static final Block HEAVY_CORE = register(new Block("heavy_core", builder() + public static final Block HEAVY_CORE = register(new Block("heavy_core", builder().destroyTime(10.0f) .booleanState(WATERLOGGED))); private static T register(T block) { diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index 459f4a5af..84822ca16 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -41,10 +41,16 @@ public class Block { public static final int JAVA_AIR_ID = 0; private final String javaIdentifier; + private final boolean requiresCorrectToolForDrops; + private final boolean hasBlockEntity; + private final float destroyTime; private int javaId = -1; public Block(String javaIdentifier, Builder builder) { this.javaIdentifier = Identifier.formalize(javaIdentifier).intern(); + this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops; + this.hasBlockEntity = builder.hasBlockEntity; + this.destroyTime = builder.destroyTime; builder.build(this); } @@ -52,6 +58,18 @@ public class Block { return javaIdentifier; } + public boolean requiresCorrectToolForDrops() { + return requiresCorrectToolForDrops; + } + + public boolean hasBlockEntity() { + return hasBlockEntity; + } + + public float destroyTime() { + return destroyTime; + } + public int javaId() { return javaId; } @@ -77,6 +95,9 @@ public class Block { public static final class Builder { private final Map, List>> states = new LinkedHashMap<>(); + private boolean requiresCorrectToolForDrops = false; + private boolean hasBlockEntity = false; + private float destroyTime; /** * For states that we're just tracking for mirroring Java states. @@ -107,6 +128,21 @@ public class Block { return this; } + public Builder requiresCorrectToolForDrops() { + this.requiresCorrectToolForDrops = true; + return this; + } + + public Builder setBlockEntity() { + this.hasBlockEntity = true; + return this; + } + + public Builder destroyTime(float destroyTime) { + this.destroyTime = destroyTime; + return this; + } + private void build(Block block) { if (states.isEmpty()) { BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size())); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index ace110f78..b623bc043 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -51,6 +51,7 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; @@ -565,6 +566,15 @@ public final class BlockRegistryPopulator { .isBlockEntity(javaBlockState.hasBlockEntity()) .build(); + Block.Builder builder = Block.builder() + .destroyTime(javaBlockState.blockHardness()); + if (!javaBlockState.canBreakWithHand()) { + builder.requiresCorrectToolForDrops(); + } + if (javaBlockState.hasBlockEntity()) { + builder.setBlockEntity(); + } + String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier()); String bedrockIdentifier = customBlockState.block().identifier(); 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 38ac32214..6da354646 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 @@ -25,15 +25,16 @@ package org.geysermc.geyser.session.cache; -import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import it.unimi.dsi.fastutil.ints.IntList; 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.registry.type.BlockMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.BlockTag; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import javax.annotation.ParametersAreNonnullByDefault; import java.util.EnumMap; @@ -95,6 +96,17 @@ public final class TagCache { } } + /** + * @return true if the block tag is present and contains this block mapping's Java ID. + */ + public boolean is(BlockTag tag, Block block) { + IntList values = this.blocks.get(tag); + if (values != null) { + return values.contains(block.javaId()); + } + return false; + } + /** * @return true if the block tag is present and contains this block mapping's Java ID. */ 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 index 690fdb371..861f55731 100644 --- 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 @@ -40,6 +40,7 @@ import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; @@ -160,7 +161,7 @@ public class BedrockActionTranslator extends PacketTranslator { @@ -42,7 +43,7 @@ public class JavaBlockDestructionTranslator extends PacketTranslator session.getTagCache().is(BlockTag.AXE_EFFECTIVE, blockMapping); - case "hoe" -> session.getTagCache().is(BlockTag.HOE_EFFECTIVE, blockMapping); - case "pickaxe" -> session.getTagCache().is(BlockTag.PICKAXE_EFFECTIVE, blockMapping); - case "shears" -> session.getTagCache().is(BlockTag.LEAVES, blockMapping) || session.getTagCache().is(BlockTag.WOOL, blockMapping); - case "shovel" -> session.getTagCache().is(BlockTag.SHOVEL_EFFECTIVE, blockMapping); - case "sword" -> blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID; + case "axe" -> session.getTagCache().is(BlockTag.AXE_EFFECTIVE, block); + case "hoe" -> session.getTagCache().is(BlockTag.HOE_EFFECTIVE, block); + case "pickaxe" -> session.getTagCache().is(BlockTag.PICKAXE_EFFECTIVE, block); + case "shears" -> session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); + case "shovel" -> session.getTagCache().is(BlockTag.SHOVEL_EFFECTIVE, block); + case "sword" -> block == Blocks.COBWEB; default -> { session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType); yield false; @@ -71,7 +71,7 @@ public final class BlockUtils { }; } - private static boolean canToolTierBreakBlock(GeyserSession session, BlockMapping blockMapping, String toolTier) { + private static boolean canToolTierBreakBlock(GeyserSession session, Block block, String toolTier) { if (toolTier.equals("netherite") || toolTier.equals("diamond")) { // As of 1.17, these tiers can mine everything that is mineable return true; @@ -80,15 +80,15 @@ public final class BlockUtils { switch (toolTier) { // Use intentional fall-throughs to check each tier with this block default: - if (session.getTagCache().is(BlockTag.NEEDS_STONE_TOOL, blockMapping)) { + if (session.getTagCache().is(BlockTag.NEEDS_STONE_TOOL, block)) { return false; } case "stone": - if (session.getTagCache().is(BlockTag.NEEDS_IRON_TOOL, blockMapping)) { + if (session.getTagCache().is(BlockTag.NEEDS_IRON_TOOL, block)) { return false; } case "iron": - if (session.getTagCache().is(BlockTag.NEEDS_DIAMOND_TOOL, blockMapping)) { + if (session.getTagCache().is(BlockTag.NEEDS_DIAMOND_TOOL, block)) { return false; } } @@ -131,9 +131,9 @@ public final class BlockUtils { return 1.0 / speed; } - public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { - boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, blockMapping) || session.getTagCache().is(BlockTag.WOOL, blockMapping); //TODO called twice - boolean canHarvestWithHand = blockMapping.isCanBreakWithHand(); + public static double getBreakTime(GeyserSession session, Block block, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { + boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); //TODO called twice + boolean canHarvestWithHand = !block.requiresCorrectToolForDrops(); String toolType = ""; String toolTier = ""; boolean correctTool = false; @@ -141,8 +141,8 @@ public final class BlockUtils { if (item.isTool()) { toolType = item.getToolType(); toolTier = item.getToolTier(); - correctTool = correctTool(session, blockMapping, toolType); - toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier); + correctTool = correctTool(session, block, toolType); + toolCanBreak = canToolTierBreakBlock(session, block, toolTier); } int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY); @@ -151,7 +151,7 @@ public final class BlockUtils { if (!isSessionPlayer) { // Another entity is currently mining; we have all the information we know - return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, + return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, true); } @@ -162,11 +162,11 @@ public final class BlockUtils { boolean insideOfWaterWithoutAquaAffinity = waterInEyes && ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY) < 1; - return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, + return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); } - public static double getSessionBreakTime(GeyserSession session, BlockMapping blockMapping) { + public static double getSessionBreakTime(GeyserSession session, Block block) { PlayerInventory inventory = session.getPlayerInventory(); GeyserItemStack item = inventory.getItemInHand(); ItemMapping mapping = ItemMapping.AIR; @@ -175,7 +175,7 @@ public final class BlockUtils { mapping = item.getMapping(session); components = item.getComponents(); } - return getBreakTime(session, blockMapping, mapping, components, true); + return getBreakTime(session, block, mapping, components, true); } /** From 1cd0aad79fdb889ee989084cd1b0c05b1251e387 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 17 May 2024 15:02:12 -0400 Subject: [PATCH 141/897] Comment out snow collision Seems to be unnecessary as of 1.20.30. Will be deleted later if no problems are found! --- .../org/geysermc/geyser/translator/collision/SnowCollision.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java index fb83e357d..af2bcb7ea 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java @@ -30,7 +30,7 @@ import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.session.GeyserSession; @EqualsAndHashCode(callSuper = true) -@CollisionRemapper(regex = "^snow$", passDefaultBoxes = true, usesParams = true) +//@CollisionRemapper(regex = "^snow$", passDefaultBoxes = true, usesParams = true) TODO remove if no bugs are found. Seems fine with Bedrock 1.20.80 and 1.20.5 public class SnowCollision extends BlockCollision { private final int layers; From b010c500d84e59ee30c58c766b954a6dc2a45423 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 17 May 2024 22:21:01 +0200 Subject: [PATCH 142/897] Various entity fixes: Ensure TNT doesn't bug into the ground, reset player entity flags properly (#4670) * Various entity fixes * actually update the tnt entity position * revert bad diff --- .../geyser/entity/EntityDefinitions.java | 3 ++- .../geysermc/geyser/entity/type/Entity.java | 5 +++- .../geyser/entity/type/ExpOrbEntity.java | 7 +++++ .../geyser/entity/type/TNTEntity.java | 12 ++++++++- .../entity/type/player/PlayerEntity.java | 26 +++++++++++++++++++ .../type/player/SessionPlayerEntity.java | 10 ++----- 6 files changed, 52 insertions(+), 11 deletions(-) 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 991b95571..21cc526dd 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -235,7 +235,7 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, (enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal .build(); - EXPERIENCE_ORB = EntityDefinition.inherited(null, entityBase) + EXPERIENCE_ORB = EntityDefinition.inherited(ExpOrbEntity::new, entityBase) .type(EntityType.EXPERIENCE_ORB) .identifier("minecraft:xp_orb") .build(); @@ -297,6 +297,7 @@ public final class EntityDefinitions { TNT = EntityDefinition.inherited(TNTEntity::new, entityBase) .type(EntityType.TNT) .heightAndWidth(0.98f) + .offset(0.49f) .addTranslator(MetadataType.INT, TNTEntity::setFuseLength) .build(); 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 fecd72f67..a3f16875d 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 @@ -59,6 +59,9 @@ import java.util.*; @Getter @Setter public class Entity implements GeyserEntity { + + private static final boolean PRINT_ENTITY_SPAWN_DEBUG = Boolean.parseBoolean(System.getProperty("Geyser.PrintEntitySpawnDebug", "false")); + protected final GeyserSession session; protected int entityId; @@ -181,7 +184,7 @@ public class Entity implements GeyserEntity { flagsDirty = false; - if (session.getGeyser().getConfig().isDebugMode()) { + if (session.getGeyser().getConfig().isDebugMode() && PRINT_ENTITY_SPAWN_DEBUG) { EntityType type = definition.entityType(); String name = type != null ? type.name() : getClass().getSimpleName(); session.getGeyser().getLogger().debug("Spawned entity " + name + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")"); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java index 5a79a98b3..9f61bc961 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java @@ -27,11 +27,18 @@ package org.geysermc.geyser.entity.type; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.session.GeyserSession; +import java.util.UUID; + public class ExpOrbEntity extends Entity { + public ExpOrbEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition entityDefinition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + this(session, 1, entityId, geyserId, position); + } + public ExpOrbEntity(GeyserSession session, int amount, int entityId, long geyserId, Vector3f position) { super(session, entityId, geyserId, null, EntityDefinitions.EXPERIENCE_ORB, position, Vector3f.ZERO, 0, 0, 0); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java index dca36cda0..47d97b8f7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java @@ -39,7 +39,17 @@ public class TNTEntity extends Entity implements Tickable { private int currentTick; public TNTEntity(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); + super(session, entityId, geyserId, uuid, definition, position.add(0, definition.offset(), 0), motion, yaw, pitch, headYaw); + } + + @Override + public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) { + super.moveRelative(relX, relY + definition.offset(), relZ, yaw, pitch, isOnGround); + } + + @Override + public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) { + super.moveAbsolute(position.add(Vector3f.from(0, definition.offset(), 0)), yaw, pitch, headYaw, isOnGround, teleported); } public void setFuseLength(IntEntityMetadata entityMetadata) { 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 25040063e..4c67b882f 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 @@ -41,6 +41,7 @@ import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.*; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; import org.geysermc.geyser.entity.EntityDefinitions; @@ -166,6 +167,31 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { session.sendUpstreamPacket(addPlayerPacket); } + @Override + public void despawnEntity() { + super.despawnEntity(); + + // Since we re-use player entities: Clear flags, held item, etc + this.resetMetadata(); + this.hand = ItemData.AIR; + this.offhand = ItemData.AIR; + this.boots = ItemData.AIR; + this.leggings = ItemData.AIR; + this.chestplate = ItemData.AIR; + this.helmet = ItemData.AIR; + } + + public void resetMetadata() { + // Reset all metadata to their default values + // This is used when a player respawns + this.flags.clear(); + this.initializeMetadata(); + + // Explicitly reset all metadata not handled by initializeMetadata + setParrot(null, true); + setParrot(null, false); + } + public void sendPlayer() { if (session.getEntityCache().getPlayerEntity(uuid) == null) return; 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 e10adb134..533ca3c59 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 @@ -264,19 +264,13 @@ public class SessionPlayerEntity extends PlayerEntity { super.setAbsorptionHearts(entityMetadata); } + @Override public void resetMetadata() { - // Reset all metadata to their default values - // This is used when a player respawns - this.flags.clear(); - this.initializeMetadata(); + super.resetMetadata(); // Reset air this.resetAir(); - // Explicitly reset all metadata not handled by initializeMetadata - setParrot(null, true); - setParrot(null, false); - // Absorption is metadata in java edition attributes.remove(GeyserAttributeType.ABSORPTION); UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); From 5ebb6ef0d66ca5871c8c42adb245a2a3f48113d2 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 17 May 2024 22:48:46 +0200 Subject: [PATCH 143/897] Fix: using curly brackets in custom Minecraft locale overrides --- .../geyser/text/MinecraftTranslationRegistry.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/text/MinecraftTranslationRegistry.java b/core/src/main/java/org/geysermc/geyser/text/MinecraftTranslationRegistry.java index b59b4db8e..67654360d 100644 --- a/core/src/main/java/org/geysermc/geyser/text/MinecraftTranslationRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/text/MinecraftTranslationRegistry.java @@ -63,6 +63,13 @@ public class MinecraftTranslationRegistry extends TranslatableComponentRenderer< } } + // replace single quote instances which get lost in MessageFormat otherwise + localeString = localeString.replace("'", "''"); + + // Wrap all curly brackets with single quote inserts - fixes https://github.com/GeyserMC/Geyser/issues/4662 + localeString = localeString.replace("{", "'{") + .replace("}", "'}"); + // Replace the `%s` with numbered inserts `{0}` Pattern p = stringReplacement; Matcher m = p.matcher(localeString); @@ -83,8 +90,7 @@ public class MinecraftTranslationRegistry extends TranslatableComponentRenderer< } m.appendTail(sb); - // replace single quote instances which get lost in MessageFormat otherwise // Locale shouldn't need to be specific - dates for example will not be handled - return new MessageFormat(sb.toString().replace("'", "''"), Locale.ROOT); + return new MessageFormat(sb.toString(), Locale.ROOT); } } From 06dc0d1ca83f820ec9fed233a7998eeead888363 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 17 May 2024 17:52:19 -0400 Subject: [PATCH 144/897] Collisions without BlockMapping --- .../java/org/geysermc/geyser/GeyserImpl.java | 2 - .../geyser/level/block/BlockStateValues.java | 3 - .../geyser/registry/BlockRegistries.java | 12 +-- .../geyser/registry/ListRegistry.java | 15 +++- .../loader/CollisionRegistryLoader.java | 76 +++++++++---------- .../populator/BlockRegistryPopulator.java | 11 +-- .../collision/CollisionRemapper.java | 6 -- .../collision/DirtPathCollision.java | 3 +- .../translator/collision/DoorCollision.java | 22 +++--- .../GlassPaneAndIronBarsCollision.java | 21 ++--- .../collision/ScaffoldingCollision.java | 3 +- .../translator/collision/SolidCollision.java | 3 +- .../collision/TrapdoorCollision.java | 47 ++++-------- core/src/main/resources/mappings | 2 +- 14 files changed, 100 insertions(+), 126 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 4f572ef63..e7237e8bf 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -69,7 +69,6 @@ import org.geysermc.geyser.event.GeyserEventBus; import org.geysermc.geyser.extension.GeyserExtensionManager; import org.geysermc.geyser.impl.MinecraftVersionImpl; import org.geysermc.geyser.level.WorldManager; -import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.GeyserServer; import org.geysermc.geyser.registry.BlockRegistries; @@ -258,7 +257,6 @@ public class GeyserImpl implements GeyserApi { VersionCheckUtils.checkForOutdatedJava(logger); - Blocks.VAULT.javaId(); for (int i = 0; i < BlockRegistries.JAVA_BLOCKS.get().length; i++) { String cleanIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getCleanJavaIdentifier(); String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier(); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 205486ced..e2a2cb5eb 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -69,9 +69,6 @@ public final class BlockStateValues { private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap(); private static final IntSet UPPER_DOORS = new IntOpenHashSet(); - public static final int JAVA_AIR_ID = 0; - - public static int JAVA_COBWEB_ID; public static int JAVA_FURNACE_ID; public static int JAVA_FURNACE_LIT_ID; public static int JAVA_HONEY_BLOCK_ID; diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 54a36dc12..416ab7793 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -34,6 +34,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; +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.loader.CollisionRegistryLoader; @@ -82,19 +83,13 @@ public class BlockRegistries { /** * A mapped registry containing which holds block IDs to its {@link BlockCollision}. */ - public static final IntMappedRegistry COLLISIONS; + public static final ListRegistry COLLISIONS; /** * A mapped registry containing the Java identifiers to IDs. */ public static final MappedRegistry> JAVA_IDENTIFIER_TO_ID = MappedRegistry.create(RegistryLoaders.empty(Object2IntOpenHashMap::new)); - /** - * A registry which stores unique Java IDs to its clean identifier - * This is used in the statistics form. - */ - public static final ArrayRegistry CLEAN_JAVA_IDENTIFIERS = ArrayRegistry.create(RegistryLoaders.uninitialized()); - /** * A registry containing all the waterlogged blockstates. */ @@ -141,12 +136,13 @@ public class BlockRegistries { public static final SimpleMappedRegistry CUSTOM_SKULLS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); static { + Blocks.VAULT.javaId(); // FIXME CustomSkullRegistryPopulator.populate(); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.PRE_INIT); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA); - COLLISIONS = IntMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new); + COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java index bb5d2538c..d13c47ba8 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.registry.loader.RegistryLoader; import java.util.List; +import java.util.function.Supplier; public class ListRegistry extends Registry> { /** @@ -98,6 +99,18 @@ public class ListRegistry extends Registry> { * @return a new registry with the given RegistryLoader supplier */ public static ListRegistry create(RegistryLoader> registryLoader) { - return new ListRegistry(null, registryLoader); + return new ListRegistry<>(null, registryLoader); + } + + /** + * Creates a new integer mapped registry with the given {@link RegistryLoader} and input. + * + * @param registryLoader the registry loader + * @param the input + * @param the type value + * @return a new registry with the given RegistryLoader supplier + */ + public static ListRegistry create(I input, Supplier>> registryLoader) { + return new ListRegistry<>(input, registryLoader.get()); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java index 95e8bd2c1..7cf39b6d7 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java @@ -25,18 +25,19 @@ package org.geysermc.geyser.registry.loader; -import com.fasterxml.jackson.databind.node.ArrayNode; 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.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import lombok.AllArgsConstructor; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.nbt.NbtUtils; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.translator.collision.CollisionRemapper; import org.geysermc.geyser.translator.collision.OtherCollision; @@ -51,41 +52,43 @@ import java.util.regex.Pattern; /** * Loads collision data from the given resource path. */ -public class CollisionRegistryLoader extends MultiResourceRegistryLoader> { +public class CollisionRegistryLoader extends MultiResourceRegistryLoader> { @Override - public Int2ObjectMap load(Pair input) { - Int2ObjectMap collisions = new Int2ObjectOpenHashMap<>(); - + public List load(Pair input) { Map, CollisionInfo> annotationMap = new IdentityHashMap<>(); for (Class clazz : FileUtils.getGeneratedClassesForAnnotation(CollisionRemapper.class.getName())) { GeyserImpl.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName()); CollisionRemapper collisionRemapper = clazz.getAnnotation(CollisionRemapper.class); - annotationMap.put(clazz, new CollisionInfo(collisionRemapper, Pattern.compile(collisionRemapper.regex()), Pattern.compile(collisionRemapper.paramRegex()))); + annotationMap.put(clazz, new CollisionInfo(collisionRemapper, Pattern.compile(collisionRemapper.regex()))); } // Load collision mappings file + int[] indices; List collisionList; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input.value())) { - ArrayNode collisionNode = (ArrayNode) GeyserImpl.JSON_MAPPER.readTree(stream); - collisionList = loadBoundingBoxes(collisionNode); + NbtMap collisionData = (NbtMap) NbtUtils.createGZIPReader(stream).readTag(); + indices = collisionData.getIntArray("indices"); + //SuppressWarnings unchecked + collisionList = loadBoundingBoxes(collisionData.getList("collisions", NbtType.LIST)); } catch (Exception e) { throw new AssertionError("Unable to load collision data", e); } - BlockMapping[] blockMappings = BlockRegistries.JAVA_BLOCKS.get(); + List blockStates = BlockRegistries.BLOCK_STATES.get(); + List collisions = new ObjectArrayList<>(blockStates.size()); // Map of unique collisions to its instance Map collisionInstances = new Object2ObjectOpenHashMap<>(); - for (int i = 0; i < blockMappings.length; i++) { - BlockMapping blockMapping = blockMappings[i]; - if (blockMapping == null) { - GeyserImpl.getInstance().getLogger().warning("Missing block mapping for Java block " + i); + for (int i = 0; i < blockStates.size(); i++) { + BlockState state = blockStates.get(i); + if (state == null) { + GeyserImpl.getInstance().getLogger().warning("Missing block state for Java block " + i); continue; } - BlockCollision newCollision = instantiateCollision(blockMapping, annotationMap, collisionList); + BlockCollision newCollision = instantiateCollision(state, annotationMap, indices[i], collisionList); if (newCollision != null) { // If there's an existing instance equal to this one, use that instead @@ -97,33 +100,27 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader, CollisionInfo> annotationMap, List collisionList) { - String[] blockIdParts = mapping.getJavaIdentifier().split("\\["); - String blockName = blockIdParts[0].replace("minecraft:", ""); - String params = ""; - if (blockIdParts.length == 2) { - params = "[" + blockIdParts[1]; - } - int collisionIndex = mapping.getCollisionIndex(); + private @Nullable BlockCollision instantiateCollision(BlockState state, Map, CollisionInfo> annotationMap, int collisionIndex, List collisionList) { + String blockName = state.block().javaIdentifier().substring("minecraft:".length()); for (Map.Entry, CollisionInfo> collisionRemappers : annotationMap.entrySet()) { Class type = collisionRemappers.getKey(); CollisionInfo collisionInfo = collisionRemappers.getValue(); CollisionRemapper annotation = collisionInfo.collisionRemapper; - if (collisionInfo.pattern.matcher(blockName).find() && collisionInfo.paramsPattern.matcher(params).find()) { + if (collisionInfo.pattern.matcher(blockName).find()) { try { if (annotation.passDefaultBoxes()) { // Create an OtherCollision instance and get the bounding boxes BoundingBox[] defaultBoxes = collisionList.get(collisionIndex); - return (BlockCollision) type.getDeclaredConstructor(String.class, BoundingBox[].class).newInstance(params, defaultBoxes); + return (BlockCollision) type.getDeclaredConstructor(BlockState.class, BoundingBox[].class).newInstance(state, defaultBoxes); } else { - return (BlockCollision) type.getDeclaredConstructor(String.class).newInstance(params); + return (BlockCollision) type.getDeclaredConstructor(BlockState.class).newInstance(state); } } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { throw new RuntimeException(e); @@ -138,25 +135,25 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader loadBoundingBoxes(ArrayNode collisionNode) { + private List loadBoundingBoxes(List collisionNode) { List collisions = new ObjectArrayList<>(); for (int collisionIndex = 0; collisionIndex < collisionNode.size(); collisionIndex++) { - ArrayNode boundingBoxArray = (ArrayNode) collisionNode.get(collisionIndex); + @SuppressWarnings("unchecked") NbtList> boundingBoxArray = (NbtList>) collisionNode.get(collisionIndex); BoundingBox[] boundingBoxes = new BoundingBox[boundingBoxArray.size()]; for (int i = 0; i < boundingBoxArray.size(); i++) { - ArrayNode boxProperties = (ArrayNode) boundingBoxArray.get(i); - boundingBoxes[i] = new BoundingBox(boxProperties.get(0).asDouble(), - boxProperties.get(1).asDouble(), - boxProperties.get(2).asDouble(), - boxProperties.get(3).asDouble(), - boxProperties.get(4).asDouble(), - boxProperties.get(5).asDouble()); + NbtList boxProperties = boundingBoxArray.get(i); + boundingBoxes[i] = new BoundingBox(boxProperties.get(0), + boxProperties.get(1), + boxProperties.get(2), + boxProperties.get(3), + boxProperties.get(4), + boxProperties.get(5)); } // Sorting by lowest Y first fixes some bugs @@ -173,6 +170,5 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader cleanIdentifiers = new ArrayDeque<>(); int javaRuntimeId = -1; - int cobwebBlockId = -1; int furnaceRuntimeId = -1; int furnaceLitRuntimeId = -1; int honeyBlockRuntimeId = -1; @@ -485,10 +484,7 @@ public final class BlockRegistryPopulator { // It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern()); - if (javaId.contains("cobweb")) { - cobwebBlockId = uniqueJavaId; - - } else if (javaId.startsWith("minecraft:furnace[facing=north")) { + if (javaId.startsWith("minecraft:furnace[facing=north")) { if (javaId.contains("lit=true")) { furnaceLitRuntimeId = javaRuntimeId; } else { @@ -507,11 +503,6 @@ public final class BlockRegistryPopulator { } } - if (cobwebBlockId == -1) { - throw new AssertionError("Unable to find cobwebs in palette"); - } - BlockStateValues.JAVA_COBWEB_ID = cobwebBlockId; - if (furnaceRuntimeId == -1) { throw new AssertionError("Unable to find furnace in palette"); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/CollisionRemapper.java b/core/src/main/java/org/geysermc/geyser/translator/collision/CollisionRemapper.java index 6980968ab..fb93a14d5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/CollisionRemapper.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/CollisionRemapper.java @@ -37,12 +37,6 @@ public @interface CollisionRemapper { */ String regex(); - /** - * Regex of block state parameters to apply this collision to - * Defaults to matching any value - */ - String paramRegex() default ".*"; - /** * Signals if a new instance needs to created for every block state */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/DirtPathCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/DirtPathCollision.java index dcbad4758..d44187a0c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/DirtPathCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/DirtPathCollision.java @@ -26,13 +26,14 @@ package org.geysermc.geyser.translator.collision; import lombok.EqualsAndHashCode; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.CollisionManager; @EqualsAndHashCode(callSuper = true) @CollisionRemapper(regex = "^dirt_path$", passDefaultBoxes = true) public class DirtPathCollision extends BlockCollision { - public DirtPathCollision(String params, BoundingBox[] defaultBoxes) { + public DirtPathCollision(BlockState state, BoundingBox[] defaultBoxes) { super(defaultBoxes); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/DoorCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/DoorCollision.java index b47b187c4..33c85ce07 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/DoorCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/DoorCollision.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.translator.collision; import lombok.EqualsAndHashCode; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.session.GeyserSession; @@ -40,20 +42,18 @@ public class DoorCollision extends BlockCollision { */ private int facing; - public DoorCollision(String params, BoundingBox[] defaultBoxes) { + public DoorCollision(BlockState state, BoundingBox[] defaultBoxes) { super(defaultBoxes); - if (params.contains("facing=north")) { - facing = 1; - } else if (params.contains("facing=east")) { - facing = 2; - } else if (params.contains("facing=south")) { - facing = 3; - } else if (params.contains("facing=west")) { - facing = 4; - } + facing = switch (state.getValue(Properties.HORIZONTAL_FACING)) { + case NORTH -> 1; + case EAST -> 2; + case SOUTH -> 3; + case WEST -> 4; + default -> throw new IllegalStateException(); + }; // If the door is open it changes direction - if (params.contains("open=true")) { + if (state.getValue(Properties.OPEN)) { facing = facing % 2 + 1; } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/GlassPaneAndIronBarsCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/GlassPaneAndIronBarsCollision.java index 14439645a..35874348c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/GlassPaneAndIronBarsCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/GlassPaneAndIronBarsCollision.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.translator.collision; import lombok.EqualsAndHashCode; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.session.GeyserSession; @@ -44,24 +46,23 @@ public class GlassPaneAndIronBarsCollision extends BlockCollision { */ private int facing; - public GlassPaneAndIronBarsCollision(String params, BoundingBox[] defaultBoxes) { + public GlassPaneAndIronBarsCollision(BlockState state, BoundingBox[] defaultBoxes) { super(defaultBoxes); - //east=true,north=true,south=true,west=true - if (params.contains("north=true") && params.contains("east=true")) { + if (state.getValue(Properties.NORTH) && state.getValue(Properties.EAST)) { facing = 5; - } else if (params.contains("east=true") && params.contains("south=true")) { + } else if (state.getValue(Properties.EAST) && state.getValue(Properties.SOUTH)) { facing = 6; - } else if (params.contains("south=true") && params.contains("west=true")) { + } else if (state.getValue(Properties.SOUTH) && state.getValue(Properties.WEST)) { facing = 7; - } else if (params.contains("west=true") && params.contains("north=true")) { + } else if (state.getValue(Properties.WEST) && state.getValue(Properties.NORTH)) { facing = 8; - } else if (params.contains("north=true")) { + } else if (state.getValue(Properties.NORTH)) { facing = 1; - } else if (params.contains("east=true")) { + } else if (state.getValue(Properties.EAST)) { facing = 2; - } else if (params.contains("south=true")) { + } else if (state.getValue(Properties.SOUTH)) { facing = 3; - } else if (params.contains("west=true")) { + } else if (state.getValue(Properties.WEST)) { facing = 4; } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/ScaffoldingCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/ScaffoldingCollision.java index dfbd1c8b8..7449987c6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/ScaffoldingCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/ScaffoldingCollision.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.translator.collision; import lombok.EqualsAndHashCode; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.session.GeyserSession; @@ -35,7 +36,7 @@ import org.geysermc.geyser.session.GeyserSession; @EqualsAndHashCode(callSuper = true) @CollisionRemapper(regex = "^scaffolding$", usesParams = true, passDefaultBoxes = true) public class ScaffoldingCollision extends BlockCollision { - public ScaffoldingCollision(String params, BoundingBox[] defaultBoxes) { + public ScaffoldingCollision(BlockState state, BoundingBox[] defaultBoxes) { super(defaultBoxes); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/SolidCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/SolidCollision.java index 822202ff2..51d1038c0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/SolidCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/SolidCollision.java @@ -26,12 +26,13 @@ package org.geysermc.geyser.translator.collision; import lombok.EqualsAndHashCode; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.BoundingBox; @EqualsAndHashCode(callSuper = true) @CollisionRemapper(regex = "shulker_box$") // These have no collision in the mappings as it depends on the NBT data public class SolidCollision extends BlockCollision { - public SolidCollision(String params) { + public SolidCollision(BlockState state) { super(new BoundingBox[] { new BoundingBox(0.5, 0.5, 0.5, 1, 1, 1) }); diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/TrapdoorCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/TrapdoorCollision.java index 836c05711..909761166 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/TrapdoorCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/TrapdoorCollision.java @@ -26,42 +26,27 @@ package org.geysermc.geyser.translator.collision; import lombok.EqualsAndHashCode; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.CollisionManager; +import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; @EqualsAndHashCode(callSuper = true) @CollisionRemapper(regex = "_trapdoor$", usesParams = true, passDefaultBoxes = true) public class TrapdoorCollision extends BlockCollision { - /** - * 1 = north - * 2 = east - * 3 = south - * 4 = west - * 5 = up - * 6 = down - */ - private int facing; + private final Direction facing; - public TrapdoorCollision(String params, BoundingBox[] defaultBoxes) { + public TrapdoorCollision(BlockState state, BoundingBox[] defaultBoxes) { super(defaultBoxes); - if (params.contains("open=true")) { - if (params.contains("facing=north")) { - facing = 1; - } else if (params.contains("facing=east")) { - facing = 2; - } else if (params.contains("facing=south")) { - facing = 3; - } else if (params.contains("facing=west")) { - facing = 4; - } + if (state.getValue(Properties.OPEN)) { + facing = state.getValue(Properties.HORIZONTAL_FACING); } else { - if (params.contains("half=bottom")) { - // Up - facing = 5; + if (state.getValue(Properties.HALF).equals("bottom")) { + facing = Direction.UP; } else { - // Down - facing = 6; + facing = Direction.DOWN; } } } @@ -72,22 +57,22 @@ public class TrapdoorCollision extends BlockCollision { // Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock) if (this.checkIntersection(x, y, z, playerCollision)) { switch (facing) { - case 1: // North + case NORTH: playerCollision.setMiddleZ(z + 0.5125); break; - case 2: // East + case EAST: playerCollision.setMiddleX(x + 0.5125); break; - case 3: // South + case SOUTH: playerCollision.setMiddleZ(z + 0.4875); break; - case 4: // West + case WEST: playerCollision.setMiddleX(x + 0.4875); break; - case 5: + case UP: // Up-facing trapdoors are handled by the step-up check break; - case 6: // Down + case DOWN: // (top y of trap door) - (trap door thickness) = top y of player playerCollision.setMiddleY(y + 1 - (3.0 / 16.0) - playerCollision.getSizeY() / 2.0 - CollisionManager.COLLISION_TOLERANCE); break; diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 7c01501ed..6b661f0d5 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 7c01501ed6a0ee8848a66d729000539f2661f785 +Subproject commit 6b661f0d517d895aebc1f55a25d2c86f033beb1d From beef01f3fc96befb0558b070c34dd04400fb4eec Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 17 May 2024 20:55:34 -0400 Subject: [PATCH 145/897] Pistons now use the new block stuff --- .../erosion/GeyserboundPacketHandlerImpl.java | 13 +- .../geysermc/geyser/level/WorldManager.java | 9 + .../geyser/level/block/BlockStateValues.java | 98 +-- .../geysermc/geyser/level/block/Blocks.java | 704 +++++++++--------- .../level/block/property/Properties.java | 2 +- .../geyser/level/block/type/Block.java | 86 +++ .../geyser/level/block/type/BlockState.java | 4 + .../level/block/type/CauldronBlock.java | 51 ++ .../geyser/level/block/type/ChestBlock.java | 52 ++ .../geyser/level/block/type/DoorBlock.java | 50 ++ .../block/type/FlowerPotBlock.java} | 74 +- .../geyser/level/block/type/LecternBlock.java | 61 ++ .../level/block/type/MovingPistonBlock.java | 42 ++ .../geyser/level/block/type/PistonBlock.java | 47 ++ .../geyser/level/block/type/SkullBlock.java | 54 ++ .../populator/BlockRegistryPopulator.java | 40 +- .../geyser/registry/type/BlockMapping.java | 15 +- .../geyser/registry/type/BlockMappings.java | 5 + .../geyser/session/cache/TagCache.java | 12 - .../geyser/session/cache/WorldCache.java | 2 +- ...a => BedrockChunkWantsBlockEntityTag.java} | 30 +- .../block/entity/BedrockOnlyBlockEntity.java | 82 -- .../DoubleChestBlockEntityTranslator.java | 21 +- .../level/block/entity/PistonBlockEntity.java | 85 +-- .../BedrockBlockPickRequestTranslator.java | 4 +- .../java/level/JavaBlockEventTranslator.java | 22 +- .../JavaLevelChunkWithLightTranslator.java | 19 +- .../geyser/util/BlockEntityUtils.java | 12 - .../org/geysermc/geyser/util/ChunkUtils.java | 111 +-- 29 files changed, 978 insertions(+), 829 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/CauldronBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/ChestBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java rename core/src/main/java/org/geysermc/geyser/{translator/level/block/entity/FlowerPotBlockEntityTranslator.java => level/block/type/FlowerPotBlock.java} (60%) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/MovingPistonBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/PistonBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java rename core/src/main/java/org/geysermc/geyser/translator/level/block/entity/{PistonBlockEntityTranslator.java => BedrockChunkWantsBlockEntityTag.java} (59%) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index b76dc0b85..6e22fd430 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -26,11 +26,12 @@ package org.geysermc.geyser.erosion; import io.netty.channel.Channel; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.Setter; import org.cloudburstmc.math.vector.Vector3i; @@ -44,6 +45,7 @@ import org.geysermc.erosion.packet.backendbound.BackendboundPacket; import org.geysermc.erosion.packet.geyserbound.*; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; @@ -153,9 +155,10 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke var stream = packet.getAttachedBlocks() .object2IntEntrySet() .stream() - .filter(entry -> BlockStateValues.canPistonMoveBlock(entry.getIntValue(), isExtend)); - Object2IntMap attachedBlocks = new Object2IntArrayMap<>(); - stream.forEach(entry -> attachedBlocks.put(entry.getKey(), entry.getIntValue())); + .map(entry -> Pair.of(entry.getKey(), BlockState.of(entry.getIntValue()))) + .filter(pair -> BlockStateValues.canPistonMoveBlock(pair.value(), isExtend)); + Object2ObjectMap attachedBlocks = new Object2ObjectOpenHashMap<>(); + stream.forEach(pair -> attachedBlocks.put(pair.key(), pair.value())); session.executeInEventLoop(() -> { PistonCache pistonCache = session.getPistonCache(); diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index cd6c9e824..5edce21dc 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -33,6 +33,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.erosion.util.BlockPositionIterator; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; @@ -58,6 +59,14 @@ import java.util.function.Function; */ public abstract class WorldManager { + public final BlockState blockAt(GeyserSession session, Vector3i vector3i) { + return BlockState.of(this.getBlockAt(session, vector3i)); + } + + public BlockState blockAt(GeyserSession session, int x, int y, int z) { + return BlockState.of(this.getBlockAt(session, x, y, z)); + } + /** * Gets the Java block state at the specified location * diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index e2a2cb5eb..a64e5c1c8 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -29,12 +29,14 @@ import com.fasterxml.jackson.databind.JsonNode; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +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.level.block.type.PistonBlock; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; -import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntityTranslator; import org.geysermc.geyser.util.collection.FixedInt2ByteMap; import org.geysermc.geyser.util.collection.FixedInt2IntMap; import org.geysermc.geyser.util.collection.LecternHasBookMap; @@ -229,28 +231,6 @@ public final class BlockStateValues { return BANNER_COLORS.getOrDefault(state, -1); } - /** - * Bed colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives a byte color that Bedrock can use - Bedrock needs a byte in the final tag. - * - * @param state BlockState of the block - * @return Bed color byte or -1 if no color - */ - public static byte getBedColor(int state) { - return BED_COLORS.getOrDefault(state, (byte) -1); - } - - /** - * The brush progress of suspicious sand/gravel is not sent by the java server when it updates the block entity. - * Although brush progress is part of the bedrock block state, it must be included in the block entity update. - * - * @param state BlockState of the block - * @return brush progress or 0 if the lookup failed - */ - public static int getBrushProgress(int state) { - return BRUSH_PROGRESS.getOrDefault(state, 0); - } - /** * @return if this Java block state is a non-empty non-water cauldron */ @@ -341,18 +321,6 @@ public final class BlockStateValues { return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID); } - /** - * Check if a block is a minecraft:moving_piston - * This is used in ChunkUtils to prevent them from being placed as it causes - * pistons to flicker and it is not needed - * - * @param state Block state of the block - * @return True if the block is a moving_piston - */ - public static boolean isMovingPiston(int state) { - return MOVING_PISTONS.contains(state); - } - /** * This is used in GeyserPistonEvents.java and accepts minecraft:piston, * minecraft:sticky_piston, and minecraft:moving_piston. @@ -371,8 +339,9 @@ public final class BlockStateValues { * @param state The block state * @return True if the block sticks to adjacent blocks */ - public static boolean isBlockSticky(int state) { - return state == JAVA_SLIME_BLOCK_ID || state == JAVA_HONEY_BLOCK_ID; + public static boolean isBlockSticky(BlockState state) { + Block block = state.block(); + return block == Blocks.SLIME_BLOCK || block == Blocks.HONEY_BLOCK; } /** @@ -382,13 +351,13 @@ public final class BlockStateValues { * @param stateB The block state of block b * @return True if the blocks are attached to each other */ - public static boolean isBlockAttached(int stateA, int stateB) { + public static boolean isBlockAttached(BlockState stateA, BlockState stateB) { boolean aSticky = isBlockSticky(stateA); boolean bSticky = isBlockSticky(stateB); if (aSticky && bSticky) { // Only matching sticky blocks are attached together // Honey + Honey & Slime + Slime - return stateA == stateB; + return stateA.block() == stateB.block(); } return aSticky || bSticky; } @@ -397,27 +366,30 @@ public final class BlockStateValues { * @param state The block state of the block * @return true if a piston can break the block */ - public static boolean canPistonDestroyBlock(int state) { - return BlockRegistries.JAVA_BLOCKS.getOrDefault(state, BlockMapping.DEFAULT).getPistonBehavior() == PistonBehavior.DESTROY; + public static boolean canPistonDestroyBlock(BlockState state) { + return state.block().pushReaction() == PistonBehavior.DESTROY; } - public static boolean canPistonMoveBlock(int javaId, boolean isPushing) { - if (javaId == Block.JAVA_AIR_ID) { + public static boolean canPistonMoveBlock(BlockState state, boolean isPushing) { + Block block = state.block(); + if (block == Blocks.AIR) { return true; } - // Pistons can only be moved if they aren't extended - if (PistonBlockEntityTranslator.isBlock(javaId)) { - return !PISTON_VALUES.get(javaId); - } - BlockMapping block = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaId, BlockMapping.DEFAULT); - // Bedrock, End portal frames, etc. can't be moved - if (block.getHardness() == -1.0d) { + if (block == Blocks.OBSIDIAN || block == Blocks.CRYING_OBSIDIAN || block == Blocks.RESPAWN_ANCHOR || block == Blocks.REINFORCED_DEEPSLATE) { // Hardcoded as of 1.20.5 return false; } - return switch (block.getPistonBehavior()) { + // Pistons can only be moved if they aren't extended + if (block instanceof PistonBlock) { + return !state.getValue(Properties.EXTENDED); + } + // Bedrock, End portal frames, etc. can't be moved + if (block.destroyTime() == -1.0f) { + return false; + } + return switch (block.pushReaction()) { case BLOCK, DESTROY -> false; case PUSH_ONLY -> isPushing; // Glazed terracotta can only be pushed - default -> !block.isBlockEntity(); // Pistons can't move block entities + default -> !block.hasBlockEntity(); // Pistons can't move block entities }; } @@ -443,17 +415,6 @@ public final class BlockStateValues { return SKULL_ROTATIONS.getOrDefault(state, (byte) -1); } - /** - * As of Java 1.20.2: - * Skull powered states are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * - * @param state BlockState of the block - * @return true if this skull is currently being powered. - */ - public static boolean isSkullPowered(int state) { - return SKULL_POWERED.contains(state); - } - /** * Skull rotations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. * This gives a integer rotation that Bedrock can use. @@ -464,17 +425,6 @@ public final class BlockStateValues { return SKULL_WALL_DIRECTIONS; } - /** - * Shulker box directions are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives a byte direction that Bedrock can use. - * - * @param state BlockState of the block - * @return Shulker direction value or -1 if no value - */ - public static byte getShulkerBoxDirection(int state) { - return SHULKERBOX_DIRECTIONS.getOrDefault(state, (byte) -1); - } - /** * Get the level of water from the block state. * 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 1f9c9c162..142708dd9 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 @@ -25,11 +25,11 @@ package org.geysermc.geyser.level.block; -import org.geysermc.geyser.level.block.type.BannerBlock; -import org.geysermc.geyser.level.block.type.BedBlock; -import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.property.ChestType; +import org.geysermc.geyser.level.block.type.*; import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Direction; +import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import static org.geysermc.geyser.level.block.property.Properties.*; @@ -62,36 +62,36 @@ public final class Blocks { 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() + public static final Block OAK_SAPLING = register(new Block("oak_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block SPRUCE_SAPLING = register(new Block("spruce_sapling", builder() + public static final Block SPRUCE_SAPLING = register(new Block("spruce_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block BIRCH_SAPLING = register(new Block("birch_sapling", builder() + public static final Block BIRCH_SAPLING = register(new Block("birch_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block JUNGLE_SAPLING = register(new Block("jungle_sapling", builder() + public static final Block JUNGLE_SAPLING = register(new Block("jungle_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block ACACIA_SAPLING = register(new Block("acacia_sapling", builder() + public static final Block ACACIA_SAPLING = register(new Block("acacia_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block CHERRY_SAPLING = register(new Block("cherry_sapling", builder() + public static final Block CHERRY_SAPLING = register(new Block("cherry_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block DARK_OAK_SAPLING = register(new Block("dark_oak_sapling", builder() + public static final Block DARK_OAK_SAPLING = register(new Block("dark_oak_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block MANGROVE_PROPAGULE = register(new Block("mangrove_propagule", builder() + public static final Block MANGROVE_PROPAGULE = register(new Block("mangrove_propagule", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_4, 0, 4) .booleanState(HANGING) .intState(STAGE, 0, 1) .booleanState(WATERLOGGED))); public static final Block BEDROCK = register(new Block("bedrock", builder().destroyTime(-1.0f))); - public static final Block WATER = register(new Block("water", builder().destroyTime(100.0f) + public static final Block WATER = register(new Block("water", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) .intState(LEVEL, 0, 15))); - public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f) + public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) .intState(LEVEL, 0, 15))); 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().destroyTime(0.25f) + public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder().setBlockEntity().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) .intState(DUSTED, 0, 3))); 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().destroyTime(0.25f) + public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder().setBlockEntity().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) .intState(DUSTED, 0, 3))); 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))); @@ -172,43 +172,43 @@ public final class Blocks { .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))); - public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder().destroyTime(0.2f) + public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block SPRUCE_LEAVES = register(new Block("spruce_leaves", builder().destroyTime(0.2f) + public static final Block SPRUCE_LEAVES = register(new Block("spruce_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block BIRCH_LEAVES = register(new Block("birch_leaves", builder().destroyTime(0.2f) + public static final Block BIRCH_LEAVES = register(new Block("birch_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block JUNGLE_LEAVES = register(new Block("jungle_leaves", builder().destroyTime(0.2f) + public static final Block JUNGLE_LEAVES = register(new Block("jungle_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block ACACIA_LEAVES = register(new Block("acacia_leaves", builder().destroyTime(0.2f) + public static final Block ACACIA_LEAVES = register(new Block("acacia_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block CHERRY_LEAVES = register(new Block("cherry_leaves", builder().destroyTime(0.2f) + public static final Block CHERRY_LEAVES = register(new Block("cherry_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_LEAVES = register(new Block("dark_oak_leaves", builder().destroyTime(0.2f) + public static final Block DARK_OAK_LEAVES = register(new Block("dark_oak_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block MANGROVE_LEAVES = register(new Block("mangrove_leaves", builder().destroyTime(0.2f) + public static final Block MANGROVE_LEAVES = register(new Block("mangrove_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block AZALEA_LEAVES = register(new Block("azalea_leaves", builder().destroyTime(0.2f) + public static final Block AZALEA_LEAVES = register(new Block("azalea_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block FLOWERING_AZALEA_LEAVES = register(new Block("flowering_azalea_leaves", builder().destroyTime(0.2f) + public static final Block FLOWERING_AZALEA_LEAVES = register(new Block("flowering_azalea_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); @@ -228,67 +228,67 @@ public final class Blocks { .enumState(NOTEBLOCK_INSTRUMENT, "harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling", "zombie", "skeleton", "creeper", "dragon", "wither_skeleton", "piglin", "custom_head") .intState(NOTE, 0, 24) .booleanState(POWERED))); - public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity().destroyTime(0.2f) + public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity().destroyTime(0.2f) + public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity().destroyTime(0.2f) + public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity().destroyTime(0.2f) + public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity().destroyTime(0.2f) + public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity().destroyTime(0.2f) + public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity().destroyTime(0.2f) + public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity().destroyTime(0.2f) + public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity().destroyTime(0.2f) + public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity().destroyTime(0.2f) + public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity().destroyTime(0.2f) + public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity().destroyTime(0.2f) + public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity().destroyTime(0.2f) + public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity().destroyTime(0.2f) + public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity().destroyTime(0.2f) + public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity().destroyTime(0.2f) + public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); @@ -300,20 +300,20 @@ public final class Blocks { .booleanState(POWERED) .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") .booleanState(WATERLOGGED))); - public static final Block STICKY_PISTON = register(new Block("sticky_piston", builder().destroyTime(1.5f) + 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))); - public static final Block COBWEB = register(new Block("cobweb", builder().requiresCorrectToolForDrops().destroyTime(4.0f))); - public static final Block SHORT_GRASS = register(new Block("short_grass", builder())); - public static final Block FERN = register(new Block("fern", builder())); - public static final Block DEAD_BUSH = register(new Block("dead_bush", builder())); - public static final Block SEAGRASS = register(new Block("seagrass", builder())); - public static final Block TALL_SEAGRASS = register(new Block("tall_seagrass", builder() + 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) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block PISTON = register(new Block("piston", builder().destroyTime(1.5f) + 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))); - public static final Block PISTON_HEAD = register(new Block("piston_head", builder().destroyTime(1.5f) + public static final Block PISTON_HEAD = register(new Block("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, "normal", "sticky"))); @@ -333,25 +333,25 @@ public final class Blocks { public static final Block GREEN_WOOL = register(new Block("green_wool", builder().destroyTime(0.8f))); 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 Block("moving_piston", builder().setBlockEntity().destroyTime(-1.0f) + public static final Block MOVING_PISTON = register(new MovingPistonBlock("moving_piston", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .enumState(PISTON_TYPE, "normal", "sticky"))); - public static final Block DANDELION = register(new Block("dandelion", builder())); - public static final Block TORCHFLOWER = register(new Block("torchflower", builder())); - public static final Block POPPY = register(new Block("poppy", builder())); - public static final Block BLUE_ORCHID = register(new Block("blue_orchid", builder())); - public static final Block ALLIUM = register(new Block("allium", builder())); - public static final Block AZURE_BLUET = register(new Block("azure_bluet", builder())); - public static final Block RED_TULIP = register(new Block("red_tulip", builder())); - public static final Block ORANGE_TULIP = register(new Block("orange_tulip", builder())); - public static final Block WHITE_TULIP = register(new Block("white_tulip", builder())); - public static final Block PINK_TULIP = register(new Block("pink_tulip", builder())); - public static final Block OXEYE_DAISY = register(new Block("oxeye_daisy", builder())); - public static final Block CORNFLOWER = register(new Block("cornflower", builder())); - public static final Block WITHER_ROSE = register(new Block("wither_rose", builder())); - public static final Block LILY_OF_THE_VALLEY = register(new Block("lily_of_the_valley", builder())); - public static final Block BROWN_MUSHROOM = register(new Block("brown_mushroom", builder())); - public static final Block RED_MUSHROOM = register(new Block("red_mushroom", builder())); + 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))); + public static final Block BLUE_ORCHID = register(new Block("blue_orchid", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block ALLIUM = register(new Block("allium", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block AZURE_BLUET = register(new Block("azure_bluet", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block RED_TULIP = register(new Block("red_tulip", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block ORANGE_TULIP = register(new Block("orange_tulip", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block WHITE_TULIP = register(new Block("white_tulip", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block PINK_TULIP = register(new Block("pink_tulip", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block OXEYE_DAISY = register(new Block("oxeye_daisy", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block CORNFLOWER = register(new Block("cornflower", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block WITHER_ROSE = register(new Block("wither_rose", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block LILY_OF_THE_VALLEY = register(new Block("lily_of_the_valley", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block BROWN_MUSHROOM = register(new Block("brown_mushroom", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block RED_MUSHROOM = register(new Block("red_mushroom", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block GOLD_BLOCK = register(new Block("gold_block", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); 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))); @@ -368,28 +368,28 @@ public final class Blocks { .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())); - public static final Block WALL_TORCH = register(new Block("wall_torch", builder() + 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))); - public static final Block FIRE = register(new Block("fire", builder() + public static final Block FIRE = register(new Block("fire", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_15, 0, 15) .booleanState(EAST) .booleanState(NORTH) .booleanState(SOUTH) .booleanState(UP) .booleanState(WEST))); - public static final Block SOUL_FIRE = register(new Block("soul_fire", builder())); + public static final Block SOUL_FIRE = register(new Block("soul_fire", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block SPAWNER = register(new Block("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); 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, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block CHEST = register(new Block("chest", builder().setBlockEntity().destroyTime(2.5f) + public static final Block CHEST = register(new ChestBlock("chest", builder().setBlockEntity().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(CHEST_TYPE, "single", "left", "right") + .enumState(CHEST_TYPE, ChestType.VALUES) .booleanState(WATERLOGGED))); - public static final Block REDSTONE_WIRE = register(new Block("redstone_wire", builder() + public static final Block REDSTONE_WIRE = register(new Block("redstone_wire", builder().pushReaction(PistonBehavior.DESTROY) .enumState(EAST_REDSTONE, "up", "side", "none") .enumState(NORTH_REDSTONE, "up", "side", "none") .intState(POWER, 0, 15) @@ -399,7 +399,7 @@ public final class Blocks { 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() + public static final Block WHEAT = register(new Block("wheat", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f) .intState(MOISTURE, 0, 7))); @@ -433,13 +433,13 @@ public final class Blocks { public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block OAK_DOOR = register(new Block("oak_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block LADDER = register(new Block("ladder", builder().destroyTime(0.4f) + 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))); public static final Block RAIL = register(new Block("rail", builder().destroyTime(0.7f) @@ -554,57 +554,57 @@ public final class Blocks { public static final Block BAMBOO_WALL_HANGING_SIGN = register(new Block("bamboo_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .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) + public static final Block LEVER = register(new Block("lever", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block STONE_PRESSURE_PLATE = register(new Block("stone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block IRON_DOOR = register(new Block("iron_door", builder().requiresCorrectToolForDrops().destroyTime(5.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block OAK_PRESSURE_PLATE = register(new Block("oak_pressure_plate", builder().destroyTime(0.5f) + public static final Block OAK_PRESSURE_PLATE = register(new Block("oak_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block SPRUCE_PRESSURE_PLATE = register(new Block("spruce_pressure_plate", builder().destroyTime(0.5f) + public static final Block SPRUCE_PRESSURE_PLATE = register(new Block("spruce_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block BIRCH_PRESSURE_PLATE = register(new Block("birch_pressure_plate", builder().destroyTime(0.5f) + public static final Block BIRCH_PRESSURE_PLATE = register(new Block("birch_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block JUNGLE_PRESSURE_PLATE = register(new Block("jungle_pressure_plate", builder().destroyTime(0.5f) + public static final Block JUNGLE_PRESSURE_PLATE = register(new Block("jungle_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block ACACIA_PRESSURE_PLATE = register(new Block("acacia_pressure_plate", builder().destroyTime(0.5f) + public static final Block ACACIA_PRESSURE_PLATE = register(new Block("acacia_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block CHERRY_PRESSURE_PLATE = register(new Block("cherry_pressure_plate", builder().destroyTime(0.5f) + public static final Block CHERRY_PRESSURE_PLATE = register(new Block("cherry_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block DARK_OAK_PRESSURE_PLATE = register(new Block("dark_oak_pressure_plate", builder().destroyTime(0.5f) + public static final Block DARK_OAK_PRESSURE_PLATE = register(new Block("dark_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) + public static final Block MANGROVE_PRESSURE_PLATE = register(new Block("mangrove_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block BAMBOO_PRESSURE_PLATE = register(new Block("bamboo_pressure_plate", builder().destroyTime(0.5f) + public static final Block BAMBOO_PRESSURE_PLATE = register(new Block("bamboo_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); public static final Block REDSTONE_ORE = register(new Block("redstone_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT))); public static final Block DEEPSLATE_REDSTONE_ORE = register(new Block("deepslate_redstone_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f) .booleanState(LIT))); - public static final Block REDSTONE_TORCH = register(new Block("redstone_torch", builder() + public static final Block REDSTONE_TORCH = register(new Block("redstone_torch", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block REDSTONE_WALL_TORCH = register(new Block("redstone_wall_torch", builder() + 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))); - public static final Block STONE_BUTTON = register(new Block("stone_button", builder().destroyTime(0.5f) + public static final Block STONE_BUTTON = register(new Block("stone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block SNOW = register(new Block("snow", builder().requiresCorrectToolForDrops().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(LAYERS, 1, 8))); 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) + public static final Block CACTUS = register(new Block("cactus", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) .intState(AGE_15, 0, 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() + public static final Block SUGAR_CANE = register(new Block("sugar_cane", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_15, 0, 15))); public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity().destroyTime(2.0f) .booleanState(HAS_RECORD))); @@ -621,19 +621,19 @@ public final class Blocks { .enumState(AXIS, Axis.VALUES))); public static final Block POLISHED_BASALT = register(new Block("polished_basalt", builder().requiresCorrectToolForDrops().destroyTime(1.25f) .enumState(AXIS, Axis.VALUES))); - public static final Block SOUL_TORCH = register(new Block("soul_torch", builder())); - public static final Block SOUL_WALL_TORCH = register(new Block("soul_wall_torch", builder() + 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))); 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) + 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))); - public static final Block CARVED_PUMPKIN = register(new Block("carved_pumpkin", builder().destroyTime(1.0f) + 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))); - public static final Block JACK_O_LANTERN = register(new Block("jack_o_lantern", builder().destroyTime(1.0f) + 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))); - public static final Block CAKE = register(new Block("cake", builder().destroyTime(0.5f) + public static final Block CAKE = register(new Block("cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .intState(BITES, 0, 6))); - public static final Block REPEATER = register(new Block("repeater", builder() + public static final Block REPEATER = register(new Block("repeater", builder().pushReaction(PistonBehavior.DESTROY) .intState(DELAY, 1, 4) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(LOCKED) @@ -756,23 +756,23 @@ public final class Blocks { .booleanState(SOUTH) .booleanState(WATERLOGGED) .booleanState(WEST))); - public static final Block PUMPKIN = register(new Block("pumpkin", builder().destroyTime(1.0f))); - public static final Block MELON = register(new Block("melon", builder().destroyTime(1.0f))); - public static final Block ATTACHED_PUMPKIN_STEM = register(new Block("attached_pumpkin_stem", builder() + 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) .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() + public static final Block ATTACHED_MELON_STEM = register(new Block("attached_melon_stem", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block PUMPKIN_STEM = register(new Block("pumpkin_stem", builder() + public static final Block PUMPKIN_STEM = register(new Block("pumpkin_stem", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); - public static final Block MELON_STEM = register(new Block("melon_stem", builder() + public static final Block MELON_STEM = register(new Block("melon_stem", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); - public static final Block VINE = register(new Block("vine", builder().destroyTime(0.2f) + 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))); - public static final Block GLOW_LICHEN = register(new Block("glow_lichen", builder().destroyTime(0.2f) + public static final Block GLOW_LICHEN = register(new Block("glow_lichen", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .booleanState(DOWN) .booleanState(EAST) .booleanState(NORTH) @@ -802,7 +802,7 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block MYCELIUM = register(new Block("mycelium", builder().destroyTime(0.6f) .booleanState(SNOWY))); - public static final Block LILY_PAD = register(new Block("lily_pad", builder())); + 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) @@ -815,28 +815,28 @@ public final class Blocks { .enumState(HALF, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block NETHER_WART = register(new Block("nether_wart", builder() + public static final Block NETHER_WART = register(new Block("nether_wart", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_3, 0, 3))); public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(0.5f) .booleanState(HAS_BOTTLE_0) .booleanState(HAS_BOTTLE_1) .booleanState(HAS_BOTTLE_2))); - public static final Block CAULDRON = register(new Block("cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); + public static final Block CAULDRON = register(new CauldronBlock("cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block WATER_CAULDRON = register(new Block("water_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .intState(LEVEL_CAULDRON, 1, 3))); public static final Block LAVA_CAULDRON = register(new Block("lava_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block POWDER_SNOW_CAULDRON = register(new Block("powder_snow_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .intState(LEVEL_CAULDRON, 1, 3))); - public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().destroyTime(-1.0f))); + public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().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))); 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))); + 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))); - public static final Block COCOA = register(new Block("cocoa", builder().destroyTime(0.2f) + public static final Block COCOA = register(new Block("cocoa", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(AGE_2, 0, 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) @@ -849,11 +849,11 @@ public final class Blocks { public static final Block ENDER_CHEST = register(new Block("ender_chest", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(22.5f) .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() + 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))); - public static final Block TRIPWIRE = register(new Block("tripwire", builder() + public static final Block TRIPWIRE = register(new Block("tripwire", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(ATTACHED) .booleanState(DISARMED) .booleanState(EAST) @@ -895,131 +895,131 @@ public final class Blocks { .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block FLOWER_POT = register(new Block("flower_pot", builder())); - public static final Block POTTED_TORCHFLOWER = register(new Block("potted_torchflower", builder())); - public static final Block POTTED_OAK_SAPLING = register(new Block("potted_oak_sapling", builder())); - public static final Block POTTED_SPRUCE_SAPLING = register(new Block("potted_spruce_sapling", builder())); - public static final Block POTTED_BIRCH_SAPLING = register(new Block("potted_birch_sapling", builder())); - public static final Block POTTED_JUNGLE_SAPLING = register(new Block("potted_jungle_sapling", builder())); - public static final Block POTTED_ACACIA_SAPLING = register(new Block("potted_acacia_sapling", builder())); - public static final Block POTTED_CHERRY_SAPLING = register(new Block("potted_cherry_sapling", builder())); - public static final Block POTTED_DARK_OAK_SAPLING = register(new Block("potted_dark_oak_sapling", builder())); - public static final Block POTTED_MANGROVE_PROPAGULE = register(new Block("potted_mangrove_propagule", builder())); - public static final Block POTTED_FERN = register(new Block("potted_fern", builder())); - public static final Block POTTED_DANDELION = register(new Block("potted_dandelion", builder())); - public static final Block POTTED_POPPY = register(new Block("potted_poppy", builder())); - public static final Block POTTED_BLUE_ORCHID = register(new Block("potted_blue_orchid", builder())); - public static final Block POTTED_ALLIUM = register(new Block("potted_allium", builder())); - public static final Block POTTED_AZURE_BLUET = register(new Block("potted_azure_bluet", builder())); - public static final Block POTTED_RED_TULIP = register(new Block("potted_red_tulip", builder())); - public static final Block POTTED_ORANGE_TULIP = register(new Block("potted_orange_tulip", builder())); - public static final Block POTTED_WHITE_TULIP = register(new Block("potted_white_tulip", builder())); - public static final Block POTTED_PINK_TULIP = register(new Block("potted_pink_tulip", builder())); - public static final Block POTTED_OXEYE_DAISY = register(new Block("potted_oxeye_daisy", builder())); - public static final Block POTTED_CORNFLOWER = register(new Block("potted_cornflower", builder())); - public static final Block POTTED_LILY_OF_THE_VALLEY = register(new Block("potted_lily_of_the_valley", builder())); - public static final Block POTTED_WITHER_ROSE = register(new Block("potted_wither_rose", builder())); - public static final Block POTTED_RED_MUSHROOM = register(new Block("potted_red_mushroom", builder())); - public static final Block POTTED_BROWN_MUSHROOM = register(new Block("potted_brown_mushroom", builder())); - public static final Block POTTED_DEAD_BUSH = register(new Block("potted_dead_bush", builder())); - public static final Block POTTED_CACTUS = register(new Block("potted_cactus", builder())); - public static final Block CARROTS = register(new Block("carrots", builder() + 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))); + public static final Block POTTED_SPRUCE_SAPLING = register(new FlowerPotBlock("potted_spruce_sapling", SPRUCE_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_BIRCH_SAPLING = register(new FlowerPotBlock("potted_birch_sapling", BIRCH_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_JUNGLE_SAPLING = register(new FlowerPotBlock("potted_jungle_sapling", JUNGLE_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + 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_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))); + public static final Block POTTED_POPPY = register(new FlowerPotBlock("potted_poppy", POPPY, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_BLUE_ORCHID = register(new FlowerPotBlock("potted_blue_orchid", BLUE_ORCHID, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_ALLIUM = register(new FlowerPotBlock("potted_allium", ALLIUM, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_AZURE_BLUET = register(new FlowerPotBlock("potted_azure_bluet", AZURE_BLUET, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_RED_TULIP = register(new FlowerPotBlock("potted_red_tulip", RED_TULIP, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_ORANGE_TULIP = register(new FlowerPotBlock("potted_orange_tulip", ORANGE_TULIP, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_WHITE_TULIP = register(new FlowerPotBlock("potted_white_tulip", WHITE_TULIP, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_PINK_TULIP = register(new FlowerPotBlock("potted_pink_tulip", PINK_TULIP, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_OXEYE_DAISY = register(new FlowerPotBlock("potted_oxeye_daisy", OXEYE_DAISY, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_CORNFLOWER = register(new FlowerPotBlock("potted_cornflower", CORNFLOWER, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_LILY_OF_THE_VALLEY = register(new FlowerPotBlock("potted_lily_of_the_valley", LILY_OF_THE_VALLEY, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_WITHER_ROSE = register(new FlowerPotBlock("potted_wither_rose", WITHER_ROSE, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_RED_MUSHROOM = register(new FlowerPotBlock("potted_red_mushroom", RED_MUSHROOM, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_BROWN_MUSHROOM = register(new FlowerPotBlock("potted_brown_mushroom", BROWN_MUSHROOM, builder().pushReaction(PistonBehavior.DESTROY))); + 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, 0, 7))); - public static final Block POTATOES = register(new Block("potatoes", builder() + public static final Block POTATOES = register(new Block("potatoes", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); - public static final Block OAK_BUTTON = register(new Block("oak_button", builder().destroyTime(0.5f) + public static final Block OAK_BUTTON = register(new Block("oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block SPRUCE_BUTTON = register(new Block("spruce_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block BIRCH_BUTTON = register(new Block("birch_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block JUNGLE_BUTTON = register(new Block("jungle_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block ACACIA_BUTTON = register(new Block("acacia_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block CHERRY_BUTTON = register(new Block("cherry_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block DARK_OAK_BUTTON = register(new Block("dark_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block MANGROVE_BUTTON = register(new Block("mangrove_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block BAMBOO_BUTTON = register(new Block("bamboo_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block SKELETON_SKULL = register(new Block("skeleton_skull", builder().setBlockEntity().destroyTime(1.0f) + public static final Block SKELETON_SKULL = register(new SkullBlock("skeleton_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block SKELETON_WALL_SKULL = register(new Block("skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f) + public static final Block SKELETON_WALL_SKULL = register(new SkullBlock("skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block WITHER_SKELETON_SKULL = register(new Block("wither_skeleton_skull", builder().setBlockEntity().destroyTime(1.0f) + public static final Block WITHER_SKELETON_SKULL = register(new SkullBlock("wither_skeleton_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block WITHER_SKELETON_WALL_SKULL = register(new Block("wither_skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f) + public static final Block WITHER_SKELETON_WALL_SKULL = register(new SkullBlock("wither_skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block ZOMBIE_HEAD = register(new Block("zombie_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block ZOMBIE_HEAD = register(new SkullBlock("zombie_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block ZOMBIE_WALL_HEAD = register(new Block("zombie_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block ZOMBIE_WALL_HEAD = register(new SkullBlock("zombie_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block PLAYER_HEAD = register(new Block("player_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block PLAYER_HEAD = register(new SkullBlock("player_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block PLAYER_WALL_HEAD = register(new Block("player_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block PLAYER_WALL_HEAD = register(new SkullBlock("player_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block CREEPER_HEAD = register(new Block("creeper_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block CREEPER_HEAD = register(new SkullBlock("creeper_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block CREEPER_WALL_HEAD = register(new Block("creeper_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block CREEPER_WALL_HEAD = register(new SkullBlock("creeper_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block DRAGON_HEAD = register(new Block("dragon_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block DRAGON_HEAD = register(new SkullBlock("dragon_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block DRAGON_WALL_HEAD = register(new Block("dragon_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block DRAGON_WALL_HEAD = register(new SkullBlock("dragon_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block PIGLIN_HEAD = register(new Block("piglin_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block PIGLIN_HEAD = register(new SkullBlock("piglin_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block PIGLIN_WALL_HEAD = register(new Block("piglin_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block PIGLIN_WALL_HEAD = register(new SkullBlock("piglin_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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) + 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))); - public static final Block CHIPPED_ANVIL = register(new Block("chipped_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f) + 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))); - public static final Block DAMAGED_ANVIL = register(new Block("damaged_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f) + 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))); - public static final Block TRAPPED_CHEST = register(new Block("trapped_chest", builder().setBlockEntity().destroyTime(2.5f) + public static final Block TRAPPED_CHEST = register(new ChestBlock("trapped_chest", builder().setBlockEntity().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(CHEST_TYPE, "single", "left", "right") + .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) + 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, 0, 15))); - public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) + 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, 0, 15))); - public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity() + public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(MODE_COMPARATOR, "compare", "subtract") .booleanState(POWERED))); @@ -1190,7 +1190,7 @@ public final class Blocks { .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .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) + public static final Block BARRIER = register(new Block("barrier", builder().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) .booleanState(WATERLOGGED))); public static final Block LIGHT = register(new Block("light", builder().destroyTime(-1.0f) .intState(LEVEL, 0, 15) @@ -1250,17 +1250,17 @@ public final class Blocks { public static final Block TERRACOTTA = register(new Block("terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); 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() + public static final Block SUNFLOWER = register(new Block("sunflower", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block LILAC = register(new Block("lilac", builder() + public static final Block LILAC = register(new Block("lilac", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block ROSE_BUSH = register(new Block("rose_bush", builder() + public static final Block ROSE_BUSH = register(new Block("rose_bush", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block PEONY = register(new Block("peony", builder() + public static final Block PEONY = register(new Block("peony", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block TALL_GRASS = register(new Block("tall_grass", builder() + public static final Block TALL_GRASS = register(new Block("tall_grass", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block LARGE_FERN = register(new Block("large_fern", builder() + public static final Block LARGE_FERN = register(new Block("large_fern", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); @@ -1498,49 +1498,49 @@ public final class Blocks { .booleanState(SOUTH) .booleanState(WATERLOGGED) .booleanState(WEST))); - public static final Block SPRUCE_DOOR = register(new Block("spruce_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block BIRCH_DOOR = register(new Block("birch_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block JUNGLE_DOOR = register(new Block("jungle_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block ACACIA_DOOR = register(new Block("acacia_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block CHERRY_DOOR = register(new Block("cherry_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block DARK_OAK_DOOR = register(new Block("dark_oak_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block MANGROVE_DOOR = register(new Block("mangrove_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block BAMBOO_DOOR = register(new Block("bamboo_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") @@ -1548,14 +1548,14 @@ public final class Blocks { .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))); - public static final Block CHORUS_PLANT = register(new Block("chorus_plant", builder().destroyTime(0.4f) + 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))); - public static final Block CHORUS_FLOWER = register(new Block("chorus_flower", builder().destroyTime(0.4f) + public static final Block CHORUS_FLOWER = register(new Block("chorus_flower", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) .intState(AGE_5, 0, 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) @@ -1566,17 +1566,17 @@ public final class Blocks { .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .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() + public static final Block TORCHFLOWER_CROP = register(new Block("torchflower_crop", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_1, 0, 1))); - public static final Block PITCHER_CROP = register(new Block("pitcher_crop", builder() + public static final Block PITCHER_CROP = register(new Block("pitcher_crop", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_4, 0, 4) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block PITCHER_PLANT = register(new Block("pitcher_plant", builder() + public static final Block PITCHER_PLANT = register(new Block("pitcher_plant", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block BEETROOTS = register(new Block("beetroots", builder() + public static final Block BEETROOTS = register(new Block("beetroots", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_3, 0, 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().destroyTime(-1.0f))); + public static final Block END_GATEWAY = register(new Block("end_gateway", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .booleanState(CONDITIONAL) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); @@ -1590,75 +1590,75 @@ public final class Blocks { 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))); - public static final Block STRUCTURE_VOID = register(new Block("structure_void", builder())); + 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))); - public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block WHITE_SHULKER_BOX = register(new Block("white_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block ORANGE_SHULKER_BOX = register(new Block("orange_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block MAGENTA_SHULKER_BOX = register(new Block("magenta_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block LIGHT_BLUE_SHULKER_BOX = register(new Block("light_blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block YELLOW_SHULKER_BOX = register(new Block("yellow_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block LIME_SHULKER_BOX = register(new Block("lime_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block PINK_SHULKER_BOX = register(new Block("pink_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block GRAY_SHULKER_BOX = register(new Block("gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block LIGHT_GRAY_SHULKER_BOX = register(new Block("light_gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block CYAN_SHULKER_BOX = register(new Block("cyan_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block PURPLE_SHULKER_BOX = register(new Block("purple_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block BLUE_SHULKER_BOX = register(new Block("blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block BROWN_SHULKER_BOX = register(new Block("brown_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block GREEN_SHULKER_BOX = register(new Block("green_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block RED_SHULKER_BOX = register(new Block("red_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(2.0f) + public static final Block BLACK_SHULKER_BOX = register(new Block("black_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .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) + 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))); - public static final Block ORANGE_GLAZED_TERRACOTTA = register(new Block("orange_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block MAGENTA_GLAZED_TERRACOTTA = register(new Block("magenta_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block LIGHT_BLUE_GLAZED_TERRACOTTA = register(new Block("light_blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block YELLOW_GLAZED_TERRACOTTA = register(new Block("yellow_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block LIME_GLAZED_TERRACOTTA = register(new Block("lime_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block PINK_GLAZED_TERRACOTTA = register(new Block("pink_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block GRAY_GLAZED_TERRACOTTA = register(new Block("gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block LIGHT_GRAY_GLAZED_TERRACOTTA = register(new Block("light_gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block CYAN_GLAZED_TERRACOTTA = register(new Block("cyan_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block PURPLE_GLAZED_TERRACOTTA = register(new Block("purple_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block BLUE_GLAZED_TERRACOTTA = register(new Block("blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block BROWN_GLAZED_TERRACOTTA = register(new Block("brown_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block GREEN_GLAZED_TERRACOTTA = register(new Block("green_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block RED_GLAZED_TERRACOTTA = register(new Block("red_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); - public static final Block BLACK_GLAZED_TERRACOTTA = register(new Block("black_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + 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))); 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))); @@ -1692,11 +1692,11 @@ public final class Blocks { public static final Block GREEN_CONCRETE_POWDER = register(new Block("green_concrete_powder", builder().destroyTime(0.5f))); 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() + public static final Block KELP = register(new Block("kelp", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25))); - public static final Block KELP_PLANT = register(new Block("kelp_plant", builder())); + public static final Block KELP_PLANT = register(new Block("kelp_plant", builder().pushReaction(PistonBehavior.DESTROY))); 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) + public static final Block TURTLE_EGG = register(new Block("turtle_egg", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .intState(EGGS, 1, 4) .intState(HATCH, 0, 2))); public static final Block SNIFFER_EGG = register(new Block("sniffer_egg", builder().destroyTime(0.5f) @@ -1721,15 +1721,15 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block DEAD_HORN_CORAL = register(new Block("dead_horn_coral", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block TUBE_CORAL = register(new Block("tube_coral", builder() + public static final Block TUBE_CORAL = register(new Block("tube_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block BRAIN_CORAL = register(new Block("brain_coral", builder() + public static final Block BRAIN_CORAL = register(new Block("brain_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block BUBBLE_CORAL = register(new Block("bubble_coral", builder() + public static final Block BUBBLE_CORAL = register(new Block("bubble_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block FIRE_CORAL = register(new Block("fire_coral", builder() + public static final Block FIRE_CORAL = register(new Block("fire_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block HORN_CORAL = register(new Block("horn_coral", builder() + public static final Block HORN_CORAL = register(new Block("horn_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); public static final Block DEAD_TUBE_CORAL_FAN = register(new Block("dead_tube_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); @@ -1741,15 +1741,15 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block DEAD_HORN_CORAL_FAN = register(new Block("dead_horn_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block TUBE_CORAL_FAN = register(new Block("tube_coral_fan", builder() + public static final Block TUBE_CORAL_FAN = register(new Block("tube_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block BRAIN_CORAL_FAN = register(new Block("brain_coral_fan", builder() + public static final Block BRAIN_CORAL_FAN = register(new Block("brain_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block BUBBLE_CORAL_FAN = register(new Block("bubble_coral_fan", builder() + public static final Block BUBBLE_CORAL_FAN = register(new Block("bubble_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block FIRE_CORAL_FAN = register(new Block("fire_coral_fan", builder() + public static final Block FIRE_CORAL_FAN = register(new Block("fire_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block HORN_CORAL_FAN = register(new Block("horn_coral_fan", builder() + public static final Block HORN_CORAL_FAN = register(new Block("horn_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .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) @@ -1766,36 +1766,36 @@ public final class Blocks { 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))); - public static final Block TUBE_CORAL_WALL_FAN = register(new Block("tube_coral_wall_fan", builder() + 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))); - public static final Block BRAIN_CORAL_WALL_FAN = register(new Block("brain_coral_wall_fan", builder() + 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))); - public static final Block BUBBLE_CORAL_WALL_FAN = register(new Block("bubble_coral_wall_fan", builder() + 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))); - public static final Block FIRE_CORAL_WALL_FAN = register(new Block("fire_coral_wall_fan", builder() + 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))); - public static final Block HORN_CORAL_WALL_FAN = register(new Block("horn_coral_wall_fan", builder() + 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))); - public static final Block SEA_PICKLE = register(new Block("sea_pickle", builder() + public static final Block SEA_PICKLE = register(new Block("sea_pickle", builder().pushReaction(PistonBehavior.DESTROY) .intState(PICKLES, 1, 4) .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().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder().destroyTime(1.0f))); - public static final Block BAMBOO = register(new Block("bamboo", builder().destroyTime(1.0f) + public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY))); + public static final Block BAMBOO = register(new Block("bamboo", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .intState(AGE_1, 0, 1) .enumState(BAMBOO_LEAVES, "none", "small", "large") .intState(STAGE, 0, 1))); - public static final Block POTTED_BAMBOO = register(new Block("potted_bamboo", builder())); + 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() + public static final Block BUBBLE_COLUMN = register(new Block("bubble_column", builder().pushReaction(PistonBehavior.DESTROY) .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) @@ -1997,7 +1997,7 @@ public final class Blocks { .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block SCAFFOLDING = register(new Block("scaffolding", builder() + public static final Block SCAFFOLDING = register(new Block("scaffolding", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(BOTTOM) .intState(STABILITY_DISTANCE, 0, 7) .booleanState(WATERLOGGED))); @@ -2014,24 +2014,24 @@ public final class Blocks { .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) + public static final Block GRINDSTONE = register(new Block("grindstone", builder().requiresCorrectToolForDrops().destroyTime(2.0f).pushReaction(PistonBehavior.BLOCK) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block LECTERN = register(new Block("lectern", builder().setBlockEntity().destroyTime(2.5f) + public static final Block LECTERN = register(new LecternBlock("lectern", builder().setBlockEntity().destroyTime(2.5f) .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))); - public static final Block BELL = register(new Block("bell", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f) + public static final Block BELL = register(new Block("bell", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) .enumState(BELL_ATTACHMENT, "floor", "ceiling", "single_wall", "double_wall") .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) + public static final Block LANTERN = register(new Block("lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(HANGING) .booleanState(WATERLOGGED))); - public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f) + public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(HANGING) .booleanState(WATERLOGGED))); public static final Block CAMPFIRE = register(new Block("campfire", builder().setBlockEntity().destroyTime(2.0f) @@ -2044,7 +2044,7 @@ public final class Blocks { .booleanState(LIT) .booleanState(SIGNAL_FIRE) .booleanState(WATERLOGGED))); - public static final Block SWEET_BERRY_BUSH = register(new Block("sweet_berry_bush", builder() + public static final Block SWEET_BERRY_BUSH = register(new Block("sweet_berry_bush", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_3, 0, 3))); public static final Block WARPED_STEM = register(new Block("warped_stem", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); @@ -2055,10 +2055,10 @@ public final class Blocks { public static final Block STRIPPED_WARPED_HYPHAE = register(new Block("stripped_warped_hyphae", builder().destroyTime(2.0f) .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())); + 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())); - public static final Block NETHER_SPROUTS = register(new Block("nether_sprouts", builder())); + 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))); public static final Block STRIPPED_CRIMSON_STEM = register(new Block("stripped_crimson_stem", builder().destroyTime(2.0f) @@ -2068,15 +2068,15 @@ public final class Blocks { public static final Block STRIPPED_CRIMSON_HYPHAE = register(new Block("stripped_crimson_hyphae", builder().destroyTime(2.0f) .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())); + 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() + public static final Block WEEPING_VINES = register(new Block("weeping_vines", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25))); - public static final Block WEEPING_VINES_PLANT = register(new Block("weeping_vines_plant", builder())); - public static final Block TWISTING_VINES = register(new Block("twisting_vines", builder() + public static final Block WEEPING_VINES_PLANT = register(new Block("weeping_vines_plant", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block TWISTING_VINES = register(new Block("twisting_vines", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25))); - public static final Block TWISTING_VINES_PLANT = register(new Block("twisting_vines_plant", builder())); - public static final Block CRIMSON_ROOTS = register(new Block("crimson_roots", builder())); + public static final Block TWISTING_VINES_PLANT = register(new Block("twisting_vines_plant", builder().pushReaction(PistonBehavior.DESTROY))); + 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) @@ -2085,9 +2085,9 @@ public final class Blocks { public static final Block WARPED_SLAB = register(new Block("warped_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block CRIMSON_PRESSURE_PLATE = register(new Block("crimson_pressure_plate", builder().destroyTime(0.5f) + public static final Block CRIMSON_PRESSURE_PLATE = register(new Block("crimson_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block WARPED_PRESSURE_PLATE = register(new Block("warped_pressure_plate", builder().destroyTime(0.5f) + public static final Block WARPED_PRESSURE_PLATE = register(new Block("warped_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); public static final Block CRIMSON_FENCE = register(new Block("crimson_fence", builder().destroyTime(2.0f) .booleanState(EAST) @@ -2133,21 +2133,21 @@ public final class Blocks { .enumState(HALF, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder().destroyTime(0.5f) + public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .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) + public static final Block WARPED_BUTTON = register(new Block("warped_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block CRIMSON_DOOR = register(new Block("crimson_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WARPED_DOOR = register(new Block("warped_door", builder().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") @@ -2186,11 +2186,11 @@ public final class Blocks { 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, 0, 4))); - public static final Block POTTED_CRIMSON_FUNGUS = register(new Block("potted_crimson_fungus", builder())); - public static final Block POTTED_WARPED_FUNGUS = register(new Block("potted_warped_fungus", builder())); - public static final Block POTTED_CRIMSON_ROOTS = register(new Block("potted_crimson_roots", builder())); - public static final Block POTTED_WARPED_ROOTS = register(new Block("potted_warped_roots", builder())); - public static final Block LODESTONE = register(new Block("lodestone", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); + 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))); + public static final Block POTTED_WARPED_ROOTS = register(new FlowerPotBlock("potted_warped_roots", WARPED_ROOTS, builder().pushReaction(PistonBehavior.DESTROY))); + 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) @@ -2235,9 +2235,9 @@ public final class Blocks { public static final Block POLISHED_BLACKSTONE_SLAB = register(new Block("polished_blackstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) + 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))); - public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f) + public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); @@ -2251,120 +2251,120 @@ public final class Blocks { 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) + public static final Block CANDLE = register(new Block("candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block WHITE_CANDLE = register(new Block("white_candle", builder().destroyTime(0.1f) + public static final Block WHITE_CANDLE = register(new Block("white_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block ORANGE_CANDLE = register(new Block("orange_candle", builder().destroyTime(0.1f) + public static final Block ORANGE_CANDLE = register(new Block("orange_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block MAGENTA_CANDLE = register(new Block("magenta_candle", builder().destroyTime(0.1f) + public static final Block MAGENTA_CANDLE = register(new Block("magenta_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIGHT_BLUE_CANDLE = register(new Block("light_blue_candle", builder().destroyTime(0.1f) + public static final Block LIGHT_BLUE_CANDLE = register(new Block("light_blue_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block YELLOW_CANDLE = register(new Block("yellow_candle", builder().destroyTime(0.1f) + public static final Block YELLOW_CANDLE = register(new Block("yellow_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIME_CANDLE = register(new Block("lime_candle", builder().destroyTime(0.1f) + public static final Block LIME_CANDLE = register(new Block("lime_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block PINK_CANDLE = register(new Block("pink_candle", builder().destroyTime(0.1f) + public static final Block PINK_CANDLE = register(new Block("pink_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block GRAY_CANDLE = register(new Block("gray_candle", builder().destroyTime(0.1f) + public static final Block GRAY_CANDLE = register(new Block("gray_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIGHT_GRAY_CANDLE = register(new Block("light_gray_candle", builder().destroyTime(0.1f) + public static final Block LIGHT_GRAY_CANDLE = register(new Block("light_gray_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block CYAN_CANDLE = register(new Block("cyan_candle", builder().destroyTime(0.1f) + public static final Block CYAN_CANDLE = register(new Block("cyan_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block PURPLE_CANDLE = register(new Block("purple_candle", builder().destroyTime(0.1f) + public static final Block PURPLE_CANDLE = register(new Block("purple_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BLUE_CANDLE = register(new Block("blue_candle", builder().destroyTime(0.1f) + public static final Block BLUE_CANDLE = register(new Block("blue_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BROWN_CANDLE = register(new Block("brown_candle", builder().destroyTime(0.1f) + public static final Block BROWN_CANDLE = register(new Block("brown_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block GREEN_CANDLE = register(new Block("green_candle", builder().destroyTime(0.1f) + public static final Block GREEN_CANDLE = register(new Block("green_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block RED_CANDLE = register(new Block("red_candle", builder().destroyTime(0.1f) + public static final Block RED_CANDLE = register(new Block("red_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BLACK_CANDLE = register(new Block("black_candle", builder().destroyTime(0.1f) + public static final Block BLACK_CANDLE = register(new Block("black_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder().destroyTime(0.5f) + public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder().destroyTime(0.5f) + public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder().destroyTime(0.5f) + public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder().destroyTime(0.5f) + public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder().destroyTime(0.5f) + public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder().destroyTime(0.5f) + public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder().destroyTime(0.5f) + public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder().destroyTime(0.5f) + public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder().destroyTime(0.5f) + public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder().destroyTime(0.5f) + public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder().destroyTime(0.5f) + public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder().destroyTime(0.5f) + public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder().destroyTime(0.5f) + public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder().destroyTime(0.5f) + public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder().destroyTime(0.5f) + public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder().destroyTime(0.5f) + public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder().destroyTime(0.5f) + public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .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))); - public static final Block AMETHYST_CLUSTER = register(new Block("amethyst_cluster", builder().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))); - public static final Block LARGE_AMETHYST_BUD = register(new Block("large_amethyst_bud", builder().destroyTime(1.5f) + 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))); - public static final Block MEDIUM_AMETHYST_BUD = register(new Block("medium_amethyst_bud", builder().destroyTime(1.5f) + 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))); - public static final Block SMALL_AMETHYST_BUD = register(new Block("small_amethyst_bud", builder().destroyTime(1.5f) + 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))); public static final Block TUFF = register(new Block("tuff", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); @@ -2430,7 +2430,7 @@ public final class Blocks { .enumState(SCULK_SENSOR_PHASE, "inactive", "active", "cooldown") .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) + public static final Block SCULK_VEIN = register(new Block("sculk_vein", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .booleanState(DOWN) .booleanState(EAST) .booleanState(NORTH) @@ -2534,49 +2534,49 @@ public final class Blocks { public static final Block WAXED_CUT_COPPER_SLAB = register(new Block("waxed_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block COPPER_DOOR = register(new Block("copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block EXPOSED_COPPER_DOOR = register(new Block("exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block OXIDIZED_COPPER_DOOR = register(new Block("oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WEATHERED_COPPER_DOOR = register(new Block("weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_COPPER_DOOR = register(new Block("waxed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_EXPOSED_COPPER_DOOR = register(new Block("waxed_exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_OXIDIZED_COPPER_DOOR = register(new Block("waxed_oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_WEATHERED_COPPER_DOOR = register(new Block("waxed_weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") @@ -2674,36 +2674,36 @@ public final class Blocks { .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) + public static final Block POINTED_DRIPSTONE = register(new Block("pointed_dripstone", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) .enumState(DRIPSTONE_THICKNESS, "tip_merge", "tip", "frustum", "middle", "base") .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() + public static final Block CAVE_VINES = register(new Block("cave_vines", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25) .booleanState(BERRIES))); - public static final Block CAVE_VINES_PLANT = register(new Block("cave_vines_plant", builder() + public static final Block CAVE_VINES_PLANT = register(new Block("cave_vines_plant", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(BERRIES))); - public static final Block SPORE_BLOSSOM = register(new Block("spore_blossom", builder())); - public static final Block AZALEA = register(new Block("azalea", builder())); - public static final Block FLOWERING_AZALEA = register(new Block("flowering_azalea", builder())); - public static final Block MOSS_CARPET = register(new Block("moss_carpet", builder().destroyTime(0.1f))); - public static final Block PINK_PETALS = register(new Block("pink_petals", builder() + 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, 1, 4))); - public static final Block MOSS_BLOCK = register(new Block("moss_block", builder().destroyTime(0.1f))); - public static final Block BIG_DRIPLEAF = register(new Block("big_dripleaf", builder().destroyTime(0.1f) + 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, "none", "unstable", "partial", "full") .booleanState(WATERLOGGED))); - public static final Block BIG_DRIPLEAF_STEM = register(new Block("big_dripleaf_stem", builder().destroyTime(0.1f) + 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))); - public static final Block SMALL_DRIPLEAF = register(new Block("small_dripleaf", builder() + 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, "upper", "lower") .booleanState(WATERLOGGED))); - public static final Block HANGING_ROOTS = register(new Block("hanging_roots", builder() + public static final Block HANGING_ROOTS = register(new Block("hanging_roots", builder().pushReaction(PistonBehavior.DESTROY) .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))); @@ -2782,17 +2782,17 @@ public final class Blocks { 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))); public static final Block RAW_GOLD_BLOCK = register(new Block("raw_gold_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); - public static final Block POTTED_AZALEA_BUSH = register(new Block("potted_azalea_bush", builder())); - public static final Block POTTED_FLOWERING_AZALEA_BUSH = register(new Block("potted_flowering_azalea_bush", builder())); + 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))); public static final Block VERDANT_FROGLIGHT = register(new Block("verdant_froglight", builder().destroyTime(0.3f) .enumState(AXIS, Axis.VALUES))); public static final Block PEARLESCENT_FROGLIGHT = register(new Block("pearlescent_froglight", builder().destroyTime(0.3f) .enumState(AXIS, Axis.VALUES))); - public static final Block FROGSPAWN = register(new Block("frogspawn", builder())); + 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() + public static final Block DECORATED_POT = register(new Block("decorated_pot", builder().setBlockEntity().pushReaction(PistonBehavior.DESTROY) .booleanState(CRACKED) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); 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 bbb6f8fe3..339d82f96 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 @@ -118,7 +118,7 @@ public final class Properties { public static final Property RESPAWN_ANCHOR_CHARGES = Property.create("charges"); public static final Property ROTATION_16 = Property.create("rotation"); public static final Property BED_PART = Property.create("part"); - public static final Property CHEST_TYPE = Property.create("type"); + public static final Property CHEST_TYPE = Property.create("type"); public static final Property MODE_COMPARATOR = Property.create("mode"); public static final Property DOOR_HINGE = Property.create("hinge"); public static final Property NOTEBLOCK_INSTRUMENT = Property.create("instrument"); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index 84822ca16..3114f31f9 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -30,8 +30,15 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; +import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.Property; +import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.Identifier; import java.util.*; @@ -44,6 +51,7 @@ public class Block { private final boolean requiresCorrectToolForDrops; private final boolean hasBlockEntity; private final float destroyTime; + private final @NonNull PistonBehavior pushReaction; private int javaId = -1; public Block(String javaIdentifier, Builder builder) { @@ -51,9 +59,76 @@ public class Block { this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops; this.hasBlockEntity = builder.hasBlockEntity; this.destroyTime = builder.destroyTime; + this.pushReaction = builder.pushReaction; builder.build(this); } + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + BlockDefinition definition = session.getBlockMappings().getBedrockBlock(state); + sendBlockUpdatePacket(session, state, definition, position); + + { + // Extended collision boxes for custom blocks + if (!session.getBlockMappings().getExtendedCollisionBoxes().isEmpty()) { + int aboveBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() + 1, position.getZ()); + BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(state.javaId()); + int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ()); + BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock); + if (belowBedrockExtendedCollisionDefinition != null && state.is(Blocks.AIR)) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position); + updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); + updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + } else if (aboveBlock == Block.JAVA_AIR_ID) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); + updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + } + } + } + + handleLecternBlockUpdate(session, state, position); + } + + protected void sendBlockUpdatePacket(GeyserSession session, BlockState state, BlockDefinition definition, Vector3i position) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position); + updateBlockPacket.setDefinition(definition); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + + UpdateBlockPacket waterPacket = new UpdateBlockPacket(); + waterPacket.setDataLayer(1); + waterPacket.setBlockPosition(position); + if (BlockRegistries.WATERLOGGED.get().get(state.javaId())) { + waterPacket.setDefinition(session.getBlockMappings().getBedrockWater()); + } else { + waterPacket.setDefinition(session.getBlockMappings().getBedrockAir()); + } + session.sendUpstreamPacket(waterPacket); + } + + protected void handleLecternBlockUpdate(GeyserSession session, BlockState state, Vector3i position) { + // Block state is out of bounds of this map - lectern has been destroyed, if it existed + if (!session.getGeyser().getWorldManager().shouldExpectLecternHandled(session)) { + session.getLecternCache().remove(position); + } + } + public String javaIdentifier() { return javaIdentifier; } @@ -70,6 +145,11 @@ public class Block { return destroyTime; } + @NonNull + public PistonBehavior pushReaction() { + return this.pushReaction; + } + public int javaId() { return javaId; } @@ -97,6 +177,7 @@ public class Block { private final Map, List>> states = new LinkedHashMap<>(); private boolean requiresCorrectToolForDrops = false; private boolean hasBlockEntity = false; + private PistonBehavior pushReaction = PistonBehavior.NORMAL; private float destroyTime; /** @@ -143,6 +224,11 @@ public class Block { return this; } + public Builder pushReaction(PistonBehavior pushReaction) { + this.pushReaction = pushReaction; + return this; + } + private void build(Block block) { if (states.isEmpty()) { BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size())); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 936b711e4..23e89d99f 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -58,6 +58,10 @@ public final class BlockState { return javaId; } + public boolean is(Block block) { + return this.block == block; + } + public static BlockState of(int javaId) { return BlockRegistries.BLOCK_STATES.get(javaId); } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/CauldronBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/CauldronBlock.java new file mode 100644 index 000000000..d27969af7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/CauldronBlock.java @@ -0,0 +1,51 @@ +/* + * 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; + +public class CauldronBlock extends Block implements BedrockChunkWantsBlockEntityTag { + public CauldronBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState) { + // As of 1.18.30: this is required to make rendering not look weird on chunk load (lava and snow cauldrons look dim) + return BlockEntityTranslator.getConstantBedrockTag("Cauldron", position.getX(), position.getY(), position.getZ()) + .putByte("isMovable", (byte) 0) + .putShort("PotionId", (short) -1) + .putShort("PotionType", (short) -1) + .putList("Items", NbtType.END, NbtList.EMPTY) + .build(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/ChestBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/ChestBlock.java new file mode 100644 index 000000000..69132ccfd --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/ChestBlock.java @@ -0,0 +1,52 @@ +/* + * 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.level.block.property.ChestType; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; +import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; + +public class ChestBlock extends Block { + public ChestBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + super.updateBlock(session, state, position); + + if (state.getValue(Properties.CHEST_TYPE) != ChestType.SINGLE) { + NbtMapBuilder tagBuilder = BlockEntityTranslator.getConstantBedrockTag(BlockEntityType.CHEST, position.getX(), position.getY(), position.getZ()); + BlockEntityUtils.getBlockEntityTranslator(BlockEntityType.CHEST).translateTag(session, tagBuilder, null, state); //TODO + BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java new file mode 100644 index 000000000..bfde51a79 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java @@ -0,0 +1,50 @@ +/* + * 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.ChunkUtils; + +public class DoorBlock extends Block { + public DoorBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + super.updateBlock(session, state, position); + + if (state.getValue(Properties.DOUBLE_BLOCK_HALF).equals("upper")) { + // Update the lower door block as Bedrock client doesn't like door to be closed from the top + // See https://github.com/GeyserMC/Geyser/issues/4358 + Vector3i belowDoorPosition = position.sub(0, 1, 0); + BlockState belowDoorBlockState = session.getGeyser().getWorldManager().blockAt(session, belowDoorPosition.getX(), belowDoorPosition.getY(), belowDoorPosition.getZ()); + ChunkUtils.updateBlock(session, belowDoorBlockState, belowDoorPosition); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java similarity index 60% rename from core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java rename to core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java index 0a60b0f32..8c911ad97 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.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,65 +23,35 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.level.block.entity; +package org.geysermc.geyser.level.block.type; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.util.BlockEntityUtils; -public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity { - /** - * @param blockState the Java block state of a potential flower pot block - * @return true if the block is a flower pot - */ - public static boolean isFlowerBlock(int blockState) { - return BlockStateValues.getFlowerPotValues().containsKey(blockState); - } +public class FlowerPotBlock extends Block implements BedrockChunkWantsBlockEntityTag { + private final Block flower; - /** - * Get the Nukkit CompoundTag of the flower pot. - * - * @param blockState Java block state of flower pot. - * @param position Bedrock position of flower pot. - * @return Bedrock tag of flower pot. - */ - public static NbtMap getTag(GeyserSession session, int blockState, Vector3i position) { - NbtMapBuilder tagBuilder = NbtMap.builder() - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) - .putByte("isMovable", (byte) 1) - .putString("id", "FlowerPot"); - // Get the Java name of the plant inside. e.g. minecraft:oak_sapling - String name = BlockStateValues.getFlowerPotValues().get(blockState); - if (name != null) { - // Get the Bedrock CompoundTag of the block. - // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. - NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(name); - if (plant != null) { - tagBuilder.put("PlantBlock", plant.toBuilder().build()); - } - } - return tagBuilder.build(); + public FlowerPotBlock(String javaIdentifier, Block flower, Builder builder) { + super(javaIdentifier, builder); + this.flower = flower; } @Override - public boolean isBlock(int blockState) { - return isFlowerBlock(blockState); - } + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + super.updateBlock(session, state, position); - @Override - public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { - NbtMap tag = getTag(session, blockState.javaId(), position); + NbtMap tag = createTag(session, position, state); BlockEntityUtils.updateBlockEntity(session, tag, position); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); - updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState.javaId())); + updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(state)); updateBlockPacket.setBlockPosition(position); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); @@ -89,4 +59,20 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity { session.sendUpstreamPacket(updateBlockPacket); BlockEntityUtils.updateBlockEntity(session, tag, position); } + + @Override + public NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState) { + NbtMapBuilder tagBuilder = BlockEntityTranslator.getConstantBedrockTag("FlowerPot", position.getX(), position.getY(), position.getZ()) + .putByte("isMovable", (byte) 1); + // Get the Java name of the plant inside. e.g. minecraft:oak_sapling + if (this.flower != Blocks.AIR) { + // Get the Bedrock CompoundTag of the block. + // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. + NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(this.flower.javaIdentifier()); + if (plant != null) { + tagBuilder.putCompound("PlantBlock", plant.toBuilder().build()); + } + } + return tagBuilder.build(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java new file mode 100644 index 000000000..6b8aa02b5 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.erosion.util.LecternUtils; +import org.geysermc.geyser.level.WorldManager; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.BlockEntityUtils; + +public class LecternBlock extends Block { + public LecternBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void handleLecternBlockUpdate(GeyserSession session, BlockState state, Vector3i position) { + WorldManager worldManager = session.getGeyser().getWorldManager(); + if (worldManager.shouldExpectLecternHandled(session)) { + worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); + return; + } + + boolean currentHasBook = state.getValue(Properties.HAS_BOOK); + Boolean previousHasBook = worldManager.blockAt(session, position).getValue(Properties.HAS_BOOK); // Can be null if not a lectern, watch out + if (currentHasBook != previousHasBook) { + if (currentHasBook) { + worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); + } else { + session.getLecternCache().remove(position); + NbtMap newLecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build(); + BlockEntityUtils.updateBlockEntity(session, newLecternTag, position); + } + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/MovingPistonBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/MovingPistonBlock.java new file mode 100644 index 000000000..e4df8d88b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/MovingPistonBlock.java @@ -0,0 +1,42 @@ +/* + * 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; +import org.geysermc.geyser.session.GeyserSession; + +public class MovingPistonBlock extends Block { + public MovingPistonBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void sendBlockUpdatePacket(GeyserSession session, BlockState state, BlockDefinition definition, Vector3i position) { + // Prevent moving_piston from being placed + // It's used for extending piston heads, but it isn't needed on Bedrock and causes pistons to flicker + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/PistonBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/PistonBlock.java new file mode 100644 index 000000000..fc54115eb --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/PistonBlock.java @@ -0,0 +1,47 @@ +/* + * 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; +import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; + +public class PistonBlock extends Block implements BedrockChunkWantsBlockEntityTag { + public PistonBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState) { + boolean extended = blockState.getValue(Properties.EXTENDED); + boolean sticky = blockState.is(Blocks.STICKY_PISTON); + return PistonBlockEntity.buildStaticPistonTag(position, extended, sticky); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java new file mode 100644 index 000000000..01a757eae --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java @@ -0,0 +1,54 @@ +/* + * 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; +import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.SkullCache; + +public class SkullBlock extends Block { + public SkullBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void sendBlockUpdatePacket(GeyserSession session, BlockState state, BlockDefinition definition, Vector3i position) { + int skullVariant = BlockStateValues.getSkullVariant(state.javaId()); // TODO + if (skullVariant == -1) { + // Skull is gone + session.getSkullCache().removeSkull(position); + } else if (skullVariant == 3) { + // The changed block was a player skull so check if a custom block was defined for this skull + SkullCache.Skull skull = session.getSkullCache().updateSkull(position, state.javaId()); + if (skull != null && skull.getBlockDefinition() != null) { + definition = skull.getBlockDefinition(); + } + } + super.sendBlockUpdatePacket(session, state, definition, position); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 64b466f12..66301cef2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -424,39 +424,12 @@ public final class BlockRegistryPopulator { // TODO fix this, (no block should have a null hardness) BlockMapping.BlockMappingBuilder builder = BlockMapping.builder(); - JsonNode hardnessNode = entry.getValue().get("block_hardness"); - if (hardnessNode != null) { - builder.hardness(hardnessNode.floatValue()); - } - - JsonNode canBreakWithHandNode = entry.getValue().get("can_break_with_hand"); - if (canBreakWithHandNode != null) { - builder.canBreakWithHand(canBreakWithHandNode.booleanValue()); - } else { - builder.canBreakWithHand(false); - } - - JsonNode collisionIndexNode = entry.getValue().get("collision_index"); - if (hardnessNode != null) { - builder.collisionIndex(collisionIndexNode.intValue()); - } JsonNode pickItemNode = entry.getValue().get("pick_item"); if (pickItemNode != null) { builder.pickItem(pickItemNode.textValue().intern()); } - if (javaId.equals("minecraft:obsidian") || javaId.equals("minecraft:crying_obsidian") || javaId.startsWith("minecraft:respawn_anchor") || javaId.startsWith("minecraft:reinforced_deepslate")) { - builder.pistonBehavior(PistonBehavior.BLOCK); - } else { - JsonNode pistonBehaviorNode = entry.getValue().get("piston_behavior"); - if (pistonBehaviorNode != null) { - builder.pistonBehavior(PistonBehavior.getByName(pistonBehaviorNode.textValue())); - } else { - builder.pistonBehavior(PistonBehavior.NORMAL); - } - } - JsonNode hasBlockEntityNode = entry.getValue().get("has_block_entity"); if (hasBlockEntityNode != null) { builder.isBlockEntity(hasBlockEntityNode.booleanValue()); @@ -475,7 +448,6 @@ public final class BlockRegistryPopulator { } builder.javaIdentifier(javaId); - builder.javaBlockId(uniqueJavaId); BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId); BlockRegistries.JAVA_BLOCKS.register(javaRuntimeId, builder.build()); @@ -547,26 +519,23 @@ public final class BlockRegistryPopulator { int stateRuntimeId = javaBlockState.javaId(); String pistonBehavior = javaBlockState.pistonBehavior(); BlockMapping blockMapping = BlockMapping.builder() - .canBreakWithHand(javaBlockState.canBreakWithHand()) .pickItem(javaBlockState.pickItem()) .isNonVanilla(true) .javaIdentifier(javaId) - .javaBlockId(javaBlockState.stateGroupId()) - .hardness(javaBlockState.blockHardness()) - .pistonBehavior(pistonBehavior == null ? PistonBehavior.NORMAL : PistonBehavior.getByName(pistonBehavior)) - .isBlockEntity(javaBlockState.hasBlockEntity()) .build(); Block.Builder builder = Block.builder() - .destroyTime(javaBlockState.blockHardness()); + .destroyTime(javaBlockState.blockHardness()) + .pushReaction(pistonBehavior == null ? PistonBehavior.NORMAL : PistonBehavior.getByName(pistonBehavior)); if (!javaBlockState.canBreakWithHand()) { builder.requiresCorrectToolForDrops(); } if (javaBlockState.hasBlockEntity()) { builder.setBlockEntity(); } - String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier()); + Block block = new Block(cleanJavaIdentifier, builder); + String bedrockIdentifier = customBlockState.block().identifier(); if (!cleanJavaIdentifier.equals(cleanIdentifiers.peekLast())) { @@ -574,6 +543,7 @@ public final class BlockRegistryPopulator { cleanIdentifiers.add(cleanJavaIdentifier.intern()); } + BlockRegistries.JAVA_BLOCKS_TO_RENAME.get().add(javaBlockState.stateGroupId(), block); //TODO don't allow duplicates, allow blanks BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, stateRuntimeId); BlockRegistries.JAVA_BLOCKS.register(stateRuntimeId, blockMapping); diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java index 0196ac22f..d6ee55965 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java @@ -27,32 +27,19 @@ package org.geysermc.geyser.registry.type; import lombok.Builder; import lombok.Value; -import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.util.BlockUtils; @Builder @Value public class BlockMapping { - public static BlockMapping DEFAULT = BlockMapping.builder().javaIdentifier("minecraft:air").pistonBehavior(PistonBehavior.NORMAL).build(); + public static BlockMapping DEFAULT = BlockMapping.builder().javaIdentifier("minecraft:air").build(); String javaIdentifier; - /** - * The block ID shared between all different block states of this block. - * NOT the runtime ID! - */ - int javaBlockId; - float hardness; boolean canBreakWithHand; - /** - * The index of this collision in collision.json - */ - int collisionIndex; @Nullable String pickItem; - @NonNull PistonBehavior pistonBehavior; boolean isBlockEntity; boolean isNonVanilla; diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index c76f024af..2fe808070 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.common.DefinitionRegistry; import org.geysermc.geyser.api.block.custom.CustomBlockState; +import org.geysermc.geyser.level.block.type.BlockState; import java.util.List; import java.util.Map; @@ -78,6 +79,10 @@ public class BlockMappings implements DefinitionRegistry { return this.javaToBedrockBlocks[javaState]; } + public GeyserBedrockBlock getBedrockBlock(BlockState javaState) { + return this.getBedrockBlock(javaState.javaId()); + } + public GeyserBedrockBlock getVanillaBedrockBlock(int javaState) { if (javaState < 0 || javaState >= this.javaToVanillaBedrockBlocks.length) { return bedrockAir; 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 6da354646..95f5c1cc3 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 @@ -30,7 +30,6 @@ 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.registry.type.BlockMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.BlockTag; import org.geysermc.geyser.session.cache.tags.ItemTag; @@ -107,17 +106,6 @@ public final class TagCache { return false; } - /** - * @return true if the block tag is present and contains this block mapping's Java ID. - */ - public boolean is(BlockTag tag, BlockMapping mapping) { - IntList values = this.blocks.get(tag); - if (values != null) { - return values.contains(mapping.getJavaBlockId()); - } - return false; - } - /** * @return true if the item tag is present and contains this item stack's Java ID. */ 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 c84126608..44ec7a6b9 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 @@ -180,7 +180,7 @@ public final class WorldCache { // This block may be out of sync with the server // In 1.19.0 Java, you can verify this by trying to mine in spawn protection Vector3i position = entry.getKey(); - ChunkUtils.updateBlockClientSide(session, session.getGeyser().getWorldManager().getBlockAt(session, position), position); + ChunkUtils.updateBlockClientSide(session, session.getGeyser().getWorldManager().blockAt(session, position), position); it.remove(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockChunkWantsBlockEntityTag.java similarity index 59% rename from core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockChunkWantsBlockEntityTag.java index a55fa8a62..189fb2c65 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockChunkWantsBlockEntityTag.java @@ -27,32 +27,18 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.session.GeyserSession; /** - * Pistons are a special case where they are only a block entity on Bedrock. + * Implemented only if a block is a block entity in Bedrock and not Java Edition. */ -public class PistonBlockEntityTranslator { +public interface BedrockChunkWantsBlockEntityTag extends RequiresBlockState { /** - * Used in ChunkUtils to determine if the block is a piston. - * + * Get the tag of the Bedrock-only block entity. Used during chunk loading. + * @param position Bedrock position of block. * @param blockState Java BlockState of block. - * @return if block is a piston or not. + * @return Bedrock tag */ - public static boolean isBlock(int blockState) { - return BlockStateValues.getPistonValues().containsKey(blockState); - } - - /** - * Calculates the Nukkit CompoundTag to send to the client on chunk - * - * @param blockState Java block state of block. - * @param position Bedrock position of piston. - * @return Bedrock tag of piston. - */ - public static NbtMap getTag(int blockState, Vector3i position) { - boolean extended = BlockStateValues.getPistonValues().get(blockState); - boolean sticky = BlockStateValues.isStickyPiston(blockState); - return PistonBlockEntity.buildStaticPistonTag(position, extended, sticky); - } + NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java deleted file mode 100644 index 01e2d3e74..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java +++ /dev/null @@ -1,82 +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.level.block.entity; - -import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtList; -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtType; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.level.block.type.BlockState; -import org.geysermc.geyser.session.GeyserSession; - -/** - * Implemented only if a block is a block entity in Bedrock and not Java Edition. - */ -public interface BedrockOnlyBlockEntity extends RequiresBlockState { - /** - * Determines if block is part of class - * @param blockState BlockState to be compared - * @return true if part of the class - */ - boolean isBlock(int blockState); - - /** - * Update the block on Bedrock Edition. - * @param session GeyserConnection. - * @param blockState The Java block state. - * @param position The Bedrock block position. - */ - void updateBlock(GeyserSession session, BlockState blockState, Vector3i position); - - /** - * Get the tag of the Bedrock-only block entity - * @param position Bedrock position of block. - * @param blockState Java BlockState of block. - * @return Bedrock tag, or null if not a Bedrock-only Block Entity - */ - static @Nullable NbtMap getTag(GeyserSession session, Vector3i position, int blockState) { - if (FlowerPotBlockEntityTranslator.isFlowerBlock(blockState)) { - return FlowerPotBlockEntityTranslator.getTag(session, blockState, position); - } else if (PistonBlockEntityTranslator.isBlock(blockState)) { - return PistonBlockEntityTranslator.getTag(blockState, position); - } else if (BlockStateValues.isCauldron(blockState)) { - // As of 1.18.30: this is required to make rendering not look weird on chunk load (lava and snow cauldrons look dim) - return NbtMap.builder() - .putString("id", "Cauldron") - .putByte("isMovable", (byte) 0) - .putShort("PotionId", (short) -1) - .putShort("PotionType", (short) -1) - .putList("Items", NbtType.END, NbtList.EMPTY) - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) - .build(); - } - return null; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index 63c5f71f3..102f4a0e6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -25,33 +25,20 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.ChestType; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; /** - * Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockOnlyBlockEntity + * Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockChunkWantsBlockEntityTag */ @BlockEntity(type = { BlockEntityType.CHEST, BlockEntityType.TRAPPED_CHEST }) -public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements BedrockOnlyBlockEntity { - @Override - public boolean isBlock(int blockState) { - return BlockStateValues.getDoubleChestValues().containsKey(blockState); - } - - @Override - public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { - NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockEntityType.CHEST), position.getX(), position.getY(), position.getZ()); - translateTag(session, tagBuilder, null, blockState); - BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); - } +public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { @@ -71,7 +58,7 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl public static void translateChestValue(NbtMapBuilder builder, BlockState state, int x, int z) { // Calculate the position of the other chest based on the Java block state Direction facing = state.getValue(Properties.HORIZONTAL_FACING); - boolean isLeft = state.getValue(Properties.CHEST_TYPE).equals("left"); //TODO enum + boolean isLeft = state.getValue(Properties.CHEST_TYPE) == ChestType.LEFT; switch (facing) { case EAST -> z = z + (isLeft ? 1 : -1); case WEST -> z = z + (isLeft ? -1 : 1); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index e09f6ae42..abe3a197e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -25,7 +25,11 @@ package org.geysermc.geyser.translator.level.block.entity; +import it.unimi.dsi.fastutil.objects.*; +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.level.block.type.PistonBlock; import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; @@ -33,9 +37,6 @@ import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.Getter; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.level.block.BlockStateValues; @@ -69,7 +70,7 @@ public class PistonBlockEntity { /** * A map of attached block positions to Java ids. */ - private final Object2IntMap attachedBlocks = new Object2IntOpenHashMap<>(); + private final Object2ObjectMap attachedBlocks = new Object2ObjectOpenHashMap<>(); /** * A flattened array of the positions of attached blocks, stored in XYZ order. */ @@ -158,7 +159,7 @@ public class PistonBlockEntity { BlockEntityUtils.updateBlockEntity(session, buildPistonTag(), position); } - public void setAction(PistonValueType action, Object2IntMap attachedBlocks) { + public void setAction(PistonValueType action, Map attachedBlocks) { // Don't check if this.action == action, since on some Paper versions BlockPistonRetractEvent is called multiple times // with the first 1-2 events being empty. placeFinalBlocks(); @@ -255,13 +256,13 @@ public class PistonBlockEntity { if (!blocksChecked.add(blockPos)) { continue; } - int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockPos); - if (blockId == Block.JAVA_AIR_ID) { + BlockState state = session.getGeyser().getWorldManager().blockAt(session, blockPos); + if (state.block() == Blocks.AIR) { continue; } - if (BlockStateValues.canPistonMoveBlock(blockId, action == PistonValueType.PUSHING)) { - attachedBlocks.put(blockPos, blockId); - if (BlockStateValues.isBlockSticky(blockId)) { + if (BlockStateValues.canPistonMoveBlock(state, action == PistonValueType.PUSHING)) { + attachedBlocks.put(blockPos, state); + if (BlockStateValues.isBlockSticky(state)) { // For honey blocks and slime blocks check the blocks adjacent to it for (Direction direction : Direction.VALUES) { Vector3i offset = direction.getUnitVector(); @@ -278,13 +279,13 @@ public class PistonBlockEntity { if (action == PistonValueType.PULLING && position.add(directionOffset).equals(adjacentPos)) { continue; } - int adjacentBlockId = session.getGeyser().getWorldManager().getBlockAt(session, adjacentPos); - if (adjacentBlockId != Block.JAVA_AIR_ID && BlockStateValues.isBlockAttached(blockId, adjacentBlockId) && BlockStateValues.canPistonMoveBlock(adjacentBlockId, false)) { + BlockState adjacentBlockState = session.getGeyser().getWorldManager().blockAt(session, adjacentPos); + if (adjacentBlockState.block() != Blocks.AIR && BlockStateValues.isBlockAttached(state, adjacentBlockState) && BlockStateValues.canPistonMoveBlock(adjacentBlockState, false)) { // If it is another slime/honey block we need to check its adjacent blocks - if (BlockStateValues.isBlockSticky(adjacentBlockId)) { + if (BlockStateValues.isBlockSticky(adjacentBlockState)) { blocksToCheck.add(adjacentPos); } else { - attachedBlocks.put(adjacentPos, adjacentBlockId); + attachedBlocks.put(adjacentPos, adjacentBlockState); blocksChecked.add(adjacentPos); blocksToCheck.add(adjacentPos.add(movement)); } @@ -293,7 +294,7 @@ public class PistonBlockEntity { } // Check next block in line blocksToCheck.add(blockPos.add(movement)); - } else if (!BlockStateValues.canPistonDestroyBlock(blockId)) { + } else if (!BlockStateValues.canPistonDestroyBlock(state)) { // Block can't be moved or destroyed, so it blocks all block movement moveBlocks = false; break; @@ -350,24 +351,24 @@ public class PistonBlockEntity { playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() - shrink.getZ()); // Resolve collision with the piston head - int pistonHeadId = BlockStateValues.getPistonHead(orientation); + BlockState pistonHeadId = BlockState.of(BlockStateValues.getPistonHead(orientation)); pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox); // Resolve collision with any attached moving blocks, but skip slime blocks // This prevents players from being launched by slime blocks covered by other blocks - for (Object2IntMap.Entry entry : attachedBlocks.object2IntEntrySet()) { - int blockId = entry.getIntValue(); - if (blockId != BlockStateValues.JAVA_SLIME_BLOCK_ID) { + for (Map.Entry entry : Object2ObjectMaps.fastIterable(attachedBlocks)) { + BlockState state = entry.getValue(); + if (!state.is(Blocks.SLIME_BLOCK)) { Vector3d blockPos = entry.getKey().toDouble(); - pushPlayerBlock(blockId, blockPos, blockMovement, playerBoundingBox); + pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox); } } // Resolve collision with slime blocks - for (Object2IntMap.Entry entry : attachedBlocks.object2IntEntrySet()) { - int blockId = entry.getIntValue(); - if (blockId == BlockStateValues.JAVA_SLIME_BLOCK_ID) { + for (Map.Entry entry : Object2ObjectMaps.fastIterable(attachedBlocks)) { + BlockState state = entry.getValue(); + if (state.is(Blocks.SLIME_BLOCK)) { Vector3d blockPos = entry.getKey().toDouble(); - pushPlayerBlock(blockId, blockPos, blockMovement, playerBoundingBox); + pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox); } } @@ -463,7 +464,7 @@ public class PistonBlockEntity { return maxIntersection; } - private void pushPlayerBlock(int javaId, Vector3d startingPos, double blockMovement, BoundingBox playerBoundingBox) { + private void pushPlayerBlock(BlockState state, Vector3d startingPos, double blockMovement, BoundingBox playerBoundingBox) { PistonCache pistonCache = session.getPistonCache(); Vector3d movement = getMovement().toDouble(); // Check if the player collides with the movingBlock block entity @@ -471,14 +472,14 @@ public class PistonBlockEntity { if (SOLID_BOUNDING_BOX.checkIntersection(finalBlockPos, playerBoundingBox)) { pistonCache.setPlayerCollided(true); - if (javaId == BlockStateValues.JAVA_SLIME_BLOCK_ID) { + if (state.is(Blocks.SLIME_BLOCK)) { pistonCache.setPlayerSlimeCollision(true); applySlimeBlockMotion(finalBlockPos, Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ())); } } Vector3d blockPos = startingPos.add(movement.mul(blockMovement)); - if (javaId == BlockStateValues.JAVA_HONEY_BLOCK_ID && isPlayerAttached(blockPos, playerBoundingBox)) { + if (state.is(Blocks.HONEY_BLOCK) && isPlayerAttached(blockPos, playerBoundingBox)) { pistonCache.setPlayerCollided(true); pistonCache.setPlayerAttachedToHoney(true); @@ -486,7 +487,7 @@ public class PistonBlockEntity { pistonCache.displacePlayer(movement.mul(delta)); } else { // Move the player out of collision - BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(javaId); + BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(state.javaId()); if (blockCollision != null) { Vector3d extend = movement.mul(Math.min(1 - blockMovement, 0.5)); Direction movementDirection = orientation; @@ -499,7 +500,7 @@ public class PistonBlockEntity { pistonCache.setPlayerCollided(true); pistonCache.displacePlayer(movement.mul(intersection + 0.01d)); - if (javaId == BlockStateValues.JAVA_SLIME_BLOCK_ID) { + if (state.is(Blocks.SLIME_BLOCK)) { pistonCache.setPlayerSlimeCollision(true); applySlimeBlockMotion(blockPos, Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ())); } @@ -509,7 +510,7 @@ public class PistonBlockEntity { } private BlockCollision getCollision(Vector3i blockPos) { - return BlockUtils.getCollision(getAttachedBlockId(blockPos)); + return BlockUtils.getCollision(getAttachedBlockId(blockPos).javaId()); } /** @@ -533,7 +534,7 @@ public class PistonBlockEntity { double y = blockPos.getY() + movementVec.getY() * movementProgress; double z = blockPos.getZ() + movementVec.getZ() * movementProgress; double adjustedMovement = blockCollision.computeCollisionOffset(x, y, z, boundingBox, axis, movement); - if (getAttachedBlockId(blockPos) == BlockStateValues.JAVA_SLIME_BLOCK_ID && adjustedMovement != movement) { + if (getAttachedBlockId(blockPos).is(Blocks.SLIME_BLOCK) && adjustedMovement != movement) { session.getPistonCache().setPlayerSlimeCollision(true); } return adjustedMovement; @@ -557,11 +558,11 @@ public class PistonBlockEntity { return false; } - private int getAttachedBlockId(Vector3i blockPos) { + private BlockState getAttachedBlockId(Vector3i blockPos) { if (blockPos.equals(getPistonHeadPos())) { - return BlockStateValues.getPistonHead(orientation); + return BlockState.of(BlockStateValues.getPistonHead(orientation)); } else { - return attachedBlocks.getOrDefault(blockPos, Block.JAVA_AIR_ID); + return attachedBlocks.getOrDefault(blockPos, BlockState.of(Block.JAVA_AIR_ID)); //FIXME } } @@ -582,12 +583,12 @@ public class PistonBlockEntity { playerBoundingBox.setSizeX(playerBoundingBox.getSizeX() + 0.5); playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() + 0.5); } - attachedBlocks.forEach((blockPos, javaId) -> { + attachedBlocks.forEach((blockPos, state) -> { Vector3i newPos = blockPos.add(movement); if (SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), playerBoundingBox) || SOLID_BOUNDING_BOX.checkIntersection(newPos.toDouble(), playerBoundingBox)) { session.getPistonCache().setPlayerCollided(true); - if (javaId == BlockStateValues.JAVA_SLIME_BLOCK_ID) { + if (state.is(Blocks.SLIME_BLOCK)) { session.getPistonCache().setPlayerSlimeCollision(true); } // Don't place moving blocks that collide with the player @@ -603,7 +604,7 @@ public class PistonBlockEntity { updateBlockPacket.setDataLayer(0); session.sendUpstreamPacket(updateBlockPacket); // Update moving block with correct details - BlockEntityUtils.updateBlockEntity(session, buildMovingBlockTag(newPos, javaId, position), newPos); + BlockEntityUtils.updateBlockEntity(session, buildMovingBlockTag(newPos, state, position), newPos); }); } @@ -773,13 +774,13 @@ public class PistonBlockEntity { * Create a moving block tag of a block that will be moved by a piston * * @param position The ending position of the block (The location of the movingBlock block entity) - * @param javaId The Java Id of the block that is moving + * @param state The Java BlockState of the block that is moving * @param pistonPosition The position for the base of the piston that's moving the block * @return A moving block data tag */ - private NbtMap buildMovingBlockTag(Vector3i position, int javaId, Vector3i pistonPosition) { + private NbtMap buildMovingBlockTag(Vector3i position, BlockState state, Vector3i pistonPosition) { // Get Bedrock block state data - NbtMap movingBlock = session.getBlockMappings().getBedrockBlock(javaId).getState(); + NbtMap movingBlock = session.getBlockMappings().getBedrockBlock(state).getState(); NbtMapBuilder builder = NbtMap.builder() .putString("id", "MovingBlock") .putBoolean("expanding", action == PistonValueType.PUSHING) @@ -791,8 +792,8 @@ public class PistonBlockEntity { .putInt("x", position.getX()) .putInt("y", position.getY()) .putInt("z", position.getZ()); - if (PistonBlockEntityTranslator.isBlock(javaId)) { - builder.putCompound("movingEntity", PistonBlockEntityTranslator.getTag(javaId, position)); + if (state.block() instanceof PistonBlock piston) { + builder.putCompound("movingEntity", piston.createTag(session, position, state)); } return builder.build(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 9cb3fb455..507d67ba5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -25,13 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.ItemMapping; @@ -39,6 +38,7 @@ 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.item.ItemStack; @Translator(packet = BlockPickRequestPacket.class) public class BedrockBlockPickRequestTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java index 36f1d3d65..b7201762f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java @@ -25,23 +25,25 @@ package org.geysermc.geyser.translator.protocol.java.level; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEventPacket; -import it.unimi.dsi.fastutil.objects.Object2IntMaps; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.level.block.BlockStateValues; +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.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PistonCache; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; @Translator(packet = ClientboundBlockEventPacket.class) public class JavaBlockEventTranslator extends PacketTranslator { @@ -63,7 +65,7 @@ public class JavaBlockEventTranslator extends PacketTranslator { - blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState)); + blockEventPacket.setEventData(BlockState.of(blockState).getValue(Properties.NOTE)); session.sendUpstreamPacket(blockEventPacket); }); } else if (value instanceof PistonValue pistonValue) { @@ -90,7 +92,7 @@ public class JavaBlockEventTranslator extends PacketTranslator new PistonBlockEntity(session, pos, direction, true, true)); if (blockEntity.getAction() != action) { - blockEntity.setAction(action, Object2IntMaps.emptyMap()); + blockEntity.setAction(action, Object2ObjectMaps.emptyMap()); } } } else { @@ -110,11 +112,7 @@ public class JavaBlockEventTranslator extends PacketTranslator 0; case WEST -> 1; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index e54fe5896..bd7096d2b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -41,7 +41,6 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.BedrockDimension; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.BlockState; @@ -53,7 +52,7 @@ import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.BiomeTranslator; -import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.SkullBlockEntityTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -193,11 +192,12 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)), - javaId + state )); } } @@ -253,7 +253,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)), - javaPalette.idToState(paletteId) + state )); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java index ec7f45c8d..1462378e9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java @@ -31,25 +31,13 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; -import org.geysermc.geyser.translator.level.block.entity.FlowerPotBlockEntityTranslator; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import java.util.List; import java.util.Locale; import java.util.Map; public class BlockEntityUtils { - /** - * A list of all block entities that require the Java block state in order to fill out their block entity information. - * This list will be smaller with cache sections on as we don't need to double-cache data - */ - public static final List BEDROCK_ONLY_BLOCK_ENTITIES = List.of( - (BedrockOnlyBlockEntity) Registries.BLOCK_ENTITIES.get().get(BlockEntityType.CHEST), - new FlowerPotBlockEntityTranslator() - ); - /** * Contains a list of irregular block entity name translations that can't be fit into the regex */ diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index a1e956ace..5504d01a8 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -33,24 +33,19 @@ import lombok.experimental.UtilityClass; import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector2i; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.GeyserChunkSection; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; @UtilityClass public class ChunkUtils { @@ -119,18 +114,30 @@ public class ChunkUtils { * @param position the position of the block */ public static void updateBlock(GeyserSession session, int blockState, Vector3i position) { - updateBlockClientSide(session, blockState, position); + updateBlockClientSide(session, BlockState.of(blockState), position); session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState); } + /** + * Sends a block update to the Bedrock client. If the platform does not have an integrated world manager, this also + * adds that block to the cache. + * @param session the Bedrock session to send/register the block to + * @param blockState the Java block state of the block + * @param position the position of the block + */ + public static void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { + updateBlockClientSide(session, blockState, position); + session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState.javaId()); + } + /** * Updates a block, but client-side only. */ - public static void updateBlockClientSide(GeyserSession session, int blockState, Vector3i position) { + public static void updateBlockClientSide(GeyserSession session, BlockState blockState, Vector3i position) { // Checks for item frames so they aren't tripped up and removed ItemFrameEntity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, position); if (itemFrameEntity != null) { - if (blockState == Block.JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it + if (blockState.is(Blocks.AIR)) { // Item frame is still present and no block overrides that; refresh it itemFrameEntity.updateBlock(true); // Still update the chunk cache with the new block if updateBlock is called return; @@ -138,91 +145,7 @@ public class ChunkUtils { // Otherwise, let's still store our reference to the item frame, but let the new block take precedence for now } - BlockDefinition definition = session.getBlockMappings().getBedrockBlock(blockState); - - int skullVariant = BlockStateValues.getSkullVariant(blockState); - if (skullVariant == -1) { - // Skull is gone - session.getSkullCache().removeSkull(position); - } else if (skullVariant == 3) { - // The changed block was a player skull so check if a custom block was defined for this skull - SkullCache.Skull skull = session.getSkullCache().updateSkull(position, blockState); - if (skull != null && skull.getBlockDefinition() != null) { - definition = skull.getBlockDefinition(); - } - } - - // Prevent moving_piston from being placed - // It's used for extending piston heads, but it isn't needed on Bedrock and causes pistons to flicker - if (!BlockStateValues.isMovingPiston(blockState)) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position); - updateBlockPacket.setDefinition(definition); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - - UpdateBlockPacket waterPacket = new UpdateBlockPacket(); - waterPacket.setDataLayer(1); - waterPacket.setBlockPosition(position); - if (BlockRegistries.WATERLOGGED.get().get(blockState)) { - waterPacket.setDefinition(session.getBlockMappings().getBedrockWater()); - } else { - waterPacket.setDefinition(session.getBlockMappings().getBedrockAir()); - } - session.sendUpstreamPacket(waterPacket); - } - - // Extended collision boxes for custom blocks - if (!session.getBlockMappings().getExtendedCollisionBoxes().isEmpty()) { - int aboveBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() + 1, position.getZ()); - BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(blockState); - int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ()); - BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock); - if (belowBedrockExtendedCollisionDefinition != null && blockState == Block.JAVA_AIR_ID) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position); - updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); - updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } else if (aboveBlock == Block.JAVA_AIR_ID) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); - updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } - } - - BlockStateValues.getLecternBookStates().handleBlockChange(session, blockState, position); - - // Iterates through all Bedrock-only block entity translators and determines if a manual block entity packet - // needs to be sent - for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityUtils.BEDROCK_ONLY_BLOCK_ENTITIES) { - if (bedrockOnlyBlockEntity.isBlock(blockState)) { - // Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks - bedrockOnlyBlockEntity.updateBlock(session, BlockState.of(blockState), position); //TODO blockState - break; //No block will be a part of two classes - } - } - - if (BlockStateValues.isUpperDoor(blockState)) { - // Update the lower door block as Bedrock client doesn't like door to be closed from the top - // See https://github.com/GeyserMC/Geyser/issues/4358 - Vector3i belowDoorPosition = position.sub(0, 1, 0); - int belowDoorBlockState = session.getGeyser().getWorldManager().getBlockAt(session, belowDoorPosition.getX(), belowDoorPosition.getY(), belowDoorPosition.getZ()); - updateBlock(session, belowDoorBlockState, belowDoorPosition); - } + blockState.block().updateBlock(session, blockState, position); } public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) { From a439f3e3d7a6a9e16f3e6dea9df4dfb0df37b7d4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 17 May 2024 21:14:59 -0400 Subject: [PATCH 146/897] Fix compilation for Spigot --- .../spigot/world/GeyserPistonListener.java | 17 ++++++------ .../erosion/GeyserboundPacketHandlerImpl.java | 4 +-- .../geyser/level/block/type/BlockState.java | 10 +++++++ .../block/entity/BlockEntityTranslator.java | 5 ++++ .../level/block/entity/PistonBlockEntity.java | 27 ++++++------------- 5 files changed, 34 insertions(+), 29 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java index 61c0d5fe8..2a6dc7a81 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java @@ -25,10 +25,8 @@ package org.geysermc.geyser.platform.spigot.world; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; -import org.cloudburstmc.math.vector.Vector3i; -import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -40,13 +38,16 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPistonEvent; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; +import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import java.util.List; import java.util.Map; @@ -85,7 +86,7 @@ public class GeyserPistonListener implements Listener { PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING; boolean sticky = event.isSticky(); - Object2IntMap attachedBlocks = new Object2IntArrayMap<>(); + Object2ObjectMap attachedBlocks = new Object2ObjectArrayMap<>(); boolean blocksFilled = false; for (Map.Entry entry : geyser.getSessionManager().getSessions().entrySet()) { @@ -108,10 +109,10 @@ public class GeyserPistonListener implements Listener { List blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks(); for (Block block : blocks) { Location attachedLocation = block.getLocation(); - int blockId = worldManager.getBlockNetworkId(block); + BlockState state = BlockState.of(worldManager.getBlockNetworkId(block)); // Ignore blocks that will be destroyed - if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) { - attachedBlocks.put(getVector(attachedLocation), blockId); + if (BlockStateValues.canPistonMoveBlock(state, isExtend)) { + attachedBlocks.put(getVector(attachedLocation), state); } } blocksFilled = true; diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index 6e22fd430..62ecaa1e9 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -30,8 +30,8 @@ import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.Setter; import org.cloudburstmc.math.vector.Vector3i; @@ -157,7 +157,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke .stream() .map(entry -> Pair.of(entry.getKey(), BlockState.of(entry.getIntValue()))) .filter(pair -> BlockStateValues.canPistonMoveBlock(pair.value(), isExtend)); - Object2ObjectMap attachedBlocks = new Object2ObjectOpenHashMap<>(); + Object2ObjectMap attachedBlocks = new Object2ObjectArrayMap<>(); stream.forEach(pair -> attachedBlocks.put(pair.key(), pair.value())); session.executeInEventLoop(() -> { diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 23e89d99f..de4806efa 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -62,6 +62,16 @@ public final class BlockState { return this.block == block; } + private String paramsToString() { + StringBuilder builder = new StringBuilder(); + var it = this.states.entrySet().iterator(); + while (it.hasNext()) { + var entry = it.next(); + builder.append(entry.getKey()).append("=").append(entry.getValue()); + } + return builder.toString(); + } + public static BlockState of(int javaId) { return BlockRegistries.BLOCK_STATES.get(javaId); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java index 5def51e01..ae44dd134 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.translator.level.block.entity; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.type.BlockState; @@ -56,6 +57,10 @@ public abstract class BlockEntityTranslator { return getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(type), x, y, z); } + public static NbtMapBuilder getConstantBedrockTag(String bedrockId, Vector3i position) { + return getConstantBedrockTag(bedrockId, position.getX(), position.getY(), position.getZ()); + } + public static NbtMapBuilder getConstantBedrockTag(String bedrockId, int x, int y, int z) { return NbtMap.builder() .putInt("x", x) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index abe3a197e..14282228b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.level.block.entity; +import it.unimi.dsi.fastutil.ints.IntArrays; import it.unimi.dsi.fastutil.objects.*; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.type.Block; @@ -74,7 +75,7 @@ public class PistonBlockEntity { /** * A flattened array of the positions of attached blocks, stored in XYZ order. */ - private int[] flattenedAttachedBlocks = new int[0]; + private int[] flattenedAttachedBlocks = IntArrays.EMPTY_ARRAY; private boolean placedFinalBlocks = true; @@ -732,18 +733,14 @@ public class PistonBlockEntity { * @return A piston data tag */ private NbtMap buildPistonTag() { - NbtMapBuilder builder = NbtMap.builder() - .putString("id", "PistonArm") + NbtMapBuilder builder = BlockEntityTranslator.getConstantBedrockTag("PistonArm", position) .putIntArray("AttachedBlocks", flattenedAttachedBlocks) .putFloat("Progress", progress) .putFloat("LastProgress", lastProgress) .putByte("NewState", getState()) .putByte("State", getState()) .putBoolean("Sticky", sticky) - .putBoolean("isMovable", false) - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()); + .putBoolean("isMovable", false); return builder.build(); } @@ -756,17 +753,13 @@ public class PistonBlockEntity { * @return A piston data tag for a fully extended/retracted piston */ public static NbtMap buildStaticPistonTag(Vector3i position, boolean extended, boolean sticky) { - NbtMapBuilder builder = NbtMap.builder() - .putString("id", "PistonArm") + NbtMapBuilder builder = BlockEntityTranslator.getConstantBedrockTag("PistonArm", position) .putFloat("Progress", extended ? 1.0f : 0.0f) .putFloat("LastProgress", extended ? 1.0f : 0.0f) .putByte("NewState", (byte) (extended ? 2 : 0)) .putByte("State", (byte) (extended ? 2 : 0)) .putBoolean("Sticky", sticky) - .putBoolean("isMovable", false) - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()); + .putBoolean("isMovable", false); return builder.build(); } @@ -781,17 +774,13 @@ public class PistonBlockEntity { private NbtMap buildMovingBlockTag(Vector3i position, BlockState state, Vector3i pistonPosition) { // Get Bedrock block state data NbtMap movingBlock = session.getBlockMappings().getBedrockBlock(state).getState(); - NbtMapBuilder builder = NbtMap.builder() - .putString("id", "MovingBlock") + NbtMapBuilder builder = BlockEntityTranslator.getConstantBedrockTag("MovingBlock", position) .putBoolean("expanding", action == PistonValueType.PUSHING) .putCompound("movingBlock", movingBlock) .putBoolean("isMovable", true) .putInt("pistonPosX", pistonPosition.getX()) .putInt("pistonPosY", pistonPosition.getY()) - .putInt("pistonPosZ", pistonPosition.getZ()) - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()); + .putInt("pistonPosZ", pistonPosition.getZ()); if (state.block() instanceof PistonBlock piston) { builder.putCompound("movingEntity", piston.createTag(session, position, state)); } From 8b7703154ef7b7df82e42cd7ce62e0211b14b3d6 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 18 May 2024 21:13:00 +0200 Subject: [PATCH 147/897] Resolve issue when trying to transfer a Geyser player (#4673) --- .../main/java/org/geysermc/geyser/session/GeyserSession.java | 3 +++ gradle/libs.versions.toml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) 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 617087f71..2b7ec0a97 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -896,6 +896,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.downstream.getSession().setFlag(BuiltinFlags.ATTEMPT_SRV_RESOLVE, resolveSrv); } + // Disable automatic creation of a new TcpClientSession when transferring - we don't use that functionality. + this.downstream.getSession().setFlag(MinecraftConstants.FOLLOW_TRANSFERS, false); + if (geyser.getConfig().getRemote().isUseProxyProtocol()) { downstream.setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true); downstream.setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress()); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 65a5e3a52..dee170705 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "e5b0bcc" -mcprotocollib = "42ea4a4" # Revert from jitpack after release +mcprotocollib = "a1b559d" # Revert from jitpack after release adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 6c904b2378e3e34e215c729001d97c9155c537c5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 18 May 2024 16:37:06 -0400 Subject: [PATCH 148/897] It's almost done. --- .../java/org/geysermc/geyser/GeyserImpl.java | 8 +- .../entity/type/FurnaceMinecartEntity.java | 8 +- .../entity/type/SpawnerMinecartEntity.java | 4 +- .../erosion/GeyserboundPacketHandlerImpl.java | 2 +- .../holder/BlockInventoryHolder.java | 22 +- .../java/org/geysermc/geyser/item/Items.java | 1851 +++++++++-------- .../geysermc/geyser/item/type/BannerItem.java | 5 +- .../geysermc/geyser/item/type/BlockItem.java | 23 +- .../geyser/item/type/DecoratedPotItem.java | 5 +- .../org/geysermc/geyser/item/type/Item.java | 35 +- .../geyser/item/type/PlayerHeadItem.java | 7 +- .../geyser/item/type/ShulkerBoxItem.java | 5 +- .../geyser/level/block/BlockStateValues.java | 49 - .../geysermc/geyser/level/block/Blocks.java | 14 +- .../geyser/level/block/property/Property.java | 4 + .../geyser/level/block/type/Block.java | 81 +- .../geyser/level/block/type/BlockState.java | 17 +- .../level/block/type/FlowerPotBlock.java | 2 +- .../geyser/level/block/type/FurnaceBlock.java | 56 + .../geyser/level/block/type/HoneyBlock.java | 45 + .../geyser/level/block/type/SpawnerBlock.java | 45 + .../geyser/level/block/type/WaterBlock.java | 41 + .../geyser/registry/BlockRegistries.java | 1 + .../geysermc/geyser/registry/Registries.java | 1 + .../loader/CollisionRegistryLoader.java | 2 +- .../populator/BlockRegistryPopulator.java | 65 +- .../geyser/registry/type/BlockMapping.java | 35 - .../geyser/session/GeyserSession.java | 3 +- .../AbstractBlockInventoryTranslator.java | 5 +- .../inventory/AnvilInventoryTranslator.java | 3 +- .../Generic3X3InventoryTranslator.java | 3 +- .../inventory/ShulkerInventoryTranslator.java | 4 +- .../chest/SingleChestInventoryTranslator.java | 4 +- .../level/block/entity/PistonBlockEntity.java | 7 +- .../BedrockBlockPickRequestTranslator.java | 31 +- ...BedrockInventoryTransactionTranslator.java | 6 +- .../java/level/JavaBlockUpdateTranslator.java | 10 +- .../JavaLevelChunkWithLightTranslator.java | 5 +- .../geysermc/geyser/util/InventoryUtils.java | 32 +- .../geysermc/geyser/util/StatisticsUtils.java | 2 +- 40 files changed, 1359 insertions(+), 1189 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/FurnaceBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/HoneyBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/SpawnerBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/WaterBlock.java diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index e7237e8bf..7be1fe15b 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -258,10 +258,10 @@ public class GeyserImpl implements GeyserApi { VersionCheckUtils.checkForOutdatedJava(logger); for (int i = 0; i < BlockRegistries.JAVA_BLOCKS.get().length; i++) { - String cleanIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getCleanJavaIdentifier(); - String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier(); - if (!cleanIdentifier.equals(newIdentifier)) { - System.out.println("Check block " + BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier()); + String oldIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getJavaIdentifier(); + String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).toString(); + if (!oldIdentifier.equals(newIdentifier)) { + System.out.println("Check block " + oldIdentifier + " " + newIdentifier); break; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java index ef584c4fd..0fc5627ed 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java @@ -25,14 +25,14 @@ package org.geysermc.geyser.entity.type; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.FurnaceBlock; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; @@ -51,7 +51,7 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity { @Override public void updateDefaultBlockMetadata() { - dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(hasFuel ? BlockStateValues.JAVA_FURNACE_LIT_ID : BlockStateValues.JAVA_FURNACE_ID)); + dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(FurnaceBlock.state(hasFuel))); dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java index 49cfc0081..65dfb800b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.SpawnerBlock; import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; @@ -41,7 +41,7 @@ public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity { @Override public void updateDefaultBlockMetadata() { - dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(BlockStateValues.JAVA_SPAWNER_ID)); + dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(SpawnerBlock.state())); dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6); } } diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index 62ecaa1e9..9894a4ba2 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -136,7 +136,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke placeBlockSoundPacket.setIdentifier(":"); session.sendUpstreamPacket(placeBlockSoundPacket); session.setLastBlockPlacePosition(null); - session.setLastBlockPlacedId(null); + session.setLastBlockPlaced(null); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index c11505ffb..686fe39ad 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -36,8 +36,9 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.LecternContainer; +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.BlockMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.util.BlockUtils; @@ -59,12 +60,14 @@ public class BlockInventoryHolder extends InventoryHolder { private final ContainerType containerType; private final Set validBlocks; - public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) { + public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, Block... validBlocks) { this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(javaBlockIdentifier); this.containerType = containerType; if (validBlocks != null) { Set validBlocksTemp = new HashSet<>(validBlocks.length + 1); - Collections.addAll(validBlocksTemp, validBlocks); + for (Block block : validBlocks) { + validBlocksTemp.add(block.javaIdentifier().toString()); + } validBlocksTemp.add(BlockUtils.getCleanIdentifier(javaBlockIdentifier)); this.validBlocks = Set.copyOf(validBlocksTemp); } else { @@ -80,14 +83,15 @@ public class BlockInventoryHolder extends InventoryHolder { if (checkInteractionPosition(session)) { // Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid // and the bedrock block is vanilla - int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); - if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(javaBlockId)) { - String[] javaBlockString = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaBlockId, BlockMapping.DEFAULT).getJavaIdentifier().split("\\["); + BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition()); + if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) { + // TODO TODO TODO + String[] javaBlockString = state.toString().split("\\["); if (isValidBlock(javaBlockString)) { // We can safely use this block inventory.setHolderPosition(session.getLastInteractionBlockPosition()); ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]); - setCustomName(session, session.getLastInteractionBlockPosition(), inventory, javaBlockId); + setCustomName(session, session.getLastInteractionBlockPosition(), inventory, state); return true; } @@ -107,7 +111,7 @@ public class BlockInventoryHolder extends InventoryHolder { session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); - setCustomName(session, position, inventory, defaultJavaBlockState); + setCustomName(session, position, inventory, BlockState.of(defaultJavaBlockState)); return true; } @@ -129,7 +133,7 @@ public class BlockInventoryHolder extends InventoryHolder { return this.validBlocks.contains(javaBlockString[0]); } - protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, int javaBlockState) { + protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) { NbtMap tag = NbtMap.builder() .putInt("x", position.getX()) .putInt("y", position.getY()) 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 f13330700..8c271a7bb 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.item; import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.item.type.*; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.registry.Registries; import java.util.Collections; @@ -39,770 +40,770 @@ import static org.geysermc.geyser.item.type.Item.builder; @SuppressWarnings("unused") public final class Items { public static final Item AIR = register(new Item("air", builder())); - public static final Item STONE = register(new BlockItem("stone", builder())); - public static final Item GRANITE = register(new BlockItem("granite", builder())); - public static final Item POLISHED_GRANITE = register(new BlockItem("polished_granite", builder())); - public static final Item DIORITE = register(new BlockItem("diorite", builder())); - public static final Item POLISHED_DIORITE = register(new BlockItem("polished_diorite", builder())); - public static final Item ANDESITE = register(new BlockItem("andesite", builder())); - public static final Item POLISHED_ANDESITE = register(new BlockItem("polished_andesite", builder())); - public static final Item DEEPSLATE = register(new BlockItem("deepslate", builder())); - public static final Item COBBLED_DEEPSLATE = register(new BlockItem("cobbled_deepslate", builder())); - public static final Item POLISHED_DEEPSLATE = register(new BlockItem("polished_deepslate", builder())); - public static final Item CALCITE = register(new BlockItem("calcite", builder())); - public static final Item TUFF = register(new BlockItem("tuff", builder())); - public static final Item TUFF_SLAB = register(new BlockItem("tuff_slab", builder())); - public static final Item TUFF_STAIRS = register(new BlockItem("tuff_stairs", builder())); - public static final Item TUFF_WALL = register(new BlockItem("tuff_wall", builder())); - public static final Item CHISELED_TUFF = register(new BlockItem("chiseled_tuff", builder())); - public static final Item POLISHED_TUFF = register(new BlockItem("polished_tuff", builder())); - public static final Item POLISHED_TUFF_SLAB = register(new BlockItem("polished_tuff_slab", builder())); - public static final Item POLISHED_TUFF_STAIRS = register(new BlockItem("polished_tuff_stairs", builder())); - public static final Item POLISHED_TUFF_WALL = register(new BlockItem("polished_tuff_wall", builder())); - public static final Item TUFF_BRICKS = register(new BlockItem("tuff_bricks", builder())); - public static final Item TUFF_BRICK_SLAB = register(new BlockItem("tuff_brick_slab", builder())); - public static final Item TUFF_BRICK_STAIRS = register(new BlockItem("tuff_brick_stairs", builder())); - public static final Item TUFF_BRICK_WALL = register(new BlockItem("tuff_brick_wall", builder())); - public static final Item CHISELED_TUFF_BRICKS = register(new BlockItem("chiseled_tuff_bricks", builder())); - public static final Item DRIPSTONE_BLOCK = register(new BlockItem("dripstone_block", builder())); - public static final Item GRASS_BLOCK = register(new BlockItem("grass_block", builder())); - public static final Item DIRT = register(new BlockItem("dirt", builder())); - public static final Item COARSE_DIRT = register(new BlockItem("coarse_dirt", builder())); - public static final Item PODZOL = register(new BlockItem("podzol", builder())); - public static final Item ROOTED_DIRT = register(new BlockItem("rooted_dirt", builder())); - public static final Item MUD = register(new BlockItem("mud", builder())); - public static final Item CRIMSON_NYLIUM = register(new BlockItem("crimson_nylium", builder())); - public static final Item WARPED_NYLIUM = register(new BlockItem("warped_nylium", builder())); - public static final Item COBBLESTONE = register(new BlockItem("cobblestone", builder())); - public static final Item OAK_PLANKS = register(new BlockItem("oak_planks", builder())); - public static final Item SPRUCE_PLANKS = register(new BlockItem("spruce_planks", builder())); - public static final Item BIRCH_PLANKS = register(new BlockItem("birch_planks", builder())); - public static final Item JUNGLE_PLANKS = register(new BlockItem("jungle_planks", builder())); - public static final Item ACACIA_PLANKS = register(new BlockItem("acacia_planks", builder())); - public static final Item CHERRY_PLANKS = register(new BlockItem("cherry_planks", builder())); - public static final Item DARK_OAK_PLANKS = register(new BlockItem("dark_oak_planks", builder())); - public static final Item MANGROVE_PLANKS = register(new BlockItem("mangrove_planks", builder())); - public static final Item BAMBOO_PLANKS = register(new BlockItem("bamboo_planks", builder())); - public static final Item CRIMSON_PLANKS = register(new BlockItem("crimson_planks", builder())); - public static final Item WARPED_PLANKS = register(new BlockItem("warped_planks", builder())); - public static final Item BAMBOO_MOSAIC = register(new BlockItem("bamboo_mosaic", builder())); - public static final Item OAK_SAPLING = register(new BlockItem("oak_sapling", builder())); - public static final Item SPRUCE_SAPLING = register(new BlockItem("spruce_sapling", builder())); - public static final Item BIRCH_SAPLING = register(new BlockItem("birch_sapling", builder())); - public static final Item JUNGLE_SAPLING = register(new BlockItem("jungle_sapling", builder())); - public static final Item ACACIA_SAPLING = register(new BlockItem("acacia_sapling", builder())); - public static final Item CHERRY_SAPLING = register(new BlockItem("cherry_sapling", builder())); - public static final Item DARK_OAK_SAPLING = register(new BlockItem("dark_oak_sapling", builder())); - public static final Item MANGROVE_PROPAGULE = register(new BlockItem("mangrove_propagule", builder())); - public static final Item BEDROCK = register(new BlockItem("bedrock", builder())); - public static final Item SAND = register(new BlockItem("sand", builder())); - public static final Item SUSPICIOUS_SAND = register(new BlockItem("suspicious_sand", builder())); - public static final Item SUSPICIOUS_GRAVEL = register(new BlockItem("suspicious_gravel", builder())); - public static final Item RED_SAND = register(new BlockItem("red_sand", builder())); - public static final Item GRAVEL = register(new BlockItem("gravel", builder())); - public static final Item COAL_ORE = register(new BlockItem("coal_ore", builder())); - public static final Item DEEPSLATE_COAL_ORE = register(new BlockItem("deepslate_coal_ore", builder())); - public static final Item IRON_ORE = register(new BlockItem("iron_ore", builder())); - public static final Item DEEPSLATE_IRON_ORE = register(new BlockItem("deepslate_iron_ore", builder())); - public static final Item COPPER_ORE = register(new BlockItem("copper_ore", builder())); - public static final Item DEEPSLATE_COPPER_ORE = register(new BlockItem("deepslate_copper_ore", builder())); - public static final Item GOLD_ORE = register(new BlockItem("gold_ore", builder())); - public static final Item DEEPSLATE_GOLD_ORE = register(new BlockItem("deepslate_gold_ore", builder())); - public static final Item REDSTONE_ORE = register(new BlockItem("redstone_ore", builder())); - public static final Item DEEPSLATE_REDSTONE_ORE = register(new BlockItem("deepslate_redstone_ore", builder())); - public static final Item EMERALD_ORE = register(new BlockItem("emerald_ore", builder())); - public static final Item DEEPSLATE_EMERALD_ORE = register(new BlockItem("deepslate_emerald_ore", builder())); - public static final Item LAPIS_ORE = register(new BlockItem("lapis_ore", builder())); - public static final Item DEEPSLATE_LAPIS_ORE = register(new BlockItem("deepslate_lapis_ore", builder())); - public static final Item DIAMOND_ORE = register(new BlockItem("diamond_ore", builder())); - public static final Item DEEPSLATE_DIAMOND_ORE = register(new BlockItem("deepslate_diamond_ore", builder())); - public static final Item NETHER_GOLD_ORE = register(new BlockItem("nether_gold_ore", builder())); - public static final Item NETHER_QUARTZ_ORE = register(new BlockItem("nether_quartz_ore", builder())); - public static final Item ANCIENT_DEBRIS = register(new BlockItem("ancient_debris", builder())); - public static final Item COAL_BLOCK = register(new BlockItem("coal_block", builder())); - public static final Item RAW_IRON_BLOCK = register(new BlockItem("raw_iron_block", builder())); - public static final Item RAW_COPPER_BLOCK = register(new BlockItem("raw_copper_block", builder())); - public static final Item RAW_GOLD_BLOCK = register(new BlockItem("raw_gold_block", builder())); - public static final Item HEAVY_CORE = register(new BlockItem("heavy_core", builder())); - public static final Item AMETHYST_BLOCK = register(new BlockItem("amethyst_block", builder())); - public static final Item BUDDING_AMETHYST = register(new BlockItem("budding_amethyst", builder())); - public static final Item IRON_BLOCK = register(new BlockItem("iron_block", builder())); - public static final Item COPPER_BLOCK = register(new BlockItem("copper_block", builder())); - public static final Item GOLD_BLOCK = register(new BlockItem("gold_block", builder())); - public static final Item DIAMOND_BLOCK = register(new BlockItem("diamond_block", builder())); - public static final Item NETHERITE_BLOCK = register(new BlockItem("netherite_block", builder())); - public static final Item EXPOSED_COPPER = register(new BlockItem("exposed_copper", builder())); - public static final Item WEATHERED_COPPER = register(new BlockItem("weathered_copper", builder())); - public static final Item OXIDIZED_COPPER = register(new BlockItem("oxidized_copper", builder())); - public static final Item CHISELED_COPPER = register(new BlockItem("chiseled_copper", builder())); - public static final Item EXPOSED_CHISELED_COPPER = register(new BlockItem("exposed_chiseled_copper", builder())); - public static final Item WEATHERED_CHISELED_COPPER = register(new BlockItem("weathered_chiseled_copper", builder())); - public static final Item OXIDIZED_CHISELED_COPPER = register(new BlockItem("oxidized_chiseled_copper", builder())); - public static final Item CUT_COPPER = register(new BlockItem("cut_copper", builder())); - public static final Item EXPOSED_CUT_COPPER = register(new BlockItem("exposed_cut_copper", builder())); - public static final Item WEATHERED_CUT_COPPER = register(new BlockItem("weathered_cut_copper", builder())); - public static final Item OXIDIZED_CUT_COPPER = register(new BlockItem("oxidized_cut_copper", builder())); - public static final Item CUT_COPPER_STAIRS = register(new BlockItem("cut_copper_stairs", builder())); - public static final Item EXPOSED_CUT_COPPER_STAIRS = register(new BlockItem("exposed_cut_copper_stairs", builder())); - public static final Item WEATHERED_CUT_COPPER_STAIRS = register(new BlockItem("weathered_cut_copper_stairs", builder())); - public static final Item OXIDIZED_CUT_COPPER_STAIRS = register(new BlockItem("oxidized_cut_copper_stairs", builder())); - public static final Item CUT_COPPER_SLAB = register(new BlockItem("cut_copper_slab", builder())); - public static final Item EXPOSED_CUT_COPPER_SLAB = register(new BlockItem("exposed_cut_copper_slab", builder())); - public static final Item WEATHERED_CUT_COPPER_SLAB = register(new BlockItem("weathered_cut_copper_slab", builder())); - public static final Item OXIDIZED_CUT_COPPER_SLAB = register(new BlockItem("oxidized_cut_copper_slab", builder())); - public static final Item WAXED_COPPER_BLOCK = register(new BlockItem("waxed_copper_block", builder())); - public static final Item WAXED_EXPOSED_COPPER = register(new BlockItem("waxed_exposed_copper", builder())); - public static final Item WAXED_WEATHERED_COPPER = register(new BlockItem("waxed_weathered_copper", builder())); - public static final Item WAXED_OXIDIZED_COPPER = register(new BlockItem("waxed_oxidized_copper", builder())); - public static final Item WAXED_CHISELED_COPPER = register(new BlockItem("waxed_chiseled_copper", builder())); - public static final Item WAXED_EXPOSED_CHISELED_COPPER = register(new BlockItem("waxed_exposed_chiseled_copper", builder())); - public static final Item WAXED_WEATHERED_CHISELED_COPPER = register(new BlockItem("waxed_weathered_chiseled_copper", builder())); - public static final Item WAXED_OXIDIZED_CHISELED_COPPER = register(new BlockItem("waxed_oxidized_chiseled_copper", builder())); - public static final Item WAXED_CUT_COPPER = register(new BlockItem("waxed_cut_copper", builder())); - public static final Item WAXED_EXPOSED_CUT_COPPER = register(new BlockItem("waxed_exposed_cut_copper", builder())); - public static final Item WAXED_WEATHERED_CUT_COPPER = register(new BlockItem("waxed_weathered_cut_copper", builder())); - public static final Item WAXED_OXIDIZED_CUT_COPPER = register(new BlockItem("waxed_oxidized_cut_copper", builder())); - public static final Item WAXED_CUT_COPPER_STAIRS = register(new BlockItem("waxed_cut_copper_stairs", builder())); - public static final Item WAXED_EXPOSED_CUT_COPPER_STAIRS = register(new BlockItem("waxed_exposed_cut_copper_stairs", builder())); - public static final Item WAXED_WEATHERED_CUT_COPPER_STAIRS = register(new BlockItem("waxed_weathered_cut_copper_stairs", builder())); - public static final Item WAXED_OXIDIZED_CUT_COPPER_STAIRS = register(new BlockItem("waxed_oxidized_cut_copper_stairs", builder())); - public static final Item WAXED_CUT_COPPER_SLAB = register(new BlockItem("waxed_cut_copper_slab", builder())); - public static final Item WAXED_EXPOSED_CUT_COPPER_SLAB = register(new BlockItem("waxed_exposed_cut_copper_slab", builder())); - public static final Item WAXED_WEATHERED_CUT_COPPER_SLAB = register(new BlockItem("waxed_weathered_cut_copper_slab", builder())); - public static final Item WAXED_OXIDIZED_CUT_COPPER_SLAB = register(new BlockItem("waxed_oxidized_cut_copper_slab", builder())); - public static final Item OAK_LOG = register(new BlockItem("oak_log", builder())); - public static final Item SPRUCE_LOG = register(new BlockItem("spruce_log", builder())); - public static final Item BIRCH_LOG = register(new BlockItem("birch_log", builder())); - public static final Item JUNGLE_LOG = register(new BlockItem("jungle_log", builder())); - public static final Item ACACIA_LOG = register(new BlockItem("acacia_log", builder())); - public static final Item CHERRY_LOG = register(new BlockItem("cherry_log", builder())); - public static final Item DARK_OAK_LOG = register(new BlockItem("dark_oak_log", builder())); - public static final Item MANGROVE_LOG = register(new BlockItem("mangrove_log", builder())); - public static final Item MANGROVE_ROOTS = register(new BlockItem("mangrove_roots", builder())); - public static final Item MUDDY_MANGROVE_ROOTS = register(new BlockItem("muddy_mangrove_roots", builder())); - public static final Item CRIMSON_STEM = register(new BlockItem("crimson_stem", builder())); - public static final Item WARPED_STEM = register(new BlockItem("warped_stem", builder())); - public static final Item BAMBOO_BLOCK = register(new BlockItem("bamboo_block", builder())); - public static final Item STRIPPED_OAK_LOG = register(new BlockItem("stripped_oak_log", builder())); - public static final Item STRIPPED_SPRUCE_LOG = register(new BlockItem("stripped_spruce_log", builder())); - public static final Item STRIPPED_BIRCH_LOG = register(new BlockItem("stripped_birch_log", builder())); - public static final Item STRIPPED_JUNGLE_LOG = register(new BlockItem("stripped_jungle_log", builder())); - public static final Item STRIPPED_ACACIA_LOG = register(new BlockItem("stripped_acacia_log", builder())); - public static final Item STRIPPED_CHERRY_LOG = register(new BlockItem("stripped_cherry_log", builder())); - public static final Item STRIPPED_DARK_OAK_LOG = register(new BlockItem("stripped_dark_oak_log", builder())); - public static final Item STRIPPED_MANGROVE_LOG = register(new BlockItem("stripped_mangrove_log", builder())); - public static final Item STRIPPED_CRIMSON_STEM = register(new BlockItem("stripped_crimson_stem", builder())); - public static final Item STRIPPED_WARPED_STEM = register(new BlockItem("stripped_warped_stem", builder())); - public static final Item STRIPPED_OAK_WOOD = register(new BlockItem("stripped_oak_wood", builder())); - public static final Item STRIPPED_SPRUCE_WOOD = register(new BlockItem("stripped_spruce_wood", builder())); - public static final Item STRIPPED_BIRCH_WOOD = register(new BlockItem("stripped_birch_wood", builder())); - public static final Item STRIPPED_JUNGLE_WOOD = register(new BlockItem("stripped_jungle_wood", builder())); - public static final Item STRIPPED_ACACIA_WOOD = register(new BlockItem("stripped_acacia_wood", builder())); - public static final Item STRIPPED_CHERRY_WOOD = register(new BlockItem("stripped_cherry_wood", builder())); - public static final Item STRIPPED_DARK_OAK_WOOD = register(new BlockItem("stripped_dark_oak_wood", builder())); - public static final Item STRIPPED_MANGROVE_WOOD = register(new BlockItem("stripped_mangrove_wood", builder())); - public static final Item STRIPPED_CRIMSON_HYPHAE = register(new BlockItem("stripped_crimson_hyphae", builder())); - public static final Item STRIPPED_WARPED_HYPHAE = register(new BlockItem("stripped_warped_hyphae", builder())); - public static final Item STRIPPED_BAMBOO_BLOCK = register(new BlockItem("stripped_bamboo_block", builder())); - public static final Item OAK_WOOD = register(new BlockItem("oak_wood", builder())); - public static final Item SPRUCE_WOOD = register(new BlockItem("spruce_wood", builder())); - public static final Item BIRCH_WOOD = register(new BlockItem("birch_wood", builder())); - public static final Item JUNGLE_WOOD = register(new BlockItem("jungle_wood", builder())); - public static final Item ACACIA_WOOD = register(new BlockItem("acacia_wood", builder())); - public static final Item CHERRY_WOOD = register(new BlockItem("cherry_wood", builder())); - public static final Item DARK_OAK_WOOD = register(new BlockItem("dark_oak_wood", builder())); - public static final Item MANGROVE_WOOD = register(new BlockItem("mangrove_wood", builder())); - public static final Item CRIMSON_HYPHAE = register(new BlockItem("crimson_hyphae", builder())); - public static final Item WARPED_HYPHAE = register(new BlockItem("warped_hyphae", builder())); - public static final Item OAK_LEAVES = register(new BlockItem("oak_leaves", builder())); - public static final Item SPRUCE_LEAVES = register(new BlockItem("spruce_leaves", builder())); - public static final Item BIRCH_LEAVES = register(new BlockItem("birch_leaves", builder())); - public static final Item JUNGLE_LEAVES = register(new BlockItem("jungle_leaves", builder())); - public static final Item ACACIA_LEAVES = register(new BlockItem("acacia_leaves", builder())); - public static final Item CHERRY_LEAVES = register(new BlockItem("cherry_leaves", builder())); - public static final Item DARK_OAK_LEAVES = register(new BlockItem("dark_oak_leaves", builder())); - public static final Item MANGROVE_LEAVES = register(new BlockItem("mangrove_leaves", builder())); - public static final Item AZALEA_LEAVES = register(new BlockItem("azalea_leaves", builder())); - public static final Item FLOWERING_AZALEA_LEAVES = register(new BlockItem("flowering_azalea_leaves", builder())); - public static final Item SPONGE = register(new BlockItem("sponge", builder())); - public static final Item WET_SPONGE = register(new BlockItem("wet_sponge", builder())); - public static final Item GLASS = register(new BlockItem("glass", builder())); - public static final Item TINTED_GLASS = register(new BlockItem("tinted_glass", builder())); - public static final Item LAPIS_BLOCK = register(new BlockItem("lapis_block", builder())); - public static final Item SANDSTONE = register(new BlockItem("sandstone", builder())); - public static final Item CHISELED_SANDSTONE = register(new BlockItem("chiseled_sandstone", builder())); - public static final Item CUT_SANDSTONE = register(new BlockItem("cut_sandstone", builder())); - public static final Item COBWEB = register(new BlockItem("cobweb", builder())); - public static final Item SHORT_GRASS = register(new BlockItem("short_grass", builder())); - public static final Item FERN = register(new BlockItem("fern", builder())); - public static final Item AZALEA = register(new BlockItem("azalea", builder())); - public static final Item FLOWERING_AZALEA = register(new BlockItem("flowering_azalea", builder())); - public static final Item DEAD_BUSH = register(new BlockItem("dead_bush", builder())); - public static final Item SEAGRASS = register(new BlockItem("seagrass", builder())); - public static final Item SEA_PICKLE = register(new BlockItem("sea_pickle", builder())); - public static final Item WHITE_WOOL = register(new BlockItem("white_wool", builder())); - public static final Item ORANGE_WOOL = register(new BlockItem("orange_wool", builder())); - public static final Item MAGENTA_WOOL = register(new BlockItem("magenta_wool", builder())); - public static final Item LIGHT_BLUE_WOOL = register(new BlockItem("light_blue_wool", builder())); - public static final Item YELLOW_WOOL = register(new BlockItem("yellow_wool", builder())); - public static final Item LIME_WOOL = register(new BlockItem("lime_wool", builder())); - public static final Item PINK_WOOL = register(new BlockItem("pink_wool", builder())); - public static final Item GRAY_WOOL = register(new BlockItem("gray_wool", builder())); - public static final Item LIGHT_GRAY_WOOL = register(new BlockItem("light_gray_wool", builder())); - public static final Item CYAN_WOOL = register(new BlockItem("cyan_wool", builder())); - public static final Item PURPLE_WOOL = register(new BlockItem("purple_wool", builder())); - public static final Item BLUE_WOOL = register(new BlockItem("blue_wool", builder())); - public static final Item BROWN_WOOL = register(new BlockItem("brown_wool", builder())); - public static final Item GREEN_WOOL = register(new BlockItem("green_wool", builder())); - public static final Item RED_WOOL = register(new BlockItem("red_wool", builder())); - public static final Item BLACK_WOOL = register(new BlockItem("black_wool", builder())); - public static final Item DANDELION = register(new BlockItem("dandelion", builder())); - public static final Item POPPY = register(new BlockItem("poppy", builder())); - public static final Item BLUE_ORCHID = register(new BlockItem("blue_orchid", builder())); - public static final Item ALLIUM = register(new BlockItem("allium", builder())); - public static final Item AZURE_BLUET = register(new BlockItem("azure_bluet", builder())); - public static final Item RED_TULIP = register(new BlockItem("red_tulip", builder())); - public static final Item ORANGE_TULIP = register(new BlockItem("orange_tulip", builder())); - public static final Item WHITE_TULIP = register(new BlockItem("white_tulip", builder())); - public static final Item PINK_TULIP = register(new BlockItem("pink_tulip", builder())); - public static final Item OXEYE_DAISY = register(new BlockItem("oxeye_daisy", builder())); - public static final Item CORNFLOWER = register(new BlockItem("cornflower", builder())); - public static final Item LILY_OF_THE_VALLEY = register(new BlockItem("lily_of_the_valley", builder())); - public static final Item WITHER_ROSE = register(new BlockItem("wither_rose", builder())); - public static final Item TORCHFLOWER = register(new BlockItem("torchflower", builder())); - public static final Item PITCHER_PLANT = register(new BlockItem("pitcher_plant", builder())); - public static final Item SPORE_BLOSSOM = register(new BlockItem("spore_blossom", builder())); - public static final Item BROWN_MUSHROOM = register(new BlockItem("brown_mushroom", builder())); - public static final Item RED_MUSHROOM = register(new BlockItem("red_mushroom", builder())); - public static final Item CRIMSON_FUNGUS = register(new BlockItem("crimson_fungus", builder())); - public static final Item WARPED_FUNGUS = register(new BlockItem("warped_fungus", builder())); - public static final Item CRIMSON_ROOTS = register(new BlockItem("crimson_roots", builder())); - public static final Item WARPED_ROOTS = register(new BlockItem("warped_roots", builder())); - public static final Item NETHER_SPROUTS = register(new BlockItem("nether_sprouts", builder())); - public static final Item WEEPING_VINES = register(new BlockItem("weeping_vines", builder())); - public static final Item TWISTING_VINES = register(new BlockItem("twisting_vines", builder())); - public static final Item SUGAR_CANE = register(new BlockItem("sugar_cane", builder())); - public static final Item KELP = register(new BlockItem("kelp", builder())); - public static final Item MOSS_CARPET = register(new BlockItem("moss_carpet", builder())); - public static final Item PINK_PETALS = register(new BlockItem("pink_petals", builder())); - public static final Item MOSS_BLOCK = register(new BlockItem("moss_block", builder())); - public static final Item HANGING_ROOTS = register(new BlockItem("hanging_roots", builder())); - public static final Item BIG_DRIPLEAF = register(new BlockItem("big_dripleaf", builder())); - public static final Item SMALL_DRIPLEAF = register(new BlockItem("small_dripleaf", builder())); - public static final Item BAMBOO = register(new BlockItem("bamboo", builder())); - public static final Item OAK_SLAB = register(new BlockItem("oak_slab", builder())); - public static final Item SPRUCE_SLAB = register(new BlockItem("spruce_slab", builder())); - public static final Item BIRCH_SLAB = register(new BlockItem("birch_slab", builder())); - public static final Item JUNGLE_SLAB = register(new BlockItem("jungle_slab", builder())); - public static final Item ACACIA_SLAB = register(new BlockItem("acacia_slab", builder())); - public static final Item CHERRY_SLAB = register(new BlockItem("cherry_slab", builder())); - public static final Item DARK_OAK_SLAB = register(new BlockItem("dark_oak_slab", builder())); - public static final Item MANGROVE_SLAB = register(new BlockItem("mangrove_slab", builder())); - public static final Item BAMBOO_SLAB = register(new BlockItem("bamboo_slab", builder())); - public static final Item BAMBOO_MOSAIC_SLAB = register(new BlockItem("bamboo_mosaic_slab", builder())); - public static final Item CRIMSON_SLAB = register(new BlockItem("crimson_slab", builder())); - public static final Item WARPED_SLAB = register(new BlockItem("warped_slab", builder())); - public static final Item STONE_SLAB = register(new BlockItem("stone_slab", builder())); - public static final Item SMOOTH_STONE_SLAB = register(new BlockItem("smooth_stone_slab", builder())); - public static final Item SANDSTONE_SLAB = register(new BlockItem("sandstone_slab", builder())); - public static final Item CUT_SANDSTONE_SLAB = register(new BlockItem("cut_sandstone_slab", builder())); - public static final Item PETRIFIED_OAK_SLAB = register(new BlockItem("petrified_oak_slab", builder())); - public static final Item COBBLESTONE_SLAB = register(new BlockItem("cobblestone_slab", builder())); - public static final Item BRICK_SLAB = register(new BlockItem("brick_slab", builder())); - public static final Item STONE_BRICK_SLAB = register(new BlockItem("stone_brick_slab", builder())); - public static final Item MUD_BRICK_SLAB = register(new BlockItem("mud_brick_slab", builder())); - public static final Item NETHER_BRICK_SLAB = register(new BlockItem("nether_brick_slab", builder())); - public static final Item QUARTZ_SLAB = register(new BlockItem("quartz_slab", builder())); - public static final Item RED_SANDSTONE_SLAB = register(new BlockItem("red_sandstone_slab", builder())); - public static final Item CUT_RED_SANDSTONE_SLAB = register(new BlockItem("cut_red_sandstone_slab", builder())); - public static final Item PURPUR_SLAB = register(new BlockItem("purpur_slab", builder())); - public static final Item PRISMARINE_SLAB = register(new BlockItem("prismarine_slab", builder())); - public static final Item PRISMARINE_BRICK_SLAB = register(new BlockItem("prismarine_brick_slab", builder())); - public static final Item DARK_PRISMARINE_SLAB = register(new BlockItem("dark_prismarine_slab", builder())); - public static final Item SMOOTH_QUARTZ = register(new BlockItem("smooth_quartz", builder())); - public static final Item SMOOTH_RED_SANDSTONE = register(new BlockItem("smooth_red_sandstone", builder())); - public static final Item SMOOTH_SANDSTONE = register(new BlockItem("smooth_sandstone", builder())); - public static final Item SMOOTH_STONE = register(new BlockItem("smooth_stone", builder())); - public static final Item BRICKS = register(new BlockItem("bricks", builder())); - public static final Item BOOKSHELF = register(new BlockItem("bookshelf", builder())); - public static final Item CHISELED_BOOKSHELF = register(new BlockItem("chiseled_bookshelf", builder())); - public static final Item DECORATED_POT = register(new DecoratedPotItem("decorated_pot", builder())); - public static final Item MOSSY_COBBLESTONE = register(new BlockItem("mossy_cobblestone", builder())); - public static final Item OBSIDIAN = register(new BlockItem("obsidian", builder())); - public static final Item TORCH = register(new BlockItem("torch", builder())); - public static final Item END_ROD = register(new BlockItem("end_rod", builder())); - public static final Item CHORUS_PLANT = register(new BlockItem("chorus_plant", builder())); - public static final Item CHORUS_FLOWER = register(new BlockItem("chorus_flower", builder())); - public static final Item PURPUR_BLOCK = register(new BlockItem("purpur_block", builder())); - public static final Item PURPUR_PILLAR = register(new BlockItem("purpur_pillar", builder())); - public static final Item PURPUR_STAIRS = register(new BlockItem("purpur_stairs", builder())); - public static final Item SPAWNER = register(new BlockItem("spawner", builder())); - public static final Item CHEST = register(new BlockItem("chest", builder())); - public static final Item CRAFTING_TABLE = register(new BlockItem("crafting_table", builder())); - public static final Item FARMLAND = register(new BlockItem("farmland", builder())); - public static final Item FURNACE = register(new BlockItem("furnace", builder())); - public static final Item LADDER = register(new BlockItem("ladder", builder())); - public static final Item COBBLESTONE_STAIRS = register(new BlockItem("cobblestone_stairs", builder())); - public static final Item SNOW = register(new BlockItem("snow", builder())); - public static final Item ICE = register(new BlockItem("ice", builder())); - public static final Item SNOW_BLOCK = register(new BlockItem("snow_block", builder())); - public static final Item CACTUS = register(new BlockItem("cactus", builder())); - public static final Item CLAY = register(new BlockItem("clay", builder())); - public static final Item JUKEBOX = register(new BlockItem("jukebox", builder())); - public static final Item OAK_FENCE = register(new BlockItem("oak_fence", builder())); - public static final Item SPRUCE_FENCE = register(new BlockItem("spruce_fence", builder())); - public static final Item BIRCH_FENCE = register(new BlockItem("birch_fence", builder())); - public static final Item JUNGLE_FENCE = register(new BlockItem("jungle_fence", builder())); - public static final Item ACACIA_FENCE = register(new BlockItem("acacia_fence", builder())); - public static final Item CHERRY_FENCE = register(new BlockItem("cherry_fence", builder())); - public static final Item DARK_OAK_FENCE = register(new BlockItem("dark_oak_fence", builder())); - public static final Item MANGROVE_FENCE = register(new BlockItem("mangrove_fence", builder())); - public static final Item BAMBOO_FENCE = register(new BlockItem("bamboo_fence", builder())); - public static final Item CRIMSON_FENCE = register(new BlockItem("crimson_fence", builder())); - public static final Item WARPED_FENCE = register(new BlockItem("warped_fence", builder())); - public static final Item PUMPKIN = register(new BlockItem("pumpkin", builder())); - public static final Item CARVED_PUMPKIN = register(new BlockItem("carved_pumpkin", builder())); - public static final Item JACK_O_LANTERN = register(new BlockItem("jack_o_lantern", builder())); - public static final Item NETHERRACK = register(new BlockItem("netherrack", builder())); - public static final Item SOUL_SAND = register(new BlockItem("soul_sand", builder())); - public static final Item SOUL_SOIL = register(new BlockItem("soul_soil", builder())); - public static final Item BASALT = register(new BlockItem("basalt", builder())); - public static final Item POLISHED_BASALT = register(new BlockItem("polished_basalt", builder())); - public static final Item SMOOTH_BASALT = register(new BlockItem("smooth_basalt", builder())); - public static final Item SOUL_TORCH = register(new BlockItem("soul_torch", builder())); - public static final Item GLOWSTONE = register(new BlockItem("glowstone", builder())); - public static final Item INFESTED_STONE = register(new BlockItem("infested_stone", builder())); - public static final Item INFESTED_COBBLESTONE = register(new BlockItem("infested_cobblestone", builder())); - public static final Item INFESTED_STONE_BRICKS = register(new BlockItem("infested_stone_bricks", builder())); - public static final Item INFESTED_MOSSY_STONE_BRICKS = register(new BlockItem("infested_mossy_stone_bricks", builder())); - public static final Item INFESTED_CRACKED_STONE_BRICKS = register(new BlockItem("infested_cracked_stone_bricks", builder())); - public static final Item INFESTED_CHISELED_STONE_BRICKS = register(new BlockItem("infested_chiseled_stone_bricks", builder())); - public static final Item INFESTED_DEEPSLATE = register(new BlockItem("infested_deepslate", builder())); - public static final Item STONE_BRICKS = register(new BlockItem("stone_bricks", builder())); - public static final Item MOSSY_STONE_BRICKS = register(new BlockItem("mossy_stone_bricks", builder())); - public static final Item CRACKED_STONE_BRICKS = register(new BlockItem("cracked_stone_bricks", builder())); - public static final Item CHISELED_STONE_BRICKS = register(new BlockItem("chiseled_stone_bricks", builder())); - public static final Item PACKED_MUD = register(new BlockItem("packed_mud", builder())); - public static final Item MUD_BRICKS = register(new BlockItem("mud_bricks", builder())); - public static final Item DEEPSLATE_BRICKS = register(new BlockItem("deepslate_bricks", builder())); - public static final Item CRACKED_DEEPSLATE_BRICKS = register(new BlockItem("cracked_deepslate_bricks", builder())); - public static final Item DEEPSLATE_TILES = register(new BlockItem("deepslate_tiles", builder())); - public static final Item CRACKED_DEEPSLATE_TILES = register(new BlockItem("cracked_deepslate_tiles", builder())); - public static final Item CHISELED_DEEPSLATE = register(new BlockItem("chiseled_deepslate", builder())); - public static final Item REINFORCED_DEEPSLATE = register(new BlockItem("reinforced_deepslate", builder())); - public static final Item BROWN_MUSHROOM_BLOCK = register(new BlockItem("brown_mushroom_block", builder())); - public static final Item RED_MUSHROOM_BLOCK = register(new BlockItem("red_mushroom_block", builder())); - public static final Item MUSHROOM_STEM = register(new BlockItem("mushroom_stem", builder())); - public static final Item IRON_BARS = register(new BlockItem("iron_bars", builder())); - public static final Item CHAIN = register(new BlockItem("chain", builder())); - public static final Item GLASS_PANE = register(new BlockItem("glass_pane", builder())); - public static final Item MELON = register(new BlockItem("melon", builder())); - public static final Item VINE = register(new BlockItem("vine", builder())); - public static final Item GLOW_LICHEN = register(new BlockItem("glow_lichen", builder())); - public static final Item BRICK_STAIRS = register(new BlockItem("brick_stairs", builder())); - public static final Item STONE_BRICK_STAIRS = register(new BlockItem("stone_brick_stairs", builder())); - public static final Item MUD_BRICK_STAIRS = register(new BlockItem("mud_brick_stairs", builder())); - public static final Item MYCELIUM = register(new BlockItem("mycelium", builder())); - public static final Item LILY_PAD = register(new BlockItem("lily_pad", builder())); - public static final Item NETHER_BRICKS = register(new BlockItem("nether_bricks", builder())); - public static final Item CRACKED_NETHER_BRICKS = register(new BlockItem("cracked_nether_bricks", builder())); - public static final Item CHISELED_NETHER_BRICKS = register(new BlockItem("chiseled_nether_bricks", builder())); - public static final Item NETHER_BRICK_FENCE = register(new BlockItem("nether_brick_fence", builder())); - public static final Item NETHER_BRICK_STAIRS = register(new BlockItem("nether_brick_stairs", builder())); - public static final Item SCULK = register(new BlockItem("sculk", builder())); - public static final Item SCULK_VEIN = register(new BlockItem("sculk_vein", builder())); - public static final Item SCULK_CATALYST = register(new BlockItem("sculk_catalyst", builder())); - public static final Item SCULK_SHRIEKER = register(new BlockItem("sculk_shrieker", builder())); - public static final Item ENCHANTING_TABLE = register(new BlockItem("enchanting_table", builder())); - public static final Item END_PORTAL_FRAME = register(new BlockItem("end_portal_frame", builder())); - public static final Item END_STONE = register(new BlockItem("end_stone", builder())); - public static final Item END_STONE_BRICKS = register(new BlockItem("end_stone_bricks", builder())); - public static final Item DRAGON_EGG = register(new BlockItem("dragon_egg", builder())); - public static final Item SANDSTONE_STAIRS = register(new BlockItem("sandstone_stairs", builder())); - public static final Item ENDER_CHEST = register(new BlockItem("ender_chest", builder())); - public static final Item EMERALD_BLOCK = register(new BlockItem("emerald_block", builder())); - public static final Item OAK_STAIRS = register(new BlockItem("oak_stairs", builder())); - public static final Item SPRUCE_STAIRS = register(new BlockItem("spruce_stairs", builder())); - public static final Item BIRCH_STAIRS = register(new BlockItem("birch_stairs", builder())); - public static final Item JUNGLE_STAIRS = register(new BlockItem("jungle_stairs", builder())); - public static final Item ACACIA_STAIRS = register(new BlockItem("acacia_stairs", builder())); - public static final Item CHERRY_STAIRS = register(new BlockItem("cherry_stairs", builder())); - public static final Item DARK_OAK_STAIRS = register(new BlockItem("dark_oak_stairs", builder())); - public static final Item MANGROVE_STAIRS = register(new BlockItem("mangrove_stairs", builder())); - public static final Item BAMBOO_STAIRS = register(new BlockItem("bamboo_stairs", builder())); - public static final Item BAMBOO_MOSAIC_STAIRS = register(new BlockItem("bamboo_mosaic_stairs", builder())); - public static final Item CRIMSON_STAIRS = register(new BlockItem("crimson_stairs", builder())); - public static final Item WARPED_STAIRS = register(new BlockItem("warped_stairs", builder())); - public static final Item COMMAND_BLOCK = register(new BlockItem("command_block", builder())); - public static final Item BEACON = register(new BlockItem("beacon", builder())); - public static final Item COBBLESTONE_WALL = register(new BlockItem("cobblestone_wall", builder())); - public static final Item MOSSY_COBBLESTONE_WALL = register(new BlockItem("mossy_cobblestone_wall", builder())); - public static final Item BRICK_WALL = register(new BlockItem("brick_wall", builder())); - public static final Item PRISMARINE_WALL = register(new BlockItem("prismarine_wall", builder())); - public static final Item RED_SANDSTONE_WALL = register(new BlockItem("red_sandstone_wall", builder())); - public static final Item MOSSY_STONE_BRICK_WALL = register(new BlockItem("mossy_stone_brick_wall", builder())); - public static final Item GRANITE_WALL = register(new BlockItem("granite_wall", builder())); - public static final Item STONE_BRICK_WALL = register(new BlockItem("stone_brick_wall", builder())); - public static final Item MUD_BRICK_WALL = register(new BlockItem("mud_brick_wall", builder())); - public static final Item NETHER_BRICK_WALL = register(new BlockItem("nether_brick_wall", builder())); - public static final Item ANDESITE_WALL = register(new BlockItem("andesite_wall", builder())); - public static final Item RED_NETHER_BRICK_WALL = register(new BlockItem("red_nether_brick_wall", builder())); - public static final Item SANDSTONE_WALL = register(new BlockItem("sandstone_wall", builder())); - public static final Item END_STONE_BRICK_WALL = register(new BlockItem("end_stone_brick_wall", builder())); - public static final Item DIORITE_WALL = register(new BlockItem("diorite_wall", builder())); - public static final Item BLACKSTONE_WALL = register(new BlockItem("blackstone_wall", builder())); - public static final Item POLISHED_BLACKSTONE_WALL = register(new BlockItem("polished_blackstone_wall", builder())); - public static final Item POLISHED_BLACKSTONE_BRICK_WALL = register(new BlockItem("polished_blackstone_brick_wall", builder())); - public static final Item COBBLED_DEEPSLATE_WALL = register(new BlockItem("cobbled_deepslate_wall", builder())); - public static final Item POLISHED_DEEPSLATE_WALL = register(new BlockItem("polished_deepslate_wall", builder())); - public static final Item DEEPSLATE_BRICK_WALL = register(new BlockItem("deepslate_brick_wall", builder())); - public static final Item DEEPSLATE_TILE_WALL = register(new BlockItem("deepslate_tile_wall", builder())); - public static final Item ANVIL = register(new BlockItem("anvil", builder())); - public static final Item CHIPPED_ANVIL = register(new BlockItem("chipped_anvil", builder())); - public static final Item DAMAGED_ANVIL = register(new BlockItem("damaged_anvil", builder())); - public static final Item CHISELED_QUARTZ_BLOCK = register(new BlockItem("chiseled_quartz_block", builder())); - public static final Item QUARTZ_BLOCK = register(new BlockItem("quartz_block", builder())); - public static final Item QUARTZ_BRICKS = register(new BlockItem("quartz_bricks", builder())); - public static final Item QUARTZ_PILLAR = register(new BlockItem("quartz_pillar", builder())); - public static final Item QUARTZ_STAIRS = register(new BlockItem("quartz_stairs", builder())); - public static final Item WHITE_TERRACOTTA = register(new BlockItem("white_terracotta", builder())); - public static final Item ORANGE_TERRACOTTA = register(new BlockItem("orange_terracotta", builder())); - public static final Item MAGENTA_TERRACOTTA = register(new BlockItem("magenta_terracotta", builder())); - public static final Item LIGHT_BLUE_TERRACOTTA = register(new BlockItem("light_blue_terracotta", builder())); - public static final Item YELLOW_TERRACOTTA = register(new BlockItem("yellow_terracotta", builder())); - public static final Item LIME_TERRACOTTA = register(new BlockItem("lime_terracotta", builder())); - public static final Item PINK_TERRACOTTA = register(new BlockItem("pink_terracotta", builder())); - public static final Item GRAY_TERRACOTTA = register(new BlockItem("gray_terracotta", builder())); - public static final Item LIGHT_GRAY_TERRACOTTA = register(new BlockItem("light_gray_terracotta", builder())); - public static final Item CYAN_TERRACOTTA = register(new BlockItem("cyan_terracotta", builder())); - public static final Item PURPLE_TERRACOTTA = register(new BlockItem("purple_terracotta", builder())); - public static final Item BLUE_TERRACOTTA = register(new BlockItem("blue_terracotta", builder())); - public static final Item BROWN_TERRACOTTA = register(new BlockItem("brown_terracotta", builder())); - public static final Item GREEN_TERRACOTTA = register(new BlockItem("green_terracotta", builder())); - public static final Item RED_TERRACOTTA = register(new BlockItem("red_terracotta", builder())); - public static final Item BLACK_TERRACOTTA = register(new BlockItem("black_terracotta", builder())); - public static final Item BARRIER = register(new BlockItem("barrier", builder())); - public static final Item LIGHT = register(new BlockItem("light", builder())); - public static final Item HAY_BLOCK = register(new BlockItem("hay_block", builder())); - public static final Item WHITE_CARPET = register(new BlockItem("white_carpet", builder())); - public static final Item ORANGE_CARPET = register(new BlockItem("orange_carpet", builder())); - public static final Item MAGENTA_CARPET = register(new BlockItem("magenta_carpet", builder())); - public static final Item LIGHT_BLUE_CARPET = register(new BlockItem("light_blue_carpet", builder())); - public static final Item YELLOW_CARPET = register(new BlockItem("yellow_carpet", builder())); - public static final Item LIME_CARPET = register(new BlockItem("lime_carpet", builder())); - public static final Item PINK_CARPET = register(new BlockItem("pink_carpet", builder())); - public static final Item GRAY_CARPET = register(new BlockItem("gray_carpet", builder())); - public static final Item LIGHT_GRAY_CARPET = register(new BlockItem("light_gray_carpet", builder())); - public static final Item CYAN_CARPET = register(new BlockItem("cyan_carpet", builder())); - public static final Item PURPLE_CARPET = register(new BlockItem("purple_carpet", builder())); - public static final Item BLUE_CARPET = register(new BlockItem("blue_carpet", builder())); - public static final Item BROWN_CARPET = register(new BlockItem("brown_carpet", builder())); - public static final Item GREEN_CARPET = register(new BlockItem("green_carpet", builder())); - public static final Item RED_CARPET = register(new BlockItem("red_carpet", builder())); - public static final Item BLACK_CARPET = register(new BlockItem("black_carpet", builder())); - public static final Item TERRACOTTA = register(new BlockItem("terracotta", builder())); - public static final Item PACKED_ICE = register(new BlockItem("packed_ice", builder())); - public static final Item DIRT_PATH = register(new BlockItem("dirt_path", builder())); - public static final Item SUNFLOWER = register(new BlockItem("sunflower", builder())); - public static final Item LILAC = register(new BlockItem("lilac", builder())); - public static final Item ROSE_BUSH = register(new BlockItem("rose_bush", builder())); - public static final Item PEONY = register(new BlockItem("peony", builder())); - public static final Item TALL_GRASS = register(new BlockItem("tall_grass", builder())); - public static final Item LARGE_FERN = register(new BlockItem("large_fern", builder())); - public static final Item WHITE_STAINED_GLASS = register(new BlockItem("white_stained_glass", builder())); - public static final Item ORANGE_STAINED_GLASS = register(new BlockItem("orange_stained_glass", builder())); - public static final Item MAGENTA_STAINED_GLASS = register(new BlockItem("magenta_stained_glass", builder())); - public static final Item LIGHT_BLUE_STAINED_GLASS = register(new BlockItem("light_blue_stained_glass", builder())); - public static final Item YELLOW_STAINED_GLASS = register(new BlockItem("yellow_stained_glass", builder())); - public static final Item LIME_STAINED_GLASS = register(new BlockItem("lime_stained_glass", builder())); - public static final Item PINK_STAINED_GLASS = register(new BlockItem("pink_stained_glass", builder())); - public static final Item GRAY_STAINED_GLASS = register(new BlockItem("gray_stained_glass", builder())); - public static final Item LIGHT_GRAY_STAINED_GLASS = register(new BlockItem("light_gray_stained_glass", builder())); - public static final Item CYAN_STAINED_GLASS = register(new BlockItem("cyan_stained_glass", builder())); - public static final Item PURPLE_STAINED_GLASS = register(new BlockItem("purple_stained_glass", builder())); - public static final Item BLUE_STAINED_GLASS = register(new BlockItem("blue_stained_glass", builder())); - public static final Item BROWN_STAINED_GLASS = register(new BlockItem("brown_stained_glass", builder())); - public static final Item GREEN_STAINED_GLASS = register(new BlockItem("green_stained_glass", builder())); - public static final Item RED_STAINED_GLASS = register(new BlockItem("red_stained_glass", builder())); - public static final Item BLACK_STAINED_GLASS = register(new BlockItem("black_stained_glass", builder())); - public static final Item WHITE_STAINED_GLASS_PANE = register(new BlockItem("white_stained_glass_pane", builder())); - public static final Item ORANGE_STAINED_GLASS_PANE = register(new BlockItem("orange_stained_glass_pane", builder())); - public static final Item MAGENTA_STAINED_GLASS_PANE = register(new BlockItem("magenta_stained_glass_pane", builder())); - public static final Item LIGHT_BLUE_STAINED_GLASS_PANE = register(new BlockItem("light_blue_stained_glass_pane", builder())); - public static final Item YELLOW_STAINED_GLASS_PANE = register(new BlockItem("yellow_stained_glass_pane", builder())); - public static final Item LIME_STAINED_GLASS_PANE = register(new BlockItem("lime_stained_glass_pane", builder())); - public static final Item PINK_STAINED_GLASS_PANE = register(new BlockItem("pink_stained_glass_pane", builder())); - public static final Item GRAY_STAINED_GLASS_PANE = register(new BlockItem("gray_stained_glass_pane", builder())); - public static final Item LIGHT_GRAY_STAINED_GLASS_PANE = register(new BlockItem("light_gray_stained_glass_pane", builder())); - public static final Item CYAN_STAINED_GLASS_PANE = register(new BlockItem("cyan_stained_glass_pane", builder())); - public static final Item PURPLE_STAINED_GLASS_PANE = register(new BlockItem("purple_stained_glass_pane", builder())); - public static final Item BLUE_STAINED_GLASS_PANE = register(new BlockItem("blue_stained_glass_pane", builder())); - public static final Item BROWN_STAINED_GLASS_PANE = register(new BlockItem("brown_stained_glass_pane", builder())); - public static final Item GREEN_STAINED_GLASS_PANE = register(new BlockItem("green_stained_glass_pane", builder())); - public static final Item RED_STAINED_GLASS_PANE = register(new BlockItem("red_stained_glass_pane", builder())); - public static final Item BLACK_STAINED_GLASS_PANE = register(new BlockItem("black_stained_glass_pane", builder())); - public static final Item PRISMARINE = register(new BlockItem("prismarine", builder())); - public static final Item PRISMARINE_BRICKS = register(new BlockItem("prismarine_bricks", builder())); - public static final Item DARK_PRISMARINE = register(new BlockItem("dark_prismarine", builder())); - public static final Item PRISMARINE_STAIRS = register(new BlockItem("prismarine_stairs", builder())); - public static final Item PRISMARINE_BRICK_STAIRS = register(new BlockItem("prismarine_brick_stairs", builder())); - public static final Item DARK_PRISMARINE_STAIRS = register(new BlockItem("dark_prismarine_stairs", builder())); - public static final Item SEA_LANTERN = register(new BlockItem("sea_lantern", builder())); - public static final Item RED_SANDSTONE = register(new BlockItem("red_sandstone", builder())); - public static final Item CHISELED_RED_SANDSTONE = register(new BlockItem("chiseled_red_sandstone", builder())); - public static final Item CUT_RED_SANDSTONE = register(new BlockItem("cut_red_sandstone", builder())); - public static final Item RED_SANDSTONE_STAIRS = register(new BlockItem("red_sandstone_stairs", builder())); - public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem("repeating_command_block", builder())); - public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem("chain_command_block", builder())); - public static final Item MAGMA_BLOCK = register(new BlockItem("magma_block", builder())); - public static final Item NETHER_WART_BLOCK = register(new BlockItem("nether_wart_block", builder())); - public static final Item WARPED_WART_BLOCK = register(new BlockItem("warped_wart_block", builder())); - public static final Item RED_NETHER_BRICKS = register(new BlockItem("red_nether_bricks", builder())); - public static final Item BONE_BLOCK = register(new BlockItem("bone_block", builder())); - public static final Item STRUCTURE_VOID = register(new BlockItem("structure_void", builder())); - public static final Item SHULKER_BOX = register(new ShulkerBoxItem("shulker_box", builder().stackSize(1))); - public static final Item WHITE_SHULKER_BOX = register(new ShulkerBoxItem("white_shulker_box", builder().stackSize(1))); - public static final Item ORANGE_SHULKER_BOX = register(new ShulkerBoxItem("orange_shulker_box", builder().stackSize(1))); - public static final Item MAGENTA_SHULKER_BOX = register(new ShulkerBoxItem("magenta_shulker_box", builder().stackSize(1))); - public static final Item LIGHT_BLUE_SHULKER_BOX = register(new ShulkerBoxItem("light_blue_shulker_box", builder().stackSize(1))); - public static final Item YELLOW_SHULKER_BOX = register(new ShulkerBoxItem("yellow_shulker_box", builder().stackSize(1))); - public static final Item LIME_SHULKER_BOX = register(new ShulkerBoxItem("lime_shulker_box", builder().stackSize(1))); - public static final Item PINK_SHULKER_BOX = register(new ShulkerBoxItem("pink_shulker_box", builder().stackSize(1))); - public static final Item GRAY_SHULKER_BOX = register(new ShulkerBoxItem("gray_shulker_box", builder().stackSize(1))); - public static final Item LIGHT_GRAY_SHULKER_BOX = register(new ShulkerBoxItem("light_gray_shulker_box", builder().stackSize(1))); - public static final Item CYAN_SHULKER_BOX = register(new ShulkerBoxItem("cyan_shulker_box", builder().stackSize(1))); - public static final Item PURPLE_SHULKER_BOX = register(new ShulkerBoxItem("purple_shulker_box", builder().stackSize(1))); - public static final Item BLUE_SHULKER_BOX = register(new ShulkerBoxItem("blue_shulker_box", builder().stackSize(1))); - public static final Item BROWN_SHULKER_BOX = register(new ShulkerBoxItem("brown_shulker_box", builder().stackSize(1))); - public static final Item GREEN_SHULKER_BOX = register(new ShulkerBoxItem("green_shulker_box", builder().stackSize(1))); - public static final Item RED_SHULKER_BOX = register(new ShulkerBoxItem("red_shulker_box", builder().stackSize(1))); - public static final Item BLACK_SHULKER_BOX = register(new ShulkerBoxItem("black_shulker_box", builder().stackSize(1))); - public static final Item WHITE_GLAZED_TERRACOTTA = register(new BlockItem("white_glazed_terracotta", builder())); - public static final Item ORANGE_GLAZED_TERRACOTTA = register(new BlockItem("orange_glazed_terracotta", builder())); - public static final Item MAGENTA_GLAZED_TERRACOTTA = register(new BlockItem("magenta_glazed_terracotta", builder())); - public static final Item LIGHT_BLUE_GLAZED_TERRACOTTA = register(new BlockItem("light_blue_glazed_terracotta", builder())); - public static final Item YELLOW_GLAZED_TERRACOTTA = register(new BlockItem("yellow_glazed_terracotta", builder())); - public static final Item LIME_GLAZED_TERRACOTTA = register(new BlockItem("lime_glazed_terracotta", builder())); - public static final Item PINK_GLAZED_TERRACOTTA = register(new BlockItem("pink_glazed_terracotta", builder())); - public static final Item GRAY_GLAZED_TERRACOTTA = register(new BlockItem("gray_glazed_terracotta", builder())); - public static final Item LIGHT_GRAY_GLAZED_TERRACOTTA = register(new BlockItem("light_gray_glazed_terracotta", builder())); - public static final Item CYAN_GLAZED_TERRACOTTA = register(new BlockItem("cyan_glazed_terracotta", builder())); - public static final Item PURPLE_GLAZED_TERRACOTTA = register(new BlockItem("purple_glazed_terracotta", builder())); - public static final Item BLUE_GLAZED_TERRACOTTA = register(new BlockItem("blue_glazed_terracotta", builder())); - public static final Item BROWN_GLAZED_TERRACOTTA = register(new BlockItem("brown_glazed_terracotta", builder())); - public static final Item GREEN_GLAZED_TERRACOTTA = register(new BlockItem("green_glazed_terracotta", builder())); - public static final Item RED_GLAZED_TERRACOTTA = register(new BlockItem("red_glazed_terracotta", builder())); - public static final Item BLACK_GLAZED_TERRACOTTA = register(new BlockItem("black_glazed_terracotta", builder())); - public static final Item WHITE_CONCRETE = register(new BlockItem("white_concrete", builder())); - public static final Item ORANGE_CONCRETE = register(new BlockItem("orange_concrete", builder())); - public static final Item MAGENTA_CONCRETE = register(new BlockItem("magenta_concrete", builder())); - public static final Item LIGHT_BLUE_CONCRETE = register(new BlockItem("light_blue_concrete", builder())); - public static final Item YELLOW_CONCRETE = register(new BlockItem("yellow_concrete", builder())); - public static final Item LIME_CONCRETE = register(new BlockItem("lime_concrete", builder())); - public static final Item PINK_CONCRETE = register(new BlockItem("pink_concrete", builder())); - public static final Item GRAY_CONCRETE = register(new BlockItem("gray_concrete", builder())); - public static final Item LIGHT_GRAY_CONCRETE = register(new BlockItem("light_gray_concrete", builder())); - public static final Item CYAN_CONCRETE = register(new BlockItem("cyan_concrete", builder())); - public static final Item PURPLE_CONCRETE = register(new BlockItem("purple_concrete", builder())); - public static final Item BLUE_CONCRETE = register(new BlockItem("blue_concrete", builder())); - public static final Item BROWN_CONCRETE = register(new BlockItem("brown_concrete", builder())); - public static final Item GREEN_CONCRETE = register(new BlockItem("green_concrete", builder())); - public static final Item RED_CONCRETE = register(new BlockItem("red_concrete", builder())); - public static final Item BLACK_CONCRETE = register(new BlockItem("black_concrete", builder())); - public static final Item WHITE_CONCRETE_POWDER = register(new BlockItem("white_concrete_powder", builder())); - public static final Item ORANGE_CONCRETE_POWDER = register(new BlockItem("orange_concrete_powder", builder())); - public static final Item MAGENTA_CONCRETE_POWDER = register(new BlockItem("magenta_concrete_powder", builder())); - public static final Item LIGHT_BLUE_CONCRETE_POWDER = register(new BlockItem("light_blue_concrete_powder", builder())); - public static final Item YELLOW_CONCRETE_POWDER = register(new BlockItem("yellow_concrete_powder", builder())); - public static final Item LIME_CONCRETE_POWDER = register(new BlockItem("lime_concrete_powder", builder())); - public static final Item PINK_CONCRETE_POWDER = register(new BlockItem("pink_concrete_powder", builder())); - public static final Item GRAY_CONCRETE_POWDER = register(new BlockItem("gray_concrete_powder", builder())); - public static final Item LIGHT_GRAY_CONCRETE_POWDER = register(new BlockItem("light_gray_concrete_powder", builder())); - public static final Item CYAN_CONCRETE_POWDER = register(new BlockItem("cyan_concrete_powder", builder())); - public static final Item PURPLE_CONCRETE_POWDER = register(new BlockItem("purple_concrete_powder", builder())); - public static final Item BLUE_CONCRETE_POWDER = register(new BlockItem("blue_concrete_powder", builder())); - public static final Item BROWN_CONCRETE_POWDER = register(new BlockItem("brown_concrete_powder", builder())); - public static final Item GREEN_CONCRETE_POWDER = register(new BlockItem("green_concrete_powder", builder())); - public static final Item RED_CONCRETE_POWDER = register(new BlockItem("red_concrete_powder", builder())); - public static final Item BLACK_CONCRETE_POWDER = register(new BlockItem("black_concrete_powder", builder())); - public static final Item TURTLE_EGG = register(new BlockItem("turtle_egg", builder())); - public static final Item SNIFFER_EGG = register(new BlockItem("sniffer_egg", builder())); - public static final Item DEAD_TUBE_CORAL_BLOCK = register(new BlockItem("dead_tube_coral_block", builder())); - public static final Item DEAD_BRAIN_CORAL_BLOCK = register(new BlockItem("dead_brain_coral_block", builder())); - public static final Item DEAD_BUBBLE_CORAL_BLOCK = register(new BlockItem("dead_bubble_coral_block", builder())); - public static final Item DEAD_FIRE_CORAL_BLOCK = register(new BlockItem("dead_fire_coral_block", builder())); - public static final Item DEAD_HORN_CORAL_BLOCK = register(new BlockItem("dead_horn_coral_block", builder())); - public static final Item TUBE_CORAL_BLOCK = register(new BlockItem("tube_coral_block", builder())); - public static final Item BRAIN_CORAL_BLOCK = register(new BlockItem("brain_coral_block", builder())); - public static final Item BUBBLE_CORAL_BLOCK = register(new BlockItem("bubble_coral_block", builder())); - public static final Item FIRE_CORAL_BLOCK = register(new BlockItem("fire_coral_block", builder())); - public static final Item HORN_CORAL_BLOCK = register(new BlockItem("horn_coral_block", builder())); - public static final Item TUBE_CORAL = register(new BlockItem("tube_coral", builder())); - public static final Item BRAIN_CORAL = register(new BlockItem("brain_coral", builder())); - public static final Item BUBBLE_CORAL = register(new BlockItem("bubble_coral", builder())); - public static final Item FIRE_CORAL = register(new BlockItem("fire_coral", builder())); - public static final Item HORN_CORAL = register(new BlockItem("horn_coral", builder())); - public static final Item DEAD_BRAIN_CORAL = register(new BlockItem("dead_brain_coral", builder())); - public static final Item DEAD_BUBBLE_CORAL = register(new BlockItem("dead_bubble_coral", builder())); - public static final Item DEAD_FIRE_CORAL = register(new BlockItem("dead_fire_coral", builder())); - public static final Item DEAD_HORN_CORAL = register(new BlockItem("dead_horn_coral", builder())); - public static final Item DEAD_TUBE_CORAL = register(new BlockItem("dead_tube_coral", builder())); - public static final Item TUBE_CORAL_FAN = register(new BlockItem("tube_coral_fan", builder())); - public static final Item BRAIN_CORAL_FAN = register(new BlockItem("brain_coral_fan", builder())); - public static final Item BUBBLE_CORAL_FAN = register(new BlockItem("bubble_coral_fan", builder())); - public static final Item FIRE_CORAL_FAN = register(new BlockItem("fire_coral_fan", builder())); - public static final Item HORN_CORAL_FAN = register(new BlockItem("horn_coral_fan", builder())); - public static final Item DEAD_TUBE_CORAL_FAN = register(new BlockItem("dead_tube_coral_fan", builder())); - public static final Item DEAD_BRAIN_CORAL_FAN = register(new BlockItem("dead_brain_coral_fan", builder())); - public static final Item DEAD_BUBBLE_CORAL_FAN = register(new BlockItem("dead_bubble_coral_fan", builder())); - public static final Item DEAD_FIRE_CORAL_FAN = register(new BlockItem("dead_fire_coral_fan", builder())); - public static final Item DEAD_HORN_CORAL_FAN = register(new BlockItem("dead_horn_coral_fan", builder())); - public static final Item BLUE_ICE = register(new BlockItem("blue_ice", builder())); - public static final Item CONDUIT = register(new BlockItem("conduit", builder())); - public static final Item POLISHED_GRANITE_STAIRS = register(new BlockItem("polished_granite_stairs", builder())); - public static final Item SMOOTH_RED_SANDSTONE_STAIRS = register(new BlockItem("smooth_red_sandstone_stairs", builder())); - public static final Item MOSSY_STONE_BRICK_STAIRS = register(new BlockItem("mossy_stone_brick_stairs", builder())); - public static final Item POLISHED_DIORITE_STAIRS = register(new BlockItem("polished_diorite_stairs", builder())); - public static final Item MOSSY_COBBLESTONE_STAIRS = register(new BlockItem("mossy_cobblestone_stairs", builder())); - public static final Item END_STONE_BRICK_STAIRS = register(new BlockItem("end_stone_brick_stairs", builder())); - public static final Item STONE_STAIRS = register(new BlockItem("stone_stairs", builder())); - public static final Item SMOOTH_SANDSTONE_STAIRS = register(new BlockItem("smooth_sandstone_stairs", builder())); - public static final Item SMOOTH_QUARTZ_STAIRS = register(new BlockItem("smooth_quartz_stairs", builder())); - public static final Item GRANITE_STAIRS = register(new BlockItem("granite_stairs", builder())); - public static final Item ANDESITE_STAIRS = register(new BlockItem("andesite_stairs", builder())); - public static final Item RED_NETHER_BRICK_STAIRS = register(new BlockItem("red_nether_brick_stairs", builder())); - public static final Item POLISHED_ANDESITE_STAIRS = register(new BlockItem("polished_andesite_stairs", builder())); - public static final Item DIORITE_STAIRS = register(new BlockItem("diorite_stairs", builder())); - public static final Item COBBLED_DEEPSLATE_STAIRS = register(new BlockItem("cobbled_deepslate_stairs", builder())); - public static final Item POLISHED_DEEPSLATE_STAIRS = register(new BlockItem("polished_deepslate_stairs", builder())); - public static final Item DEEPSLATE_BRICK_STAIRS = register(new BlockItem("deepslate_brick_stairs", builder())); - public static final Item DEEPSLATE_TILE_STAIRS = register(new BlockItem("deepslate_tile_stairs", builder())); - public static final Item POLISHED_GRANITE_SLAB = register(new BlockItem("polished_granite_slab", builder())); - public static final Item SMOOTH_RED_SANDSTONE_SLAB = register(new BlockItem("smooth_red_sandstone_slab", builder())); - public static final Item MOSSY_STONE_BRICK_SLAB = register(new BlockItem("mossy_stone_brick_slab", builder())); - public static final Item POLISHED_DIORITE_SLAB = register(new BlockItem("polished_diorite_slab", builder())); - public static final Item MOSSY_COBBLESTONE_SLAB = register(new BlockItem("mossy_cobblestone_slab", builder())); - public static final Item END_STONE_BRICK_SLAB = register(new BlockItem("end_stone_brick_slab", builder())); - public static final Item SMOOTH_SANDSTONE_SLAB = register(new BlockItem("smooth_sandstone_slab", builder())); - public static final Item SMOOTH_QUARTZ_SLAB = register(new BlockItem("smooth_quartz_slab", builder())); - public static final Item GRANITE_SLAB = register(new BlockItem("granite_slab", builder())); - public static final Item ANDESITE_SLAB = register(new BlockItem("andesite_slab", builder())); - public static final Item RED_NETHER_BRICK_SLAB = register(new BlockItem("red_nether_brick_slab", builder())); - public static final Item POLISHED_ANDESITE_SLAB = register(new BlockItem("polished_andesite_slab", builder())); - public static final Item DIORITE_SLAB = register(new BlockItem("diorite_slab", builder())); - public static final Item COBBLED_DEEPSLATE_SLAB = register(new BlockItem("cobbled_deepslate_slab", builder())); - public static final Item POLISHED_DEEPSLATE_SLAB = register(new BlockItem("polished_deepslate_slab", builder())); - public static final Item DEEPSLATE_BRICK_SLAB = register(new BlockItem("deepslate_brick_slab", builder())); - public static final Item DEEPSLATE_TILE_SLAB = register(new BlockItem("deepslate_tile_slab", builder())); - public static final Item SCAFFOLDING = register(new BlockItem("scaffolding", builder())); - public static final Item REDSTONE = register(new BlockItem("redstone", builder())); - public static final Item REDSTONE_TORCH = register(new BlockItem("redstone_torch", builder())); - public static final Item REDSTONE_BLOCK = register(new BlockItem("redstone_block", builder())); - public static final Item REPEATER = register(new BlockItem("repeater", builder())); - public static final Item COMPARATOR = register(new BlockItem("comparator", builder())); - public static final Item PISTON = register(new BlockItem("piston", builder())); - public static final Item STICKY_PISTON = register(new BlockItem("sticky_piston", builder())); - public static final Item SLIME_BLOCK = register(new BlockItem("slime_block", builder())); - public static final Item HONEY_BLOCK = register(new BlockItem("honey_block", builder())); - public static final Item OBSERVER = register(new BlockItem("observer", builder())); - public static final Item HOPPER = register(new BlockItem("hopper", builder())); - public static final Item DISPENSER = register(new BlockItem("dispenser", builder())); - public static final Item DROPPER = register(new BlockItem("dropper", builder())); - public static final Item LECTERN = register(new BlockItem("lectern", builder())); - public static final Item TARGET = register(new BlockItem("target", builder())); - public static final Item LEVER = register(new BlockItem("lever", builder())); - public static final Item LIGHTNING_ROD = register(new BlockItem("lightning_rod", builder())); - public static final Item DAYLIGHT_DETECTOR = register(new BlockItem("daylight_detector", builder())); - public static final Item SCULK_SENSOR = register(new BlockItem("sculk_sensor", builder())); - public static final Item CALIBRATED_SCULK_SENSOR = register(new BlockItem("calibrated_sculk_sensor", builder())); - public static final Item TRIPWIRE_HOOK = register(new BlockItem("tripwire_hook", builder())); - public static final Item TRAPPED_CHEST = register(new BlockItem("trapped_chest", builder())); - public static final Item TNT = register(new BlockItem("tnt", builder())); - public static final Item REDSTONE_LAMP = register(new BlockItem("redstone_lamp", builder())); - public static final Item NOTE_BLOCK = register(new BlockItem("note_block", builder())); - public static final Item STONE_BUTTON = register(new BlockItem("stone_button", builder())); - public static final Item POLISHED_BLACKSTONE_BUTTON = register(new BlockItem("polished_blackstone_button", builder())); - public static final Item OAK_BUTTON = register(new BlockItem("oak_button", builder())); - public static final Item SPRUCE_BUTTON = register(new BlockItem("spruce_button", builder())); - public static final Item BIRCH_BUTTON = register(new BlockItem("birch_button", builder())); - public static final Item JUNGLE_BUTTON = register(new BlockItem("jungle_button", builder())); - public static final Item ACACIA_BUTTON = register(new BlockItem("acacia_button", builder())); - public static final Item CHERRY_BUTTON = register(new BlockItem("cherry_button", builder())); - public static final Item DARK_OAK_BUTTON = register(new BlockItem("dark_oak_button", builder())); - public static final Item MANGROVE_BUTTON = register(new BlockItem("mangrove_button", builder())); - public static final Item BAMBOO_BUTTON = register(new BlockItem("bamboo_button", builder())); - public static final Item CRIMSON_BUTTON = register(new BlockItem("crimson_button", builder())); - public static final Item WARPED_BUTTON = register(new BlockItem("warped_button", builder())); - public static final Item STONE_PRESSURE_PLATE = register(new BlockItem("stone_pressure_plate", builder())); - public static final Item POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new BlockItem("polished_blackstone_pressure_plate", builder())); - public static final Item LIGHT_WEIGHTED_PRESSURE_PLATE = register(new BlockItem("light_weighted_pressure_plate", builder())); - public static final Item HEAVY_WEIGHTED_PRESSURE_PLATE = register(new BlockItem("heavy_weighted_pressure_plate", builder())); - public static final Item OAK_PRESSURE_PLATE = register(new BlockItem("oak_pressure_plate", builder())); - public static final Item SPRUCE_PRESSURE_PLATE = register(new BlockItem("spruce_pressure_plate", builder())); - public static final Item BIRCH_PRESSURE_PLATE = register(new BlockItem("birch_pressure_plate", builder())); - public static final Item JUNGLE_PRESSURE_PLATE = register(new BlockItem("jungle_pressure_plate", builder())); - public static final Item ACACIA_PRESSURE_PLATE = register(new BlockItem("acacia_pressure_plate", builder())); - public static final Item CHERRY_PRESSURE_PLATE = register(new BlockItem("cherry_pressure_plate", builder())); - public static final Item DARK_OAK_PRESSURE_PLATE = register(new BlockItem("dark_oak_pressure_plate", builder())); - public static final Item MANGROVE_PRESSURE_PLATE = register(new BlockItem("mangrove_pressure_plate", builder())); - public static final Item BAMBOO_PRESSURE_PLATE = register(new BlockItem("bamboo_pressure_plate", builder())); - public static final Item CRIMSON_PRESSURE_PLATE = register(new BlockItem("crimson_pressure_plate", builder())); - public static final Item WARPED_PRESSURE_PLATE = register(new BlockItem("warped_pressure_plate", builder())); - public static final Item IRON_DOOR = register(new BlockItem("iron_door", builder())); - public static final Item OAK_DOOR = register(new BlockItem("oak_door", builder())); - public static final Item SPRUCE_DOOR = register(new BlockItem("spruce_door", builder())); - public static final Item BIRCH_DOOR = register(new BlockItem("birch_door", builder())); - public static final Item JUNGLE_DOOR = register(new BlockItem("jungle_door", builder())); - public static final Item ACACIA_DOOR = register(new BlockItem("acacia_door", builder())); - public static final Item CHERRY_DOOR = register(new BlockItem("cherry_door", builder())); - public static final Item DARK_OAK_DOOR = register(new BlockItem("dark_oak_door", builder())); - public static final Item MANGROVE_DOOR = register(new BlockItem("mangrove_door", builder())); - public static final Item BAMBOO_DOOR = register(new BlockItem("bamboo_door", builder())); - public static final Item CRIMSON_DOOR = register(new BlockItem("crimson_door", builder())); - public static final Item WARPED_DOOR = register(new BlockItem("warped_door", builder())); - public static final Item COPPER_DOOR = register(new BlockItem("copper_door", builder())); - public static final Item EXPOSED_COPPER_DOOR = register(new BlockItem("exposed_copper_door", builder())); - public static final Item WEATHERED_COPPER_DOOR = register(new BlockItem("weathered_copper_door", builder())); - public static final Item OXIDIZED_COPPER_DOOR = register(new BlockItem("oxidized_copper_door", builder())); - public static final Item WAXED_COPPER_DOOR = register(new BlockItem("waxed_copper_door", builder())); - public static final Item WAXED_EXPOSED_COPPER_DOOR = register(new BlockItem("waxed_exposed_copper_door", builder())); - public static final Item WAXED_WEATHERED_COPPER_DOOR = register(new BlockItem("waxed_weathered_copper_door", builder())); - public static final Item WAXED_OXIDIZED_COPPER_DOOR = register(new BlockItem("waxed_oxidized_copper_door", builder())); - public static final Item IRON_TRAPDOOR = register(new BlockItem("iron_trapdoor", builder())); - public static final Item OAK_TRAPDOOR = register(new BlockItem("oak_trapdoor", builder())); - public static final Item SPRUCE_TRAPDOOR = register(new BlockItem("spruce_trapdoor", builder())); - public static final Item BIRCH_TRAPDOOR = register(new BlockItem("birch_trapdoor", builder())); - public static final Item JUNGLE_TRAPDOOR = register(new BlockItem("jungle_trapdoor", builder())); - public static final Item ACACIA_TRAPDOOR = register(new BlockItem("acacia_trapdoor", builder())); - public static final Item CHERRY_TRAPDOOR = register(new BlockItem("cherry_trapdoor", builder())); - public static final Item DARK_OAK_TRAPDOOR = register(new BlockItem("dark_oak_trapdoor", builder())); - public static final Item MANGROVE_TRAPDOOR = register(new BlockItem("mangrove_trapdoor", builder())); - public static final Item BAMBOO_TRAPDOOR = register(new BlockItem("bamboo_trapdoor", builder())); - public static final Item CRIMSON_TRAPDOOR = register(new BlockItem("crimson_trapdoor", builder())); - public static final Item WARPED_TRAPDOOR = register(new BlockItem("warped_trapdoor", builder())); - public static final Item COPPER_TRAPDOOR = register(new BlockItem("copper_trapdoor", builder())); - public static final Item EXPOSED_COPPER_TRAPDOOR = register(new BlockItem("exposed_copper_trapdoor", builder())); - public static final Item WEATHERED_COPPER_TRAPDOOR = register(new BlockItem("weathered_copper_trapdoor", builder())); - public static final Item OXIDIZED_COPPER_TRAPDOOR = register(new BlockItem("oxidized_copper_trapdoor", builder())); - public static final Item WAXED_COPPER_TRAPDOOR = register(new BlockItem("waxed_copper_trapdoor", builder())); - public static final Item WAXED_EXPOSED_COPPER_TRAPDOOR = register(new BlockItem("waxed_exposed_copper_trapdoor", builder())); - public static final Item WAXED_WEATHERED_COPPER_TRAPDOOR = register(new BlockItem("waxed_weathered_copper_trapdoor", builder())); - public static final Item WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new BlockItem("waxed_oxidized_copper_trapdoor", builder())); - public static final Item OAK_FENCE_GATE = register(new BlockItem("oak_fence_gate", builder())); - public static final Item SPRUCE_FENCE_GATE = register(new BlockItem("spruce_fence_gate", builder())); - public static final Item BIRCH_FENCE_GATE = register(new BlockItem("birch_fence_gate", builder())); - public static final Item JUNGLE_FENCE_GATE = register(new BlockItem("jungle_fence_gate", builder())); - public static final Item ACACIA_FENCE_GATE = register(new BlockItem("acacia_fence_gate", builder())); - public static final Item CHERRY_FENCE_GATE = register(new BlockItem("cherry_fence_gate", builder())); - public static final Item DARK_OAK_FENCE_GATE = register(new BlockItem("dark_oak_fence_gate", builder())); - public static final Item MANGROVE_FENCE_GATE = register(new BlockItem("mangrove_fence_gate", builder())); - public static final Item BAMBOO_FENCE_GATE = register(new BlockItem("bamboo_fence_gate", builder())); - public static final Item CRIMSON_FENCE_GATE = register(new BlockItem("crimson_fence_gate", builder())); - public static final Item WARPED_FENCE_GATE = register(new BlockItem("warped_fence_gate", builder())); - public static final Item POWERED_RAIL = register(new BlockItem("powered_rail", builder())); - public static final Item DETECTOR_RAIL = register(new BlockItem("detector_rail", builder())); - public static final Item RAIL = register(new BlockItem("rail", builder())); - public static final Item ACTIVATOR_RAIL = register(new BlockItem("activator_rail", builder())); + public static final Item STONE = register(new BlockItem(builder(), Blocks.STONE)); + public static final Item GRANITE = register(new BlockItem(builder(), Blocks.GRANITE)); + public static final Item POLISHED_GRANITE = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE)); + public static final Item DIORITE = register(new BlockItem(builder(), Blocks.DIORITE)); + public static final Item POLISHED_DIORITE = register(new BlockItem(builder(), Blocks.POLISHED_DIORITE)); + public static final Item ANDESITE = register(new BlockItem(builder(), Blocks.ANDESITE)); + public static final Item POLISHED_ANDESITE = register(new BlockItem(builder(), Blocks.POLISHED_ANDESITE)); + public static final Item DEEPSLATE = register(new BlockItem(builder(), Blocks.DEEPSLATE)); + public static final Item COBBLED_DEEPSLATE = register(new BlockItem(builder(), Blocks.COBBLED_DEEPSLATE)); + public static final Item POLISHED_DEEPSLATE = register(new BlockItem(builder(), Blocks.POLISHED_DEEPSLATE)); + public static final Item CALCITE = register(new BlockItem(builder(), Blocks.CALCITE)); + public static final Item TUFF = register(new BlockItem(builder(), Blocks.TUFF)); + public static final Item TUFF_SLAB = register(new BlockItem(builder(), Blocks.TUFF_SLAB)); + public static final Item TUFF_STAIRS = register(new BlockItem(builder(), Blocks.TUFF_STAIRS)); + public static final Item TUFF_WALL = register(new BlockItem(builder(), Blocks.TUFF_WALL)); + public static final Item CHISELED_TUFF = register(new BlockItem(builder(), Blocks.CHISELED_TUFF)); + public static final Item POLISHED_TUFF = register(new BlockItem(builder(), Blocks.POLISHED_TUFF)); + public static final Item POLISHED_TUFF_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_TUFF_SLAB)); + public static final Item POLISHED_TUFF_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_TUFF_STAIRS)); + public static final Item POLISHED_TUFF_WALL = register(new BlockItem(builder(), Blocks.POLISHED_TUFF_WALL)); + public static final Item TUFF_BRICKS = register(new BlockItem(builder(), Blocks.TUFF_BRICKS)); + public static final Item TUFF_BRICK_SLAB = register(new BlockItem(builder(), Blocks.TUFF_BRICK_SLAB)); + public static final Item TUFF_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.TUFF_BRICK_STAIRS)); + public static final Item TUFF_BRICK_WALL = register(new BlockItem(builder(), Blocks.TUFF_BRICK_WALL)); + public static final Item CHISELED_TUFF_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_TUFF_BRICKS)); + public static final Item DRIPSTONE_BLOCK = register(new BlockItem(builder(), Blocks.DRIPSTONE_BLOCK)); + public static final Item GRASS_BLOCK = register(new BlockItem(builder(), Blocks.GRASS_BLOCK)); + public static final Item DIRT = register(new BlockItem(builder(), Blocks.DIRT)); + public static final Item COARSE_DIRT = register(new BlockItem(builder(), Blocks.COARSE_DIRT)); + public static final Item PODZOL = register(new BlockItem(builder(), Blocks.PODZOL)); + public static final Item ROOTED_DIRT = register(new BlockItem(builder(), Blocks.ROOTED_DIRT)); + public static final Item MUD = register(new BlockItem(builder(), Blocks.MUD)); + public static final Item CRIMSON_NYLIUM = register(new BlockItem(builder(), Blocks.CRIMSON_NYLIUM)); + public static final Item WARPED_NYLIUM = register(new BlockItem(builder(), Blocks.WARPED_NYLIUM)); + public static final Item COBBLESTONE = register(new BlockItem(builder(), Blocks.COBBLESTONE)); + public static final Item OAK_PLANKS = register(new BlockItem(builder(), Blocks.OAK_PLANKS)); + public static final Item SPRUCE_PLANKS = register(new BlockItem(builder(), Blocks.SPRUCE_PLANKS)); + public static final Item BIRCH_PLANKS = register(new BlockItem(builder(), Blocks.BIRCH_PLANKS)); + public static final Item JUNGLE_PLANKS = register(new BlockItem(builder(), Blocks.JUNGLE_PLANKS)); + 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 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)); + public static final Item WARPED_PLANKS = register(new BlockItem(builder(), Blocks.WARPED_PLANKS)); + public static final Item BAMBOO_MOSAIC = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC)); + public static final Item OAK_SAPLING = register(new BlockItem(builder(), Blocks.OAK_SAPLING)); + public static final Item SPRUCE_SAPLING = register(new BlockItem(builder(), Blocks.SPRUCE_SAPLING)); + public static final Item BIRCH_SAPLING = register(new BlockItem(builder(), Blocks.BIRCH_SAPLING)); + public static final Item JUNGLE_SAPLING = register(new BlockItem(builder(), Blocks.JUNGLE_SAPLING)); + 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 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)); + public static final Item SUSPICIOUS_SAND = register(new BlockItem(builder(), Blocks.SUSPICIOUS_SAND)); + public static final Item SUSPICIOUS_GRAVEL = register(new BlockItem(builder(), Blocks.SUSPICIOUS_GRAVEL)); + public static final Item RED_SAND = register(new BlockItem(builder(), Blocks.RED_SAND)); + public static final Item GRAVEL = register(new BlockItem(builder(), Blocks.GRAVEL)); + public static final Item COAL_ORE = register(new BlockItem(builder(), Blocks.COAL_ORE)); + public static final Item DEEPSLATE_COAL_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_COAL_ORE)); + public static final Item IRON_ORE = register(new BlockItem(builder(), Blocks.IRON_ORE)); + public static final Item DEEPSLATE_IRON_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_IRON_ORE)); + public static final Item COPPER_ORE = register(new BlockItem(builder(), Blocks.COPPER_ORE)); + public static final Item DEEPSLATE_COPPER_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_COPPER_ORE)); + public static final Item GOLD_ORE = register(new BlockItem(builder(), Blocks.GOLD_ORE)); + public static final Item DEEPSLATE_GOLD_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_GOLD_ORE)); + public static final Item REDSTONE_ORE = register(new BlockItem(builder(), Blocks.REDSTONE_ORE)); + public static final Item DEEPSLATE_REDSTONE_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_REDSTONE_ORE)); + public static final Item EMERALD_ORE = register(new BlockItem(builder(), Blocks.EMERALD_ORE)); + public static final Item DEEPSLATE_EMERALD_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_EMERALD_ORE)); + public static final Item LAPIS_ORE = register(new BlockItem(builder(), Blocks.LAPIS_ORE)); + public static final Item DEEPSLATE_LAPIS_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_LAPIS_ORE)); + public static final Item DIAMOND_ORE = register(new BlockItem(builder(), Blocks.DIAMOND_ORE)); + public static final Item DEEPSLATE_DIAMOND_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_DIAMOND_ORE)); + public static final Item NETHER_GOLD_ORE = register(new BlockItem(builder(), Blocks.NETHER_GOLD_ORE)); + public static final Item NETHER_QUARTZ_ORE = register(new BlockItem(builder(), Blocks.NETHER_QUARTZ_ORE)); + public static final Item ANCIENT_DEBRIS = register(new BlockItem(builder(), Blocks.ANCIENT_DEBRIS)); + public static final Item COAL_BLOCK = register(new BlockItem(builder(), Blocks.COAL_BLOCK)); + 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(), 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)); + public static final Item COPPER_BLOCK = register(new BlockItem(builder(), Blocks.COPPER_BLOCK)); + public static final Item GOLD_BLOCK = register(new BlockItem(builder(), Blocks.GOLD_BLOCK)); + public static final Item DIAMOND_BLOCK = register(new BlockItem(builder(), Blocks.DIAMOND_BLOCK)); + public static final Item NETHERITE_BLOCK = register(new BlockItem(builder(), Blocks.NETHERITE_BLOCK)); + public static final Item EXPOSED_COPPER = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER)); + public static final Item WEATHERED_COPPER = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER)); + public static final Item OXIDIZED_COPPER = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER)); + public static final Item CHISELED_COPPER = register(new BlockItem(builder(), Blocks.CHISELED_COPPER)); + public static final Item EXPOSED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.EXPOSED_CHISELED_COPPER)); + public static final Item WEATHERED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WEATHERED_CHISELED_COPPER)); + public static final Item OXIDIZED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.OXIDIZED_CHISELED_COPPER)); + public static final Item CUT_COPPER = register(new BlockItem(builder(), Blocks.CUT_COPPER)); + public static final Item EXPOSED_CUT_COPPER = register(new BlockItem(builder(), Blocks.EXPOSED_CUT_COPPER)); + public static final Item WEATHERED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WEATHERED_CUT_COPPER)); + public static final Item OXIDIZED_CUT_COPPER = register(new BlockItem(builder(), Blocks.OXIDIZED_CUT_COPPER)); + public static final Item CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.CUT_COPPER_STAIRS)); + public static final Item EXPOSED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.EXPOSED_CUT_COPPER_STAIRS)); + public static final Item WEATHERED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WEATHERED_CUT_COPPER_STAIRS)); + public static final Item OXIDIZED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.OXIDIZED_CUT_COPPER_STAIRS)); + public static final Item CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.CUT_COPPER_SLAB)); + public static final Item EXPOSED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.EXPOSED_CUT_COPPER_SLAB)); + public static final Item WEATHERED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WEATHERED_CUT_COPPER_SLAB)); + public static final Item OXIDIZED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.OXIDIZED_CUT_COPPER_SLAB)); + public static final Item WAXED_COPPER_BLOCK = register(new BlockItem(builder(), Blocks.WAXED_COPPER_BLOCK)); + public static final Item WAXED_EXPOSED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER)); + public static final Item WAXED_WEATHERED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER)); + public static final Item WAXED_OXIDIZED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER)); + public static final Item WAXED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_CHISELED_COPPER)); + public static final Item WAXED_EXPOSED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_CHISELED_COPPER)); + public static final Item WAXED_WEATHERED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_CHISELED_COPPER)); + public static final Item WAXED_OXIDIZED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_CHISELED_COPPER)); + public static final Item WAXED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WAXED_CUT_COPPER)); + public static final Item WAXED_EXPOSED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_CUT_COPPER)); + public static final Item WAXED_WEATHERED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_CUT_COPPER)); + public static final Item WAXED_OXIDIZED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_CUT_COPPER)); + public static final Item WAXED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WAXED_CUT_COPPER_STAIRS)); + public static final Item WAXED_EXPOSED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_CUT_COPPER_STAIRS)); + public static final Item WAXED_WEATHERED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_CUT_COPPER_STAIRS)); + public static final Item WAXED_OXIDIZED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_CUT_COPPER_STAIRS)); + public static final Item WAXED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WAXED_CUT_COPPER_SLAB)); + public static final Item WAXED_EXPOSED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_CUT_COPPER_SLAB)); + public static final Item WAXED_WEATHERED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_CUT_COPPER_SLAB)); + public static final Item WAXED_OXIDIZED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_CUT_COPPER_SLAB)); + public static final Item OAK_LOG = register(new BlockItem(builder(), Blocks.OAK_LOG)); + public static final Item SPRUCE_LOG = register(new BlockItem(builder(), Blocks.SPRUCE_LOG)); + public static final Item BIRCH_LOG = register(new BlockItem(builder(), Blocks.BIRCH_LOG)); + 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 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)); + public static final Item MUDDY_MANGROVE_ROOTS = register(new BlockItem(builder(), Blocks.MUDDY_MANGROVE_ROOTS)); + public static final Item CRIMSON_STEM = register(new BlockItem(builder(), Blocks.CRIMSON_STEM)); + public static final Item WARPED_STEM = register(new BlockItem(builder(), Blocks.WARPED_STEM)); + public static final Item BAMBOO_BLOCK = register(new BlockItem(builder(), Blocks.BAMBOO_BLOCK)); + public static final Item STRIPPED_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_OAK_LOG)); + public static final Item STRIPPED_SPRUCE_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_SPRUCE_LOG)); + public static final Item STRIPPED_BIRCH_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_BIRCH_LOG)); + public static final Item STRIPPED_JUNGLE_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_JUNGLE_LOG)); + 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_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)); + public static final Item STRIPPED_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_OAK_WOOD)); + public static final Item STRIPPED_SPRUCE_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_SPRUCE_WOOD)); + public static final Item STRIPPED_BIRCH_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_BIRCH_WOOD)); + public static final Item STRIPPED_JUNGLE_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_JUNGLE_WOOD)); + 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_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)); + public static final Item STRIPPED_BAMBOO_BLOCK = register(new BlockItem(builder(), Blocks.STRIPPED_BAMBOO_BLOCK)); + public static final Item OAK_WOOD = register(new BlockItem(builder(), Blocks.OAK_WOOD)); + public static final Item SPRUCE_WOOD = register(new BlockItem(builder(), Blocks.SPRUCE_WOOD)); + public static final Item BIRCH_WOOD = register(new BlockItem(builder(), Blocks.BIRCH_WOOD)); + 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 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)); + public static final Item WARPED_HYPHAE = register(new BlockItem(builder(), Blocks.WARPED_HYPHAE)); + public static final Item OAK_LEAVES = register(new BlockItem(builder(), Blocks.OAK_LEAVES)); + public static final Item SPRUCE_LEAVES = register(new BlockItem(builder(), Blocks.SPRUCE_LEAVES)); + public static final Item BIRCH_LEAVES = register(new BlockItem(builder(), Blocks.BIRCH_LEAVES)); + public static final Item JUNGLE_LEAVES = register(new BlockItem(builder(), Blocks.JUNGLE_LEAVES)); + 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 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)); + public static final Item SPONGE = register(new BlockItem(builder(), Blocks.SPONGE)); + public static final Item WET_SPONGE = register(new BlockItem(builder(), Blocks.WET_SPONGE)); + public static final Item GLASS = register(new BlockItem(builder(), Blocks.GLASS)); + public static final Item TINTED_GLASS = register(new BlockItem(builder(), Blocks.TINTED_GLASS)); + public static final Item LAPIS_BLOCK = register(new BlockItem(builder(), Blocks.LAPIS_BLOCK)); + public static final Item SANDSTONE = register(new BlockItem(builder(), Blocks.SANDSTONE)); + public static final Item CHISELED_SANDSTONE = register(new BlockItem(builder(), Blocks.CHISELED_SANDSTONE)); + public static final Item CUT_SANDSTONE = register(new BlockItem(builder(), Blocks.CUT_SANDSTONE)); + public static final Item COBWEB = register(new BlockItem(builder(), Blocks.COBWEB)); + public static final Item SHORT_GRASS = register(new BlockItem(builder(), Blocks.SHORT_GRASS)); + public static final Item FERN = register(new BlockItem(builder(), Blocks.FERN)); + public static final Item AZALEA = register(new BlockItem(builder(), Blocks.AZALEA)); + public static final Item FLOWERING_AZALEA = register(new BlockItem(builder(), Blocks.FLOWERING_AZALEA)); + public static final Item DEAD_BUSH = register(new BlockItem(builder(), Blocks.DEAD_BUSH)); + public static final Item SEAGRASS = register(new BlockItem(builder(), Blocks.SEAGRASS)); + public static final Item SEA_PICKLE = register(new BlockItem(builder(), Blocks.SEA_PICKLE)); + public static final Item WHITE_WOOL = register(new BlockItem(builder(), Blocks.WHITE_WOOL)); + public static final Item ORANGE_WOOL = register(new BlockItem(builder(), Blocks.ORANGE_WOOL)); + public static final Item MAGENTA_WOOL = register(new BlockItem(builder(), Blocks.MAGENTA_WOOL)); + public static final Item LIGHT_BLUE_WOOL = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_WOOL)); + public static final Item YELLOW_WOOL = register(new BlockItem(builder(), Blocks.YELLOW_WOOL)); + public static final Item LIME_WOOL = register(new BlockItem(builder(), Blocks.LIME_WOOL)); + public static final Item PINK_WOOL = register(new BlockItem(builder(), Blocks.PINK_WOOL)); + public static final Item GRAY_WOOL = register(new BlockItem(builder(), Blocks.GRAY_WOOL)); + public static final Item LIGHT_GRAY_WOOL = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_WOOL)); + public static final Item CYAN_WOOL = register(new BlockItem(builder(), Blocks.CYAN_WOOL)); + public static final Item PURPLE_WOOL = register(new BlockItem(builder(), Blocks.PURPLE_WOOL)); + public static final Item BLUE_WOOL = register(new BlockItem(builder(), Blocks.BLUE_WOOL)); + public static final Item BROWN_WOOL = register(new BlockItem(builder(), Blocks.BROWN_WOOL)); + public static final Item GREEN_WOOL = register(new BlockItem(builder(), Blocks.GREEN_WOOL)); + public static final Item RED_WOOL = register(new BlockItem(builder(), Blocks.RED_WOOL)); + public static final Item BLACK_WOOL = register(new BlockItem(builder(), Blocks.BLACK_WOOL)); + public static final Item DANDELION = register(new BlockItem(builder(), Blocks.DANDELION)); + public static final Item POPPY = register(new BlockItem(builder(), Blocks.POPPY)); + public static final Item BLUE_ORCHID = register(new BlockItem(builder(), Blocks.BLUE_ORCHID)); + public static final Item ALLIUM = register(new BlockItem(builder(), Blocks.ALLIUM)); + public static final Item AZURE_BLUET = register(new BlockItem(builder(), Blocks.AZURE_BLUET)); + public static final Item RED_TULIP = register(new BlockItem(builder(), Blocks.RED_TULIP)); + public static final Item ORANGE_TULIP = register(new BlockItem(builder(), Blocks.ORANGE_TULIP)); + public static final Item WHITE_TULIP = register(new BlockItem(builder(), Blocks.WHITE_TULIP)); + public static final Item PINK_TULIP = register(new BlockItem(builder(), Blocks.PINK_TULIP)); + public static final Item OXEYE_DAISY = register(new BlockItem(builder(), Blocks.OXEYE_DAISY)); + public static final Item CORNFLOWER = register(new BlockItem(builder(), Blocks.CORNFLOWER)); + public static final Item LILY_OF_THE_VALLEY = register(new BlockItem(builder(), Blocks.LILY_OF_THE_VALLEY)); + public static final Item WITHER_ROSE = register(new BlockItem(builder(), Blocks.WITHER_ROSE)); + public static final Item TORCHFLOWER = register(new BlockItem(builder(), Blocks.TORCHFLOWER)); + public static final Item PITCHER_PLANT = register(new BlockItem(builder(), Blocks.PITCHER_PLANT)); + public static final Item SPORE_BLOSSOM = register(new BlockItem(builder(), Blocks.SPORE_BLOSSOM)); + public static final Item BROWN_MUSHROOM = register(new BlockItem(builder(), Blocks.BROWN_MUSHROOM)); + public static final Item RED_MUSHROOM = register(new BlockItem(builder(), Blocks.RED_MUSHROOM)); + public static final Item CRIMSON_FUNGUS = register(new BlockItem(builder(), Blocks.CRIMSON_FUNGUS)); + public static final Item WARPED_FUNGUS = register(new BlockItem(builder(), Blocks.WARPED_FUNGUS)); + public static final Item CRIMSON_ROOTS = register(new BlockItem(builder(), Blocks.CRIMSON_ROOTS)); + public static final Item WARPED_ROOTS = register(new BlockItem(builder(), Blocks.WARPED_ROOTS)); + public static final Item NETHER_SPROUTS = register(new BlockItem(builder(), Blocks.NETHER_SPROUTS)); + public static final Item WEEPING_VINES = register(new BlockItem(builder(), Blocks.WEEPING_VINES)); + 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_BLOCK = register(new BlockItem(builder(), Blocks.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)); + public static final Item BAMBOO = register(new BlockItem(builder(), Blocks.BAMBOO)); + public static final Item OAK_SLAB = register(new BlockItem(builder(), Blocks.OAK_SLAB)); + public static final Item SPRUCE_SLAB = register(new BlockItem(builder(), Blocks.SPRUCE_SLAB)); + public static final Item BIRCH_SLAB = register(new BlockItem(builder(), Blocks.BIRCH_SLAB)); + public static final Item JUNGLE_SLAB = register(new BlockItem(builder(), Blocks.JUNGLE_SLAB)); + 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 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)); + public static final Item CRIMSON_SLAB = register(new BlockItem(builder(), Blocks.CRIMSON_SLAB)); + public static final Item WARPED_SLAB = register(new BlockItem(builder(), Blocks.WARPED_SLAB)); + public static final Item STONE_SLAB = register(new BlockItem(builder(), Blocks.STONE_SLAB)); + public static final Item SMOOTH_STONE_SLAB = register(new BlockItem(builder(), Blocks.SMOOTH_STONE_SLAB)); + public static final Item SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.SANDSTONE_SLAB)); + public static final Item CUT_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.CUT_SANDSTONE_SLAB)); + public static final Item PETRIFIED_OAK_SLAB = register(new BlockItem(builder(), Blocks.PETRIFIED_OAK_SLAB)); + public static final Item COBBLESTONE_SLAB = register(new BlockItem(builder(), Blocks.COBBLESTONE_SLAB)); + public static final Item BRICK_SLAB = register(new BlockItem(builder(), Blocks.BRICK_SLAB)); + public static final Item STONE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.STONE_BRICK_SLAB)); + public static final Item MUD_BRICK_SLAB = register(new BlockItem(builder(), Blocks.MUD_BRICK_SLAB)); + public static final Item NETHER_BRICK_SLAB = register(new BlockItem(builder(), Blocks.NETHER_BRICK_SLAB)); + public static final Item QUARTZ_SLAB = register(new BlockItem(builder(), Blocks.QUARTZ_SLAB)); + public static final Item RED_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_SLAB)); + public static final Item CUT_RED_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.CUT_RED_SANDSTONE_SLAB)); + public static final Item PURPUR_SLAB = register(new BlockItem(builder(), Blocks.PURPUR_SLAB)); + public static final Item PRISMARINE_SLAB = register(new BlockItem(builder(), Blocks.PRISMARINE_SLAB)); + public static final Item PRISMARINE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.PRISMARINE_BRICK_SLAB)); + public static final Item DARK_PRISMARINE_SLAB = register(new BlockItem(builder(), Blocks.DARK_PRISMARINE_SLAB)); + public static final Item SMOOTH_QUARTZ = register(new BlockItem(builder(), Blocks.SMOOTH_QUARTZ)); + public static final Item SMOOTH_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE)); + public static final Item SMOOTH_SANDSTONE = register(new BlockItem(builder(), Blocks.SMOOTH_SANDSTONE)); + public static final Item SMOOTH_STONE = register(new BlockItem(builder(), Blocks.SMOOTH_STONE)); + public static final Item BRICKS = register(new BlockItem(builder(), Blocks.BRICKS)); + public static final Item BOOKSHELF = register(new BlockItem(builder(), Blocks.BOOKSHELF)); + public static final Item CHISELED_BOOKSHELF = register(new BlockItem(builder(), Blocks.CHISELED_BOOKSHELF)); + public static final Item DECORATED_POT = register(new DecoratedPotItem(builder(), Blocks.DECORATED_POT)); + public static final Item MOSSY_COBBLESTONE = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE)); + public static final Item OBSIDIAN = register(new BlockItem(builder(), Blocks.OBSIDIAN)); + public static final Item TORCH = register(new BlockItem(builder(), Blocks.TORCH, Blocks.WALL_TORCH)); + public static final Item END_ROD = register(new BlockItem(builder(), Blocks.END_ROD)); + public static final Item CHORUS_PLANT = register(new BlockItem(builder(), Blocks.CHORUS_PLANT)); + public static final Item CHORUS_FLOWER = register(new BlockItem(builder(), Blocks.CHORUS_FLOWER)); + public static final Item PURPUR_BLOCK = register(new BlockItem(builder(), Blocks.PURPUR_BLOCK)); + 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 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)); + public static final Item FURNACE = register(new BlockItem(builder(), Blocks.FURNACE)); + public static final Item LADDER = register(new BlockItem(builder(), Blocks.LADDER)); + public static final Item COBBLESTONE_STAIRS = register(new BlockItem(builder(), Blocks.COBBLESTONE_STAIRS)); + public static final Item SNOW = register(new BlockItem(builder(), Blocks.SNOW)); + public static final Item ICE = register(new BlockItem(builder(), Blocks.ICE)); + public static final Item SNOW_BLOCK = register(new BlockItem(builder(), Blocks.SNOW_BLOCK)); + public static final Item CACTUS = register(new BlockItem(builder(), Blocks.CACTUS)); + public static final Item CLAY = register(new BlockItem(builder(), Blocks.CLAY)); + public static final Item JUKEBOX = register(new BlockItem(builder(), Blocks.JUKEBOX)); + public static final Item OAK_FENCE = register(new BlockItem(builder(), Blocks.OAK_FENCE)); + public static final Item SPRUCE_FENCE = register(new BlockItem(builder(), Blocks.SPRUCE_FENCE)); + public static final Item BIRCH_FENCE = register(new BlockItem(builder(), Blocks.BIRCH_FENCE)); + public static final Item JUNGLE_FENCE = register(new BlockItem(builder(), Blocks.JUNGLE_FENCE)); + 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 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)); + public static final Item WARPED_FENCE = register(new BlockItem(builder(), Blocks.WARPED_FENCE)); + public static final Item PUMPKIN = register(new BlockItem(builder(), Blocks.PUMPKIN)); + public static final Item CARVED_PUMPKIN = register(new BlockItem(builder(), Blocks.CARVED_PUMPKIN)); + public static final Item JACK_O_LANTERN = register(new BlockItem(builder(), Blocks.JACK_O_LANTERN)); + public static final Item NETHERRACK = register(new BlockItem(builder(), Blocks.NETHERRACK)); + public static final Item SOUL_SAND = register(new BlockItem(builder(), Blocks.SOUL_SAND)); + public static final Item SOUL_SOIL = register(new BlockItem(builder(), Blocks.SOUL_SOIL)); + public static final Item BASALT = register(new BlockItem(builder(), Blocks.BASALT)); + public static final Item POLISHED_BASALT = register(new BlockItem(builder(), Blocks.POLISHED_BASALT)); + public static final Item SMOOTH_BASALT = register(new BlockItem(builder(), Blocks.SMOOTH_BASALT)); + public static final Item SOUL_TORCH = register(new BlockItem(builder(), Blocks.SOUL_TORCH, Blocks.SOUL_WALL_TORCH)); + public static final Item GLOWSTONE = register(new BlockItem(builder(), Blocks.GLOWSTONE)); + public static final Item INFESTED_STONE = register(new BlockItem(builder(), Blocks.INFESTED_STONE)); + public static final Item INFESTED_COBBLESTONE = register(new BlockItem(builder(), Blocks.INFESTED_COBBLESTONE)); + public static final Item INFESTED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.INFESTED_STONE_BRICKS)); + public static final Item INFESTED_MOSSY_STONE_BRICKS = register(new BlockItem(builder(), Blocks.INFESTED_MOSSY_STONE_BRICKS)); + public static final Item INFESTED_CRACKED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.INFESTED_CRACKED_STONE_BRICKS)); + public static final Item INFESTED_CHISELED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.INFESTED_CHISELED_STONE_BRICKS)); + public static final Item INFESTED_DEEPSLATE = register(new BlockItem(builder(), Blocks.INFESTED_DEEPSLATE)); + public static final Item STONE_BRICKS = register(new BlockItem(builder(), Blocks.STONE_BRICKS)); + public static final Item MOSSY_STONE_BRICKS = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICKS)); + public static final Item CRACKED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.CRACKED_STONE_BRICKS)); + public static final Item CHISELED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_STONE_BRICKS)); + public static final Item PACKED_MUD = register(new BlockItem(builder(), Blocks.PACKED_MUD)); + public static final Item MUD_BRICKS = register(new BlockItem(builder(), Blocks.MUD_BRICKS)); + public static final Item DEEPSLATE_BRICKS = register(new BlockItem(builder(), Blocks.DEEPSLATE_BRICKS)); + public static final Item CRACKED_DEEPSLATE_BRICKS = register(new BlockItem(builder(), Blocks.CRACKED_DEEPSLATE_BRICKS)); + public static final Item DEEPSLATE_TILES = register(new BlockItem(builder(), Blocks.DEEPSLATE_TILES)); + public static final Item CRACKED_DEEPSLATE_TILES = register(new BlockItem(builder(), Blocks.CRACKED_DEEPSLATE_TILES)); + public static final Item CHISELED_DEEPSLATE = register(new BlockItem(builder(), Blocks.CHISELED_DEEPSLATE)); + public static final Item REINFORCED_DEEPSLATE = register(new BlockItem(builder(), Blocks.REINFORCED_DEEPSLATE)); + public static final Item BROWN_MUSHROOM_BLOCK = register(new BlockItem(builder(), Blocks.BROWN_MUSHROOM_BLOCK)); + public static final Item RED_MUSHROOM_BLOCK = register(new BlockItem(builder(), Blocks.RED_MUSHROOM_BLOCK)); + public static final Item MUSHROOM_STEM = register(new BlockItem(builder(), Blocks.MUSHROOM_STEM)); + public static final Item IRON_BARS = register(new BlockItem(builder(), Blocks.IRON_BARS)); + public static final Item CHAIN = register(new BlockItem(builder(), Blocks.CHAIN)); + public static final Item GLASS_PANE = register(new BlockItem(builder(), Blocks.GLASS_PANE)); + public static final Item MELON = register(new BlockItem(builder(), Blocks.MELON)); + public static final Item VINE = register(new BlockItem(builder(), Blocks.VINE)); + public static final Item GLOW_LICHEN = register(new BlockItem(builder(), Blocks.GLOW_LICHEN)); + public static final Item BRICK_STAIRS = register(new BlockItem(builder(), Blocks.BRICK_STAIRS)); + public static final Item STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.STONE_BRICK_STAIRS)); + public static final Item MUD_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MUD_BRICK_STAIRS)); + public static final Item MYCELIUM = register(new BlockItem(builder(), Blocks.MYCELIUM)); + public static final Item LILY_PAD = register(new BlockItem(builder(), Blocks.LILY_PAD)); + public static final Item NETHER_BRICKS = register(new BlockItem(builder(), Blocks.NETHER_BRICKS)); + public static final Item CRACKED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.CRACKED_NETHER_BRICKS)); + public static final Item CHISELED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_NETHER_BRICKS)); + public static final Item NETHER_BRICK_FENCE = register(new BlockItem(builder(), Blocks.NETHER_BRICK_FENCE)); + public static final Item NETHER_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.NETHER_BRICK_STAIRS)); + public static final Item SCULK = register(new BlockItem(builder(), Blocks.SCULK)); + public static final Item SCULK_VEIN = register(new BlockItem(builder(), Blocks.SCULK_VEIN)); + public static final Item SCULK_CATALYST = register(new BlockItem(builder(), Blocks.SCULK_CATALYST)); + public static final Item SCULK_SHRIEKER = register(new BlockItem(builder(), Blocks.SCULK_SHRIEKER)); + public static final Item ENCHANTING_TABLE = register(new BlockItem(builder(), Blocks.ENCHANTING_TABLE)); + 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(), 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)); + public static final Item OAK_STAIRS = register(new BlockItem(builder(), Blocks.OAK_STAIRS)); + public static final Item SPRUCE_STAIRS = register(new BlockItem(builder(), Blocks.SPRUCE_STAIRS)); + public static final Item BIRCH_STAIRS = register(new BlockItem(builder(), Blocks.BIRCH_STAIRS)); + public static final Item JUNGLE_STAIRS = register(new BlockItem(builder(), Blocks.JUNGLE_STAIRS)); + 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 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(), 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)); + public static final Item PRISMARINE_WALL = register(new BlockItem(builder(), Blocks.PRISMARINE_WALL)); + public static final Item RED_SANDSTONE_WALL = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_WALL)); + public static final Item MOSSY_STONE_BRICK_WALL = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_WALL)); + public static final Item GRANITE_WALL = register(new BlockItem(builder(), Blocks.GRANITE_WALL)); + public static final Item STONE_BRICK_WALL = register(new BlockItem(builder(), Blocks.STONE_BRICK_WALL)); + public static final Item MUD_BRICK_WALL = register(new BlockItem(builder(), Blocks.MUD_BRICK_WALL)); + public static final Item NETHER_BRICK_WALL = register(new BlockItem(builder(), Blocks.NETHER_BRICK_WALL)); + public static final Item ANDESITE_WALL = register(new BlockItem(builder(), Blocks.ANDESITE_WALL)); + public static final Item RED_NETHER_BRICK_WALL = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICK_WALL)); + public static final Item SANDSTONE_WALL = register(new BlockItem(builder(), Blocks.SANDSTONE_WALL)); + public static final Item END_STONE_BRICK_WALL = register(new BlockItem(builder(), Blocks.END_STONE_BRICK_WALL)); + public static final Item DIORITE_WALL = register(new BlockItem(builder(), Blocks.DIORITE_WALL)); + public static final Item BLACKSTONE_WALL = register(new BlockItem(builder(), Blocks.BLACKSTONE_WALL)); + public static final Item POLISHED_BLACKSTONE_WALL = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_WALL)); + public static final Item POLISHED_BLACKSTONE_BRICK_WALL = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BRICK_WALL)); + public static final Item COBBLED_DEEPSLATE_WALL = register(new BlockItem(builder(), Blocks.COBBLED_DEEPSLATE_WALL)); + public static final Item POLISHED_DEEPSLATE_WALL = register(new BlockItem(builder(), Blocks.POLISHED_DEEPSLATE_WALL)); + public static final Item DEEPSLATE_BRICK_WALL = register(new BlockItem(builder(), Blocks.DEEPSLATE_BRICK_WALL)); + public static final Item DEEPSLATE_TILE_WALL = register(new BlockItem(builder(), Blocks.DEEPSLATE_TILE_WALL)); + public static final Item ANVIL = register(new BlockItem(builder(), Blocks.ANVIL)); + public static final Item CHIPPED_ANVIL = register(new BlockItem(builder(), Blocks.CHIPPED_ANVIL)); + public static final Item DAMAGED_ANVIL = register(new BlockItem(builder(), Blocks.DAMAGED_ANVIL)); + public static final Item CHISELED_QUARTZ_BLOCK = register(new BlockItem(builder(), Blocks.CHISELED_QUARTZ_BLOCK)); + public static final Item QUARTZ_BLOCK = register(new BlockItem(builder(), Blocks.QUARTZ_BLOCK)); + public static final Item QUARTZ_BRICKS = register(new BlockItem(builder(), Blocks.QUARTZ_BRICKS)); + public static final Item QUARTZ_PILLAR = register(new BlockItem(builder(), Blocks.QUARTZ_PILLAR)); + public static final Item QUARTZ_STAIRS = register(new BlockItem(builder(), Blocks.QUARTZ_STAIRS)); + public static final Item WHITE_TERRACOTTA = register(new BlockItem(builder(), Blocks.WHITE_TERRACOTTA)); + public static final Item ORANGE_TERRACOTTA = register(new BlockItem(builder(), Blocks.ORANGE_TERRACOTTA)); + public static final Item MAGENTA_TERRACOTTA = register(new BlockItem(builder(), Blocks.MAGENTA_TERRACOTTA)); + public static final Item LIGHT_BLUE_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_TERRACOTTA)); + public static final Item YELLOW_TERRACOTTA = register(new BlockItem(builder(), Blocks.YELLOW_TERRACOTTA)); + public static final Item LIME_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIME_TERRACOTTA)); + public static final Item PINK_TERRACOTTA = register(new BlockItem(builder(), Blocks.PINK_TERRACOTTA)); + public static final Item GRAY_TERRACOTTA = register(new BlockItem(builder(), Blocks.GRAY_TERRACOTTA)); + public static final Item LIGHT_GRAY_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_TERRACOTTA)); + public static final Item CYAN_TERRACOTTA = register(new BlockItem(builder(), Blocks.CYAN_TERRACOTTA)); + public static final Item PURPLE_TERRACOTTA = register(new BlockItem(builder(), Blocks.PURPLE_TERRACOTTA)); + public static final Item BLUE_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLUE_TERRACOTTA)); + public static final Item BROWN_TERRACOTTA = register(new BlockItem(builder(), Blocks.BROWN_TERRACOTTA)); + 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(), 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)); + public static final Item MAGENTA_CARPET = register(new BlockItem(builder(), Blocks.MAGENTA_CARPET)); + public static final Item LIGHT_BLUE_CARPET = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_CARPET)); + public static final Item YELLOW_CARPET = register(new BlockItem(builder(), Blocks.YELLOW_CARPET)); + public static final Item LIME_CARPET = register(new BlockItem(builder(), Blocks.LIME_CARPET)); + public static final Item PINK_CARPET = register(new BlockItem(builder(), Blocks.PINK_CARPET)); + public static final Item GRAY_CARPET = register(new BlockItem(builder(), Blocks.GRAY_CARPET)); + public static final Item LIGHT_GRAY_CARPET = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_CARPET)); + public static final Item CYAN_CARPET = register(new BlockItem(builder(), Blocks.CYAN_CARPET)); + public static final Item PURPLE_CARPET = register(new BlockItem(builder(), Blocks.PURPLE_CARPET)); + public static final Item BLUE_CARPET = register(new BlockItem(builder(), Blocks.BLUE_CARPET)); + public static final Item BROWN_CARPET = register(new BlockItem(builder(), Blocks.BROWN_CARPET)); + public static final Item GREEN_CARPET = register(new BlockItem(builder(), Blocks.GREEN_CARPET)); + public static final Item RED_CARPET = register(new BlockItem(builder(), Blocks.RED_CARPET)); + public static final Item BLACK_CARPET = register(new BlockItem(builder(), Blocks.BLACK_CARPET)); + public static final Item TERRACOTTA = register(new BlockItem(builder(), Blocks.TERRACOTTA)); + public static final Item PACKED_ICE = register(new BlockItem(builder(), Blocks.PACKED_ICE)); + public static final Item DIRT_PATH = register(new BlockItem(builder(), Blocks.DIRT_PATH)); + public static final Item SUNFLOWER = register(new BlockItem(builder(), Blocks.SUNFLOWER)); + public static final Item LILAC = register(new BlockItem(builder(), Blocks.LILAC)); + public static final Item ROSE_BUSH = register(new BlockItem(builder(), Blocks.ROSE_BUSH)); + public static final Item PEONY = register(new BlockItem(builder(), Blocks.PEONY)); + public static final Item TALL_GRASS = register(new BlockItem(builder(), Blocks.TALL_GRASS)); + public static final Item LARGE_FERN = register(new BlockItem(builder(), Blocks.LARGE_FERN)); + public static final Item WHITE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.WHITE_STAINED_GLASS)); + public static final Item ORANGE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.ORANGE_STAINED_GLASS)); + public static final Item MAGENTA_STAINED_GLASS = register(new BlockItem(builder(), Blocks.MAGENTA_STAINED_GLASS)); + public static final Item LIGHT_BLUE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_STAINED_GLASS)); + public static final Item YELLOW_STAINED_GLASS = register(new BlockItem(builder(), Blocks.YELLOW_STAINED_GLASS)); + public static final Item LIME_STAINED_GLASS = register(new BlockItem(builder(), Blocks.LIME_STAINED_GLASS)); + public static final Item PINK_STAINED_GLASS = register(new BlockItem(builder(), Blocks.PINK_STAINED_GLASS)); + public static final Item GRAY_STAINED_GLASS = register(new BlockItem(builder(), Blocks.GRAY_STAINED_GLASS)); + public static final Item LIGHT_GRAY_STAINED_GLASS = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_STAINED_GLASS)); + public static final Item CYAN_STAINED_GLASS = register(new BlockItem(builder(), Blocks.CYAN_STAINED_GLASS)); + public static final Item PURPLE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.PURPLE_STAINED_GLASS)); + public static final Item BLUE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.BLUE_STAINED_GLASS)); + public static final Item BROWN_STAINED_GLASS = register(new BlockItem(builder(), Blocks.BROWN_STAINED_GLASS)); + public static final Item GREEN_STAINED_GLASS = register(new BlockItem(builder(), Blocks.GREEN_STAINED_GLASS)); + public static final Item RED_STAINED_GLASS = register(new BlockItem(builder(), Blocks.RED_STAINED_GLASS)); + public static final Item BLACK_STAINED_GLASS = register(new BlockItem(builder(), Blocks.BLACK_STAINED_GLASS)); + public static final Item WHITE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.WHITE_STAINED_GLASS_PANE)); + public static final Item ORANGE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.ORANGE_STAINED_GLASS_PANE)); + public static final Item MAGENTA_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.MAGENTA_STAINED_GLASS_PANE)); + public static final Item LIGHT_BLUE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_STAINED_GLASS_PANE)); + public static final Item YELLOW_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.YELLOW_STAINED_GLASS_PANE)); + public static final Item LIME_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.LIME_STAINED_GLASS_PANE)); + public static final Item PINK_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.PINK_STAINED_GLASS_PANE)); + public static final Item GRAY_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.GRAY_STAINED_GLASS_PANE)); + public static final Item LIGHT_GRAY_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_STAINED_GLASS_PANE)); + public static final Item CYAN_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.CYAN_STAINED_GLASS_PANE)); + public static final Item PURPLE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.PURPLE_STAINED_GLASS_PANE)); + public static final Item BLUE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.BLUE_STAINED_GLASS_PANE)); + public static final Item BROWN_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.BROWN_STAINED_GLASS_PANE)); + public static final Item GREEN_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.GREEN_STAINED_GLASS_PANE)); + public static final Item RED_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.RED_STAINED_GLASS_PANE)); + public static final Item BLACK_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.BLACK_STAINED_GLASS_PANE)); + public static final Item PRISMARINE = register(new BlockItem(builder(), Blocks.PRISMARINE)); + public static final Item PRISMARINE_BRICKS = register(new BlockItem(builder(), Blocks.PRISMARINE_BRICKS)); + public static final Item DARK_PRISMARINE = register(new BlockItem(builder(), Blocks.DARK_PRISMARINE)); + public static final Item PRISMARINE_STAIRS = register(new BlockItem(builder(), Blocks.PRISMARINE_STAIRS)); + public static final Item PRISMARINE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.PRISMARINE_BRICK_STAIRS)); + public static final Item DARK_PRISMARINE_STAIRS = register(new BlockItem(builder(), Blocks.DARK_PRISMARINE_STAIRS)); + public static final Item SEA_LANTERN = register(new BlockItem(builder(), Blocks.SEA_LANTERN)); + public static final Item RED_SANDSTONE = register(new BlockItem(builder(), Blocks.RED_SANDSTONE)); + 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(), 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(), 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)); + public static final Item MAGENTA_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.MAGENTA_SHULKER_BOX)); + public static final Item LIGHT_BLUE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIGHT_BLUE_SHULKER_BOX)); + public static final Item YELLOW_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.YELLOW_SHULKER_BOX)); + public static final Item LIME_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIME_SHULKER_BOX)); + public static final Item PINK_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.PINK_SHULKER_BOX)); + public static final Item GRAY_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.GRAY_SHULKER_BOX)); + public static final Item LIGHT_GRAY_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIGHT_GRAY_SHULKER_BOX)); + public static final Item CYAN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.CYAN_SHULKER_BOX)); + public static final Item PURPLE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.PURPLE_SHULKER_BOX)); + public static final Item BLUE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BLUE_SHULKER_BOX)); + public static final Item BROWN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BROWN_SHULKER_BOX)); + public static final Item GREEN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.GREEN_SHULKER_BOX)); + public static final Item RED_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.RED_SHULKER_BOX)); + public static final Item BLACK_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BLACK_SHULKER_BOX)); + public static final Item WHITE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.WHITE_GLAZED_TERRACOTTA)); + public static final Item ORANGE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.ORANGE_GLAZED_TERRACOTTA)); + public static final Item MAGENTA_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.MAGENTA_GLAZED_TERRACOTTA)); + public static final Item LIGHT_BLUE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_GLAZED_TERRACOTTA)); + public static final Item YELLOW_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.YELLOW_GLAZED_TERRACOTTA)); + public static final Item LIME_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIME_GLAZED_TERRACOTTA)); + public static final Item PINK_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.PINK_GLAZED_TERRACOTTA)); + public static final Item GRAY_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.GRAY_GLAZED_TERRACOTTA)); + public static final Item LIGHT_GRAY_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_GLAZED_TERRACOTTA)); + public static final Item CYAN_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.CYAN_GLAZED_TERRACOTTA)); + public static final Item PURPLE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.PURPLE_GLAZED_TERRACOTTA)); + public static final Item BLUE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLUE_GLAZED_TERRACOTTA)); + public static final Item BROWN_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.BROWN_GLAZED_TERRACOTTA)); + public static final Item GREEN_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.GREEN_GLAZED_TERRACOTTA)); + public static final Item RED_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.RED_GLAZED_TERRACOTTA)); + public static final Item BLACK_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLACK_GLAZED_TERRACOTTA)); + public static final Item WHITE_CONCRETE = register(new BlockItem(builder(), Blocks.WHITE_CONCRETE)); + public static final Item ORANGE_CONCRETE = register(new BlockItem(builder(), Blocks.ORANGE_CONCRETE)); + public static final Item MAGENTA_CONCRETE = register(new BlockItem(builder(), Blocks.MAGENTA_CONCRETE)); + public static final Item LIGHT_BLUE_CONCRETE = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_CONCRETE)); + public static final Item YELLOW_CONCRETE = register(new BlockItem(builder(), Blocks.YELLOW_CONCRETE)); + public static final Item LIME_CONCRETE = register(new BlockItem(builder(), Blocks.LIME_CONCRETE)); + public static final Item PINK_CONCRETE = register(new BlockItem(builder(), Blocks.PINK_CONCRETE)); + public static final Item GRAY_CONCRETE = register(new BlockItem(builder(), Blocks.GRAY_CONCRETE)); + public static final Item LIGHT_GRAY_CONCRETE = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_CONCRETE)); + public static final Item CYAN_CONCRETE = register(new BlockItem(builder(), Blocks.CYAN_CONCRETE)); + public static final Item PURPLE_CONCRETE = register(new BlockItem(builder(), Blocks.PURPLE_CONCRETE)); + public static final Item BLUE_CONCRETE = register(new BlockItem(builder(), Blocks.BLUE_CONCRETE)); + public static final Item BROWN_CONCRETE = register(new BlockItem(builder(), Blocks.BROWN_CONCRETE)); + public static final Item GREEN_CONCRETE = register(new BlockItem(builder(), Blocks.GREEN_CONCRETE)); + public static final Item RED_CONCRETE = register(new BlockItem(builder(), Blocks.RED_CONCRETE)); + public static final Item BLACK_CONCRETE = register(new BlockItem(builder(), Blocks.BLACK_CONCRETE)); + public static final Item WHITE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.WHITE_CONCRETE_POWDER)); + public static final Item ORANGE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.ORANGE_CONCRETE_POWDER)); + public static final Item MAGENTA_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.MAGENTA_CONCRETE_POWDER)); + public static final Item LIGHT_BLUE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_CONCRETE_POWDER)); + public static final Item YELLOW_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.YELLOW_CONCRETE_POWDER)); + public static final Item LIME_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.LIME_CONCRETE_POWDER)); + public static final Item PINK_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.PINK_CONCRETE_POWDER)); + public static final Item GRAY_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.GRAY_CONCRETE_POWDER)); + public static final Item LIGHT_GRAY_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_CONCRETE_POWDER)); + public static final Item CYAN_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.CYAN_CONCRETE_POWDER)); + public static final Item PURPLE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.PURPLE_CONCRETE_POWDER)); + public static final Item BLUE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.BLUE_CONCRETE_POWDER)); + public static final Item BROWN_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.BROWN_CONCRETE_POWDER)); + public static final Item GREEN_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.GREEN_CONCRETE_POWDER)); + public static final Item RED_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.RED_CONCRETE_POWDER)); + public static final Item BLACK_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.BLACK_CONCRETE_POWDER)); + public static final Item TURTLE_EGG = register(new BlockItem(builder(), Blocks.TURTLE_EGG)); + public static final Item SNIFFER_EGG = register(new BlockItem(builder(), Blocks.SNIFFER_EGG)); + public static final Item DEAD_TUBE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_TUBE_CORAL_BLOCK)); + public static final Item DEAD_BRAIN_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_BRAIN_CORAL_BLOCK)); + public static final Item DEAD_BUBBLE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_BUBBLE_CORAL_BLOCK)); + public static final Item DEAD_FIRE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL_BLOCK)); + public static final Item DEAD_HORN_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL_BLOCK)); + public static final Item TUBE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.TUBE_CORAL_BLOCK)); + public static final Item BRAIN_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.BRAIN_CORAL_BLOCK)); + public static final Item BUBBLE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.BUBBLE_CORAL_BLOCK)); + public static final Item FIRE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.FIRE_CORAL_BLOCK)); + public static final Item HORN_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.HORN_CORAL_BLOCK)); + public static final Item TUBE_CORAL = register(new BlockItem(builder(), Blocks.TUBE_CORAL)); + public static final Item BRAIN_CORAL = register(new BlockItem(builder(), Blocks.BRAIN_CORAL)); + public static final Item BUBBLE_CORAL = register(new BlockItem(builder(), Blocks.BUBBLE_CORAL)); + public static final Item FIRE_CORAL = register(new BlockItem(builder(), Blocks.FIRE_CORAL)); + public static final Item HORN_CORAL = register(new BlockItem(builder(), Blocks.HORN_CORAL)); + public static final Item DEAD_BRAIN_CORAL = register(new BlockItem(builder(), Blocks.DEAD_BRAIN_CORAL)); + public static final Item DEAD_BUBBLE_CORAL = register(new BlockItem(builder(), Blocks.DEAD_BUBBLE_CORAL)); + public static final Item DEAD_FIRE_CORAL = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL)); + public static final Item DEAD_HORN_CORAL = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL)); + public static final Item DEAD_TUBE_CORAL = register(new BlockItem(builder(), Blocks.DEAD_TUBE_CORAL)); + public static final Item TUBE_CORAL_FAN = register(new BlockItem(builder(), Blocks.TUBE_CORAL_FAN, Blocks.TUBE_CORAL_WALL_FAN)); + public static final Item BRAIN_CORAL_FAN = register(new BlockItem(builder(), Blocks.BRAIN_CORAL_FAN, Blocks.BRAIN_CORAL_WALL_FAN)); + public static final Item BUBBLE_CORAL_FAN = register(new BlockItem(builder(), Blocks.BUBBLE_CORAL_FAN, Blocks.BUBBLE_CORAL_WALL_FAN)); + public static final Item FIRE_CORAL_FAN = register(new BlockItem(builder(), Blocks.FIRE_CORAL_FAN, Blocks.FIRE_CORAL_WALL_FAN)); + public static final Item HORN_CORAL_FAN = register(new BlockItem(builder(), Blocks.HORN_CORAL_FAN, Blocks.HORN_CORAL_WALL_FAN)); + public static final Item DEAD_TUBE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_TUBE_CORAL_FAN, Blocks.DEAD_TUBE_CORAL_WALL_FAN)); + public static final Item DEAD_BRAIN_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_BRAIN_CORAL_FAN, Blocks.DEAD_BRAIN_CORAL_WALL_FAN)); + public static final Item DEAD_BUBBLE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_BUBBLE_CORAL_FAN, Blocks.DEAD_BUBBLE_CORAL_WALL_FAN)); + 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(), 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)); + public static final Item POLISHED_DIORITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_DIORITE_STAIRS)); + public static final Item MOSSY_COBBLESTONE_STAIRS = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_STAIRS)); + public static final Item END_STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.END_STONE_BRICK_STAIRS)); + public static final Item STONE_STAIRS = register(new BlockItem(builder(), Blocks.STONE_STAIRS)); + public static final Item SMOOTH_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_SANDSTONE_STAIRS)); + public static final Item SMOOTH_QUARTZ_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_QUARTZ_STAIRS)); + public static final Item GRANITE_STAIRS = register(new BlockItem(builder(), Blocks.GRANITE_STAIRS)); + public static final Item ANDESITE_STAIRS = register(new BlockItem(builder(), Blocks.ANDESITE_STAIRS)); + public static final Item RED_NETHER_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICK_STAIRS)); + public static final Item POLISHED_ANDESITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_ANDESITE_STAIRS)); + public static final Item DIORITE_STAIRS = register(new BlockItem(builder(), Blocks.DIORITE_STAIRS)); + public static final Item COBBLED_DEEPSLATE_STAIRS = register(new BlockItem(builder(), Blocks.COBBLED_DEEPSLATE_STAIRS)); + public static final Item POLISHED_DEEPSLATE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_DEEPSLATE_STAIRS)); + public static final Item DEEPSLATE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.DEEPSLATE_BRICK_STAIRS)); + public static final Item DEEPSLATE_TILE_STAIRS = register(new BlockItem(builder(), Blocks.DEEPSLATE_TILE_STAIRS)); + public static final Item POLISHED_GRANITE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE_SLAB)); + public static final Item SMOOTH_RED_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE_SLAB)); + public static final Item MOSSY_STONE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_SLAB)); + public static final Item POLISHED_DIORITE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_DIORITE_SLAB)); + public static final Item MOSSY_COBBLESTONE_SLAB = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_SLAB)); + public static final Item END_STONE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.END_STONE_BRICK_SLAB)); + public static final Item SMOOTH_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.SMOOTH_SANDSTONE_SLAB)); + public static final Item SMOOTH_QUARTZ_SLAB = register(new BlockItem(builder(), Blocks.SMOOTH_QUARTZ_SLAB)); + public static final Item GRANITE_SLAB = register(new BlockItem(builder(), Blocks.GRANITE_SLAB)); + public static final Item ANDESITE_SLAB = register(new BlockItem(builder(), Blocks.ANDESITE_SLAB)); + public static final Item RED_NETHER_BRICK_SLAB = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICK_SLAB)); + public static final Item POLISHED_ANDESITE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_ANDESITE_SLAB)); + public static final Item DIORITE_SLAB = register(new BlockItem(builder(), Blocks.DIORITE_SLAB)); + public static final Item COBBLED_DEEPSLATE_SLAB = register(new BlockItem(builder(), Blocks.COBBLED_DEEPSLATE_SLAB)); + public static final Item POLISHED_DEEPSLATE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_DEEPSLATE_SLAB)); + public static final Item DEEPSLATE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.DEEPSLATE_BRICK_SLAB)); + public static final Item DEEPSLATE_TILE_SLAB = register(new BlockItem(builder(), Blocks.DEEPSLATE_TILE_SLAB)); + public static final Item SCAFFOLDING = register(new BlockItem(builder(), Blocks.SCAFFOLDING)); + public static final Item REDSTONE = register(new BlockItem("redstone", builder(), Blocks.REDSTONE_WIRE)); + public static final Item REDSTONE_TORCH = register(new BlockItem(builder(), Blocks.REDSTONE_TORCH, Blocks.REDSTONE_WALL_TORCH)); + public static final Item REDSTONE_BLOCK = register(new BlockItem(builder(), Blocks.REDSTONE_BLOCK)); + public static final Item REPEATER = register(new BlockItem(builder(), Blocks.REPEATER)); + public static final Item COMPARATOR = register(new BlockItem(builder(), Blocks.COMPARATOR)); + public static final Item PISTON = register(new BlockItem(builder(), Blocks.PISTON)); + public static final Item STICKY_PISTON = register(new BlockItem(builder(), Blocks.STICKY_PISTON)); + public static final Item SLIME_BLOCK = register(new BlockItem(builder(), Blocks.SLIME_BLOCK)); + public static final Item HONEY_BLOCK = register(new BlockItem(builder(), Blocks.HONEY_BLOCK)); + public static final Item OBSERVER = register(new BlockItem(builder(), Blocks.OBSERVER)); + public static final Item HOPPER = register(new BlockItem(builder(), Blocks.HOPPER)); + public static final Item DISPENSER = register(new BlockItem(builder(), Blocks.DISPENSER)); + public static final Item DROPPER = register(new BlockItem(builder(), Blocks.DROPPER)); + public static final Item LECTERN = register(new BlockItem(builder(), Blocks.LECTERN)); + public static final Item TARGET = register(new BlockItem(builder(), Blocks.TARGET)); + public static final Item LEVER = register(new BlockItem(builder(), Blocks.LEVER)); + public static final Item LIGHTNING_ROD = register(new BlockItem(builder(), Blocks.LIGHTNING_ROD)); + public static final Item DAYLIGHT_DETECTOR = register(new BlockItem(builder(), Blocks.DAYLIGHT_DETECTOR)); + public static final Item SCULK_SENSOR = register(new BlockItem(builder(), Blocks.SCULK_SENSOR)); + public static final Item CALIBRATED_SCULK_SENSOR = register(new BlockItem(builder(), Blocks.CALIBRATED_SCULK_SENSOR)); + public static final Item TRIPWIRE_HOOK = register(new BlockItem(builder(), Blocks.TRIPWIRE_HOOK)); + public static final Item TRAPPED_CHEST = register(new BlockItem(builder(), Blocks.TRAPPED_CHEST)); + public static final Item TNT = register(new BlockItem(builder(), Blocks.TNT)); + public static final Item REDSTONE_LAMP = register(new BlockItem(builder(), Blocks.REDSTONE_LAMP)); + public static final Item NOTE_BLOCK = register(new BlockItem(builder(), Blocks.NOTE_BLOCK)); + public static final Item STONE_BUTTON = register(new BlockItem(builder(), Blocks.STONE_BUTTON)); + public static final Item POLISHED_BLACKSTONE_BUTTON = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BUTTON)); + public static final Item OAK_BUTTON = register(new BlockItem(builder(), Blocks.OAK_BUTTON)); + public static final Item SPRUCE_BUTTON = register(new BlockItem(builder(), Blocks.SPRUCE_BUTTON)); + public static final Item BIRCH_BUTTON = register(new BlockItem(builder(), Blocks.BIRCH_BUTTON)); + public static final Item JUNGLE_BUTTON = register(new BlockItem(builder(), Blocks.JUNGLE_BUTTON)); + 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 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)); + public static final Item WARPED_BUTTON = register(new BlockItem(builder(), Blocks.WARPED_BUTTON)); + public static final Item STONE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.STONE_PRESSURE_PLATE)); + public static final Item POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_PRESSURE_PLATE)); + public static final Item LIGHT_WEIGHTED_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.LIGHT_WEIGHTED_PRESSURE_PLATE)); + public static final Item HEAVY_WEIGHTED_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.HEAVY_WEIGHTED_PRESSURE_PLATE)); + public static final Item OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.OAK_PRESSURE_PLATE)); + public static final Item SPRUCE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.SPRUCE_PRESSURE_PLATE)); + public static final Item BIRCH_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.BIRCH_PRESSURE_PLATE)); + public static final Item JUNGLE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.JUNGLE_PRESSURE_PLATE)); + 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 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)); + public static final Item WARPED_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.WARPED_PRESSURE_PLATE)); + public static final Item IRON_DOOR = register(new BlockItem(builder(), Blocks.IRON_DOOR)); + public static final Item OAK_DOOR = register(new BlockItem(builder(), Blocks.OAK_DOOR)); + public static final Item SPRUCE_DOOR = register(new BlockItem(builder(), Blocks.SPRUCE_DOOR)); + public static final Item BIRCH_DOOR = register(new BlockItem(builder(), Blocks.BIRCH_DOOR)); + public static final Item JUNGLE_DOOR = register(new BlockItem(builder(), Blocks.JUNGLE_DOOR)); + 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 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)); + public static final Item WARPED_DOOR = register(new BlockItem(builder(), Blocks.WARPED_DOOR)); + public static final Item COPPER_DOOR = register(new BlockItem(builder(), Blocks.COPPER_DOOR)); + public static final Item EXPOSED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER_DOOR)); + public static final Item WEATHERED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER_DOOR)); + public static final Item OXIDIZED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER_DOOR)); + public static final Item WAXED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WAXED_COPPER_DOOR)); + public static final Item WAXED_EXPOSED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER_DOOR)); + public static final Item WAXED_WEATHERED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER_DOOR)); + public static final Item WAXED_OXIDIZED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER_DOOR)); + public static final Item IRON_TRAPDOOR = register(new BlockItem(builder(), Blocks.IRON_TRAPDOOR)); + public static final Item OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.OAK_TRAPDOOR)); + public static final Item SPRUCE_TRAPDOOR = register(new BlockItem(builder(), Blocks.SPRUCE_TRAPDOOR)); + public static final Item BIRCH_TRAPDOOR = register(new BlockItem(builder(), Blocks.BIRCH_TRAPDOOR)); + public static final Item JUNGLE_TRAPDOOR = register(new BlockItem(builder(), Blocks.JUNGLE_TRAPDOOR)); + 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 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)); + public static final Item WARPED_TRAPDOOR = register(new BlockItem(builder(), Blocks.WARPED_TRAPDOOR)); + public static final Item COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.COPPER_TRAPDOOR)); + public static final Item EXPOSED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER_TRAPDOOR)); + public static final Item WEATHERED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER_TRAPDOOR)); + public static final Item OXIDIZED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER_TRAPDOOR)); + public static final Item WAXED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WAXED_COPPER_TRAPDOOR)); + public static final Item WAXED_EXPOSED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER_TRAPDOOR)); + public static final Item WAXED_WEATHERED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER_TRAPDOOR)); + public static final Item WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER_TRAPDOOR)); + public static final Item OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.OAK_FENCE_GATE)); + public static final Item SPRUCE_FENCE_GATE = register(new BlockItem(builder(), Blocks.SPRUCE_FENCE_GATE)); + public static final Item BIRCH_FENCE_GATE = register(new BlockItem(builder(), Blocks.BIRCH_FENCE_GATE)); + public static final Item JUNGLE_FENCE_GATE = register(new BlockItem(builder(), Blocks.JUNGLE_FENCE_GATE)); + 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 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)); + public static final Item WARPED_FENCE_GATE = register(new BlockItem(builder(), Blocks.WARPED_FENCE_GATE)); + public static final Item POWERED_RAIL = register(new BlockItem(builder(), Blocks.POWERED_RAIL)); + public static final Item DETECTOR_RAIL = register(new BlockItem(builder(), Blocks.DETECTOR_RAIL)); + public static final Item RAIL = register(new BlockItem(builder(), Blocks.RAIL)); + public static final Item ACTIVATOR_RAIL = register(new BlockItem(builder(), Blocks.ACTIVATOR_RAIL)); public static final Item SADDLE = register(new Item("saddle", builder().stackSize(1))); public static final Item MINECART = register(new Item("minecart", builder().stackSize(1))); public static final Item CHEST_MINECART = register(new Item("chest_minecart", builder().stackSize(1))); @@ -830,8 +831,8 @@ public final class Items { 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("structure_block", builder())); - public static final Item JIGSAW = register(new BlockItem("jigsaw", builder())); + 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())); @@ -888,10 +889,10 @@ public final class Items { public static final Item STICK = register(new Item("stick", builder())); public static final Item BOWL = register(new Item("bowl", builder())); public static final Item MUSHROOM_STEW = register(new Item("mushroom_stew", builder().stackSize(1))); - public static final Item STRING = register(new BlockItem("string", builder())); + public static final Item STRING = register(new BlockItem("string", builder(), Blocks.TRIPWIRE)); public static final Item FEATHER = register(new Item("feather", builder())); public static final Item GUNPOWDER = register(new Item("gunpowder", builder())); - public static final Item WHEAT_SEEDS = register(new BlockItem("wheat_seeds", builder())); + public static final Item WHEAT_SEEDS = register(new BlockItem("wheat_seeds", builder(), Blocks.WHEAT)); public static final Item WHEAT = register(new Item("wheat", builder())); public static final Item BREAD = register(new Item("bread", builder())); public static final Item LEATHER_HELMET = register(new DyeableArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(55))); @@ -924,32 +925,32 @@ public final class Items { public static final Item PAINTING = register(new Item("painting", builder())); 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("oak_sign", builder().stackSize(16))); - public static final Item SPRUCE_SIGN = register(new BlockItem("spruce_sign", builder().stackSize(16))); - public static final Item BIRCH_SIGN = register(new BlockItem("birch_sign", builder().stackSize(16))); - public static final Item JUNGLE_SIGN = register(new BlockItem("jungle_sign", builder().stackSize(16))); - public static final Item ACACIA_SIGN = register(new BlockItem("acacia_sign", builder().stackSize(16))); - public static final Item CHERRY_SIGN = register(new BlockItem("cherry_sign", builder().stackSize(16))); - public static final Item DARK_OAK_SIGN = register(new BlockItem("dark_oak_sign", builder().stackSize(16))); - public static final Item MANGROVE_SIGN = register(new BlockItem("mangrove_sign", builder().stackSize(16))); - public static final Item BAMBOO_SIGN = register(new BlockItem("bamboo_sign", builder().stackSize(16))); - public static final Item CRIMSON_SIGN = register(new BlockItem("crimson_sign", builder().stackSize(16))); - public static final Item WARPED_SIGN = register(new BlockItem("warped_sign", builder().stackSize(16))); - public static final Item OAK_HANGING_SIGN = register(new BlockItem("oak_hanging_sign", builder().stackSize(16))); - public static final Item SPRUCE_HANGING_SIGN = register(new BlockItem("spruce_hanging_sign", builder().stackSize(16))); - public static final Item BIRCH_HANGING_SIGN = register(new BlockItem("birch_hanging_sign", builder().stackSize(16))); - public static final Item JUNGLE_HANGING_SIGN = register(new BlockItem("jungle_hanging_sign", builder().stackSize(16))); - public static final Item ACACIA_HANGING_SIGN = register(new BlockItem("acacia_hanging_sign", builder().stackSize(16))); - public static final Item CHERRY_HANGING_SIGN = register(new BlockItem("cherry_hanging_sign", builder().stackSize(16))); - public static final Item DARK_OAK_HANGING_SIGN = register(new BlockItem("dark_oak_hanging_sign", builder().stackSize(16))); - public static final Item MANGROVE_HANGING_SIGN = register(new BlockItem("mangrove_hanging_sign", builder().stackSize(16))); - public static final Item BAMBOO_HANGING_SIGN = register(new BlockItem("bamboo_hanging_sign", builder().stackSize(16))); - public static final Item CRIMSON_HANGING_SIGN = register(new BlockItem("crimson_hanging_sign", builder().stackSize(16))); - public static final Item WARPED_HANGING_SIGN = register(new BlockItem("warped_hanging_sign", builder().stackSize(16))); + 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)); + public static final Item JUNGLE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.JUNGLE_SIGN, Blocks.JUNGLE_WALL_SIGN)); + 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 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)); + public static final Item WARPED_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.WARPED_SIGN, Blocks.WARPED_WALL_SIGN)); + public static final Item OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.OAK_HANGING_SIGN, Blocks.OAK_WALL_HANGING_SIGN)); + public static final Item SPRUCE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.SPRUCE_HANGING_SIGN, Blocks.SPRUCE_WALL_HANGING_SIGN)); + public static final Item BIRCH_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BIRCH_HANGING_SIGN, Blocks.BIRCH_WALL_HANGING_SIGN)); + public static final Item JUNGLE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.JUNGLE_HANGING_SIGN, Blocks.JUNGLE_WALL_HANGING_SIGN)); + 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 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)); + public static final Item WARPED_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.WARPED_HANGING_SIGN, Blocks.WARPED_WALL_HANGING_SIGN)); public static final Item BUCKET = register(new Item("bucket", builder().stackSize(16))); public static final Item WATER_BUCKET = register(new Item("water_bucket", builder().stackSize(1))); public static final Item LAVA_BUCKET = register(new Item("lava_bucket", builder().stackSize(1))); - public static final Item POWDER_SNOW_BUCKET = register(new BlockItem("powder_snow_bucket", builder().stackSize(1))); + public static final Item POWDER_SNOW_BUCKET = register(new BlockItem("powder_snow_bucket", builder().stackSize(1), Blocks.POWDER_SNOW)); public static final Item SNOWBALL = register(new Item("snowball", builder().stackSize(16))); public static final Item LEATHER = register(new Item("leather", builder())); public static final Item MILK_BUCKET = register(new Item("milk_bucket", builder().stackSize(1))); @@ -961,7 +962,7 @@ public final class Items { public static final Item TADPOLE_BUCKET = register(new Item("tadpole_bucket", builder().stackSize(1))); public static final Item BRICK = register(new Item("brick", builder())); public static final Item CLAY_BALL = register(new Item("clay_ball", builder())); - public static final Item DRIED_KELP_BLOCK = register(new BlockItem("dried_kelp_block", builder())); + public static final Item DRIED_KELP_BLOCK = register(new BlockItem(builder(), Blocks.DRIED_KELP_BLOCK)); public static final Item PAPER = register(new Item("paper", builder())); public static final Item BOOK = register(new Item("book", builder())); public static final Item SLIME_BALL = register(new Item("slime_ball", builder())); @@ -981,7 +982,7 @@ public final class Items { public static final Item COOKED_SALMON = register(new Item("cooked_salmon", builder())); public static final Item INK_SAC = register(new Item("ink_sac", builder())); public static final Item GLOW_INK_SAC = register(new Item("glow_ink_sac", builder())); - public static final Item COCOA_BEANS = register(new BlockItem("cocoa_beans", builder())); + public static final Item COCOA_BEANS = register(new BlockItem("cocoa_beans", builder(), Blocks.COCOA)); public static final Item WHITE_DYE = register(new DyeItem("white_dye", 0, builder())); public static final Item ORANGE_DYE = register(new DyeItem("orange_dye", 1, builder())); public static final Item MAGENTA_DYE = register(new DyeItem("magenta_dye", 2, builder())); @@ -1001,31 +1002,31 @@ public final class Items { public static final Item BONE_MEAL = register(new Item("bone_meal", builder())); public static final Item BONE = register(new Item("bone", builder())); public static final Item SUGAR = register(new Item("sugar", builder())); - public static final Item CAKE = register(new BlockItem("cake", builder().stackSize(1))); - public static final Item WHITE_BED = register(new BlockItem("white_bed", builder().stackSize(1))); - public static final Item ORANGE_BED = register(new BlockItem("orange_bed", builder().stackSize(1))); - public static final Item MAGENTA_BED = register(new BlockItem("magenta_bed", builder().stackSize(1))); - public static final Item LIGHT_BLUE_BED = register(new BlockItem("light_blue_bed", builder().stackSize(1))); - public static final Item YELLOW_BED = register(new BlockItem("yellow_bed", builder().stackSize(1))); - public static final Item LIME_BED = register(new BlockItem("lime_bed", builder().stackSize(1))); - public static final Item PINK_BED = register(new BlockItem("pink_bed", builder().stackSize(1))); - public static final Item GRAY_BED = register(new BlockItem("gray_bed", builder().stackSize(1))); - public static final Item LIGHT_GRAY_BED = register(new BlockItem("light_gray_bed", builder().stackSize(1))); - public static final Item CYAN_BED = register(new BlockItem("cyan_bed", builder().stackSize(1))); - public static final Item PURPLE_BED = register(new BlockItem("purple_bed", builder().stackSize(1))); - public static final Item BLUE_BED = register(new BlockItem("blue_bed", builder().stackSize(1))); - public static final Item BROWN_BED = register(new BlockItem("brown_bed", builder().stackSize(1))); - public static final Item GREEN_BED = register(new BlockItem("green_bed", builder().stackSize(1))); - public static final Item RED_BED = register(new BlockItem("red_bed", builder().stackSize(1))); - public static final Item BLACK_BED = register(new BlockItem("black_bed", builder().stackSize(1))); + public static final Item CAKE = register(new BlockItem(builder().stackSize(1), Blocks.CAKE)); + public static final Item WHITE_BED = register(new BlockItem(builder().stackSize(1), Blocks.WHITE_BED)); + public static final Item ORANGE_BED = register(new BlockItem(builder().stackSize(1), Blocks.ORANGE_BED)); + public static final Item MAGENTA_BED = register(new BlockItem(builder().stackSize(1), Blocks.MAGENTA_BED)); + public static final Item LIGHT_BLUE_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIGHT_BLUE_BED)); + public static final Item YELLOW_BED = register(new BlockItem(builder().stackSize(1), Blocks.YELLOW_BED)); + public static final Item LIME_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIME_BED)); + public static final Item PINK_BED = register(new BlockItem(builder().stackSize(1), Blocks.PINK_BED)); + public static final Item GRAY_BED = register(new BlockItem(builder().stackSize(1), Blocks.GRAY_BED)); + public static final Item LIGHT_GRAY_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIGHT_GRAY_BED)); + public static final Item CYAN_BED = register(new BlockItem(builder().stackSize(1), Blocks.CYAN_BED)); + public static final Item PURPLE_BED = register(new BlockItem(builder().stackSize(1), Blocks.PURPLE_BED)); + public static final Item BLUE_BED = register(new BlockItem(builder().stackSize(1), Blocks.BLUE_BED)); + public static final Item BROWN_BED = register(new BlockItem(builder().stackSize(1), Blocks.BROWN_BED)); + public static final Item GREEN_BED = register(new BlockItem(builder().stackSize(1), Blocks.GREEN_BED)); + public static final Item RED_BED = register(new BlockItem(builder().stackSize(1), Blocks.RED_BED)); + public static final Item BLACK_BED = register(new BlockItem(builder().stackSize(1), Blocks.BLACK_BED)); public static final Item COOKIE = register(new Item("cookie", builder())); - public static final Item CRAFTER = register(new BlockItem("crafter", builder())); + public static final Item CRAFTER = register(new BlockItem(builder(), Blocks.CRAFTER)); public static final Item FILLED_MAP = register(new FilledMapItem("filled_map", builder())); public static final Item SHEARS = register(new Item("shears", builder().stackSize(1).maxDamage(238))); public static final Item MELON_SLICE = register(new Item("melon_slice", builder())); public static final Item DRIED_KELP = register(new Item("dried_kelp", builder())); - public static final Item PUMPKIN_SEEDS = register(new BlockItem("pumpkin_seeds", builder())); - public static final Item MELON_SEEDS = register(new BlockItem("melon_seeds", builder())); + public static final Item PUMPKIN_SEEDS = register(new BlockItem("pumpkin_seeds", builder(), Blocks.PUMPKIN_STEM)); + public static final Item MELON_SEEDS = register(new BlockItem("melon_seeds", builder(), Blocks.MELON_STEM)); public static final Item BEEF = register(new Item("beef", builder())); public static final Item COOKED_BEEF = register(new Item("cooked_beef", builder())); public static final Item CHICKEN = register(new Item("chicken", builder())); @@ -1035,15 +1036,15 @@ public final class Items { public static final Item BLAZE_ROD = register(new Item("blaze_rod", builder())); 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("nether_wart", 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 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("brewing_stand", builder())); - public static final Item CAULDRON = register(new BlockItem("cauldron", 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.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.WATER_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())); @@ -1134,20 +1135,20 @@ public final class Items { public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(250))); 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("flower_pot", builder())); - public static final Item CARROT = register(new BlockItem("carrot", builder())); - public static final Item POTATO = register(new BlockItem("potato", builder())); + public static final Item FLOWER_POT = register(new BlockItem(builder(), Blocks.FLOWER_POT)); + public static final Item CARROT = register(new BlockItem("carrot", builder(), Blocks.CARROTS)); + public static final Item POTATO = register(new BlockItem("potato", builder(), Blocks.POTATOES)); public static final Item BAKED_POTATO = register(new Item("baked_potato", builder())); 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("skeleton_skull", builder())); - public static final Item WITHER_SKELETON_SKULL = register(new BlockItem("wither_skeleton_skull", builder())); - public static final Item PLAYER_HEAD = register(new PlayerHeadItem("player_head", builder())); - public static final Item ZOMBIE_HEAD = register(new BlockItem("zombie_head", builder())); - public static final Item CREEPER_HEAD = register(new BlockItem("creeper_head", builder())); - public static final Item DRAGON_HEAD = register(new BlockItem("dragon_head", builder())); - public static final Item PIGLIN_HEAD = register(new BlockItem("piglin_head", builder())); + 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())); @@ -1171,29 +1172,29 @@ public final class Items { 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("white_banner", builder().stackSize(16))); - public static final Item ORANGE_BANNER = register(new BannerItem("orange_banner", builder().stackSize(16))); - public static final Item MAGENTA_BANNER = register(new BannerItem("magenta_banner", builder().stackSize(16))); - public static final Item LIGHT_BLUE_BANNER = register(new BannerItem("light_blue_banner", builder().stackSize(16))); - public static final Item YELLOW_BANNER = register(new BannerItem("yellow_banner", builder().stackSize(16))); - public static final Item LIME_BANNER = register(new BannerItem("lime_banner", builder().stackSize(16))); - public static final Item PINK_BANNER = register(new BannerItem("pink_banner", builder().stackSize(16))); - public static final Item GRAY_BANNER = register(new BannerItem("gray_banner", builder().stackSize(16))); - public static final Item LIGHT_GRAY_BANNER = register(new BannerItem("light_gray_banner", builder().stackSize(16))); - public static final Item CYAN_BANNER = register(new BannerItem("cyan_banner", builder().stackSize(16))); - public static final Item PURPLE_BANNER = register(new BannerItem("purple_banner", builder().stackSize(16))); - public static final Item BLUE_BANNER = register(new BannerItem("blue_banner", builder().stackSize(16))); - public static final Item BROWN_BANNER = register(new BannerItem("brown_banner", builder().stackSize(16))); - public static final Item GREEN_BANNER = register(new BannerItem("green_banner", builder().stackSize(16))); - public static final Item RED_BANNER = register(new BannerItem("red_banner", builder().stackSize(16))); - public static final Item BLACK_BANNER = register(new BannerItem("black_banner", builder().stackSize(16))); + public static final Item WHITE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.WHITE_BANNER, Blocks.WHITE_WALL_BANNER)); + public static final Item ORANGE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.ORANGE_BANNER, Blocks.ORANGE_WALL_BANNER)); + public static final Item MAGENTA_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.MAGENTA_BANNER, Blocks.MAGENTA_WALL_BANNER)); + public static final Item LIGHT_BLUE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIGHT_BLUE_BANNER, Blocks.LIGHT_BLUE_WALL_BANNER)); + public static final Item YELLOW_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.YELLOW_BANNER, Blocks.YELLOW_WALL_BANNER)); + public static final Item LIME_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIME_BANNER, Blocks.LIME_WALL_BANNER)); + public static final Item PINK_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.PINK_BANNER, Blocks.PINK_WALL_BANNER)); + public static final Item GRAY_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.GRAY_BANNER, Blocks.GRAY_WALL_BANNER)); + public static final Item LIGHT_GRAY_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIGHT_GRAY_BANNER, Blocks.LIGHT_GRAY_WALL_BANNER)); + public static final Item CYAN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.CYAN_BANNER, Blocks.CYAN_WALL_BANNER)); + public static final Item PURPLE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.PURPLE_BANNER, Blocks.PURPLE_WALL_BANNER)); + public static final Item BLUE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BLUE_BANNER, Blocks.BLUE_WALL_BANNER)); + public static final Item BROWN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BROWN_BANNER, Blocks.BROWN_WALL_BANNER)); + 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())); 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())); - public static final Item PITCHER_POD = register(new BlockItem("pitcher_pod", builder())); + public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder(), Blocks.TORCHFLOWER_CROP)); + public static final Item PITCHER_POD = register(new BlockItem("pitcher_pod", builder(), Blocks.PITCHER_CROP)); public static final Item BEETROOT = register(new Item("beetroot", builder())); - public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", 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())); public static final Item SPLASH_POTION = register(new PotionItem("splash_potion", builder().stackSize(1))); @@ -1229,7 +1230,7 @@ public final class Items { 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("loom", builder())); + 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))); public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1))); @@ -1239,69 +1240,69 @@ public final class Items { 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 GOAT_HORN = register(new GoatHornItem("goat_horn", builder().stackSize(1))); - public static final Item COMPOSTER = register(new BlockItem("composter", builder())); - public static final Item BARREL = register(new BlockItem("barrel", builder())); - public static final Item SMOKER = register(new BlockItem("smoker", builder())); - public static final Item BLAST_FURNACE = register(new BlockItem("blast_furnace", builder())); - public static final Item CARTOGRAPHY_TABLE = register(new BlockItem("cartography_table", builder())); - public static final Item FLETCHING_TABLE = register(new BlockItem("fletching_table", builder())); - public static final Item GRINDSTONE = register(new BlockItem("grindstone", builder())); - public static final Item SMITHING_TABLE = register(new BlockItem("smithing_table", builder())); - public static final Item STONECUTTER = register(new BlockItem("stonecutter", builder())); - public static final Item BELL = register(new BlockItem("bell", builder())); - public static final Item LANTERN = register(new BlockItem("lantern", builder())); - public static final Item SOUL_LANTERN = register(new BlockItem("soul_lantern", builder())); - public static final Item SWEET_BERRIES = register(new BlockItem("sweet_berries", builder())); - public static final Item GLOW_BERRIES = register(new BlockItem("glow_berries", builder())); - public static final Item CAMPFIRE = register(new BlockItem("campfire", builder())); - public static final Item SOUL_CAMPFIRE = register(new BlockItem("soul_campfire", builder())); - public static final Item SHROOMLIGHT = register(new BlockItem("shroomlight", builder())); + public static final Item COMPOSTER = register(new BlockItem(builder(), Blocks.COMPOSTER)); + public static final Item BARREL = register(new BlockItem(builder(), Blocks.BARREL)); + public static final Item SMOKER = register(new BlockItem(builder(), Blocks.SMOKER)); + public static final Item BLAST_FURNACE = register(new BlockItem(builder(), Blocks.BLAST_FURNACE)); + public static final Item CARTOGRAPHY_TABLE = register(new BlockItem(builder(), Blocks.CARTOGRAPHY_TABLE)); + public static final Item FLETCHING_TABLE = register(new BlockItem(builder(), Blocks.FLETCHING_TABLE)); + public static final Item GRINDSTONE = register(new BlockItem(builder(), Blocks.GRINDSTONE)); + public static final Item SMITHING_TABLE = register(new BlockItem(builder(), Blocks.SMITHING_TABLE)); + public static final Item STONECUTTER = register(new BlockItem(builder(), Blocks.STONECUTTER)); + public static final Item BELL = register(new BlockItem(builder(), Blocks.BELL)); + public static final Item LANTERN = register(new BlockItem(builder(), Blocks.LANTERN)); + public static final Item SOUL_LANTERN = register(new BlockItem(builder(), Blocks.SOUL_LANTERN)); + public static final Item SWEET_BERRIES = register(new BlockItem("sweet_berries", builder(), Blocks.SWEET_BERRY_BUSH)); + public static final Item GLOW_BERRIES = register(new BlockItem("glow_berries", builder(), Blocks.CAVE_VINES)); + public static final Item CAMPFIRE = register(new BlockItem(builder(), Blocks.CAMPFIRE)); + public static final Item SOUL_CAMPFIRE = register(new BlockItem(builder(), Blocks.SOUL_CAMPFIRE)); + public static final Item SHROOMLIGHT = register(new BlockItem(builder(), Blocks.SHROOMLIGHT)); public static final Item HONEYCOMB = register(new Item("honeycomb", builder())); - public static final Item BEE_NEST = register(new BlockItem("bee_nest", builder())); - public static final Item BEEHIVE = register(new BlockItem("beehive", builder())); + public static final Item BEE_NEST = register(new BlockItem(builder(), Blocks.BEE_NEST)); + public static final Item BEEHIVE = register(new BlockItem(builder(), Blocks.BEEHIVE)); public static final Item HONEY_BOTTLE = register(new Item("honey_bottle", builder().stackSize(16))); - public static final Item HONEYCOMB_BLOCK = register(new BlockItem("honeycomb_block", builder())); - public static final Item LODESTONE = register(new BlockItem("lodestone", builder())); - public static final Item CRYING_OBSIDIAN = register(new BlockItem("crying_obsidian", builder())); - public static final Item BLACKSTONE = register(new BlockItem("blackstone", builder())); - public static final Item BLACKSTONE_SLAB = register(new BlockItem("blackstone_slab", builder())); - public static final Item BLACKSTONE_STAIRS = register(new BlockItem("blackstone_stairs", builder())); - public static final Item GILDED_BLACKSTONE = register(new BlockItem("gilded_blackstone", builder())); - public static final Item POLISHED_BLACKSTONE = register(new BlockItem("polished_blackstone", builder())); - public static final Item POLISHED_BLACKSTONE_SLAB = register(new BlockItem("polished_blackstone_slab", builder())); - public static final Item POLISHED_BLACKSTONE_STAIRS = register(new BlockItem("polished_blackstone_stairs", builder())); - public static final Item CHISELED_POLISHED_BLACKSTONE = register(new BlockItem("chiseled_polished_blackstone", builder())); - public static final Item POLISHED_BLACKSTONE_BRICKS = register(new BlockItem("polished_blackstone_bricks", builder())); - public static final Item POLISHED_BLACKSTONE_BRICK_SLAB = register(new BlockItem("polished_blackstone_brick_slab", builder())); - public static final Item POLISHED_BLACKSTONE_BRICK_STAIRS = register(new BlockItem("polished_blackstone_brick_stairs", builder())); - public static final Item CRACKED_POLISHED_BLACKSTONE_BRICKS = register(new BlockItem("cracked_polished_blackstone_bricks", builder())); - public static final Item RESPAWN_ANCHOR = register(new BlockItem("respawn_anchor", builder())); - public static final Item CANDLE = register(new BlockItem("candle", builder())); - public static final Item WHITE_CANDLE = register(new BlockItem("white_candle", builder())); - public static final Item ORANGE_CANDLE = register(new BlockItem("orange_candle", builder())); - public static final Item MAGENTA_CANDLE = register(new BlockItem("magenta_candle", builder())); - public static final Item LIGHT_BLUE_CANDLE = register(new BlockItem("light_blue_candle", builder())); - public static final Item YELLOW_CANDLE = register(new BlockItem("yellow_candle", builder())); - public static final Item LIME_CANDLE = register(new BlockItem("lime_candle", builder())); - public static final Item PINK_CANDLE = register(new BlockItem("pink_candle", builder())); - public static final Item GRAY_CANDLE = register(new BlockItem("gray_candle", builder())); - public static final Item LIGHT_GRAY_CANDLE = register(new BlockItem("light_gray_candle", builder())); - public static final Item CYAN_CANDLE = register(new BlockItem("cyan_candle", builder())); - public static final Item PURPLE_CANDLE = register(new BlockItem("purple_candle", builder())); - public static final Item BLUE_CANDLE = register(new BlockItem("blue_candle", builder())); - public static final Item BROWN_CANDLE = register(new BlockItem("brown_candle", builder())); - public static final Item GREEN_CANDLE = register(new BlockItem("green_candle", builder())); - public static final Item RED_CANDLE = register(new BlockItem("red_candle", builder())); - public static final Item BLACK_CANDLE = register(new BlockItem("black_candle", builder())); - public static final Item SMALL_AMETHYST_BUD = register(new BlockItem("small_amethyst_bud", builder())); - public static final Item MEDIUM_AMETHYST_BUD = register(new BlockItem("medium_amethyst_bud", builder())); - public static final Item LARGE_AMETHYST_BUD = register(new BlockItem("large_amethyst_bud", builder())); - public static final Item AMETHYST_CLUSTER = register(new BlockItem("amethyst_cluster", builder())); - public static final Item POINTED_DRIPSTONE = register(new BlockItem("pointed_dripstone", builder())); - public static final Item OCHRE_FROGLIGHT = register(new BlockItem("ochre_froglight", builder())); - public static final Item VERDANT_FROGLIGHT = register(new BlockItem("verdant_froglight", builder())); - public static final Item PEARLESCENT_FROGLIGHT = register(new BlockItem("pearlescent_froglight", builder())); - public static final Item FROGSPAWN = register(new BlockItem("frogspawn", builder())); + public static final Item HONEYCOMB_BLOCK = register(new BlockItem(builder(), Blocks.HONEYCOMB_BLOCK)); + public static final Item LODESTONE = register(new BlockItem(builder(), Blocks.LODESTONE)); + public static final Item CRYING_OBSIDIAN = register(new BlockItem(builder(), Blocks.CRYING_OBSIDIAN)); + public static final Item BLACKSTONE = register(new BlockItem(builder(), Blocks.BLACKSTONE)); + public static final Item BLACKSTONE_SLAB = register(new BlockItem(builder(), Blocks.BLACKSTONE_SLAB)); + public static final Item BLACKSTONE_STAIRS = register(new BlockItem(builder(), Blocks.BLACKSTONE_STAIRS)); + public static final Item GILDED_BLACKSTONE = register(new BlockItem(builder(), Blocks.GILDED_BLACKSTONE)); + public static final Item POLISHED_BLACKSTONE = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE)); + public static final Item POLISHED_BLACKSTONE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_SLAB)); + public static final Item POLISHED_BLACKSTONE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_STAIRS)); + public static final Item CHISELED_POLISHED_BLACKSTONE = register(new BlockItem(builder(), Blocks.CHISELED_POLISHED_BLACKSTONE)); + public static final Item POLISHED_BLACKSTONE_BRICKS = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BRICKS)); + public static final Item POLISHED_BLACKSTONE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BRICK_SLAB)); + public static final Item POLISHED_BLACKSTONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BRICK_STAIRS)); + public static final Item CRACKED_POLISHED_BLACKSTONE_BRICKS = register(new BlockItem(builder(), Blocks.CRACKED_POLISHED_BLACKSTONE_BRICKS)); + public static final Item RESPAWN_ANCHOR = register(new BlockItem(builder(), Blocks.RESPAWN_ANCHOR)); + public static final Item CANDLE = register(new BlockItem(builder(), Blocks.CANDLE)); + public static final Item WHITE_CANDLE = register(new BlockItem(builder(), Blocks.WHITE_CANDLE)); + public static final Item ORANGE_CANDLE = register(new BlockItem(builder(), Blocks.ORANGE_CANDLE)); + public static final Item MAGENTA_CANDLE = register(new BlockItem(builder(), Blocks.MAGENTA_CANDLE)); + public static final Item LIGHT_BLUE_CANDLE = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_CANDLE)); + public static final Item YELLOW_CANDLE = register(new BlockItem(builder(), Blocks.YELLOW_CANDLE)); + public static final Item LIME_CANDLE = register(new BlockItem(builder(), Blocks.LIME_CANDLE)); + public static final Item PINK_CANDLE = register(new BlockItem(builder(), Blocks.PINK_CANDLE)); + public static final Item GRAY_CANDLE = register(new BlockItem(builder(), Blocks.GRAY_CANDLE)); + public static final Item LIGHT_GRAY_CANDLE = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_CANDLE)); + public static final Item CYAN_CANDLE = register(new BlockItem(builder(), Blocks.CYAN_CANDLE)); + public static final Item PURPLE_CANDLE = register(new BlockItem(builder(), Blocks.PURPLE_CANDLE)); + public static final Item BLUE_CANDLE = register(new BlockItem(builder(), Blocks.BLUE_CANDLE)); + public static final Item BROWN_CANDLE = register(new BlockItem(builder(), Blocks.BROWN_CANDLE)); + public static final Item GREEN_CANDLE = register(new BlockItem(builder(), Blocks.GREEN_CANDLE)); + public static final Item RED_CANDLE = register(new BlockItem(builder(), Blocks.RED_CANDLE)); + public static final Item BLACK_CANDLE = register(new BlockItem(builder(), Blocks.BLACK_CANDLE)); + public static final Item SMALL_AMETHYST_BUD = register(new BlockItem(builder(), Blocks.SMALL_AMETHYST_BUD)); + public static final Item MEDIUM_AMETHYST_BUD = register(new BlockItem(builder(), Blocks.MEDIUM_AMETHYST_BUD)); + public static final Item LARGE_AMETHYST_BUD = register(new BlockItem(builder(), Blocks.LARGE_AMETHYST_BUD)); + public static final Item AMETHYST_CLUSTER = register(new BlockItem(builder(), Blocks.AMETHYST_CLUSTER)); + public static final Item POINTED_DRIPSTONE = register(new BlockItem(builder(), Blocks.POINTED_DRIPSTONE)); + public static final Item OCHRE_FROGLIGHT = register(new BlockItem(builder(), Blocks.OCHRE_FROGLIGHT)); + public static final Item VERDANT_FROGLIGHT = register(new BlockItem(builder(), Blocks.VERDANT_FROGLIGHT)); + public static final Item PEARLESCENT_FROGLIGHT = register(new BlockItem(builder(), Blocks.PEARLESCENT_FROGLIGHT)); + public static final Item FROGSPAWN = register(new BlockItem(builder(), Blocks.FROGSPAWN)); public static final Item ECHO_SHARD = register(new Item("echo_shard", builder())); public static final Item BRUSH = register(new Item("brush", builder().stackSize(1).maxDamage(64))); public static final Item NETHERITE_UPGRADE_SMITHING_TEMPLATE = register(new Item("netherite_upgrade_smithing_template", builder())); @@ -1346,26 +1347,26 @@ public final class Items { public static final Item SHELTER_POTTERY_SHERD = register(new Item("shelter_pottery_sherd", builder())); public static final Item SKULL_POTTERY_SHERD = register(new Item("skull_pottery_sherd", builder())); public static final Item SNORT_POTTERY_SHERD = register(new Item("snort_pottery_sherd", builder())); - public static final Item COPPER_GRATE = register(new BlockItem("copper_grate", builder())); - public static final Item EXPOSED_COPPER_GRATE = register(new BlockItem("exposed_copper_grate", builder())); - public static final Item WEATHERED_COPPER_GRATE = register(new BlockItem("weathered_copper_grate", builder())); - public static final Item OXIDIZED_COPPER_GRATE = register(new BlockItem("oxidized_copper_grate", builder())); - public static final Item WAXED_COPPER_GRATE = register(new BlockItem("waxed_copper_grate", builder())); - public static final Item WAXED_EXPOSED_COPPER_GRATE = register(new BlockItem("waxed_exposed_copper_grate", builder())); - public static final Item WAXED_WEATHERED_COPPER_GRATE = register(new BlockItem("waxed_weathered_copper_grate", builder())); - public static final Item WAXED_OXIDIZED_COPPER_GRATE = register(new BlockItem("waxed_oxidized_copper_grate", builder())); - public static final Item COPPER_BULB = register(new BlockItem("copper_bulb", builder())); - public static final Item EXPOSED_COPPER_BULB = register(new BlockItem("exposed_copper_bulb", builder())); - public static final Item WEATHERED_COPPER_BULB = register(new BlockItem("weathered_copper_bulb", builder())); - public static final Item OXIDIZED_COPPER_BULB = register(new BlockItem("oxidized_copper_bulb", builder())); - public static final Item WAXED_COPPER_BULB = register(new BlockItem("waxed_copper_bulb", builder())); - public static final Item WAXED_EXPOSED_COPPER_BULB = register(new BlockItem("waxed_exposed_copper_bulb", builder())); - public static final Item WAXED_WEATHERED_COPPER_BULB = register(new BlockItem("waxed_weathered_copper_bulb", builder())); - public static final Item WAXED_OXIDIZED_COPPER_BULB = register(new BlockItem("waxed_oxidized_copper_bulb", builder())); - public static final Item TRIAL_SPAWNER = register(new BlockItem("trial_spawner", builder())); + public static final Item COPPER_GRATE = register(new BlockItem(builder(), Blocks.COPPER_GRATE)); + public static final Item EXPOSED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER_GRATE)); + public static final Item WEATHERED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER_GRATE)); + public static final Item OXIDIZED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER_GRATE)); + public static final Item WAXED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WAXED_COPPER_GRATE)); + public static final Item WAXED_EXPOSED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER_GRATE)); + public static final Item WAXED_WEATHERED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER_GRATE)); + public static final Item WAXED_OXIDIZED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER_GRATE)); + public static final Item COPPER_BULB = register(new BlockItem(builder(), Blocks.COPPER_BULB)); + public static final Item EXPOSED_COPPER_BULB = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER_BULB)); + public static final Item WEATHERED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER_BULB)); + public static final Item OXIDIZED_COPPER_BULB = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER_BULB)); + public static final Item WAXED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WAXED_COPPER_BULB)); + public static final Item WAXED_EXPOSED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER_BULB)); + public static final Item WAXED_WEATHERED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER_BULB)); + public static final Item WAXED_OXIDIZED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER_BULB)); + public static final Item TRIAL_SPAWNER = register(new BlockItem(builder(), Blocks.TRIAL_SPAWNER)); 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("vault", builder())); + public static final Item VAULT = register(new BlockItem(builder(), Blocks.VAULT)); public static final Item OMINOUS_BOTTLE = register(new Item("ominous_bottle", builder())); public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder())); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 6c2678db9..b53843882 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -35,6 +35,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.item.DyeColor; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.registry.JavaRegistry; @@ -199,8 +200,8 @@ public class BannerItem extends BlockItem { return null; } - public BannerItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); + public BannerItem(Builder builder, Block block, Block... otherBlocks) { + super(builder, block, otherBlocks); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BlockItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BlockItem.java index 0dbf0971a..30a31a100 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BlockItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BlockItem.java @@ -25,11 +25,26 @@ package org.geysermc.geyser.item.type; -/** - * TODO needed? - */ +import org.geysermc.geyser.level.block.type.Block; + public class BlockItem extends Item { - public BlockItem(String javaIdentifier, Builder builder) { + public BlockItem(Builder builder, Block block, Block... otherBlocks) { + super(block.javaIdentifier().value(), builder); + + // Ensure this item can be looked up by its block(s) + registerBlock(block, this); + for (Block otherBlock : otherBlocks) { + registerBlock(otherBlock, this); + } + } + + // Use this constructor if the item name is not the same as its primary block + public BlockItem(String javaIdentifier, Builder builder, Block block, Block... otherBlocks) { super(javaIdentifier, builder); + + registerBlock(block, this); + for (Block otherBlock : otherBlocks) { + registerBlock(otherBlock, this); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index 2631bf9be..578ba4063 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -38,8 +39,8 @@ import java.util.List; public class DecoratedPotItem extends BlockItem { - public DecoratedPotItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); + public DecoratedPotItem(Builder builder, Block block, Block... otherBlocks) { + super(builder, block, otherBlocks); } @Override 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 fc4fda07c..1ec410eaf 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 @@ -35,6 +35,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; @@ -49,20 +50,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; public class Item { - /** - * This is a map from Java-only enchantments to their translation keys so that we can - * map these enchantments to Bedrock clients, since they don't actually exist there. - */ - private static final Map ENCHANTMENT_TRANSLATION_KEYS = Map.of( - Enchantment.JavaEnchantment.SWEEPING_EDGE, "enchantment.minecraft.sweeping", - Enchantment.JavaEnchantment.DENSITY, "enchantment.minecraft.density", - Enchantment.JavaEnchantment.BREACH, "enchantment.minecraft.breach", - Enchantment.JavaEnchantment.WIND_BURST, "enchantment.minecraft.wind_burst"); - + private static final Map BLOCK_TO_ITEM = new HashMap<>(); private final String javaIdentifier; private int javaId = -1; private final int stackSize; @@ -233,6 +226,16 @@ public class Item { // } } + /** + * This is a map from Java-only enchantments to their translation keys so that we can + * map these enchantments to Bedrock clients, since they don't actually exist there. + */ + private static final Map ENCHANTMENT_TRANSLATION_KEYS = Map.of( + Enchantment.JavaEnchantment.SWEEPING_EDGE, "enchantment.minecraft.sweeping", + Enchantment.JavaEnchantment.DENSITY, "enchantment.minecraft.density", + Enchantment.JavaEnchantment.BREACH, "enchantment.minecraft.breach", + Enchantment.JavaEnchantment.WIND_BURST, "enchantment.minecraft.wind_burst"); + protected final @Nullable NbtMap remapEnchantment(GeyserSession session, int enchantId, int level, BedrockItemBuilder builder) { // TODO verify // TODO streamline Enchantment process @@ -281,6 +284,18 @@ public class Item { '}'; } + /** + * @return the block associated with this item, or air if nothing + */ + @NonNull + public static Item byBlock(Block block) { + return BLOCK_TO_ITEM.getOrDefault(block, Items.AIR); + } + + protected static void registerBlock(Block block, Item item) { + BLOCK_TO_ITEM.put(block, item); + } + public static Builder builder() { return new Builder(); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index 0cdbe70f1..86572d60c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.auth.data.GameProfile; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; @@ -34,9 +35,9 @@ import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -public class PlayerHeadItem extends Item { - public PlayerHeadItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); +public class PlayerHeadItem extends BlockItem { + public PlayerHeadItem(Builder builder, Block block, Block... otherBlocks) { + super(builder, block, otherBlocks); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index 6b2d589d6..a539fa739 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -30,6 +30,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -42,8 +43,8 @@ import java.util.ArrayList; import java.util.List; public class ShulkerBoxItem extends BlockItem { - public ShulkerBoxItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); + public ShulkerBoxItem(Builder builder, Block block, Block... otherBlocks) { + super(builder, block, otherBlocks); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index a64e5c1c8..9b390f6ee 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -249,25 +249,6 @@ public final class BlockStateValues { return ALL_CAULDRONS.contains(state); } - /** - * All double chest values are part of the block state in Java and part of the block entity tag in Bedrock. - * This gives the DoubleChestValue that can be calculated into the final tag. - * - * @return The map of all DoubleChestValues. - */ - public static Int2ObjectMap getDoubleChestValues() { - return DOUBLE_CHEST_VALUES; - } - - /** - * Get the Int2ObjectMap of flower pot block states to containing plant - * - * @return Int2ObjectMap of flower pot values - */ - public static Int2ObjectMap getFlowerPotValues() { - return FLOWER_POT_VALUES; - } - /** * @return a set of all forward-facing jigsaws, to use as a fallback if NBT is missing. */ @@ -282,26 +263,6 @@ public final class BlockStateValues { return LECTERN_BOOK_STATES; } - /** - * The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock. - * This gives an integer pitch that Bedrock can use. - * - * @param state BlockState of the block - * @return note block note integer or -1 if not present - */ - public static int getNoteblockPitch(int state) { - return NOTEBLOCK_PITCHES.getOrDefault(state, -1); - } - - /** - * Get the Int2BooleanMap showing if a piston block state is extended or not. - * - * @return the Int2BooleanMap of piston extensions. - */ - public static Int2BooleanMap getPistonValues() { - return PISTON_VALUES; - } - public static boolean isStickyPiston(int blockState) { return STICKY_PISTONS.contains(blockState); } @@ -435,16 +396,6 @@ public final class BlockStateValues { return WATER_LEVEL.getOrDefault(state, -1); } - /** - * Check if a block is the upper half of a door. - * - * @param state BlockState of the block - * @return True if the block is the upper half of a door - */ - public static boolean isUpperDoor(int state) { - return UPPER_DOORS.contains(state); - } - /** * Get the height of water from the block state * This is used in FishingHookEntity to create splash sounds when the hook hits the water. In addition, 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 142708dd9..485d52161 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 @@ -82,7 +82,7 @@ public final class Blocks { .intState(STAGE, 0, 1) .booleanState(WATERLOGGED))); public static final Block BEDROCK = register(new Block("bedrock", builder().destroyTime(-1.0f))); - public static final Block WATER = register(new Block("water", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block WATER = register(new WaterBlock("water", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) .intState(LEVEL, 0, 15))); public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) .intState(LEVEL, 0, 15))); @@ -379,7 +379,7 @@ public final class Blocks { .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 Block("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); + public static final Block SPAWNER = register(new SpawnerBlock("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); 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, "top", "bottom") @@ -403,7 +403,7 @@ public final class Blocks { .intState(AGE_7, 0, 7))); public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f) .intState(MOISTURE, 0, 7))); - public static final Block FURNACE = register(new Block("furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) + public static final Block FURNACE = register(new FurnaceBlock("furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) .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().destroyTime(1.0f) @@ -823,10 +823,10 @@ public final class Blocks { .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 Block("water_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, 1, 3))); - public static final Block LAVA_CAULDRON = register(new Block("lava_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); - public static final Block POWDER_SNOW_CAULDRON = register(new Block("powder_snow_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) + 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, 1, 3))); public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); public static final Block END_PORTAL_FRAME = register(new Block("end_portal_frame", builder().destroyTime(-1.0f) @@ -2179,7 +2179,7 @@ public final class Blocks { public static final Block BEEHIVE = register(new Block("beehive", builder().setBlockEntity().destroyTime(0.6f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .intState(LEVEL_HONEY, 0, 5))); - public static final Block HONEY_BLOCK = register(new Block("honey_block", builder())); + 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))); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java b/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java index da68c54e4..ca5f62daa 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java @@ -32,6 +32,10 @@ public class Property> { this.name = name; } + public String name() { + return name; + } + @Override public String toString() { return getClass().getSimpleName() + "[" + name + "]"; diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index 3114f31f9..491894a35 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -25,21 +25,24 @@ package org.geysermc.geyser.level.block.type; -import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; +import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.property.Property; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.mcprotocollib.protocol.data.game.Identifier; +import org.intellij.lang.annotations.Subst; import java.util.*; import java.util.stream.Stream; @@ -47,20 +50,21 @@ import java.util.stream.Stream; public class Block { public static final int JAVA_AIR_ID = 0; - private final String javaIdentifier; + private final Key javaIdentifier; private final boolean requiresCorrectToolForDrops; private final boolean hasBlockEntity; private final float destroyTime; private final @NonNull PistonBehavior pushReaction; + protected Item item = null; private int javaId = -1; - public Block(String javaIdentifier, Builder builder) { - this.javaIdentifier = Identifier.formalize(javaIdentifier).intern(); + public Block(@Subst("empty") String javaIdentifier, Builder builder) { + this.javaIdentifier = Key.key(javaIdentifier); this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops; this.hasBlockEntity = builder.hasBlockEntity; this.destroyTime = builder.destroyTime; this.pushReaction = builder.pushReaction; - builder.build(this); + processStates(builder.build(this)); } public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { @@ -114,7 +118,8 @@ public class Block { UpdateBlockPacket waterPacket = new UpdateBlockPacket(); waterPacket.setDataLayer(1); waterPacket.setBlockPosition(position); - if (BlockRegistries.WATERLOGGED.get().get(state.javaId())) { + Boolean waterlogged = state.getValue(Properties.WATERLOGGED); + if (waterlogged == Boolean.TRUE) { waterPacket.setDefinition(session.getBlockMappings().getBedrockWater()); } else { waterPacket.setDefinition(session.getBlockMappings().getBedrockAir()); @@ -129,7 +134,21 @@ public class Block { } } - public String javaIdentifier() { + public Item asItem() { + if (this.item == null) { + return this.item = Item.byBlock(this); + } + return this.item; + } + + /** + * A list of BlockStates is created pertaining to this block. Do we need any of them? If so, override this method. + */ + protected void processStates(List states) { + } + + @NonNull + public Key javaIdentifier() { return javaIdentifier; } @@ -163,7 +182,7 @@ public class Block { @Override public String toString() { - return "Item{" + + return "Block{" + "javaIdentifier='" + javaIdentifier + '\'' + ", javaId=" + javaId + '}'; @@ -229,14 +248,27 @@ public class Block { return this; } - private void build(Block block) { + private List build(Block block) { if (states.isEmpty()) { - BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size())); + BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size()); + BlockRegistries.BLOCK_STATES.get().add(state); + return List.of(state); + } else if (states.size() == 1) { + // We can optimize because we don't need to worry about combinations + Map.Entry, List>> property = this.states.entrySet().stream().findFirst().orElseThrow(); + List states = new ArrayList<>(property.getValue().size()); + property.getValue().forEach(value -> { + Reference2ObjectMap, Comparable> propertyMap = Reference2ObjectMaps.singleton(property.getKey(), value); + BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap); + BlockRegistries.BLOCK_STATES.get().add(state); + states.add(state); + }); + return states; } else { // Think of this stream as another list containing, at the start, one empty list. // It's two collections. Not a stream from the empty list. - Stream, Comparable>>> stream = Stream.of(Collections.emptyList()); - for (var state : this.states.entrySet()) { + Stream>> stream = Stream.of(Collections.emptyList()); + for (var values : this.states.values()) { // OK, so here's how I understand this works. Because this was staring at vanilla Java code trying // to figure out exactly how it works so we don't have any discrepencies. // For each existing pair in the list, a new list is created, adding one of the new values. @@ -247,24 +279,29 @@ public class Block { // or it may be populated if this is not the first property. // We're about to create a new stream, each with a new list, // for every previous property - state.getValue().stream().map(value -> { + values.stream().map(value -> { var newProperties = new ArrayList<>(aPreviousPropertiesList); - newProperties.add(Pair.of(state.getKey(), value)); + newProperties.add(value); return newProperties; })); } + List states = new ArrayList<>(); // Now we have a list of Pairs. Each list is a block state! // If we have two boolean properties: up [true/false] and down [true/false], // We'll see [up=true,down=true], [up=false,down=true], [up=true,down=false], [up=false,down=false] - stream.forEach(properties -> { - Reference2ObjectMap, Comparable> propertyMap = new Reference2ObjectArrayMap<>(properties.size()); - for (int i = 0; i < properties.size(); i++) { - Pair, Comparable> property = properties.get(i); - propertyMap.put(property.key(), property.value()); - } - BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap)); + List>> result = stream.toList(); + // Ensure each block state shares the same key array. Creating a keySet here shouldn't be an issue since + // this states map should be removed after build. + Property[] keys = this.states.keySet().toArray(new Property[0]); + result.forEach(properties -> { + Comparable[] values = properties.toArray(new Comparable[0]); + Reference2ObjectMap, Comparable> propertyMap = new Reference2ObjectArrayMap<>(keys, values); + BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap); + BlockRegistries.BLOCK_STATES.get().add(state); + states.add(state); }); + return states; } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index de4806efa..cb375eaf9 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -30,6 +30,8 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps; import org.geysermc.geyser.level.block.property.Property; import org.geysermc.geyser.registry.BlockRegistries; +import java.util.Locale; + public final class BlockState { private final Block block; private final int javaId; @@ -62,12 +64,25 @@ public final class BlockState { return this.block == block; } + @Override + public String toString() { + if (this.states.isEmpty()) { + return this.block.javaIdentifier().toString(); + } + return this.block.javaIdentifier().toString() + "[" + paramsToString() + "]"; + } + private String paramsToString() { StringBuilder builder = new StringBuilder(); var it = this.states.entrySet().iterator(); while (it.hasNext()) { var entry = it.next(); - builder.append(entry.getKey()).append("=").append(entry.getValue()); + builder.append(entry.getKey().name()) + .append("=") + .append(entry.getValue().toString().toLowerCase(Locale.ROOT)); // lowercase covers enums + if (it.hasNext()) { + builder.append(","); + } } return builder.toString(); } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java index 8c911ad97..53d0b1ec1 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java @@ -68,7 +68,7 @@ public class FlowerPotBlock extends Block implements BedrockChunkWantsBlockEntit if (this.flower != Blocks.AIR) { // Get the Bedrock CompoundTag of the block. // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. - NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(this.flower.javaIdentifier()); + NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(this.flower.javaIdentifier().asString()); if (plant != null) { tagBuilder.putCompound("PlantBlock", plant.toBuilder().build()); } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/FurnaceBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/FurnaceBlock.java new file mode 100644 index 000000000..2b898e089 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/FurnaceBlock.java @@ -0,0 +1,56 @@ +/* + * 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.level.block.type; + +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.physics.Direction; + +import java.util.List; + +public class FurnaceBlock extends Block { + private static BlockState LIT; + private static BlockState UNLIT; + + public FurnaceBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void processStates(List states) { + LIT = states.stream() + .filter(state -> state.getValue(Properties.HORIZONTAL_FACING) == Direction.NORTH + && state.getValue(Properties.LIT)) + .findFirst().orElseThrow(); + UNLIT = states.stream() + .filter(state -> state.getValue(Properties.HORIZONTAL_FACING) == Direction.NORTH + && !state.getValue(Properties.LIT)) + .findFirst().orElseThrow(); + } + + public static BlockState state(boolean lit) { + return lit ? LIT : UNLIT; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/HoneyBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/HoneyBlock.java new file mode 100644 index 000000000..73c4d02aa --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/HoneyBlock.java @@ -0,0 +1,45 @@ +/* + * 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.level.block.type; + +import java.util.List; + +public class HoneyBlock extends Block { + private static BlockState STATE; + + public HoneyBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void processStates(List states) { + STATE = states.get(0); + } + + public static BlockState state() { + return STATE; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/SpawnerBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/SpawnerBlock.java new file mode 100644 index 000000000..2103fe6e5 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/SpawnerBlock.java @@ -0,0 +1,45 @@ +/* + * 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.level.block.type; + +import java.util.List; + +public class SpawnerBlock extends Block { + private static BlockState STATE; + + public SpawnerBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void processStates(List states) { + STATE = states.get(0); + } + + public static BlockState state() { + return STATE; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/WaterBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/WaterBlock.java new file mode 100644 index 000000000..801a7f9e7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/WaterBlock.java @@ -0,0 +1,41 @@ +/* + * 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.level.block.type; + +import java.util.List; + +public class WaterBlock extends Block { + private static BlockState LEVEL_0; + + public WaterBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void processStates(List states) { + super.processStates(states); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 416ab7793..a18ffff7d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -147,6 +147,7 @@ public class BlockRegistries { CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.POST_INIT); + System.out.println("Block registries loaded"); } public static void init() { 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 54d013140..7f0d9013a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -204,5 +204,6 @@ public final class Registries { biomesNbt.put(key, value.build()); } BIOMES_NBT.set(biomesNbt.build()); + System.out.println("Registries loaded"); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java index 7cf39b6d7..2cd7f82d6 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java @@ -106,7 +106,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader, CollisionInfo> annotationMap, int collisionIndex, List collisionList) { - String blockName = state.block().javaIdentifier().substring("minecraft:".length()); + String blockName = state.block().javaIdentifier().value(); for (Map.Entry, CollisionInfo> collisionRemappers : annotationMap.entrySet()) { Class type = collisionRemappers.getKey(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 66301cef2..0180fc8b7 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -50,10 +50,12 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.GeyserBedrockBlock; @@ -391,7 +393,7 @@ public final class BlockRegistryPopulator { throw new AssertionError("Unable to load Java block mappings", e); } - JAVA_BLOCKS_SIZE = blocksJson.size(); + JAVA_BLOCKS_SIZE = BlockRegistries.BLOCK_STATES.get().size(); if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) { MIN_CUSTOM_RUNTIME_ID = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet().stream().min(Comparator.comparing(JavaBlockState::javaId)).orElseThrow().javaId(); @@ -409,12 +411,6 @@ public final class BlockRegistryPopulator { Deque cleanIdentifiers = new ArrayDeque<>(); int javaRuntimeId = -1; - int furnaceRuntimeId = -1; - int furnaceLitRuntimeId = -1; - int honeyBlockRuntimeId = -1; - int slimeBlockRuntimeId = -1; - int spawnerRuntimeId = -1; - int uniqueJavaId = -1; int waterRuntimeId = -1; Iterator> blocksIterator = blocksJson.fields(); while (blocksIterator.hasNext()) { @@ -422,7 +418,6 @@ public final class BlockRegistryPopulator { Map.Entry entry = blocksIterator.next(); String javaId = entry.getKey(); - // TODO fix this, (no block should have a null hardness) BlockMapping.BlockMappingBuilder builder = BlockMapping.builder(); JsonNode pickItemNode = entry.getValue().get("pick_item"); @@ -443,7 +438,6 @@ public final class BlockRegistryPopulator { String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); if (!cleanJavaIdentifier.equals(cleanIdentifiers.peekLast())) { - uniqueJavaId++; cleanIdentifiers.add(cleanJavaIdentifier.intern()); } @@ -456,50 +450,11 @@ public final class BlockRegistryPopulator { // It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern()); - if (javaId.startsWith("minecraft:furnace[facing=north")) { - if (javaId.contains("lit=true")) { - furnaceLitRuntimeId = javaRuntimeId; - } else { - furnaceRuntimeId = javaRuntimeId; - } - - } else if (javaId.startsWith("minecraft:spawner")) { - spawnerRuntimeId = javaRuntimeId; - - } else if ("minecraft:water[level=0]".equals(javaId)) { + if ("minecraft:water[level=0]".equals(javaId)) { waterRuntimeId = javaRuntimeId; - } else if (javaId.equals("minecraft:honey_block")) { - honeyBlockRuntimeId = javaRuntimeId; - } else if (javaId.equals("minecraft:slime_block")) { - slimeBlockRuntimeId = javaRuntimeId; } } - if (furnaceRuntimeId == -1) { - throw new AssertionError("Unable to find furnace in palette"); - } - BlockStateValues.JAVA_FURNACE_ID = furnaceRuntimeId; - - if (furnaceLitRuntimeId == -1) { - throw new AssertionError("Unable to find lit furnace in palette"); - } - BlockStateValues.JAVA_FURNACE_LIT_ID = furnaceLitRuntimeId; - - if (honeyBlockRuntimeId == -1) { - throw new AssertionError("Unable to find honey block in palette"); - } - BlockStateValues.JAVA_HONEY_BLOCK_ID = honeyBlockRuntimeId; - - if (slimeBlockRuntimeId == -1) { - throw new AssertionError("Unable to find slime block in palette"); - } - BlockStateValues.JAVA_SLIME_BLOCK_ID = slimeBlockRuntimeId; - - if (spawnerRuntimeId == -1) { - throw new AssertionError("Unable to find spawner in palette"); - } - BlockStateValues.JAVA_SPAWNER_ID = spawnerRuntimeId; - if (waterRuntimeId == -1) { throw new AssertionError("Unable to find Java water in palette"); } @@ -534,12 +489,20 @@ public final class BlockRegistryPopulator { builder.setBlockEntity(); } String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier()); - Block block = new Block(cleanJavaIdentifier, builder); + String pickItem = javaBlockState.pickItem(); + Block block = new Block(cleanJavaIdentifier, builder) { + @Override + public Item asItem() { + if (this.item == null) { + return Registries.JAVA_ITEM_IDENTIFIERS.get(pickItem); + } + return this.item; + } + }; String bedrockIdentifier = customBlockState.block().identifier(); if (!cleanJavaIdentifier.equals(cleanIdentifiers.peekLast())) { - uniqueJavaId++; cleanIdentifiers.add(cleanJavaIdentifier.intern()); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java index d6ee55965..0520924f8 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java @@ -28,7 +28,6 @@ package org.geysermc.geyser.registry.type; import lombok.Builder; import lombok.Value; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.util.BlockUtils; @Builder @Value @@ -37,42 +36,8 @@ public class BlockMapping { String javaIdentifier; - boolean canBreakWithHand; @Nullable String pickItem; boolean isBlockEntity; boolean isNonVanilla; - - /** - * @return the identifier without the additional block states - */ - public String getCleanJavaIdentifier() { - return BlockUtils.getCleanIdentifier(javaIdentifier); - } - - /** - * @return the corresponding Java identifier for this item - */ - public String getItemIdentifier() { - if (pickItem != null && !pickItem.equals("minecraft:air")) { - // Spawners can have air as their pick item which we are not interested in. - return pickItem; - } - - return getCleanJavaIdentifier(); - } - - /** - * Get the item a Java client would receive when pressing - * the Pick Block key on a specific Java block state. - * - * @return The Java identifier of the item - */ - public String getPickItem() { - if (pickItem != null) { - return pickItem; - } - - return getCleanJavaIdentifier(); - } } 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 144cd9f27..c85c0fd28 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -97,6 +97,7 @@ import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.physics.CollisionManager; @@ -349,7 +350,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private Vector3i lastBlockPlacePosition; @Setter - private String lastBlockPlacedId; + private BlockItem lastBlockPlaced; @Setter private boolean interacting; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java index ac6e9870e..2dfa2a85a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java @@ -30,6 +30,7 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.holder.InventoryHolder; import org.geysermc.geyser.inventory.updater.InventoryUpdater; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; /** @@ -44,10 +45,10 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran * @param javaBlockIdentifier a Java block identifier that is used as a temporary block * @param containerType the container type of this inventory * @param updater updater - * @param additionalValidBlocks any other block identifiers that can safely use this inventory without a fake block + * @param additionalValidBlocks any other blocks that can safely use this inventory without a fake block */ public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater, - String... additionalValidBlocks) { + Block... additionalValidBlocks) { super(size); this.holder = new BlockInventoryHolder(javaBlockIdentifier, containerType, additionalValidBlocks); this.updater = updater; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java index 2da51a0eb..705fac362 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java @@ -37,6 +37,7 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.updater.AnvilInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; @@ -45,7 +46,7 @@ import java.util.Objects; public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { super(3, "minecraft:anvil[facing=north]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE, - "minecraft:chipped_anvil", "minecraft:damaged_anvil"); + Blocks.CHIPPED_ANVIL, Blocks.DAMAGED_ANVIL); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java index 2a80161c0..f47a367d8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java @@ -32,6 +32,7 @@ import org.geysermc.geyser.inventory.Generic3X3Container; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; @@ -41,7 +42,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator { public Generic3X3InventoryTranslator() { super(9, "minecraft:dispenser[facing=north,triggered=false]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE, - "minecraft:dropper"); + Blocks.DROPPER); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java index 795eba101..72f5260a0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java @@ -52,14 +52,14 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator } @Override - protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, int javaBlockState) { + protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) { NbtMapBuilder tag = NbtMap.builder() .putInt("x", position.getX()) .putInt("y", position.getY()) .putInt("z", position.getZ()) .putString("CustomName", inventory.getTitle()); // Don't reset facing property - shulkerBoxTranslator.translateTag(session, tag, null, BlockState.of(javaBlockState)); + shulkerBoxTranslator.translateTag(session, tag, null, javaBlockState); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag.build()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java index d09e7e990..e18096862 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java @@ -29,15 +29,17 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.holder.InventoryHolder; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; public class SingleChestInventoryTranslator extends ChestInventoryTranslator { private final InventoryHolder holder; + // TODO add barrel??? public SingleChestInventoryTranslator(int size) { super(size, 27); this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, - "minecraft:ender_chest", "minecraft:trapped_chest") { + Blocks.ENDER_CHEST, Blocks.TRAPPED_CHEST) { @Override protected boolean isValidBlock(String[] javaBlockString) { if (javaBlockString[0].equals("minecraft:ender_chest")) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index 14282228b..ca8679319 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.objects.*; 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.level.block.type.HoneyBlock; import org.geysermc.geyser.level.block.type.PistonBlock; import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import org.cloudburstmc.math.vector.Vector3d; @@ -98,7 +99,7 @@ public class PistonBlockEntity { static { // Create a ~1 x ~0.5 x ~1 bounding box above the honey block - BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(BlockStateValues.JAVA_HONEY_BLOCK_ID); + BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(HoneyBlock.state().javaId()); if (blockCollision == null) { throw new RuntimeException("Failed to find honey block collision"); } @@ -622,11 +623,11 @@ public class PistonBlockEntity { } placedFinalBlocks = true; Vector3i movement = getMovement(); - attachedBlocks.forEach((blockPos, javaId) -> { + attachedBlocks.forEach((blockPos, state) -> { blockPos = blockPos.add(movement); // Don't place blocks that collide with the player if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { - ChunkUtils.updateBlock(session, javaId, blockPos); + ChunkUtils.updateBlock(session, state, blockPos); } }); if (action == PistonValueType.PUSHING) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 507d67ba5..be3af2061 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -29,11 +29,10 @@ import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.ItemFrameEntity; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.type.BannerBlock; import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.BlockMapping; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -46,10 +45,10 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator session.ensureInEventLoop(() -> { if (components == null) { - pickItem(session, blockMapping); + pickItem(session, blockToPick); return; } - // I don't really like this... I'd rather get an ID from the block mapping I think - ItemMapping mapping = session.getItemMappings().getMapping(blockMapping.getPickItem()); - - ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), 1, components); + ItemStack itemStack = new ItemStack(blockToPick.asItem().javaId(), 1, components); InventoryUtils.findOrCreateItem(session, itemStack); })); return; } - pickItem(session, blockMapping); + pickItem(session, blockToPick); } - private void pickItem(GeyserSession session, BlockMapping blockToPick) { - InventoryUtils.findOrCreateItem(session, blockToPick.getPickItem()); + private void pickItem(GeyserSession session, Block block) { + InventoryUtils.findOrCreateItem(session, block.asItem()); } } 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 9c6a1cb56..78745aeb8 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 @@ -355,9 +355,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator * This attempts to mimic Java Edition behavior as best as it can. * @param session the Bedrock client's session - * @param itemName the Java identifier of the item to search/select + * @param item the Java item to search/select for */ - public static void findOrCreateItem(GeyserSession session, String itemName) { + public static void findOrCreateItem(GeyserSession session, Item item) { // Get the inventory to choose a slot to pick PlayerInventory inventory = session.getPlayerInventory(); - if (itemName.equals("minecraft:air")) { + if (item == Items.AIR) { return; } @@ -326,7 +332,7 @@ public class InventoryUtils { continue; } // If this isn't the item we're looking for - if (!geyserItem.asItem().javaIdentifier().equals(itemName)) { + if (!geyserItem.asItem().equals(item)) { continue; } @@ -342,7 +348,7 @@ public class InventoryUtils { continue; } // If this isn't the item we're looking for - if (!geyserItem.asItem().javaIdentifier().equals(itemName)) { + if (!geyserItem.asItem().equals(item)) { continue; } @@ -355,17 +361,13 @@ public class InventoryUtils { if (session.getGameMode() == GameMode.CREATIVE) { int slot = findEmptyHotbarSlot(inventory); - ItemMapping mapping = session.getItemMappings().getMapping(itemName); // TODO - if (mapping != null) { - ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket((short)slot, - new ItemStack(mapping.getJavaItem().javaId())); - if ((slot - 36) != inventory.getHeldItemSlot()) { - setHotbarItem(session, slot); - } - session.sendDownstreamGamePacket(actionPacket); - } else { - session.getGeyser().getLogger().debug("Cannot find item for block " + itemName); + 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); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index 8f9be0b98..7e1227f6c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -96,7 +96,7 @@ public class StatisticsUtils { if (entry.getKey() instanceof BreakBlockStatistic statistic) { Block block = BlockRegistries.JAVA_BLOCKS_TO_RENAME.get(statistic.getId()); if (block != null) { - String identifier = block.javaIdentifier().replace("minecraft:", "block.minecraft."); + String identifier = "block.minecraft." + block.javaIdentifier().value(); content.add(identifier + ": " + entry.getIntValue()); } } From 1e9dbaf38be7895f0d44f408c56c64ef87ff3947 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 18 May 2024 16:54:42 -0400 Subject: [PATCH 149/897] Here is the Spigot change --- .../platform/spigot/world/GeyserSpigotBlockPlaceListener.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java index b5f4bd4f9..1cdd77c64 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java @@ -33,7 +33,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.registry.BlockRegistries; @@ -65,6 +64,6 @@ public class GeyserSpigotBlockPlaceListener implements Listener { placeBlockSoundPacket.setIdentifier(":"); session.sendUpstreamPacket(placeBlockSoundPacket); session.setLastBlockPlacePosition(null); - session.setLastBlockPlacedId(null); + session.setLastBlockPlaced(null); } } From d85549c38dd404ade6aa364990c53548f8f4fea3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 19 May 2024 20:24:19 -0400 Subject: [PATCH 150/897] BlockMapping is removed --- .../java/org/geysermc/geyser/GeyserImpl.java | 11 - .../geyser/entity/type/ItemEntity.java | 3 +- .../type/living/merchant/VillagerEntity.java | 39 ++-- .../entity/type/player/SkullPlayerEntity.java | 26 ++- .../geysermc/geyser/inventory/Container.java | 5 +- .../geyser/inventory/Generic3X3Container.java | 8 +- .../holder/BlockInventoryHolder.java | 2 +- .../geysermc/geyser/level/WorldManager.java | 6 +- .../geyser/level/block/BlockStateValues.java | 220 ++---------------- .../geysermc/geyser/level/block/Blocks.java | 82 +++---- .../geyser/level/block/DoubleChestValue.java | 40 ---- .../geyser/level/block/type/Block.java | 37 ++- .../geyser/level/block/type/BlockState.java | 10 +- .../level/block/type/FlowerPotBlock.java | 16 +- .../geyser/level/block/type/SkullBlock.java | 46 +++- .../block/type/WallSkullBlock.java} | 34 +-- .../geyser/registry/BlockRegistries.java | 15 +- .../populator/BlockRegistryPopulator.java | 176 ++++++-------- .../geyser/registry/type/BlockMappings.java | 3 +- .../geyser/session/cache/SkullCache.java | 27 ++- .../chest/DoubleChestInventoryTranslator.java | 28 +-- .../entity/SkullBlockEntityTranslator.java | 15 +- .../BedrockBlockPickRequestTranslator.java | 16 +- ...BedrockInventoryTransactionTranslator.java | 23 +- .../player/BedrockActionTranslator.java | 28 +-- .../BedrockLevelSoundEventTranslator.java | 15 +- .../level/JavaBlockEntityDataTranslator.java | 2 +- .../java/level/JavaBlockUpdateTranslator.java | 10 +- .../JavaLevelChunkWithLightTranslator.java | 5 +- .../geysermc/geyser/util/StatisticsUtils.java | 2 +- .../util/collection/FixedInt2BooleanMap.java | 120 ---------- .../util/collection/FixedInt2ByteMap.java | 121 ---------- .../util/collection/FixedInt2IntMap.java | 120 ---------- .../util/collection/LecternHasBookMap.java | 75 ------ .../geyser/util/collection/package-info.java | 34 --- core/src/main/resources/mappings | 2 +- .../collection/GeyserCollectionsTest.java | 181 -------------- 37 files changed, 378 insertions(+), 1225 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java rename core/src/main/java/org/geysermc/geyser/{registry/type/BlockMapping.java => level/block/type/WallSkullBlock.java} (58%) delete mode 100644 core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2BooleanMap.java delete mode 100644 core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2ByteMap.java delete mode 100644 core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2IntMap.java delete mode 100644 core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java delete mode 100644 core/src/main/java/org/geysermc/geyser/util/collection/package-info.java delete mode 100644 core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 7be1fe15b..a60a14ea0 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -256,17 +256,6 @@ public class GeyserImpl implements GeyserApi { } VersionCheckUtils.checkForOutdatedJava(logger); - - for (int i = 0; i < BlockRegistries.JAVA_BLOCKS.get().length; i++) { - String oldIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getJavaIdentifier(); - String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).toString(); - if (!oldIdentifier.equals(newIdentifier)) { - System.out.println("Check block " + oldIdentifier + " " + newIdentifier); - break; - } - } - System.out.println(BlockRegistries.JAVA_BLOCKS.get().length); - System.out.println(BlockRegistries.BLOCK_STATES.get().size()); } private void startInstance() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java index ead717b34..49eb9ddc4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java @@ -34,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.packet.AddItemEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; @@ -137,7 +138,7 @@ public class ItemEntity extends ThrowableEntity { protected float getDrag() { if (isOnGround()) { Vector3i groundBlockPos = position.toInt().down(1); - int blockState = session.getGeyser().getWorldManager().getBlockAt(session, groundBlockPos); + BlockState blockState = session.getGeyser().getWorldManager().blockAt(session, groundBlockPos); return BlockStateValues.getSlipperiness(blockState) * 0.98f; } return 0.98f; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java index 3c2160a2b..fb07572e6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java @@ -33,8 +33,8 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.BlockMapping; +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.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData; @@ -119,28 +119,29 @@ public class VillagerEntity extends AbstractMerchantEntity { } // The bed block - int blockId = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition); - String fullIdentifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(blockId, BlockMapping.DEFAULT).getJavaIdentifier(); + BlockState state = session.getGeyser().getWorldManager().blockAt(session, bedPosition); // Set the correct position offset and rotation when sleeping int bedRotation = 0; float xOffset = 0; float zOffset = 0; - if (fullIdentifier.contains("facing=south")) { - // bed is facing south - bedRotation = 180; - zOffset = -.5f; - } else if (fullIdentifier.contains("facing=east")) { - // bed is facing east - bedRotation = 90; - xOffset = -.5f; - } else if (fullIdentifier.contains("facing=west")) { - // bed is facing west - bedRotation = 270; - xOffset = .5f; - } else if (fullIdentifier.contains("facing=north")) { - // rotation does not change because north is 0 - zOffset = .5f; + switch (state.getValue(Properties.HORIZONTAL_FACING)) { + case SOUTH -> { + bedRotation = 180; + zOffset = -.5f; + } + case EAST -> { + bedRotation = 90; + xOffset = -.5f; + } + case WEST -> { + bedRotation = 270; + xOffset = .5f; + } + case NORTH -> { + // rotation does not change because north is 0 + zOffset = .5f; + } } setYaw(yaw); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java index 89f9c37d6..f2f93b266 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java @@ -34,7 +34,10 @@ import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.type.WallSkullBlock; +import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.skin.SkullSkinManager; @@ -137,20 +140,19 @@ public class SkullPlayerEntity extends PlayerEntity { float z = skull.getPosition().getZ() + .5f; float rotation; - int blockState = skull.getBlockState(); - byte floorRotation = BlockStateValues.getSkullRotation(blockState); - if (floorRotation == -1) { - // Wall skull + BlockState blockState = skull.getBlockState(); + if (blockState.block() instanceof WallSkullBlock) { y += 0.25f; - rotation = BlockStateValues.getSkullWallDirections().get(blockState); - switch ((int) rotation) { - case 180 -> z += 0.24f; // North - case 0 -> z -= 0.24f; // South - case 90 -> x += 0.24f; // West - case 270 -> x -= 0.24f; // East + Direction direction = blockState.getValue(Properties.HORIZONTAL_FACING); + rotation = WallSkullBlock.getDegrees(direction); + switch (direction) { + case NORTH -> z += 0.24f; + case SOUTH -> z -= 0.24f; + case WEST -> x += 0.24f; + case EAST -> x -= 0.24f; } } else { - rotation = (180f + (floorRotation * 22.5f)) % 360; + rotation = (180f + (blockState.getValue(Properties.ROTATION_16) * 22.5f)) % 360; } moveAbsolute(Vector3f.from(x, y, z), rotation, 0, rotation, true, true); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Container.java index 209aeb24f..81818613f 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Container.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Container.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.inventory; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; @@ -83,9 +84,9 @@ public class Container extends Inventory { * Will be overwritten for droppers. * * @param usingRealBlock whether this container is using a real container or not - * @param javaBlockId the Java block string of the block, if real + * @param block the Java block, if real */ - public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) { + public void setUsingRealBlock(boolean usingRealBlock, Block block) { isUsingRealBlock = usingRealBlock; } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java index 65e47d877..0b14d1105 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.inventory; import lombok.Getter; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.Generic3X3InventoryTranslator; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; @@ -44,10 +46,10 @@ public class Generic3X3Container extends Container { } @Override - public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) { - super.setUsingRealBlock(usingRealBlock, javaBlockId); + public void setUsingRealBlock(boolean usingRealBlock, Block block) { + super.setUsingRealBlock(usingRealBlock, block); if (usingRealBlock) { - isDropper = javaBlockId.startsWith("minecraft:dropper"); + isDropper = block == Blocks.DROPPER; } } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index 686fe39ad..0a51d43ef 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -90,7 +90,7 @@ public class BlockInventoryHolder extends InventoryHolder { if (isValidBlock(javaBlockString)) { // We can safely use this block inventory.setHolderPosition(session.getLastInteractionBlockPosition()); - ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]); + ((Container) inventory).setUsingRealBlock(true, state.block()); setCustomName(session, session.getLastInteractionBlockPosition(), inventory, state); return true; diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index 5edce21dc..6cd9c3e26 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -59,10 +59,12 @@ import java.util.function.Function; */ public abstract class WorldManager { - public final BlockState blockAt(GeyserSession session, Vector3i vector3i) { - return BlockState.of(this.getBlockAt(session, vector3i)); + @NonNull + public final BlockState blockAt(GeyserSession session, Vector3i vector) { + return this.blockAt(session, vector.getX(), vector.getY(), vector.getZ()); } + @NonNull public BlockState blockAt(GeyserSession session, int x, int y, int z) { return BlockState.of(this.getBlockAt(session, x, y, z)); } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 9b390f6ee..8bc9cf1e2 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.level.block; -import com.fasterxml.jackson.databind.JsonNode; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -36,10 +35,6 @@ import org.geysermc.geyser.level.block.type.PistonBlock; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.BlockMapping; -import org.geysermc.geyser.util.collection.FixedInt2ByteMap; -import org.geysermc.geyser.util.collection.FixedInt2IntMap; -import org.geysermc.geyser.util.collection.LecternHasBookMap; import java.util.Locale; @@ -47,35 +42,13 @@ import java.util.Locale; * Used for block entities if the Java block state contains Bedrock block information. */ public final class BlockStateValues { - private static final IntSet ALL_CAULDRONS = new IntOpenHashSet(); - private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap(); - private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap(); - private static final Int2IntMap BRUSH_PROGRESS = new Int2IntOpenHashMap(); - private static final Int2ObjectMap DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>(); - private static final Int2ObjectMap FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>(); private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet(); - private static final LecternHasBookMap LECTERN_BOOK_STATES = new LecternHasBookMap(); - private static final IntSet NON_WATER_CAULDRONS = new IntOpenHashSet(); - private static final Int2IntMap NOTEBLOCK_PITCHES = new FixedInt2IntMap(); - private static final Int2BooleanMap PISTON_VALUES = new Int2BooleanOpenHashMap(); private static final IntSet STICKY_PISTONS = new IntOpenHashSet(); private static final Object2IntMap PISTON_HEADS = new Object2IntOpenHashMap<>(); private static final Int2ObjectMap PISTON_ORIENTATION = new Int2ObjectOpenHashMap<>(); private static final IntSet ALL_PISTON_HEADS = new IntOpenHashSet(); - private static final IntSet MOVING_PISTONS = new IntOpenHashSet(); - private static final Int2ByteMap SKULL_VARIANTS = new FixedInt2ByteMap(); - private static final IntSet SKULL_POWERED = new IntOpenHashSet(); - private static final Int2ByteMap SKULL_ROTATIONS = new Int2ByteOpenHashMap(); - private static final Int2IntMap SKULL_WALL_DIRECTIONS = new Int2IntOpenHashMap(); - private static final Int2ByteMap SHULKERBOX_DIRECTIONS = new FixedInt2ByteMap(); private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap(); - private static final IntSet UPPER_DOORS = new IntOpenHashSet(); - public static int JAVA_FURNACE_ID; - public static int JAVA_FURNACE_LIT_ID; - public static int JAVA_HONEY_BLOCK_ID; - public static int JAVA_SLIME_BLOCK_ID; - public static int JAVA_SPAWNER_ID; public static int JAVA_WATER_ID; public static final int NUM_WATER_LEVELS = 9; @@ -85,66 +58,9 @@ public final class BlockStateValues { * * @param javaId The Java Identifier of the block * @param javaBlockState the Java Block State of the block - * @param blockData JsonNode of info about the block from blocks.json */ - public static void storeBlockStateValues(String javaId, int javaBlockState, JsonNode blockData) { - JsonNode bannerColor = blockData.get("banner_color"); - if (bannerColor != null) { - BANNER_COLORS.put(javaBlockState, (byte) bannerColor.intValue()); - return; // There will never be a banner color and a skull variant - } - - JsonNode bedColor = blockData.get("bed_color"); - if (bedColor != null) { - BED_COLORS.put(javaBlockState, (byte) bedColor.intValue()); - return; - } - - JsonNode bedrockStates = blockData.get("bedrock_states"); - if (bedrockStates != null) { - JsonNode brushedProgress = bedrockStates.get("brushed_progress"); - if (brushedProgress != null) { - BRUSH_PROGRESS.put(javaBlockState, brushedProgress.intValue()); - return; - } - } - - if (blockData.get("double_chest_position") != null) { - boolean isX = (blockData.get("x") != null); - boolean isDirectionPositive = ((blockData.get("x") != null && blockData.get("x").asBoolean()) || - (blockData.get("z") != null && blockData.get("z").asBoolean())); - boolean isLeft = (blockData.get("double_chest_position").asText().contains("left")); - DOUBLE_CHEST_VALUES.put(javaBlockState, new DoubleChestValue(isX, isDirectionPositive, isLeft)); - return; - } - - if (javaId.startsWith("minecraft:potted_") || javaId.equals("minecraft:flower_pot")) { - String name = javaId.replace("potted_", ""); - if (name.contains("azalea")) { - // Exception to the rule - name = name.replace("_bush", ""); - } - FLOWER_POT_VALUES.put(javaBlockState, name); - return; - } - - if (javaId.startsWith("minecraft:lectern")) { - LECTERN_BOOK_STATES.put(javaBlockState, javaId.contains("has_book=true")); - return; - } - - JsonNode notePitch = blockData.get("note_pitch"); - if (notePitch != null) { - NOTEBLOCK_PITCHES.put(javaBlockState, blockData.get("note_pitch").intValue()); - return; - } - + public static void storeBlockStateValues(String javaId, int javaBlockState) { if (javaId.contains("piston[")) { // minecraft:moving_piston, minecraft:sticky_piston, minecraft:piston - if (javaId.startsWith("minecraft:moving_piston")) { - MOVING_PISTONS.add(javaBlockState); - } else { - PISTON_VALUES.put(javaBlockState, javaId.contains("extended=true")); - } if (javaId.contains("sticky")) { STICKY_PISTONS.add(javaBlockState); } @@ -158,40 +74,6 @@ public final class BlockStateValues { return; } - JsonNode skullVariation = blockData.get("variation"); - if (skullVariation != null) { - SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue()); - } - - JsonNode skullRotation = blockData.get("skull_rotation"); - if (skullRotation != null) { - SKULL_ROTATIONS.put(javaBlockState, (byte) skullRotation.intValue()); - } - - if (javaId.startsWith("minecraft:dragon_head[") || javaId.startsWith("minecraft:piglin_head[") - || javaId.startsWith("minecraft:dragon_wall_head[") || javaId.startsWith("minecraft:piglin_wall_head[")) { - if (javaId.contains("powered=true")) { - SKULL_POWERED.add(javaBlockState); - } - } - - if (javaId.contains("wall_skull") || javaId.contains("wall_head")) { - String direction = javaId.substring(javaId.lastIndexOf("facing=") + 7, javaId.lastIndexOf("powered=") - 1); - int rotation = switch (direction) { - case "north" -> 180; - case "west" -> 90; - case "east" -> 270; - default -> 0; // Also south - }; - SKULL_WALL_DIRECTIONS.put(javaBlockState, rotation); - } - - JsonNode shulkerDirection = blockData.get("shulker_direction"); - if (shulkerDirection != null) { - BlockStateValues.SHULKERBOX_DIRECTIONS.put(javaBlockState, (byte) shulkerDirection.intValue()); - return; - } - if (javaId.startsWith("minecraft:water") && !javaId.contains("cauldron")) { String strLevel = javaId.substring(javaId.lastIndexOf("level=") + 6, javaId.length() - 1); int level = Integer.parseInt(strLevel); @@ -205,48 +87,7 @@ public final class BlockStateValues { if (direction.isHorizontal()) { HORIZONTAL_FACING_JIGSAWS.add(javaBlockState); } - return; } - - if (javaId.contains("cauldron")) { - ALL_CAULDRONS.add(javaBlockState); - } - if (javaId.contains("_cauldron") && !javaId.contains("water_")) { - NON_WATER_CAULDRONS.add(javaBlockState); - } - - if (javaId.contains("_door[") && javaId.contains("half=upper")) { - UPPER_DOORS.add(javaBlockState); - } - } - - /** - * Banner colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives an integer color that Bedrock can use. - * - * @param state BlockState of the block - * @return Banner color integer or -1 if no color - */ - public static int getBannerColor(int state) { - return BANNER_COLORS.getOrDefault(state, -1); - } - - /** - * @return if this Java block state is a non-empty non-water cauldron - */ - public static boolean isNonWaterCauldron(int state) { - return NON_WATER_CAULDRONS.contains(state); - } - - /** - * Cauldrons (since Bedrock 1.18.30) must have a block entity packet sent on chunk load to fix rendering issues. - *

- * When using a bucket on a cauldron sending a ServerboundUseItemPacket can result in the liquid being placed. - * - * @return if this Java block state is a cauldron - */ - public static boolean isCauldron(int state) { - return ALL_CAULDRONS.contains(state); } /** @@ -256,13 +97,6 @@ public final class BlockStateValues { return HORIZONTAL_FACING_JIGSAWS; } - /** - * @return the lectern book state map pointing to book present state - */ - public static LecternHasBookMap getLecternBookStates() { - return LECTERN_BOOK_STATES; - } - public static boolean isStickyPiston(int blockState) { return STICKY_PISTONS.contains(blockState); } @@ -354,38 +188,6 @@ public final class BlockStateValues { }; } - /** - * Skull variations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives a byte variant ID that Bedrock can use. - * - * @param state BlockState of the block - * @return Skull variant byte or -1 if no variant - */ - public static byte getSkullVariant(int state) { - return SKULL_VARIANTS.getOrDefault(state, (byte) -1); - } - - /** - * Skull rotations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives a byte rotation that Bedrock can use. - * - * @param state BlockState of the block - * @return Skull rotation value or -1 if no value - */ - public static byte getSkullRotation(int state) { - return SKULL_ROTATIONS.getOrDefault(state, (byte) -1); - } - - /** - * Skull rotations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives a integer rotation that Bedrock can use. - * - * @return Skull wall rotation value with the blockstate - */ - public static Int2IntMap getSkullWallDirections() { - return SKULL_WALL_DIRECTIONS; - } - /** * Get the level of water from the block state. * @@ -427,14 +229,18 @@ public final class BlockStateValues { * @param state BlockState of the block * @return The block's slipperiness */ - public static float getSlipperiness(int state) { - String blockIdentifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(state, BlockMapping.DEFAULT).getJavaIdentifier(); - return switch (blockIdentifier) { - case "minecraft:slime_block" -> 0.8f; - case "minecraft:ice", "minecraft:packed_ice" -> 0.98f; - case "minecraft:blue_ice" -> 0.989f; - default -> 0.6f; - }; + public static float getSlipperiness(BlockState state) { + Block block = state.block(); + if (block == Blocks.SLIME_BLOCK) { + return 0.8f; + } + if (block == Blocks.ICE || block == Blocks.PACKED_ICE) { + return 0.98f; + } + if (block == Blocks.BLUE_ICE) { + return 0.989f; + } + return 0.6f; } private static Direction getBlockDirection(String javaId) { 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 485d52161..178887754 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.level.block; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.property.ChestType; import org.geysermc.geyser.level.block.type.*; import org.geysermc.geyser.level.physics.Axis; @@ -308,7 +309,7 @@ public final class Blocks { 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) + public static final Block TALL_SEAGRASS = register(new Block("tall_seagrass", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.SEAGRASS) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); public static final Block PISTON = register(new PistonBlock("piston", builder().destroyTime(1.5f).pushReaction(PistonBehavior.BLOCK) .booleanState(EXTENDED) @@ -758,9 +759,9 @@ public final class Blocks { .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) + 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))); - public static final Block ATTACHED_MELON_STEM = register(new Block("attached_melon_stem", builder().pushReaction(PistonBehavior.DESTROY) + 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))); public static final Block PUMPKIN_STEM = register(new Block("pumpkin_stem", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); @@ -963,46 +964,46 @@ public final class Blocks { .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block SKELETON_SKULL = register(new SkullBlock("skeleton_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block SKELETON_SKULL = register(new SkullBlock("skeleton_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block SKELETON_WALL_SKULL = register(new SkullBlock("skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block SKELETON_WALL_SKULL = register(new WallSkullBlock("skeleton_wall_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block WITHER_SKELETON_SKULL = register(new SkullBlock("wither_skeleton_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block WITHER_SKELETON_WALL_SKULL = register(new SkullBlock("wither_skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block WITHER_SKELETON_WALL_SKULL = register(new WallSkullBlock("wither_skeleton_wall_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block ZOMBIE_HEAD = register(new SkullBlock("zombie_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block ZOMBIE_HEAD = register(new SkullBlock("zombie_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block ZOMBIE_WALL_HEAD = register(new SkullBlock("zombie_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block ZOMBIE_WALL_HEAD = register(new WallSkullBlock("zombie_wall_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block PLAYER_HEAD = register(new SkullBlock("player_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block PLAYER_HEAD = register(new SkullBlock("player_head", SkullBlock.Type.PLAYER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block PLAYER_WALL_HEAD = register(new SkullBlock("player_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block PLAYER_WALL_HEAD = register(new WallSkullBlock("player_wall_head", SkullBlock.Type.PLAYER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block CREEPER_HEAD = register(new SkullBlock("creeper_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block CREEPER_HEAD = register(new SkullBlock("creeper_head", SkullBlock.Type.CREEPER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block CREEPER_WALL_HEAD = register(new SkullBlock("creeper_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block CREEPER_WALL_HEAD = register(new WallSkullBlock("creeper_wall_head", SkullBlock.Type.CREEPER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block DRAGON_HEAD = register(new SkullBlock("dragon_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block DRAGON_HEAD = register(new SkullBlock("dragon_head", SkullBlock.Type.DRAGON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block DRAGON_WALL_HEAD = register(new SkullBlock("dragon_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block DRAGON_WALL_HEAD = register(new WallSkullBlock("dragon_wall_head", SkullBlock.Type.DRAGON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block PIGLIN_HEAD = register(new SkullBlock("piglin_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block PIGLIN_HEAD = register(new SkullBlock("piglin_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block PIGLIN_WALL_HEAD = register(new SkullBlock("piglin_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block PIGLIN_WALL_HEAD = register(new WallSkullBlock("piglin_wall_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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) @@ -1694,7 +1695,7 @@ public final class Blocks { 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, 0, 25))); - public static final Block KELP_PLANT = register(new Block("kelp_plant", builder().pushReaction(PistonBehavior.DESTROY))); + 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, 1, 4) @@ -1787,7 +1788,7 @@ public final class Blocks { 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().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY))); + 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, 0, 1) .enumState(BAMBOO_LEAVES, "none", "small", "large") @@ -2072,10 +2073,10 @@ public final class Blocks { 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, 0, 25))); - public static final Block WEEPING_VINES_PLANT = register(new Block("weeping_vines_plant", builder().pushReaction(PistonBehavior.DESTROY))); + 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, 0, 25))); - public static final Block TWISTING_VINES_PLANT = register(new Block("twisting_vines_plant", builder().pushReaction(PistonBehavior.DESTROY))); + 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))); @@ -2319,39 +2320,39 @@ public final class Blocks { .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) .booleanState(LIT))); - public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); 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))); @@ -2682,7 +2683,7 @@ public final class Blocks { public static final Block CAVE_VINES = register(new Block("cave_vines", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25) .booleanState(BERRIES))); - public static final Block CAVE_VINES_PLANT = register(new Block("cave_vines_plant", builder().pushReaction(PistonBehavior.DESTROY) + public static final Block CAVE_VINES_PLANT = register(new Block("cave_vines_plant", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.GLOW_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))); @@ -2811,7 +2812,8 @@ public final class Blocks { .booleanState(WATERLOGGED))); private static T register(T block) { - BlockRegistries.JAVA_BLOCKS_TO_RENAME.get().add(block); + block.setJavaId(BlockRegistries.JAVA_BLOCKS.get().size()); + BlockRegistries.JAVA_BLOCKS.get().add(block); return block; } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java b/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java deleted file mode 100644 index 97c861df7..000000000 --- a/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java +++ /dev/null @@ -1,40 +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.level.block; - -/** - * This stores all values of double chests that are part of the Java block state. - * - * @param isFacingEast If true, then chest is facing east/west; if false, south/north - * @param isDirectionPositive If true, direction is positive (east/south); if false, direction is negative (west/north) - * @param isLeft If true, chest is the left of a pair; if false, chest is the right of a pair. - */ -public record DoubleChestValue( - boolean isFacingEast, - boolean isDirectionPositive, - boolean isLeft) { - -} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index 491894a35..b31c9aeb5 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -37,24 +37,33 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.Blocks; -import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.property.Property; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.intellij.lang.annotations.Subst; import java.util.*; +import java.util.function.Supplier; import java.util.stream.Stream; public class Block { public static final int JAVA_AIR_ID = 0; private final Key javaIdentifier; + /** + * Can you harvest this with your hand. + */ private final boolean requiresCorrectToolForDrops; private final boolean hasBlockEntity; private final float destroyTime; private final @NonNull PistonBehavior pushReaction; + /** + * Used for classes we don't have implemented yet that override Mojmap getCloneItemStack with their own item. + * A supplier prevents any issues arising where the Items class finishes before the Blocks class. + */ + private final Supplier pickItem; protected Item item = null; private int javaId = -1; @@ -64,10 +73,13 @@ public class Block { this.hasBlockEntity = builder.hasBlockEntity; this.destroyTime = builder.destroyTime; this.pushReaction = builder.pushReaction; + this.pickItem = builder.pickItem; processStates(builder.build(this)); } public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + checkForEmptySkull(session, state, position); + BlockDefinition definition = session.getBlockMappings().getBedrockBlock(state); sendBlockUpdatePacket(session, state, definition, position); @@ -118,8 +130,7 @@ public class Block { UpdateBlockPacket waterPacket = new UpdateBlockPacket(); waterPacket.setDataLayer(1); waterPacket.setBlockPosition(position); - Boolean waterlogged = state.getValue(Properties.WATERLOGGED); - if (waterlogged == Boolean.TRUE) { + if (BlockRegistries.WATERLOGGED.get().get(state.javaId())) { waterPacket.setDefinition(session.getBlockMappings().getBedrockWater()); } else { waterPacket.setDefinition(session.getBlockMappings().getBedrockAir()); @@ -127,6 +138,13 @@ public class Block { session.sendUpstreamPacket(waterPacket); } + protected void checkForEmptySkull(GeyserSession session, BlockState state, Vector3i position) { + if (!(state.block() instanceof SkullBlock)) { + // Skull is gone + session.getSkullCache().removeSkull(position); + } + } + protected void handleLecternBlockUpdate(GeyserSession session, BlockState state, Vector3i position) { // Block state is out of bounds of this map - lectern has been destroyed, if it existed if (!session.getGeyser().getWorldManager().shouldExpectLecternHandled(session)) { @@ -141,6 +159,13 @@ public class Block { return this.item; } + public ItemStack pickItem(BlockState state) { + if (this.pickItem != null) { + return new ItemStack(this.pickItem.get().javaId()); + } + return new ItemStack(this.asItem().javaId()); + } + /** * A list of BlockStates is created pertaining to this block. Do we need any of them? If so, override this method. */ @@ -198,6 +223,7 @@ public class Block { private boolean hasBlockEntity = false; private PistonBehavior pushReaction = PistonBehavior.NORMAL; private float destroyTime; + private Supplier pickItem; /** * For states that we're just tracking for mirroring Java states. @@ -248,6 +274,11 @@ public class Block { return this; } + public Builder pickItem(Supplier pickItem) { + this.pickItem = pickItem; + return this; + } + private List build(Block block) { if (states.isEmpty()) { BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size()); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index cb375eaf9..4fed30e7a 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -37,7 +37,7 @@ public final class BlockState { private final int javaId; private final Reference2ObjectMap, Comparable> states; - BlockState(Block block, int javaId) { + public BlockState(Block block, int javaId) { this(block, javaId, Reference2ObjectMaps.emptyMap()); } @@ -52,6 +52,14 @@ public final class BlockState { return (T) states.get(property); } + public boolean getValue(Property property, boolean def) { + var value = states.get(property); + if (value == null) { + return def; + } + return (Boolean) value; + } + public Block block() { return block; } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java index 53d0b1ec1..5107616af 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java @@ -34,6 +34,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; public class FlowerPotBlock extends Block implements BedrockChunkWantsBlockEntityTag { private final Block flower; @@ -68,11 +69,24 @@ public class FlowerPotBlock extends Block implements BedrockChunkWantsBlockEntit if (this.flower != Blocks.AIR) { // Get the Bedrock CompoundTag of the block. // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. - NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(this.flower.javaIdentifier().asString()); + // TODO flattening might make this nicer in the future! + NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(this.flower); if (plant != null) { tagBuilder.putCompound("PlantBlock", plant.toBuilder().build()); } } return tagBuilder.build(); } + + @Override + public ItemStack pickItem(BlockState state) { + if (this.flower != Blocks.AIR) { + return new ItemStack(this.flower.asItem().javaId()); + } + return super.pickItem(state); + } + + public Block flower() { + return flower; + } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java index 01a757eae..76b532919 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java @@ -27,28 +27,58 @@ package org.geysermc.geyser.level.block.type; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; public class SkullBlock extends Block { - public SkullBlock(String javaIdentifier, Builder builder) { + private final Type type; + + public SkullBlock(String javaIdentifier, Type type, Builder builder) { super(javaIdentifier, builder); + this.type = type; } @Override protected void sendBlockUpdatePacket(GeyserSession session, BlockState state, BlockDefinition definition, Vector3i position) { - int skullVariant = BlockStateValues.getSkullVariant(state.javaId()); // TODO - if (skullVariant == -1) { - // Skull is gone - session.getSkullCache().removeSkull(position); - } else if (skullVariant == 3) { + if (this.type == Type.PLAYER) { // The changed block was a player skull so check if a custom block was defined for this skull - SkullCache.Skull skull = session.getSkullCache().updateSkull(position, state.javaId()); + SkullCache.Skull skull = session.getSkullCache().updateSkull(position, state); if (skull != null && skull.getBlockDefinition() != null) { definition = skull.getBlockDefinition(); } } super.sendBlockUpdatePacket(session, state, definition, position); } + + @Override + protected void checkForEmptySkull(GeyserSession session, BlockState state, Vector3i position) { + // It's not an empty skull. + } + + public Type skullType() { + return type; + } + + /** + * Enum order matches Java. + */ + public enum Type { + SKELETON(0), + WITHER_SKELETON(1), + PLAYER(3), + ZOMBIE(2), + CREEPER(4), + PIGLIN(6), + DRAGON(5); + + private final int bedrockId; + + Type(int bedrockId) { + this.bedrockId = bedrockId; + } + + public int bedrockId() { + return bedrockId; + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java b/core/src/main/java/org/geysermc/geyser/level/block/type/WallSkullBlock.java similarity index 58% rename from core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java rename to core/src/main/java/org/geysermc/geyser/level/block/type/WallSkullBlock.java index 0520924f8..e8fedcc76 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/WallSkullBlock.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,21 +23,27 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.registry.type; +package org.geysermc.geyser.level.block.type; -import lombok.Builder; -import lombok.Value; -import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.physics.Direction; -@Builder -@Value -public class BlockMapping { - public static BlockMapping DEFAULT = BlockMapping.builder().javaIdentifier("minecraft:air").build(); +public class WallSkullBlock extends SkullBlock { + public WallSkullBlock(String javaIdentifier, Type type, Builder builder) { + super(javaIdentifier, type, builder); + } - String javaIdentifier; + public static int getDegrees(BlockState state) { + return getDegrees(state.getValue(Properties.HORIZONTAL_FACING)); + } - @Nullable String pickItem; - - boolean isBlockEntity; - boolean isNonVanilla; + public static int getDegrees(Direction direction) { + return switch (direction) { + case NORTH -> 180; + case WEST -> 90; + case EAST -> 270; + case SOUTH -> 0; + default -> throw new IllegalStateException(); + }; + } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index a18ffff7d..93ac5e457 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -42,7 +42,6 @@ import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.registry.populator.BlockRegistryPopulator; import org.geysermc.geyser.registry.populator.CustomBlockRegistryPopulator; import org.geysermc.geyser.registry.populator.CustomSkullRegistryPopulator; -import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.CustomSkull; import org.geysermc.geyser.translator.collision.BlockCollision; @@ -67,24 +66,22 @@ public class BlockRegistries { */ public static final ListRegistry BLOCK_STATES = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); - public static final ListRegistry JAVA_BLOCKS_TO_RENAME = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); - /** * A mapped registry which stores Java to Bedrock block identifiers. */ public static final SimpleMappedRegistry JAVA_TO_BEDROCK_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); - /** - * A registry which stores Java IDs to {@link BlockMapping}, containing miscellaneous information about - * blocks and their behavior in many cases. - */ - public static final ArrayRegistry JAVA_BLOCKS = ArrayRegistry.create(RegistryLoaders.uninitialized()); - /** * A mapped registry containing which holds block IDs to its {@link BlockCollision}. */ public static final ListRegistry COLLISIONS; + /** + * A registry which stores Java IDs to {@link Block}, containing miscellaneous information about + * blocks and their behavior in many cases. + */ + public static final ListRegistry JAVA_BLOCKS = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); + /** * A mapped registry containing the Java identifiers to IDs. */ diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 0180fc8b7..a0af4cfa0 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -32,13 +32,12 @@ import com.google.common.collect.Interner; import com.google.common.collect.Interners; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.*; import org.cloudburstmc.blockstateupdater.BlockStateUpdater; import org.cloudburstmc.blockstateupdater.util.tagupdater.CompoundTagUpdaterContext; -import org.cloudburstmc.nbt.NBTInputStream; -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.nbt.*; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; @@ -50,21 +49,26 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; -import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.BlockStateValues; +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.level.block.type.FlowerPotBlock; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.GeyserBedrockBlock; import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.io.DataInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.stream.Stream; import java.util.zip.GZIPInputStream; /** @@ -102,7 +106,7 @@ public final class BlockRegistryPopulator { public static void populate(Stage stage) { switch (stage) { - case PRE_INIT, POST_INIT -> nullifyBlocksNode(); + case PRE_INIT, POST_INIT -> nullifyBlocksNbt(); case INIT_JAVA -> registerJavaBlocks(); case INIT_BEDROCK -> registerBedrockBlocks(); default -> throw new IllegalArgumentException("Unknown stage: " + stage); @@ -110,14 +114,14 @@ public final class BlockRegistryPopulator { } /** - * Stores the raw blocks JSON until it is no longer needed. + * Stores the raw blocks NBT until it is no longer needed. */ - private static JsonNode BLOCKS_JSON; + private static List BLOCKS_NBT; private static int MIN_CUSTOM_RUNTIME_ID = -1; private static int JAVA_BLOCKS_SIZE = -1; - private static void nullifyBlocksNode() { - BLOCKS_JSON = null; + private static void nullifyBlocksNbt() { + BLOCKS_NBT = null; } private static void registerBedrockBlocks() { @@ -218,19 +222,31 @@ public final class BlockRegistryPopulator { int javaRuntimeId = -1; + List javaBlockStates = BlockRegistries.BLOCK_STATES.get(); + GeyserBedrockBlock airDefinition = null; BlockDefinition commandBlockDefinition = null; BlockDefinition mobSpawnerBlockDefinition = null; BlockDefinition waterDefinition = null; BlockDefinition movingBlockDefinition = null; - Iterator> blocksIterator = BLOCKS_JSON.fields(); + Iterator blocksIterator = BLOCKS_NBT.iterator(); Remapper stateMapper = blockMappers.get(palette); GeyserBedrockBlock[] javaToBedrockBlocks = new GeyserBedrockBlock[JAVA_BLOCKS_SIZE]; GeyserBedrockBlock[] javaToVanillaBedrockBlocks = new GeyserBedrockBlock[JAVA_BLOCKS_SIZE]; - Map flowerPotBlocks = new Object2ObjectOpenHashMap<>(); + // Stream isn't ideal. + List javaPottable = BlockRegistries.JAVA_BLOCKS.get() + .parallelStream() + .flatMap(block -> { + if (block instanceof FlowerPotBlock flowerPot && flowerPot.flower() != Blocks.AIR) { + return Stream.of(flowerPot.flower()); + } + return null; + }) + .toList(); + Map flowerPotBlocks = new Object2ObjectOpenHashMap<>(); Map itemFrames = new Object2ObjectOpenHashMap<>(); Set jigsawDefinitions = new ObjectOpenHashSet<>(); @@ -239,10 +255,11 @@ public final class BlockRegistryPopulator { BlockMappings.BlockMappingsBuilder builder = BlockMappings.builder(); while (blocksIterator.hasNext()) { javaRuntimeId++; - Map.Entry entry = blocksIterator.next(); - String javaId = entry.getKey(); + NbtMap entry = blocksIterator.next(); + BlockState blockState = javaBlockStates.get(javaRuntimeId); + String javaId = blockState.toString(); - NbtMap originalBedrockTag = buildBedrockState(entry.getValue()); + NbtMap originalBedrockTag = buildBedrockState(blockState, entry); NbtMap bedrockTag = stateMapper.remap(originalBedrockTag); GeyserBedrockBlock vanillaBedrockDefinition = blockStateOrderedMap.get(bedrockTag); @@ -274,35 +291,27 @@ public final class BlockRegistryPopulator { case "minecraft:moving_piston[facing=north,type=normal]" -> movingBlockDefinition = bedrockDefinition; } - if (javaId.contains("jigsaw")) { + if (blockState.block() == Blocks.JIGSAW) { jigsawDefinitions.add(bedrockDefinition); } - if (javaId.contains("structure_block")) { - int modeIndex = javaId.indexOf("mode="); - if (modeIndex != -1) { - int startIndex = modeIndex + 5; // Length of "mode=" is 5 - int endIndex = javaId.indexOf("]", startIndex); - if (endIndex != -1) { - String modeValue = javaId.substring(startIndex, endIndex); - structureBlockDefinitions.put(modeValue.toUpperCase(), bedrockDefinition); - } - } + if (blockState.block() == Blocks.STRUCTURE_BLOCK) { + String mode = blockState.getValue(Properties.STRUCTUREBLOCK_MODE); + structureBlockDefinitions.put(mode.toUpperCase(Locale.ROOT), bedrockDefinition); } - boolean waterlogged = entry.getKey().contains("waterlogged=true") - || javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass"); + boolean waterlogged = blockState.getValue(Properties.WATERLOGGED, false) + || blockState.block() == Blocks.BUBBLE_COLUMN || blockState.block() == Blocks.KELP || blockState.block() == Blocks.SEAGRASS; if (waterlogged) { int finalJavaRuntimeId = javaRuntimeId; BlockRegistries.WATERLOGGED.register(set -> set.set(finalJavaRuntimeId)); } - String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey()); - // Get the tag needed for non-empty flower pots - if (entry.getValue().get("pottable") != null) { - flowerPotBlocks.put(cleanJavaIdentifier.intern(), blockStates.get(bedrockDefinition.getRuntimeId())); + if (javaPottable.contains(blockState.block())) { + // Specifically NOT putIfAbsent - mangrove propagule breaks otherwise + flowerPotBlocks.put(blockState.block(), blockStates.get(bedrockDefinition.getRuntimeId())); } javaToVanillaBedrockBlocks[javaRuntimeId] = vanillaBedrockDefinition; @@ -386,9 +395,10 @@ public final class BlockRegistryPopulator { } private static void registerJavaBlocks() { - JsonNode blocksJson; - try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/blocks.json")) { - blocksJson = GeyserImpl.JSON_MAPPER.readTree(stream); + List blocksNbt; + try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/blocks.nbt")) { + blocksNbt = ((NbtMap) NbtUtils.createGZIPReader(stream).readTag()) + .getList("bedrock_mappings", NbtType.COMPOUND); } catch (Exception e) { throw new AssertionError("Unable to load Java block mappings", e); } @@ -399,56 +409,29 @@ public final class BlockRegistryPopulator { MIN_CUSTOM_RUNTIME_ID = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet().stream().min(Comparator.comparing(JavaBlockState::javaId)).orElseThrow().javaId(); int maxCustomRuntimeID = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet().stream().max(Comparator.comparing(JavaBlockState::javaId)).orElseThrow().javaId(); - if (MIN_CUSTOM_RUNTIME_ID < blocksJson.size()) { + if (MIN_CUSTOM_RUNTIME_ID < blocksNbt.size()) { throw new RuntimeException("Non vanilla custom block state overrides runtime ID must start after the last vanilla block state (" + JAVA_BLOCKS_SIZE + ")"); } JAVA_BLOCKS_SIZE = maxCustomRuntimeID + 1; // Runtime ids start at 0, so we need to add 1 } - BlockRegistries.JAVA_BLOCKS.set(new BlockMapping[JAVA_BLOCKS_SIZE]); // Set array size to number of blockstates - - Deque cleanIdentifiers = new ArrayDeque<>(); - int javaRuntimeId = -1; int waterRuntimeId = -1; - Iterator> blocksIterator = blocksJson.fields(); - while (blocksIterator.hasNext()) { + for (BlockState javaBlockState : BlockRegistries.BLOCK_STATES.get()) { javaRuntimeId++; - Map.Entry entry = blocksIterator.next(); - String javaId = entry.getKey(); + String javaId = javaBlockState.toString().intern(); - BlockMapping.BlockMappingBuilder builder = BlockMapping.builder(); + BlockStateValues.storeBlockStateValues(javaId, javaRuntimeId); - JsonNode pickItemNode = entry.getValue().get("pick_item"); - if (pickItemNode != null) { - builder.pickItem(pickItemNode.textValue().intern()); - } - - JsonNode hasBlockEntityNode = entry.getValue().get("has_block_entity"); - if (hasBlockEntityNode != null) { - builder.isBlockEntity(hasBlockEntityNode.booleanValue()); - } else { - builder.isBlockEntity(false); - } - - BlockStateValues.storeBlockStateValues(entry.getKey(), javaRuntimeId, entry.getValue()); - - String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey()); - String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); - - if (!cleanJavaIdentifier.equals(cleanIdentifiers.peekLast())) { - cleanIdentifiers.add(cleanJavaIdentifier.intern()); - } - - builder.javaIdentifier(javaId); + //String cleanJavaIdentifier = javaBlockState.block().javaIdentifier().toString(); + //String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId); - BlockRegistries.JAVA_BLOCKS.register(javaRuntimeId, builder.build()); // Keeping this here since this is currently unchanged between versions // It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions - BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern()); + //BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern()); if ("minecraft:water[level=0]".equals(javaId)) { waterRuntimeId = javaRuntimeId; @@ -461,7 +444,7 @@ public final class BlockRegistryPopulator { BlockStateValues.JAVA_WATER_ID = waterRuntimeId; if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) { - Set usedNonVanillaRuntimeIDs = new HashSet<>(); + IntSet usedNonVanillaRuntimeIDs = new IntOpenHashSet(); for (JavaBlockState javaBlockState : BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet()) { if (!usedNonVanillaRuntimeIDs.add(javaBlockState.javaId())) { @@ -473,11 +456,6 @@ public final class BlockRegistryPopulator { String javaId = javaBlockState.identifier(); int stateRuntimeId = javaBlockState.javaId(); String pistonBehavior = javaBlockState.pistonBehavior(); - BlockMapping blockMapping = BlockMapping.builder() - .pickItem(javaBlockState.pickItem()) - .isNonVanilla(true) - .javaIdentifier(javaId) - .build(); Block.Builder builder = Block.builder() .destroyTime(javaBlockState.blockHardness()) @@ -492,23 +470,25 @@ public final class BlockRegistryPopulator { String pickItem = javaBlockState.pickItem(); Block block = new Block(cleanJavaIdentifier, builder) { @Override - public Item asItem() { + public ItemStack pickItem(BlockState state) { if (this.item == null) { - return Registries.JAVA_ITEM_IDENTIFIERS.get(pickItem); + this.item = Registries.JAVA_ITEM_IDENTIFIERS.get(pickItem); + if (this.item == null) { + GeyserImpl.getInstance().getLogger().warning("We could not find item " + pickItem + + " for getting the item for block " + javaBlockState.identifier()); + this.item = Items.AIR; + } } - return this.item; + return new ItemStack(this.item.javaId()); } }; + block.setJavaId(javaBlockState.stateGroupId()); String bedrockIdentifier = customBlockState.block().identifier(); - if (!cleanJavaIdentifier.equals(cleanIdentifiers.peekLast())) { - cleanIdentifiers.add(cleanJavaIdentifier.intern()); - } - - BlockRegistries.JAVA_BLOCKS_TO_RENAME.get().add(javaBlockState.stateGroupId(), block); //TODO don't allow duplicates, allow blanks + BlockRegistries.JAVA_BLOCKS.get().add(javaBlockState.stateGroupId(), block); //TODO don't allow duplicates, allow blanks BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, stateRuntimeId); - BlockRegistries.JAVA_BLOCKS.register(stateRuntimeId, blockMapping); + BlockRegistries.BLOCK_STATES.register(stateRuntimeId, new BlockState(block, stateRuntimeId)); // Keeping this here since this is currently unchanged between versions // It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions @@ -516,7 +496,7 @@ public final class BlockRegistryPopulator { } } - BLOCKS_JSON = blocksJson; + BLOCKS_NBT = blocksNbt; JsonNode blockInteractionsJson; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/interactions.json")) { @@ -537,29 +517,11 @@ public final class BlockRegistryPopulator { return blockStateSet; } - private static NbtMap buildBedrockState(JsonNode node) { + private static NbtMap buildBedrockState(BlockState state, NbtMap nbt) { NbtMapBuilder tagBuilder = NbtMap.builder(); - String bedrockIdentifier = node.get("bedrock_identifier").textValue(); + String bedrockIdentifier = "minecraft:" + nbt.getString("bedrock_identifier", state.block().javaIdentifier().value()); tagBuilder.putString("name", bedrockIdentifier); - - NbtMapBuilder statesBuilder = NbtMap.builder(); - - // check for states - JsonNode states = node.get("bedrock_states"); - if (states != null) { - Iterator> statesIterator = states.fields(); - - while (statesIterator.hasNext()) { - Map.Entry stateEntry = statesIterator.next(); - JsonNode stateValue = stateEntry.getValue(); - switch (stateValue.getNodeType()) { - case BOOLEAN -> statesBuilder.putBoolean(stateEntry.getKey(), stateValue.booleanValue()); - case STRING -> statesBuilder.putString(stateEntry.getKey(), stateValue.textValue()); - case NUMBER -> statesBuilder.putInt(stateEntry.getKey(), stateValue.intValue()); - } - } - } - tagBuilder.put("states", statesBuilder.build()); + tagBuilder.put("states", nbt.getCompound("state")); return tagBuilder.build(); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index 2fe808070..e4b7111b3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.common.DefinitionRegistry; import org.geysermc.geyser.api.block.custom.CustomBlockState; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.BlockState; import java.util.List; @@ -59,7 +60,7 @@ public class BlockMappings implements DefinitionRegistry { BlockDefinition mobSpawnerBlock; Map itemFrames; - Map flowerPotBlocks; + Map flowerPotBlocks; Set jigsawStates; Map structureBlockStates; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java index 5b208a41f..a40a1156d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java @@ -25,18 +25,20 @@ package org.geysermc.geyser.session.cache; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.math.vector.Vector3i; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Data; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.type.WallSkullBlock; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.CustomSkull; import org.geysermc.geyser.session.GeyserSession; @@ -80,7 +82,7 @@ public class SkullCache { this.skullRenderDistanceSquared = distance * distance; } - public Skull putSkull(Vector3i position, UUID uuid, String texturesProperty, int blockState) { + public Skull putSkull(Vector3i position, UUID uuid, String texturesProperty, BlockState blockState) { Skull skull = skulls.computeIfAbsent(position, Skull::new); skull.uuid = uuid; if (!texturesProperty.equals(skull.texturesProperty)) { @@ -147,7 +149,7 @@ public class SkullCache { } } - public Skull updateSkull(Vector3i position, int blockState) { + public Skull updateSkull(Vector3i position, BlockState blockState) { Skull skull = skulls.get(position); if (skull != null) { putSkull(position, skull.uuid, skull.texturesProperty, blockState); @@ -248,17 +250,14 @@ public class SkullCache { lastPlayerPosition = null; } - private @Nullable BlockDefinition translateCustomSkull(String skinHash, int blockState) { + private @Nullable BlockDefinition translateCustomSkull(String skinHash, BlockState blockState) { CustomSkull customSkull = BlockRegistries.CUSTOM_SKULLS.get(skinHash); if (customSkull != null) { - byte floorRotation = BlockStateValues.getSkullRotation(blockState); CustomBlockState customBlockState; - if (floorRotation == -1) { - // Wall skull - int wallDirection = BlockStateValues.getSkullWallDirections().get(blockState); - customBlockState = customSkull.getWallBlockState(wallDirection); + if (blockState.block() instanceof WallSkullBlock) { + customBlockState = customSkull.getWallBlockState(WallSkullBlock.getDegrees(blockState)); } else { - customBlockState = customSkull.getFloorBlockState(floorRotation); + customBlockState = customSkull.getFloorBlockState(blockState.getValue(Properties.ROTATION_16)); } return session.getBlockMappings().getCustomBlockStateDefinitions().get(customBlockState); @@ -273,7 +272,7 @@ public class SkullCache { private String texturesProperty; private String skinHash; - private int blockState; + private BlockState blockState; private BlockDefinition blockDefinition; private SkullPlayerEntity entity; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index cb973fa18..4c49c8e5a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -36,10 +36,13 @@ import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.ChestType; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.DoubleChestBlockEntityTranslator; import org.geysermc.geyser.util.InventoryUtils; @@ -55,24 +58,17 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { public boolean prepareInventory(GeyserSession session, Inventory inventory) { // See BlockInventoryHolder - same concept there except we're also dealing with a specific block state if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { - int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); - if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(javaBlockId)) { - String[] javaBlockString = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaBlockId, BlockMapping.DEFAULT).getJavaIdentifier().split("\\["); - if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest")) - && !javaBlockString[1].contains("type=single")) { + BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition()); + if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) { + if (state.block() == Blocks.CHEST || state.block() == Blocks.TRAPPED_CHEST + && state.getValue(Properties.CHEST_TYPE) != ChestType.SINGLE) { inventory.setHolderPosition(session.getLastInteractionBlockPosition()); - ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]); + ((Container) inventory).setUsingRealBlock(true, state.block()); - NbtMapBuilder tag = NbtMap.builder() - .putString("id", "Chest") - .putInt("x", session.getLastInteractionBlockPosition().getX()) - .putInt("y", session.getLastInteractionBlockPosition().getY()) - .putInt("z", session.getLastInteractionBlockPosition().getZ()) - .putString("CustomName", inventory.getTitle()) - .putString("id", "Chest"); + NbtMapBuilder tag = BlockEntityTranslator.getConstantBedrockTag("Chest", session.getLastInteractionBlockPosition()) + .putString("CustomName", inventory.getTitle()); - BlockState blockState = BlockState.of(javaBlockId); - DoubleChestBlockEntityTranslator.translateChestValue(tag, blockState, + DoubleChestBlockEntityTranslator.translateChestValue(tag, state, session.getLastInteractionBlockPosition().getX(), session.getLastInteractionBlockPosition().getZ()); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index c03ae8ef0..cdbb20c44 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -33,9 +33,9 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.type.SkullBlock; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.skin.SkinProvider; @@ -53,17 +53,12 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { - byte skullVariant = BlockStateValues.getSkullVariant(blockState.javaId()); // TODO - // Just in case... - if (skullVariant == -1) { - skullVariant = 0; - } Integer rotation = blockState.getValue(Properties.ROTATION_16); if (rotation != null) { - // Could be a wall skull block + // Could be a wall skull block otherwise, which has rotation in its Bedrock state bedrockNbt.putFloat("Rotation", rotation * 22.5f); } - bedrockNbt.putByte("SkullType", skullVariant); + bedrockNbt.putByte("SkullType", (byte) (blockState.block() instanceof SkullBlock skull ? skull.skullType().bedrockId() : 0)); if (blockState.getValue(Properties.POWERED)) { bedrockNbt.putBoolean("MouthMoving", true); } @@ -106,7 +101,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements return CompletableFuture.completedFuture(texture); } - public static @Nullable BlockDefinition translateSkull(GeyserSession session, NbtMap javaNbt, Vector3i blockPosition, int blockState) { + public static @Nullable BlockDefinition translateSkull(GeyserSession session, NbtMap javaNbt, Vector3i blockPosition, BlockState blockState) { NbtMap profile = javaNbt.getCompound("profile"); if (profile.isEmpty()) { session.getSkullCache().removeSkull(blockPosition); @@ -150,7 +145,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements return null; } - private static void putSkull(GeyserSession session, Vector3i blockPosition, UUID uuid, String texturesProperty, int blockState) { + private static void putSkull(GeyserSession session, Vector3i blockPosition, UUID uuid, String texturesProperty, BlockState blockState) { SkullCache.Skull skull = session.getSkullCache().putSkull(blockPosition, uuid, texturesProperty, blockState); if (skull.getBlockDefinition() != null) { UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index be3af2061..0a721e4b0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -32,7 +32,7 @@ import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.type.BannerBlock; -import org.geysermc.geyser.level.block.type.Block; +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; @@ -45,10 +45,10 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator session.ensureInEventLoop(() -> { if (components == null) { @@ -73,7 +73,7 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator { @@ -77,9 +78,9 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator { @@ -102,7 +100,7 @@ public class JavaBlockUpdateTranslator extends PacketTranslator> 4) - (bedrockDimension.minY() >> 4); int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4); diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index 7e1227f6c..72fcb4fa6 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -94,7 +94,7 @@ public class StatisticsUtils { for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof BreakBlockStatistic statistic) { - Block block = BlockRegistries.JAVA_BLOCKS_TO_RENAME.get(statistic.getId()); + Block block = BlockRegistries.JAVA_BLOCKS.get(statistic.getId()); if (block != null) { String identifier = "block.minecraft." + block.javaIdentifier().value(); content.add(identifier + ": " + entry.getIntValue()); diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2BooleanMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2BooleanMap.java deleted file mode 100644 index dc4545529..000000000 --- a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2BooleanMap.java +++ /dev/null @@ -1,120 +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.util.collection; - -import it.unimi.dsi.fastutil.ints.AbstractInt2BooleanMap; -import it.unimi.dsi.fastutil.objects.ObjectSet; - -import java.io.Serial; - -public class FixedInt2BooleanMap extends AbstractInt2BooleanMap { - - @Serial - private static final long serialVersionUID = 1L; - - protected boolean[] value; - protected int start = -1; - - @Override - public int size() { - return value.length; - } - - @Override - public ObjectSet int2BooleanEntrySet() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean get(int i) { - return getOrDefault(i, defRetValue); - } - - @Override - public boolean getOrDefault(int key, boolean defaultValue) { - int offset = key - start; - if (offset < 0 || offset >= value.length) { - return defaultValue; - } - - return value[offset]; - } - - @Override - public boolean put(int key, boolean value) { - if (start == -1) { - start = key; - this.value = new boolean[] {value}; - } else { - int offset = key - start; - if (offset >= 0 && offset < this.value.length) { - boolean curr = this.value[offset]; - this.value[offset] = value; - return curr; - } else if (offset != this.value.length) { - throw new IndexOutOfBoundsException("Expected: " + (this.value.length + start) + ", got " + key); - } - - boolean[] newValue = new boolean[offset + 1]; - System.arraycopy(this.value, 0, newValue, 0, this.value.length); - this.value = newValue; - this.value[offset] = value; - } - - return this.defRetValue; - } - - @Override - public boolean containsKey(int k) { - int offset = k - start; - return offset >= 0 && offset < value.length; - } - - @Override - public boolean containsValue(boolean v) { - for (boolean b : value) { - if (b == v) { - return true; - } - } - - return false; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("{"); - int index = start; - for (boolean b : value) { - builder.append(index++).append("=>").append(b); - if (index < value.length + start) { - // Add commas while there are still more entries in the list - builder.append(", "); - } - } - return builder.append('}').toString(); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2ByteMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2ByteMap.java deleted file mode 100644 index 46cb2a2ca..000000000 --- a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2ByteMap.java +++ /dev/null @@ -1,121 +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.util.collection; - -import it.unimi.dsi.fastutil.ints.AbstractInt2ByteMap; -import it.unimi.dsi.fastutil.ints.Int2ByteMap; -import it.unimi.dsi.fastutil.objects.ObjectSet; - -import java.io.Serial; - -public class FixedInt2ByteMap extends AbstractInt2ByteMap { - - @Serial - private static final long serialVersionUID = 1L; - - protected byte[] value; - protected int start = -1; - - @Override - public int size() { - return value.length; - } - - @Override - public ObjectSet int2ByteEntrySet() { - throw new UnsupportedOperationException(); - } - - @Override - public byte get(int i) { - return getOrDefault(i, defRetValue); - } - - @Override - public byte getOrDefault(int key, byte defaultValue) { - int offset = key - start; - if (offset < 0 || offset >= value.length) { - return defaultValue; - } - - return value[offset]; - } - - @Override - public byte put(int key, byte value) { - if (start == -1) { - start = key; - this.value = new byte[] {value}; - } else { - int offset = key - start; - if (offset >= 0 && offset < this.value.length) { - byte curr = this.value[offset]; - this.value[offset] = value; - return curr; - } else if (offset != this.value.length) { - throw new IndexOutOfBoundsException("Expected: " + (this.value.length + start) + ", got " + key); - } - - byte[] newValue = new byte[offset + 1]; - System.arraycopy(this.value, 0, newValue, 0, this.value.length); - this.value = newValue; - this.value[offset] = value; - } - - return this.defRetValue; - } - - @Override - public boolean containsKey(int k) { - int offset = k - start; - return offset >= 0 && offset < value.length; - } - - @Override - public boolean containsValue(byte v) { - for (byte i : value) { - if (i == v) { - return true; - } - } - - return false; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("{"); - int index = start; - for (byte b : value) { - builder.append(index++).append("=>").append(b); - if (index < value.length + start) { - // Add commas while there are still more entries in the list - builder.append(", "); - } - } - return builder.append('}').toString(); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2IntMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2IntMap.java deleted file mode 100644 index 4a27d51a9..000000000 --- a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2IntMap.java +++ /dev/null @@ -1,120 +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.util.collection; - -import it.unimi.dsi.fastutil.ints.AbstractInt2IntMap; -import it.unimi.dsi.fastutil.ints.Int2IntMap; -import it.unimi.dsi.fastutil.objects.ObjectSet; - -import java.io.Serial; - -public class FixedInt2IntMap extends AbstractInt2IntMap { - protected int[] value; - protected int start = -1; - - @Serial - private static final long serialVersionUID = 1L; - - @Override - public int size() { - return value.length; - } - - @Override - public ObjectSet int2IntEntrySet() { - throw new UnsupportedOperationException(); - } - - @Override - public int get(int i) { - return getOrDefault(i, defRetValue); - } - - @Override - public int getOrDefault(int key, int defaultValue) { - int offset = key - start; - if (offset < 0 || offset >= value.length) { - return defaultValue; - } - - return value[offset]; - } - - @Override - public int put(int key, int value) { - if (start == -1) { - start = key; - this.value = new int[] {value}; - } else { - int offset = key - start; - if (offset >= 0 && offset < this.value.length) { - int curr = this.value[offset]; - this.value[offset] = value; - return curr; - } else if (offset != this.value.length) { - throw new IndexOutOfBoundsException("Expected: " + (this.value.length + start) + ", got " + key); - } - - int[] newValue = new int[offset + 1]; - System.arraycopy(this.value, 0, newValue, 0, this.value.length); - this.value = newValue; - this.value[offset] = value; - } - - return this.defRetValue; - } - - @Override - public boolean containsKey(int k) { - int offset = k - start; - return offset >= 0 && offset < value.length; - } - - @Override - public boolean containsValue(int v) { - for (int i : value) { - if (i == v) { - return true; - } - } - - return false; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("{"); - int index = start; - for (int i : value) { - builder.append(index++).append("=>").append(i); - if (index < value.length + start) { - // Add commas while there are still more entries in the list - builder.append(", "); - } - } - return builder.append('}').toString(); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java deleted file mode 100644 index 42d0da803..000000000 --- a/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java +++ /dev/null @@ -1,75 +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.util.collection; - -import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.erosion.util.LecternUtils; -import org.geysermc.geyser.level.WorldManager; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockEntityUtils; - -import java.io.Serial; - -/** - * Map that takes advantage of its internals for fast operations on block states to determine if they are lecterns. - */ -public class LecternHasBookMap extends FixedInt2BooleanMap { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * Update a potential lectern within the world. This is a map method so it can use the internal fields to - * optimize lectern determining. - */ - public void handleBlockChange(GeyserSession session, int blockState, Vector3i position) { - WorldManager worldManager = session.getGeyser().getWorldManager(); - - int offset = blockState - this.start; - if (offset < 0 || offset >= this.value.length) { - // Block state is out of bounds of this map - lectern has been destroyed, if it existed - if (!worldManager.shouldExpectLecternHandled(session)) { - session.getLecternCache().remove(position); - } - return; - } - - boolean newLecternHasBook; - if (worldManager.shouldExpectLecternHandled(session)) { - worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); - } else if ((newLecternHasBook = this.value[offset]) != this.get(worldManager.getBlockAt(session, position))) { - // newLecternHasBook = the new lectern block state's "has book" toggle. - if (newLecternHasBook) { - worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); - } else { - session.getLecternCache().remove(position); - NbtMap newLecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build(); - BlockEntityUtils.updateBlockEntity(session, newLecternTag, position); - } - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java b/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java deleted file mode 100644 index 46fa5df11..000000000 --- a/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java +++ /dev/null @@ -1,34 +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 - */ - -/** - * Contains useful collections for use in Geyser. - *

- * Of note are the fixed int maps. Designed for use with block states that are positive and sequential, they do not allow keys to be - * added that are not greater by one versus the previous key. Because of this, speedy operations of {@link java.util.Map#get(java.lang.Object)} - * and {@link java.util.Map#containsKey(java.lang.Object)} can be performed by simply checking the bounds of the map - * size and its "start" integer. - */ -package org.geysermc.geyser.util.collection; \ No newline at end of file diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 6b661f0d5..968a22bba 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 6b661f0d517d895aebc1f55a25d2c86f033beb1d +Subproject commit 968a22bbab02d7d003c5b451a40d8bb2439b0d97 diff --git a/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java b/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java deleted file mode 100644 index 639c79331..000000000 --- a/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java +++ /dev/null @@ -1,181 +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.util.collection; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -public class GeyserCollectionsTest { - private final byte[] bytes = new byte[] {(byte) 5, (byte) 4, (byte) 3, (byte) 2, (byte) 2, (byte) 1}; - private final boolean[] booleans = new boolean[] {true, false, false, true}; - private final int[] ints = new int[] {76, 3006, 999, 2323, 888, 0, 111, 999}; - - private final int[] startBlockRanges = new int[] {0, 70, 600, 450, 787, 1980}; - - @Test - public void testBytes() { - for (int startRange : startBlockRanges) { - testBytes(startRange, new FixedInt2ByteMap()); - } - } - - private void testBytes(final int start, final FixedInt2ByteMap map) { - int index = start; - for (byte b : bytes) { - map.put(index++, b); - } - - int lastKey = index; - - // Easy, understandable out-of-bounds checks - Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!"); - Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!"); - - // Ensure the first and last values do not throw an exception on get, and test getOrDefault - map.get(start - 1); - map.get(lastKey); - Assertions.assertEquals(map.getOrDefault(start - 1, Byte.MAX_VALUE), Byte.MAX_VALUE); - Assertions.assertEquals(map.getOrDefault(lastKey, Byte.MAX_VALUE), Byte.MAX_VALUE); - Assertions.assertEquals(map.getOrDefault(lastKey, Byte.MIN_VALUE), Byte.MIN_VALUE); - - Assertions.assertEquals(map.size(), bytes.length); - - for (int i = start; i < bytes.length; i++) { - Assertions.assertTrue(map.containsKey(i)); - Assertions.assertEquals(map.get(i), bytes[i - start]); - } - - for (int i = start - 1; i >= (start - 6); i--) { - // Lower than expected check - Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start); - } - - for (int i = bytes.length + start; i < bytes.length + 5 + start; i++) { - // Higher than expected check - Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + bytes.length)); - } - - for (byte b : bytes) { - Assertions.assertTrue(map.containsValue(b)); - } - } - - @Test - public void testBooleans() { - for (int startRange : startBlockRanges) { - testBooleans(startRange, new FixedInt2BooleanMap()); - } - } - - private void testBooleans(final int start, final FixedInt2BooleanMap map) { - int index = start; - for (boolean b : booleans) { - map.put(index++, b); - } - - int lastKey = index; - - // Easy, understandable out-of-bounds checks - Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!"); - Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!"); - - // Ensure the first and last values do not throw an exception on get - map.get(start - 1); - map.get(lastKey); - Assertions.assertTrue(map.getOrDefault(lastKey, true)); - - Assertions.assertEquals(map.size(), booleans.length); - - for (int i = start; i < booleans.length; i++) { - Assertions.assertTrue(map.containsKey(i)); - Assertions.assertEquals(map.get(i), booleans[i - start]); - } - - for (int i = start - 1; i >= (start - 6); i--) { - // Lower than expected check - Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start); - } - - for (int i = booleans.length + start; i < booleans.length + start + 5; i++) { - // Higher than expected check - Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + booleans.length)); - } - - for (boolean b : booleans) { - Assertions.assertTrue(map.containsValue(b)); - } - } - - @Test - public void testInts() { - for (int startRange : startBlockRanges) { - testInts(startRange, new FixedInt2IntMap()); - } - } - - private void testInts(final int start, final FixedInt2IntMap map) { - int index = start; - for (int i : ints) { - map.put(index++, i); - } - - int lastKey = index; - - // Easy, understandable out-of-bounds checks - Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!"); - Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!"); - - // Ensure the first and last values do not throw an exception on get, and test getOrDefault - map.get(start - 1); - map.get(lastKey); - Assertions.assertEquals(map.getOrDefault(start - 1, Integer.MAX_VALUE), Integer.MAX_VALUE); - Assertions.assertEquals(map.getOrDefault(lastKey, Integer.MAX_VALUE), Integer.MAX_VALUE); - Assertions.assertEquals(map.getOrDefault(lastKey, Integer.MIN_VALUE), Integer.MIN_VALUE); - - Assertions.assertEquals(map.size(), ints.length); - - for (int i = start; i < ints.length; i++) { - Assertions.assertTrue(map.containsKey(i)); - Assertions.assertEquals(map.get(i), ints[i - start]); - } - - for (int i = start - 1; i >= (start - 6); i--) { - // Lower than expected check - Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start); - } - - for (int i = ints.length + start; i < ints.length + 5 + start; i++) { - // Higher than expected check - Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + ints.length)); - } - - for (int i : ints) { - Assertions.assertTrue(map.containsValue(i)); - } - } -} From 1b075badcedbba8332842562c651f8bf9c24d1c3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 19 May 2024 23:15:52 -0400 Subject: [PATCH 151/897] Actually implement adventure mode predicates, kind of. If it's just block IDs, it'll work. --- .../geyser/registry/BlockRegistries.java | 9 +-- .../geysermc/geyser/registry/Registries.java | 1 - .../populator/BlockRegistryPopulator.java | 36 +++++++---- .../geyser/registry/type/BlockMappings.java | 6 ++ .../translator/item/ItemTranslator.java | 64 +++++++++++-------- .../protocol/java/JavaCommandsTranslator.java | 11 +--- gradle/libs.versions.toml | 2 +- 7 files changed, 71 insertions(+), 58 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 93ac5e457..2f15094ef 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -66,11 +66,6 @@ public class BlockRegistries { */ public static final ListRegistry BLOCK_STATES = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); - /** - * A mapped registry which stores Java to Bedrock block identifiers. - */ - public static final SimpleMappedRegistry JAVA_TO_BEDROCK_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); - /** * A mapped registry containing which holds block IDs to its {@link BlockCollision}. */ @@ -89,6 +84,9 @@ public class BlockRegistries { /** * A registry containing all the waterlogged blockstates. + * Properties.WATERLOGGED should not be relied on for two reasons: + * - Custom blocks + * - Seagrass, kelp, and bubble columns are assumed waterlogged and don't have a waterlogged property */ public static final SimpleRegistry WATERLOGGED = SimpleRegistry.create(RegistryLoaders.empty(BitSet::new)); @@ -144,7 +142,6 @@ public class BlockRegistries { CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.POST_INIT); - System.out.println("Block registries loaded"); } public static void init() { 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 7f0d9013a..54d013140 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -204,6 +204,5 @@ public final class Registries { biomesNbt.put(key, value.build()); } BIOMES_NBT.set(biomesNbt.build()); - System.out.println("Registries loaded"); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index a0af4cfa0..5f50f4f68 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -236,6 +236,10 @@ public final class BlockRegistryPopulator { GeyserBedrockBlock[] javaToBedrockBlocks = new GeyserBedrockBlock[JAVA_BLOCKS_SIZE]; GeyserBedrockBlock[] javaToVanillaBedrockBlocks = new GeyserBedrockBlock[JAVA_BLOCKS_SIZE]; + //List javaToBedrockIdentifiers = new ArrayList<>(BlockRegistries.JAVA_BLOCKS.get().size()); + var javaToBedrockIdentifiers = new Int2ObjectOpenHashMap(); + Block lastBlockSeen = null; + // Stream isn't ideal. List javaPottable = BlockRegistries.JAVA_BLOCKS.get() .parallelStream() @@ -291,27 +295,35 @@ public final class BlockRegistryPopulator { case "minecraft:moving_piston[facing=north,type=normal]" -> movingBlockDefinition = bedrockDefinition; } - if (blockState.block() == Blocks.JIGSAW) { + Block block = blockState.block(); + if (block != lastBlockSeen) { + lastBlockSeen = block; + String bedrockName = bedrockDefinition.getState().getString("name"); + if (!block.javaIdentifier().toString().equals(bedrockName)) { + javaToBedrockIdentifiers.put(block.javaId(), bedrockName.substring("minecraft:".length()).intern()); + } + } + + if (block == Blocks.JIGSAW) { jigsawDefinitions.add(bedrockDefinition); } - if (blockState.block() == Blocks.STRUCTURE_BLOCK) { + if (block == Blocks.STRUCTURE_BLOCK) { String mode = blockState.getValue(Properties.STRUCTUREBLOCK_MODE); structureBlockDefinitions.put(mode.toUpperCase(Locale.ROOT), bedrockDefinition); } boolean waterlogged = blockState.getValue(Properties.WATERLOGGED, false) - || blockState.block() == Blocks.BUBBLE_COLUMN || blockState.block() == Blocks.KELP || blockState.block() == Blocks.SEAGRASS; + || block == Blocks.BUBBLE_COLUMN || block == Blocks.KELP || block == Blocks.SEAGRASS; if (waterlogged) { - int finalJavaRuntimeId = javaRuntimeId; - BlockRegistries.WATERLOGGED.register(set -> set.set(finalJavaRuntimeId)); + BlockRegistries.WATERLOGGED.get().set(javaRuntimeId); } // Get the tag needed for non-empty flower pots - if (javaPottable.contains(blockState.block())) { + if (javaPottable.contains(block)) { // Specifically NOT putIfAbsent - mangrove propagule breaks otherwise - flowerPotBlocks.put(blockState.block(), blockStates.get(bedrockDefinition.getRuntimeId())); + flowerPotBlocks.put(block, blockStates.get(bedrockDefinition.getRuntimeId())); } javaToVanillaBedrockBlocks[javaRuntimeId] = vanillaBedrockDefinition; @@ -367,9 +379,12 @@ public final class BlockRegistryPopulator { javaToVanillaBedrockBlocks[stateRuntimeId] = bedrockDefinition; // TODO: Check this? javaToBedrockBlocks[stateRuntimeId] = bedrockDefinition; + javaToBedrockIdentifiers.put(entry.getKey().stateGroupId(), entry.getValue().block().identifier()); } } + javaToBedrockIdentifiers.trim(); + // Loop around again to find all item frame runtime IDs Object2ObjectMaps.fastForEach(blockStateOrderedMap, entry -> { String name = entry.getKey().getString("name"); @@ -381,6 +396,7 @@ public final class BlockRegistryPopulator { BlockRegistries.BLOCKS.register(palette.valueInt(), builder.bedrockRuntimeMap(bedrockRuntimeMap) .javaToBedrockBlocks(javaToBedrockBlocks) .javaToVanillaBedrockBlocks(javaToVanillaBedrockBlocks) + .javaToBedrockIdentifiers(javaToBedrockIdentifiers) .stateDefinitionMap(blockStateOrderedMap) .itemFrames(itemFrames) .flowerPotBlocks(flowerPotBlocks) @@ -484,15 +500,9 @@ public final class BlockRegistryPopulator { }; block.setJavaId(javaBlockState.stateGroupId()); - String bedrockIdentifier = customBlockState.block().identifier(); - BlockRegistries.JAVA_BLOCKS.get().add(javaBlockState.stateGroupId(), block); //TODO don't allow duplicates, allow blanks BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, stateRuntimeId); BlockRegistries.BLOCK_STATES.register(stateRuntimeId, new BlockState(block, stateRuntimeId)); - - // Keeping this here since this is currently unchanged between versions - // It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions - BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern()); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index e4b7111b3..f618fde46 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -52,6 +52,12 @@ public class BlockMappings implements DefinitionRegistry { GeyserBedrockBlock[] javaToBedrockBlocks; GeyserBedrockBlock[] javaToVanillaBedrockBlocks; + /** + * Java block ID -> Bedrock block ID (without minecraft:), IF they are different + * While Bedrock is progressing slowly through their flattening, some Bedrock identifiers may differ. + */ + Int2ObjectMap javaToBedrockIdentifiers; + Map stateDefinitionMap; GeyserBedrockBlock[] bedrockRuntimeMap; int[] remappedVanillaIds; 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 768c94791..251aacba8 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 @@ -42,6 +42,7 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; 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.Registries; import org.geysermc.geyser.registry.type.CustomSkull; @@ -52,20 +53,12 @@ import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.InventoryUtils; -import org.geysermc.mcprotocollib.protocol.data.game.Identifier; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.AdventureModePredicate; -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.ItemAttributeModifiers; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.*; import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public final class ItemTranslator { @@ -185,11 +178,11 @@ public final class ItemTranslator { translateCustomItem(components, builder, bedrockItem); if (components != null) { - // Translate the canDestroy and canPlaceOn Java NBT + // Translate the canDestroy and canPlaceOn Java components AdventureModePredicate canDestroy = components.get(DataComponentType.CAN_BREAK); AdventureModePredicate canPlaceOn = components.get(DataComponentType.CAN_PLACE_ON); - String[] canBreak = getCanModify(canDestroy); - String[] canPlace = getCanModify(canPlaceOn); + String[] canBreak = getCanModify(session, canDestroy); + String[] canPlace = getCanModify(session, canPlaceOn); if (canBreak != null) { builder.canBreak(canBreak); } @@ -325,27 +318,42 @@ public final class ItemTranslator { * @param canModifyJava the list of items in Java * @return the new list of items in Bedrock */ - // TODO this is now more complicated in 1.20.5. Yippee! - private static String @Nullable [] getCanModify(@Nullable AdventureModePredicate canModifyJava) { + // TODO blocks by tag, maybe NBT, maybe properties + // Blocks by tag will be easy enough, most likely, we just need to... save all block tags. + // Probably do that with Guava interning around sessions + private static String @Nullable [] getCanModify(GeyserSession session, @Nullable AdventureModePredicate canModifyJava) { if (canModifyJava == null) { return null; } List predicates = canModifyJava.getPredicates(); - if (predicates.size() > 0) { - String[] canModifyBedrock = new String[predicates.size()]; - for (int i = 0; i < canModifyBedrock.length; i++) { - // Get the Java identifier of the block that can be placed - String location = predicates.get(i).getLocation(); - if (location == null) { - canModifyBedrock[i] = ""; // So it'll serialize - continue; // ??? + if (!predicates.isEmpty()) { + List canModifyBedrock = new ArrayList<>(); // This used to be an array, but we need to be flexible with what blocks can be supported + for (int i = 0; i < predicates.size(); i++) { + HolderSet holderSet = predicates.get(i).getBlocks(); + if (holderSet == null) { + continue; + } + int[] holders = holderSet.getHolders(); + if (holders == null) { + continue; + } + // Holders is an int state of Java block IDs (not block states) + for (int blockId : holders) { + // Get the Bedrock identifier of the item + // This will unfortunately be limited - for example, beds and banners will be translated weirdly + Block block = BlockRegistries.JAVA_BLOCKS.get(blockId); + if (block == null) { + continue; + } + String identifier = session.getBlockMappings().getJavaToBedrockIdentifiers().get(block.javaId()); + if (identifier == null) { + canModifyBedrock.add(block.javaIdentifier().value()); + } else { + canModifyBedrock.add(identifier); + } } - String block = Identifier.formalize(location); - // Get the Bedrock identifier of the item and replace it. - // This will unfortunately be limited - for example, beds and banners will be translated weirdly - canModifyBedrock[i] = BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.getOrDefault(block, block).replace("minecraft:", ""); } - return canModifyBedrock; + return canModifyBedrock.toArray(new String[0]); } return null; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 706997402..d9f190197 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -59,6 +59,7 @@ import java.util.*; @Translator(packet = ClientboundCommandsPacket.class) public class JavaCommandsTranslator extends PacketTranslator { + private static final String[] ALL_BLOCK_NAMES = BlockRegistries.JAVA_BLOCKS.get().stream().map(block -> block.javaIdentifier().toString()).toArray(String[]::new); private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers(); private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(AttributeType::getIdentifier).toList().toArray(new String[0]); private static final String[] ENUM_BOOLEAN = {"true", "false"}; @@ -246,7 +247,7 @@ public class JavaCommandsTranslator extends PacketTranslator CommandParam.FILE_PATH; case BOOL -> ENUM_BOOLEAN; case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc - case BLOCK_STATE -> context.getBlockStates(); + case BLOCK_STATE -> ALL_BLOCK_NAMES; case ITEM_STACK -> context.getItemNames(); case COLOR -> VALID_COLORS; case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS; @@ -286,7 +287,6 @@ public class JavaCommandsTranslator extends PacketTranslator Date: Mon, 20 May 2024 00:28:40 -0400 Subject: [PATCH 152/897] Add TrapDoorBlock --- .../geysermc/geyser/level/block/Blocks.java | 40 +++++++++---------- .../level/block/type/TrapDoorBlock.java | 32 +++++++++++++++ 2 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/TrapDoorBlock.java 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 178887754..91f02d65e 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 @@ -655,55 +655,55 @@ public final class Blocks { public static final Block GREEN_STAINED_GLASS = register(new Block("green_stained_glass", builder().destroyTime(0.3f))); 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 Block("oak_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block SPRUCE_TRAPDOOR = register(new Block("spruce_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block BIRCH_TRAPDOOR = register(new Block("birch_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block JUNGLE_TRAPDOOR = register(new Block("jungle_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block ACACIA_TRAPDOOR = register(new Block("acacia_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block CHERRY_TRAPDOOR = register(new Block("cherry_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_TRAPDOOR = register(new Block("dark_oak_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block MANGROVE_TRAPDOOR = register(new Block("mangrove_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_TRAPDOOR = register(new Block("bamboo_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) @@ -1196,7 +1196,7 @@ public final class Blocks { public static final Block LIGHT = register(new Block("light", builder().destroyTime(-1.0f) .intState(LEVEL, 0, 15) .booleanState(WATERLOGGED))); - public static final Block IRON_TRAPDOOR = register(new Block("iron_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(5.0f) + 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, "top", "bottom") .booleanState(OPEN) @@ -2102,13 +2102,13 @@ public final class Blocks { .booleanState(SOUTH) .booleanState(WATERLOGGED) .booleanState(WEST))); - public static final Block CRIMSON_TRAPDOOR = register(new Block("crimson_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WARPED_TRAPDOOR = register(new Block("warped_trapdoor", builder().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) @@ -2583,49 +2583,49 @@ public final class Blocks { .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block COPPER_TRAPDOOR = register(new Block("copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block EXPOSED_COPPER_TRAPDOOR = register(new Block("exposed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block OXIDIZED_COPPER_TRAPDOOR = register(new Block("oxidized_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WEATHERED_COPPER_TRAPDOOR = register(new Block("weathered_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WAXED_COPPER_TRAPDOOR = register(new Block("waxed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WAXED_EXPOSED_COPPER_TRAPDOOR = register(new Block("waxed_exposed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new Block("waxed_oxidized_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block WAXED_WEATHERED_COPPER_TRAPDOOR = register(new Block("waxed_weathered_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + 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, "top", "bottom") .booleanState(OPEN) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/TrapDoorBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/TrapDoorBlock.java new file mode 100644 index 000000000..a94414ac2 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/TrapDoorBlock.java @@ -0,0 +1,32 @@ +/* + * 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.level.block.type; + +public class TrapDoorBlock extends Block { + public TrapDoorBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } +} From a780eeaae8d7a13c2c198a1880c14f0a704f5fb7 Mon Sep 17 00:00:00 2001 From: gecko10000 <60494179+gecko10000@users.noreply.github.com> Date: Mon, 20 May 2024 10:52:41 -0700 Subject: [PATCH 153/897] Open advancement tab regardless of currently open tab (#4665) --- .../geyser/session/cache/AdvancementsCache.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java index da3c83ed4..6769b4330 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java @@ -91,15 +91,13 @@ public class AdvancementsCache { builder.validResultHandler((response) -> { String id = rootAdvancementIds.get(response.clickedButtonId()); if (!id.equals("")) { - if (id.equals(currentAdvancementCategoryId)) { - // The server thinks we are already on this tab - buildAndShowListForm(); - } else { - // Send a packet indicating that we intend to open this particular advancement window + if (!id.equals(currentAdvancementCategoryId)) { + // Send a packet indicating that we are opening this particular advancement window ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id); session.sendDownstreamGamePacket(packet); - // Wait for a response there } + currentAdvancementCategoryId = id; + buildAndShowListForm(); } }); From db166ad8dec5cc23998eeb2480629c8ca5884a97 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 20 May 2024 21:26:01 -0400 Subject: [PATCH 154/897] Small optimizations and BlockStateValues reduction --- .../spigot/world/GeyserPistonListener.java | 3 +- .../manager/GeyserSpigotWorldManager.java | 3 +- .../erosion/GeyserboundPacketHandlerImpl.java | 3 +- .../geyser/level/block/BlockStateValues.java | 45 ++------------- .../geysermc/geyser/level/block/Blocks.java | 5 +- .../level/block/property/FrontAndTop.java | 55 +++++++++++++++++++ .../level/block/property/Properties.java | 2 +- .../geyser/registry/ListRegistry.java | 18 ++++++ .../loader/CollisionRegistryLoader.java | 3 +- .../populator/BlockRegistryPopulator.java | 11 +--- .../JigsawBlockBlockEntityTranslator.java | 4 +- .../java/level/JavaBlockEventTranslator.java | 10 ++-- 12 files changed, 97 insertions(+), 65 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/property/FrontAndTop.java diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java index 2a6dc7a81..963f5bac3 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java @@ -41,6 +41,7 @@ import org.bukkit.event.block.BlockPistonRetractEvent; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; @@ -120,7 +121,7 @@ public class GeyserPistonListener implements Listener { int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock()); // event.getDirection() is unreliable - Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId); + Direction orientation = BlockState.of(pistonBlockId).getValue(Properties.FACING); session.executeInEventLoop(() -> { PistonCache pistonCache = session.getPistonCache(); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index a04c60126..f45b68675 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -42,7 +42,6 @@ import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.WorldManager; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; @@ -88,7 +87,7 @@ public class GeyserSpigotWorldManager extends WorldManager { Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString())); return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); } - return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); + return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); // TODO could just make this a BlockState lookup? } @Override diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index 9894a4ba2..c8cbe384b 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -44,6 +44,7 @@ import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket; import org.geysermc.erosion.packet.backendbound.BackendboundPacket; import org.geysermc.erosion.packet.geyserbound.*; import org.geysermc.geyser.level.block.BlockStateValues; +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.level.physics.Direction; @@ -148,7 +149,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke @Override public void handlePistonEvent(GeyserboundPistonEventPacket packet) { - Direction orientation = BlockStateValues.getPistonOrientation(packet.getBlockId()); + Direction orientation = BlockState.of(packet.getBlockId()).getValue(Properties.FACING); Vector3i position = packet.getPos(); boolean isExtend = packet.isExtend(); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 8bc9cf1e2..d52c46e33 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -25,7 +25,10 @@ package org.geysermc.geyser.level.block; -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.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.geysermc.geyser.level.block.property.Properties; @@ -36,16 +39,11 @@ import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; -import java.util.Locale; - /** * Used for block entities if the Java block state contains Bedrock block information. */ public final class BlockStateValues { - private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet(); - private static final IntSet STICKY_PISTONS = new IntOpenHashSet(); private static final Object2IntMap PISTON_HEADS = new Object2IntOpenHashMap<>(); - private static final Int2ObjectMap PISTON_ORIENTATION = new Int2ObjectOpenHashMap<>(); private static final IntSet ALL_PISTON_HEADS = new IntOpenHashSet(); private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap(); @@ -61,10 +59,6 @@ public final class BlockStateValues { */ public static void storeBlockStateValues(String javaId, int javaBlockState) { if (javaId.contains("piston[")) { // minecraft:moving_piston, minecraft:sticky_piston, minecraft:piston - if (javaId.contains("sticky")) { - STICKY_PISTONS.add(javaBlockState); - } - PISTON_ORIENTATION.put(javaBlockState, getBlockDirection(javaId)); return; } else if (javaId.startsWith("minecraft:piston_head")) { ALL_PISTON_HEADS.add(javaBlockState); @@ -78,27 +72,7 @@ public final class BlockStateValues { String strLevel = javaId.substring(javaId.lastIndexOf("level=") + 6, javaId.length() - 1); int level = Integer.parseInt(strLevel); WATER_LEVEL.put(javaBlockState, level); - return; } - - if (javaId.startsWith("minecraft:jigsaw[orientation=")) { - String blockStateData = javaId.substring(javaId.indexOf("orientation=") + "orientation=".length(), javaId.lastIndexOf('_')); - Direction direction = Direction.valueOf(blockStateData.toUpperCase(Locale.ROOT)); - if (direction.isHorizontal()) { - HORIZONTAL_FACING_JIGSAWS.add(javaBlockState); - } - } - } - - /** - * @return a set of all forward-facing jigsaws, to use as a fallback if NBT is missing. - */ - public static IntSet getHorizontalFacingJigsaws() { - return HORIZONTAL_FACING_JIGSAWS; - } - - public static boolean isStickyPiston(int blockState) { - return STICKY_PISTONS.contains(blockState); } public static boolean isPistonHead(int state) { @@ -116,17 +90,6 @@ public final class BlockStateValues { return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID); } - /** - * This is used in GeyserPistonEvents.java and accepts minecraft:piston, - * minecraft:sticky_piston, and minecraft:moving_piston. - * - * @param state The block state of the piston base - * @return The direction in which the piston faces - */ - public static Direction getPistonOrientation(int state) { - return PISTON_ORIENTATION.get(state); - } - /** * Checks if a block sticks to other blocks * (Slime and honey blocks) 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 91f02d65e..283ca2503 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.level.block; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.property.ChestType; +import org.geysermc.geyser.level.block.property.FrontAndTop; import org.geysermc.geyser.level.block.type.*; import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Direction; @@ -2169,7 +2170,7 @@ public final class Blocks { public static final Block STRUCTURE_BLOCK = register(new Block("structure_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .enumState(STRUCTUREBLOCK_MODE, "save", "load", "corner", "data"))); public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) - .enumState(ORIENTATION, "down_east", "down_north", "down_south", "down_west", "up_east", "up_north", "up_south", "up_west", "west_up", "east_up", "north_up", "south_up"))); + .enumState(ORIENTATION, FrontAndTop.VALUES))); public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f) .intState(LEVEL_COMPOSTER, 0, 8))); public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f) @@ -2799,7 +2800,7 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block CRAFTER = register(new Block("crafter", builder().setBlockEntity().destroyTime(1.5f) .booleanState(CRAFTING) - .enumState(ORIENTATION, "down_east", "down_north", "down_south", "down_west", "up_east", "up_north", "up_south", "up_west", "west_up", "east_up", "north_up", "south_up") + .enumState(ORIENTATION, FrontAndTop.VALUES) .booleanState(TRIGGERED))); public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f) .booleanState(OMINOUS) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/FrontAndTop.java b/core/src/main/java/org/geysermc/geyser/level/block/property/FrontAndTop.java new file mode 100644 index 000000000..e674ac424 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/FrontAndTop.java @@ -0,0 +1,55 @@ +/* + * 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.level.block.property; + +import org.geysermc.geyser.level.physics.Direction; + +public enum FrontAndTop { + DOWN_EAST(Direction.DOWN), + DOWN_NORTH(Direction.DOWN), + DOWN_SOUTH(Direction.DOWN), + DOWN_WEST(Direction.DOWN), + UP_EAST(Direction.UP), + UP_NORTH(Direction.UP), + UP_SOUTH(Direction.UP), + UP_WEST(Direction.UP), + WEST_UP(Direction.WEST), + EAST_UP(Direction.EAST), + NORTH_UP(Direction.NORTH), + SOUTH_UP(Direction.SOUTH); + + private final boolean horizontal; + + FrontAndTop(Direction front) { + this.horizontal = front.isHorizontal(); + } + + public boolean isHorizontal() { + return horizontal; + } + + public static final FrontAndTop[] VALUES = values(); +} 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 339d82f96..7df09003d 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 @@ -74,7 +74,7 @@ public final class Properties { public static final Property FACING_HOPPER = Property.create("facing"); public static final Property HORIZONTAL_FACING = Property.create("facing"); public static final Property FLOWER_AMOUNT = Property.create("flower_amount"); - public static final Property ORIENTATION = Property.create("orientation"); + public static final Property ORIENTATION = Property.create("orientation"); public static final Property ATTACH_FACE = Property.create("face"); public static final Property BELL_ATTACHMENT = Property.create("attachment"); public static final Property EAST_WALL = Property.create("east"); diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java index d13c47ba8..34a78c370 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java @@ -28,10 +28,13 @@ package org.geysermc.geyser.registry; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.registry.loader.RegistryLoader; +import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; public class ListRegistry extends Registry> { + private boolean frozen = false; + /** * Creates a new instance of this class with the given input and * {@link RegistryLoader}. The input specified is what the registry @@ -85,9 +88,24 @@ public class ListRegistry extends Registry> { * @return a new value into this registry with the given index. */ public M register(int index, M value) { + if (this.frozen) { + throw new IllegalStateException("Registry should not be modified after frozen!"); + } return this.mappings.set(index, value); } + /** + * Mark this registry as unsuitable for new additions. The backing list will then be optimized for storage. + */ + public void freeze() { + if (!this.frozen) { + this.frozen = true; + if (this.mappings instanceof ArrayList arrayList) { + arrayList.trimToSize(); + } + } + } + /** * Creates a new array registry with the given {@link RegistryLoader}. The * input type is not specified here, meaning the loader return type is either diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java index 2cd7f82d6..bd98ae0a5 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java @@ -77,7 +77,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader blockStates = BlockRegistries.BLOCK_STATES.get(); - List collisions = new ObjectArrayList<>(blockStates.size()); + var collisions = new ObjectArrayList(blockStates.size()); // Map of unique collisions to its instance Map collisionInstances = new Object2ObjectOpenHashMap<>(); @@ -102,6 +102,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader { - int blockId = session.getGeyser().getWorldManager().getBlockAt(session, position); - boolean sticky = BlockStateValues.isStickyPiston(blockId); + BlockState state = session.getGeyser().getWorldManager().blockAt(session, position); + boolean sticky = state.is(Blocks.STICKY_PISTON); boolean extended = action != PistonValueType.PUSHING; return new PistonBlockEntity(session, pos, direction, sticky, extended); }); From 0094fa1418e313361b94bc2e13010a9a84f20ab7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 21 May 2024 14:25:57 -0400 Subject: [PATCH 155/897] BlockState values can now be switched at runtime E.G. Blocks.PISTON_HEAD.defaultBlockState().withValue(FACING, Direction.SOUTH) Some of the inspiration may be thanks to FerriteCore, at least with the shared property keys idea, so thank you to them. --- .../entity/type/FurnaceMinecartEntity.java | 7 +- .../entity/type/SpawnerMinecartEntity.java | 4 +- .../holder/BlockInventoryHolder.java | 33 +- .../geyser/level/block/BlockStateValues.java | 75 +- .../geysermc/geyser/level/block/Blocks.java | 1052 ++++++++--------- .../block/property/BasicEnumProperty.java | 63 + .../level/block/property/BooleanProperty.java | 46 + .../level/block/property/EnumProperty.java | 59 + .../level/block/property/IntegerProperty.java | 59 + .../level/block/property/Properties.java | 228 ++-- .../geyser/level/block/property/Property.java | 12 +- .../geyser/level/block/type/Block.java | 50 +- .../geyser/level/block/type/BlockState.java | 115 +- .../geyser/level/block/type/FurnaceBlock.java | 21 +- .../geyser/level/block/type/HoneyBlock.java | 13 - .../geyser/level/block/type/SpawnerBlock.java | 13 - .../geyser/level/block/type/WaterBlock.java | 9 - .../level/physics/CollisionManager.java | 6 +- .../populator/BlockRegistryPopulator.java | 13 - .../geyser/registry/type/BlockMappings.java | 4 + .../AbstractBlockInventoryTranslator.java | 15 +- .../inventory/AnvilInventoryTranslator.java | 2 +- .../inventory/BeaconInventoryTranslator.java | 11 +- .../inventory/BrewingInventoryTranslator.java | 7 +- .../CartographyInventoryTranslator.java | 3 +- .../inventory/CrafterInventoryTranslator.java | 3 +- .../CraftingInventoryTranslator.java | 3 +- .../EnchantingInventoryTranslator.java | 3 +- .../Generic3X3InventoryTranslator.java | 2 +- .../GrindstoneInventoryTranslator.java | 3 +- .../inventory/HopperInventoryTranslator.java | 3 +- .../inventory/LecternInventoryTranslator.java | 3 +- .../inventory/LoomInventoryTranslator.java | 3 +- .../inventory/OldSmithingTableTranslator.java | 3 +- .../inventory/ShulkerInventoryTranslator.java | 10 +- .../SmithingInventoryTranslator.java | 3 +- .../StonecutterInventoryTranslator.java | 3 +- .../chest/DoubleChestInventoryTranslator.java | 12 +- .../chest/SingleChestInventoryTranslator.java | 11 +- .../AbstractFurnaceInventoryTranslator.java | 6 +- .../BlastFurnaceInventoryTranslator.java | 3 +- .../furnace/FurnaceInventoryTranslator.java | 3 +- .../furnace/SmokerInventoryTranslator.java | 3 +- .../level/block/entity/PistonBlockEntity.java | 41 +- ...BedrockInventoryTransactionTranslator.java | 8 +- .../protocol/java/JavaCommandsTranslator.java | 9 +- gradle/libs.versions.toml | 3 +- 47 files changed, 1160 insertions(+), 901 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/property/BasicEnumProperty.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/property/BooleanProperty.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/property/EnumProperty.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/property/IntegerProperty.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java index 0fc5627ed..e33e6d7b6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java @@ -28,7 +28,9 @@ package org.geysermc.geyser.entity.type; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.level.block.type.FurnaceBlock; +import org.geysermc.geyser.level.block.Blocks; +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.util.InteractionResult; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -51,7 +53,8 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity { @Override public void updateDefaultBlockMetadata() { - dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(FurnaceBlock.state(hasFuel))); + BlockState furnace = Blocks.FURNACE.defaultBlockState().withValue(Properties.LIT, hasFuel); + dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(furnace)); dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java index 65dfb800b..4d69c8a1e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.level.block.type.SpawnerBlock; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; @@ -41,7 +41,7 @@ public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity { @Override public void updateDefaultBlockMetadata() { - dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(SpawnerBlock.state())); + dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(Blocks.SPAWNER.defaultBlockState())); dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6); } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index 0a51d43ef..9c8e5de15 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -41,7 +41,6 @@ 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.inventory.InventoryTranslator; -import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.InventoryUtils; import java.util.Collections; @@ -56,22 +55,24 @@ public class BlockInventoryHolder extends InventoryHolder { /** * The default Java block ID to translate as a fake block */ - private final int defaultJavaBlockState; + private final BlockState defaultJavaBlockState; private final ContainerType containerType; - private final Set validBlocks; + private final Set validBlocks; - public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, Block... validBlocks) { - this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(javaBlockIdentifier); + public BlockInventoryHolder(Block defaultJavaBlock, ContainerType containerType, Block... validBlocks) { + this(defaultJavaBlock.defaultBlockState(), containerType, validBlocks); + } + + public BlockInventoryHolder(BlockState defaultJavaBlockState, ContainerType containerType, Block... validBlocks) { + this.defaultJavaBlockState = defaultJavaBlockState; this.containerType = containerType; if (validBlocks != null) { - Set validBlocksTemp = new HashSet<>(validBlocks.length + 1); - for (Block block : validBlocks) { - validBlocksTemp.add(block.javaIdentifier().toString()); - } - validBlocksTemp.add(BlockUtils.getCleanIdentifier(javaBlockIdentifier)); + Set validBlocksTemp = new HashSet<>(validBlocks.length + 1); + Collections.addAll(validBlocksTemp, validBlocks); + validBlocksTemp.add(defaultJavaBlockState.block()); this.validBlocks = Set.copyOf(validBlocksTemp); } else { - this.validBlocks = Collections.singleton(BlockUtils.getCleanIdentifier(javaBlockIdentifier)); + this.validBlocks = Collections.singleton(defaultJavaBlockState.block()); } } @@ -85,9 +86,7 @@ public class BlockInventoryHolder extends InventoryHolder { // and the bedrock block is vanilla BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition()); if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) { - // TODO TODO TODO - String[] javaBlockString = state.toString().split("\\["); - if (isValidBlock(javaBlockString)) { + if (isValidBlock(state)) { // We can safely use this block inventory.setHolderPosition(session.getLastInteractionBlockPosition()); ((Container) inventory).setUsingRealBlock(true, state.block()); @@ -111,7 +110,7 @@ public class BlockInventoryHolder extends InventoryHolder { session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); - setCustomName(session, position, inventory, BlockState.of(defaultJavaBlockState)); + setCustomName(session, position, inventory, defaultJavaBlockState); return true; } @@ -129,8 +128,8 @@ public class BlockInventoryHolder extends InventoryHolder { /** * @return true if this Java block ID can be used for player inventory. */ - protected boolean isValidBlock(String[] javaBlockString) { - return this.validBlocks.contains(javaBlockString[0]); + protected boolean isValidBlock(BlockState blockState) { + return this.validBlocks.contains(blockState.block()); } protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) { diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index d52c46e33..01e95fc7a 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -25,17 +25,10 @@ package org.geysermc.geyser.level.block; -import it.unimi.dsi.fastutil.ints.Int2IntMap; -import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; 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.level.block.type.PistonBlock; -import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; @@ -43,53 +36,8 @@ import org.geysermc.geyser.registry.BlockRegistries; * Used for block entities if the Java block state contains Bedrock block information. */ public final class BlockStateValues { - private static final Object2IntMap PISTON_HEADS = new Object2IntOpenHashMap<>(); - private static final IntSet ALL_PISTON_HEADS = new IntOpenHashSet(); - private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap(); - - public static int JAVA_WATER_ID; - public static final int NUM_WATER_LEVELS = 9; - /** - * Determines if the block state contains Bedrock block information - * - * @param javaId The Java Identifier of the block - * @param javaBlockState the Java Block State of the block - */ - public static void storeBlockStateValues(String javaId, int javaBlockState) { - if (javaId.contains("piston[")) { // minecraft:moving_piston, minecraft:sticky_piston, minecraft:piston - return; - } else if (javaId.startsWith("minecraft:piston_head")) { - ALL_PISTON_HEADS.add(javaBlockState); - if (javaId.contains("short=false")) { - PISTON_HEADS.put(getBlockDirection(javaId), javaBlockState); - } - return; - } - - if (javaId.startsWith("minecraft:water") && !javaId.contains("cauldron")) { - String strLevel = javaId.substring(javaId.lastIndexOf("level=") + 6, javaId.length() - 1); - int level = Integer.parseInt(strLevel); - WATER_LEVEL.put(javaBlockState, level); - } - } - - public static boolean isPistonHead(int state) { - return ALL_PISTON_HEADS.contains(state); - } - - /** - * Get the Java Block State for a piston head for a specific direction - * This is used in PistonBlockEntity to get the BlockCollision for the piston head. - * - * @param direction Direction the piston head points in - * @return Block state for the piston head - */ - public static int getPistonHead(Direction direction) { - return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID); - } - /** * Checks if a block sticks to other blocks * (Slime and honey blocks) @@ -158,7 +106,11 @@ public final class BlockStateValues { * @return The water level or -1 if the block isn't water */ public static int getWaterLevel(int state) { - return WATER_LEVEL.getOrDefault(state, -1); + BlockState blockState = BlockState.of(state); + if (!blockState.is(Blocks.WATER)) { + return -1; + } + return blockState.getValue(Properties.LEVEL); } /** @@ -206,23 +158,6 @@ public final class BlockStateValues { return 0.6f; } - private static Direction getBlockDirection(String javaId) { - if (javaId.contains("down")) { - return Direction.DOWN; - } else if (javaId.contains("up")) { - return Direction.UP; - } else if (javaId.contains("south")) { - return Direction.SOUTH; - } else if (javaId.contains("west")) { - return Direction.WEST; - } else if (javaId.contains("north")) { - return Direction.NORTH; - } else if (javaId.contains("east")) { - return Direction.EAST; - } - throw new IllegalStateException(); - } - private BlockStateValues() { } } 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 283ca2503..fa605c079 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 @@ -65,36 +65,36 @@ public final class Blocks { 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, 0, 1))); + .intState(STAGE))); public static final Block SPRUCE_SAPLING = register(new Block("spruce_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE, 0, 1))); + .intState(STAGE))); public static final Block BIRCH_SAPLING = register(new Block("birch_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE, 0, 1))); + .intState(STAGE))); public static final Block JUNGLE_SAPLING = register(new Block("jungle_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE, 0, 1))); + .intState(STAGE))); public static final Block ACACIA_SAPLING = register(new Block("acacia_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE, 0, 1))); + .intState(STAGE))); public static final Block CHERRY_SAPLING = register(new Block("cherry_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE, 0, 1))); + .intState(STAGE))); public static final Block DARK_OAK_SAPLING = register(new Block("dark_oak_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE, 0, 1))); + .intState(STAGE))); public static final Block MANGROVE_PROPAGULE = register(new Block("mangrove_propagule", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_4, 0, 4) + .intState(AGE_4) .booleanState(HANGING) - .intState(STAGE, 0, 1) + .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, 0, 15))); + .intState(LEVEL))); public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) - .intState(LEVEL, 0, 15))); + .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().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) - .intState(DUSTED, 0, 3))); + .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().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) - .intState(DUSTED, 0, 3))); + .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))); @@ -175,43 +175,43 @@ public final class Blocks { public static final Block STRIPPED_MANGROVE_WOOD = register(new Block("stripped_mangrove_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE, 1, 7) + .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, 1, 7) + .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, 1, 7) + .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, 1, 7) + .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, 1, 7) + .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, 1, 7) + .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, 1, 7) + .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, 1, 7) + .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, 1, 7) + .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, 1, 7) + .intState(DISTANCE) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); public static final Block SPONGE = register(new Block("sponge", builder().destroyTime(0.6f))); @@ -227,80 +227,80 @@ public final class Blocks { 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, "harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling", "zombie", "skeleton", "creeper", "dragon", "wither_skeleton", "piglin", "custom_head") - .intState(NOTE, 0, 24) + .enumState(NOTEBLOCK_INSTRUMENT) + .intState(NOTE) .booleanState(POWERED))); public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) - .enumState(BED_PART, "head", "foot"))); + .enumState(BED_PART))); public static final Block POWERED_RAIL = register(new Block("powered_rail", builder().destroyTime(0.7f) .booleanState(POWERED) - .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") + .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, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") + .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) @@ -311,14 +311,14 @@ public final class Blocks { 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, "upper", "lower"))); + .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))); public static final Block PISTON_HEAD = register(new Block("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, "normal", "sticky"))); + .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,7 +337,7 @@ public final class Blocks { 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().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .enumState(PISTON_TYPE, "normal", "sticky"))); + .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))); @@ -374,7 +374,7 @@ public final class Blocks { 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))); public static final Block FIRE = register(new Block("fire", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_15, 0, 15) + .intState(AGE_15) .booleanState(EAST) .booleanState(NORTH) .booleanState(SOUTH) @@ -384,73 +384,73 @@ public final class Blocks { public static final Block SPAWNER = register(new SpawnerBlock("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .enumState(HALF) + .enumState(STAIRS_SHAPE) .booleanState(WATERLOGGED))); public static final Block CHEST = register(new ChestBlock("chest", builder().setBlockEntity().destroyTime(2.5f) .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, "up", "side", "none") - .enumState(NORTH_REDSTONE, "up", "side", "none") - .intState(POWER, 0, 15) - .enumState(SOUTH_REDSTONE, "up", "side", "none") - .enumState(WEST_REDSTONE, "up", "side", "none"))); + .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, 0, 7))); + .intState(AGE_7))); public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f) - .intState(MOISTURE, 0, 7))); + .intState(MOISTURE))); public static final Block FURNACE = register(new FurnaceBlock("furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) .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().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block DARK_OAK_SIGN = register(new Block("dark_oak_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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))); public static final Block RAIL = register(new Block("rail", builder().destroyTime(0.7f) - .enumState(RAIL_SHAPE, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south", "south_east", "south_west", "north_west", "north_east") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .enumState(HALF) + .enumState(STAIRS_SHAPE) .booleanState(WATERLOGGED))); public static final Block OAK_WALL_SIGN = register(new Block("oak_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) @@ -481,47 +481,47 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block OAK_HANGING_SIGN = register(new Block("oak_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block SPRUCE_HANGING_SIGN = register(new Block("spruce_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block BIRCH_HANGING_SIGN = register(new Block("birch_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block ACACIA_HANGING_SIGN = register(new Block("acacia_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block CHERRY_HANGING_SIGN = register(new Block("cherry_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block JUNGLE_HANGING_SIGN = register(new Block("jungle_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block DARK_OAK_HANGING_SIGN = register(new Block("dark_oak_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block CRIMSON_HANGING_SIGN = register(new Block("crimson_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block WARPED_HANGING_SIGN = register(new Block("warped_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block MANGROVE_HANGING_SIGN = register(new Block("mangrove_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block BAMBOO_HANGING_SIGN = register(new Block("bamboo_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .booleanState(ATTACHED) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block OAK_WALL_HANGING_SIGN = register(new Block("oak_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) @@ -557,15 +557,15 @@ public final class Blocks { .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, "floor", "wall", "ceiling") + .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))); 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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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) @@ -596,18 +596,18 @@ public final class Blocks { .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, "floor", "wall", "ceiling") + .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, 1, 8))); + .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, 0, 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, 0, 15))); + .intState(AGE_15))); public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity().destroyTime(2.0f) .booleanState(HAS_RECORD))); public static final Block OAK_FENCE = register(new Block("oak_fence", builder().destroyTime(2.0f) @@ -634,9 +634,9 @@ public final class Blocks { 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))); public static final Block CAKE = register(new Block("cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .intState(BITES, 0, 6))); + .intState(BITES))); public static final Block REPEATER = register(new Block("repeater", builder().pushReaction(PistonBehavior.DESTROY) - .intState(DELAY, 1, 4) + .intState(DELAY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(LOCKED) .booleanState(POWERED))); @@ -658,55 +658,55 @@ public final class Blocks { 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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .enumState(HALF) .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); @@ -765,9 +765,9 @@ public final class Blocks { 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))); public static final Block PUMPKIN_STEM = register(new Block("pumpkin_stem", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_7, 0, 7))); + .intState(AGE_7))); public static final Block MELON_STEM = register(new Block("melon_stem", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_7, 0, 7))); + .intState(AGE_7))); public static final Block VINE = register(new Block("vine", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .booleanState(EAST) .booleanState(NORTH) @@ -789,18 +789,18 @@ public final class Blocks { .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .enumState(HALF) + .enumState(STAIRS_SHAPE) .booleanState(WATERLOGGED))); public static final Block MYCELIUM = register(new Block("mycelium", builder().destroyTime(0.6f) .booleanState(SNOWY))); @@ -814,11 +814,11 @@ public final class Blocks { .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, 0, 3))); + .intState(AGE_3))); public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(0.5f) .booleanState(HAS_BOTTLE_0) @@ -826,10 +826,10 @@ public final class Blocks { .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, 1, 3))); + .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, 1, 3))); + .intState(LEVEL_CAULDRON))); public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().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) @@ -839,12 +839,12 @@ public final class Blocks { public static final Block REDSTONE_LAMP = register(new Block("redstone_lamp", builder().destroyTime(0.3f) .booleanState(LIT))); public static final Block COCOA = register(new Block("cocoa", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(AGE_2, 0, 2) + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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))); @@ -866,37 +866,37 @@ public final class Blocks { 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .enumState(HALF) + .enumState(STAIRS_SHAPE) .booleanState(WATERLOGGED))); public static final Block COMMAND_BLOCK = register(new Block("command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .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().destroyTime(3.0f))); public static final Block COBBLESTONE_WALL = register(new Block("cobblestone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block MOSSY_COBBLESTONE_WALL = register(new Block("mossy_cobblestone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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))); @@ -926,84 +926,84 @@ 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, 0, 7))); + .intState(AGE_7))); public static final Block POTATOES = register(new Block("potatoes", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_7, 0, 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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block SKELETON_WALL_SKULL = register(new WallSkullBlock("skeleton_wall_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block WITHER_SKELETON_WALL_SKULL = register(new WallSkullBlock("wither_skeleton_wall_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block ZOMBIE_WALL_HEAD = register(new WallSkullBlock("zombie_wall_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block PLAYER_WALL_HEAD = register(new WallSkullBlock("player_wall_head", SkullBlock.Type.PLAYER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block CREEPER_WALL_HEAD = register(new WallSkullBlock("creeper_wall_head", SkullBlock.Type.CREEPER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block DRAGON_WALL_HEAD = register(new WallSkullBlock("dragon_wall_head", SkullBlock.Type.DRAGON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block PIGLIN_WALL_HEAD = register(new WallSkullBlock("piglin_wall_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); @@ -1018,16 +1018,16 @@ public final class Blocks { .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, 0, 15))); + .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, 0, 15))); + .intState(POWER))); public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(MODE_COMPARATOR, "compare", "subtract") + .enumState(MODE_COMPARATOR) .booleanState(POWERED))); public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder().setBlockEntity().destroyTime(0.2f) .booleanState(INVERTED) - .intState(POWER, 0, 15))); + .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().requiresCorrectToolForDrops().destroyTime(3.0f) @@ -1039,12 +1039,12 @@ public final class Blocks { .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") + .enumState(RAIL_SHAPE_STRAIGHT) .booleanState(WATERLOGGED))); public static final Block DROPPER = register(new Block("dropper", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) @@ -1163,43 +1163,43 @@ public final class Blocks { .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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))); public static final Block LIGHT = register(new Block("light", builder().destroyTime(-1.0f) - .intState(LEVEL, 0, 15) + .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, "top", "bottom") + .enumState(HALF) .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); @@ -1208,27 +1208,27 @@ public final class Blocks { 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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) @@ -1253,49 +1253,49 @@ 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, "upper", "lower"))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block LILAC = register(new Block("lilac", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block ROSE_BUSH = register(new Block("rose_bush", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block PEONY = register(new Block("peony", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block TALL_GRASS = register(new Block("tall_grass", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block LARGE_FERN = register(new Block("large_fern", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15))); + .intState(ROTATION_16))); public static final Block WHITE_WALL_BANNER = register(new BannerBlock("white_wall_banner", 0, builder().setBlockEntity().destroyTime(1.0f) .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().destroyTime(1.0f) @@ -1333,80 +1333,80 @@ public final class Blocks { 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block SPRUCE_SLAB = register(new Block("spruce_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block BIRCH_SLAB = register(new Block("birch_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block JUNGLE_SLAB = register(new Block("jungle_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block ACACIA_SLAB = register(new Block("acacia_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block CHERRY_SLAB = register(new Block("cherry_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block MANGROVE_SLAB = register(new Block("mangrove_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block BAMBOO_SLAB = register(new Block("bamboo_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block STONE_SLAB = register(new Block("stone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block SANDSTONE_SLAB = register(new Block("sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block COBBLESTONE_SLAB = register(new Block("cobblestone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block BRICK_SLAB = register(new Block("brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block QUARTZ_SLAB = register(new Block("quartz_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block PURPUR_SLAB = register(new Block("purpur_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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))); @@ -1502,50 +1502,50 @@ public final class Blocks { .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) .booleanState(OPEN) .booleanState(POWERED))); public static final Block END_ROD = register(new Block("end_rod", builder() @@ -1558,25 +1558,25 @@ public final class Blocks { .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, 0, 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))); 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, 0, 1))); + .intState(AGE_1))); public static final Block PITCHER_CROP = register(new Block("pitcher_crop", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_4, 0, 4) - .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); + .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, "upper", "lower"))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block BEETROOTS = register(new Block("beetroots", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_3, 0, 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().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) @@ -1586,7 +1586,7 @@ public final class Blocks { .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, 0, 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))); @@ -1695,14 +1695,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, 0, 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, 1, 4) - .intState(HATCH, 0, 2))); + .intState(EGGS) + .intState(HATCH))); public static final Block SNIFFER_EGG = register(new Block("sniffer_egg", builder().destroyTime(0.5f) - .intState(HATCH, 0, 2))); + .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))); @@ -1784,16 +1784,16 @@ public final class Blocks { .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, 1, 4) + .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().destroyTime(3.0f) .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, 0, 1) - .enumState(BAMBOO_LEAVES, "none", "small", "large") - .intState(STAGE, 0, 1))); + .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())); @@ -1801,207 +1801,207 @@ public final class Blocks { .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block GRANITE_SLAB = register(new Block("granite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block ANDESITE_SLAB = register(new Block("andesite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block DIORITE_SLAB = register(new Block("diorite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block BRICK_WALL = register(new Block("brick_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block PRISMARINE_WALL = register(new Block("prismarine_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block RED_SANDSTONE_WALL = register(new Block("red_sandstone_wall", builder().requiresCorrectToolForDrops().destroyTime(0.8f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block GRANITE_WALL = register(new Block("granite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block STONE_BRICK_WALL = register(new Block("stone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block MUD_BRICK_WALL = register(new Block("mud_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block NETHER_BRICK_WALL = register(new Block("nether_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block ANDESITE_WALL = register(new Block("andesite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block SANDSTONE_WALL = register(new Block("sandstone_wall", builder().requiresCorrectToolForDrops().destroyTime(0.8f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block DIORITE_WALL = register(new Block("diorite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block SCAFFOLDING = register(new Block("scaffolding", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(BOTTOM) - .intState(STABILITY_DISTANCE, 0, 7) + .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))); @@ -2017,7 +2017,7 @@ public final class Blocks { 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, "floor", "wall", "ceiling") + .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().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) @@ -2027,7 +2027,7 @@ public final class Blocks { 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))); public static final Block BELL = register(new Block("bell", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(BELL_ATTACHMENT, "floor", "ceiling", "single_wall", "double_wall") + .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) @@ -2047,7 +2047,7 @@ public final class Blocks { .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, 0, 3))); + .intState(AGE_3))); public static final Block WARPED_STEM = register(new Block("warped_stem", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_WARPED_STEM = register(new Block("stripped_warped_stem", builder().destroyTime(2.0f) @@ -2073,19 +2073,19 @@ public final class Blocks { 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, 0, 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, 0, 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, "top", "bottom", "double") + .enumState(SLAB_TYPE) .booleanState(WATERLOGGED))); public static final Block WARPED_SLAB = register(new Block("warped_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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))); @@ -2105,13 +2105,13 @@ public final class Blocks { .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, "top", "bottom") + .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, "top", "bottom") + .enumState(HALF) .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); @@ -2127,39 +2127,39 @@ public final class Blocks { .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "floor", "wall", "ceiling") + .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, "floor", "wall", "ceiling") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) .booleanState(OPEN) .booleanState(POWERED))); public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block WARPED_SIGN = register(new Block("warped_sign", builder().setBlockEntity().destroyTime(1.0f) - .intState(ROTATION_16, 0, 15) + .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block CRIMSON_WALL_SIGN = register(new Block("crimson_wall_sign", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) @@ -2168,26 +2168,26 @@ public final class Blocks { .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().requiresCorrectToolForDrops().destroyTime(-1.0f) - .enumState(STRUCTUREBLOCK_MODE, "save", "load", "corner", "data"))); + .enumState(STRUCTUREBLOCK_MODE))); public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .enumState(ORIENTATION, FrontAndTop.VALUES))); public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f) - .intState(LEVEL_COMPOSTER, 0, 8))); + .intState(LEVEL_COMPOSTER))); public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f) - .intState(POWER, 0, 15))); + .intState(POWER))); public static final Block BEE_NEST = register(new Block("bee_nest", builder().setBlockEntity().destroyTime(0.3f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .intState(LEVEL_HONEY, 0, 5))); + .intState(LEVEL_HONEY))); public static final Block BEEHIVE = register(new Block("beehive", builder().setBlockEntity().destroyTime(0.6f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .intState(LEVEL_HONEY, 0, 5))); + .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, 0, 4))); + .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,129 +2196,129 @@ public final class Blocks { 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .enumState(WEST_WALL))); public static final Block BLACKSTONE_SLAB = register(new Block("blackstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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))); public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE, "floor", "wall", "ceiling") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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, 1, 4) + .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) @@ -2371,65 +2371,65 @@ public final class Blocks { .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, "top", "bottom", "double") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "top", "bottom", "double") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "top", "bottom", "double") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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().destroyTime(1.5f) - .intState(POWER, 0, 15) - .enumState(SCULK_SENSOR_PHASE, "inactive", "active", "cooldown") + .intState(POWER) + .enumState(SCULK_SENSOR_PHASE) .booleanState(WATERLOGGED))); public static final Block CALIBRATED_SCULK_SENSOR = register(new Block("calibrated_sculk_sensor", builder().setBlockEntity().destroyTime(1.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .intState(POWER, 0, 15) - .enumState(SCULK_SENSOR_PHASE, "inactive", "active", "cooldown") + .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) @@ -2466,35 +2466,35 @@ public final class Blocks { 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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))); @@ -2506,129 +2506,129 @@ public final class Blocks { 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "top", "bottom", "double") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "upper", "lower") - .enumState(DOOR_HINGE, "left", "right") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .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, "top", "bottom") + .enumState(HALF) .booleanState(OPEN) .booleanState(POWERED) .booleanState(WATERLOGGED))); @@ -2677,12 +2677,12 @@ public final class Blocks { .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, "tip_merge", "tip", "frustum", "middle", "base") + .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, 0, 25) + .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))); @@ -2692,18 +2692,18 @@ public final class Blocks { 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, 1, 4))); + .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, "none", "unstable", "partial", "full") + .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))); 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, "upper", "lower") + .enumState(DOUBLE_BLOCK_HALF) .booleanState(WATERLOGGED))); public static final Block HANGING_ROOTS = register(new Block("hanging_roots", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); @@ -2714,67 +2714,67 @@ public final class Blocks { 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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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, "top", "bottom") - .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") + .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, "top", "bottom", "double") + .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, "none", "low", "tall") - .enumState(NORTH_WALL, "none", "low", "tall") - .enumState(SOUTH_WALL, "none", "low", "tall") + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) .booleanState(UP) .booleanState(WATERLOGGED) - .enumState(WEST_WALL, "none", "low", "tall"))); + .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))); @@ -2804,11 +2804,11 @@ public final class Blocks { .booleanState(TRIGGERED))); public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f) .booleanState(OMINOUS) - .enumState(TRIAL_SPAWNER_STATE, "inactive", "waiting_for_players", "active", "waiting_for_reward_ejection", "ejecting_reward", "cooldown"))); + .enumState(TRIAL_SPAWNER_STATE))); public static final Block VAULT = register(new Block("vault", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OMINOUS) - .enumState(VAULT_STATE, "inactive", "active", "unlocking", "ejecting"))); + .enumState(VAULT_STATE))); public static final Block HEAVY_CORE = register(new Block("heavy_core", builder().destroyTime(10.0f) .booleanState(WATERLOGGED))); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/BasicEnumProperty.java b/core/src/main/java/org/geysermc/geyser/level/block/property/BasicEnumProperty.java new file mode 100644 index 000000000..f55b85d7b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/BasicEnumProperty.java @@ -0,0 +1,63 @@ +/* + * 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.level.block.property; + +import java.util.List; + +/** + * Represents enums we don't need classes for in Geyser. + */ +public final class BasicEnumProperty extends Property { + private final List values; + + private BasicEnumProperty(String name, List values) { + super(name); + this.values = values; + } + + @Override + public int valuesCount() { + return this.values.size(); + } + + @Override + public int indexOf(String value) { + int index = this.values.indexOf(value); + if (index == -1) { + throw new IllegalStateException("Property " + this + " does not have value " + value); + } + return index; + } + + @SuppressWarnings("unchecked") + public T values() { + return (T) this.values; + } + + public static BasicEnumProperty create(String name, String... values) { + return new BasicEnumProperty(name, List.of(values)); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/BooleanProperty.java b/core/src/main/java/org/geysermc/geyser/level/block/property/BooleanProperty.java new file mode 100644 index 000000000..56877f537 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/BooleanProperty.java @@ -0,0 +1,46 @@ +/* + * 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.level.block.property; + +public final class BooleanProperty extends Property { + private BooleanProperty(String name) { + super(name); + } + + @Override + public int valuesCount() { + return 2; + } + + @Override + public int indexOf(Boolean value) { + return value ? 0 : 1; + } + + public static BooleanProperty create(String name) { + return new BooleanProperty(name); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/EnumProperty.java b/core/src/main/java/org/geysermc/geyser/level/block/property/EnumProperty.java new file mode 100644 index 000000000..e31f665f9 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/EnumProperty.java @@ -0,0 +1,59 @@ +/* + * 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.level.block.property; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; + +public final class EnumProperty> extends Property { + private final IntList ordinalValues; + + /** + * @param values all possible values of this enum. + */ + private EnumProperty(String name, T[] values) { + super(name); + this.ordinalValues = new IntArrayList(values.length); + for (T anEnum : values) { + this.ordinalValues.add(anEnum.ordinal()); + } + } + + @Override + public int valuesCount() { + return this.ordinalValues.size(); + } + + @Override + public int indexOf(T value) { + return this.ordinalValues.indexOf(value.ordinal()); + } + + @SafeVarargs + public static > EnumProperty create(String name, T... values) { + return new EnumProperty<>(name, values); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/IntegerProperty.java b/core/src/main/java/org/geysermc/geyser/level/block/property/IntegerProperty.java new file mode 100644 index 000000000..a772f414d --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/IntegerProperty.java @@ -0,0 +1,59 @@ +/* + * 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.level.block.property; + +public final class IntegerProperty extends Property { + private final int offset; + private final int valuesCount; + + private IntegerProperty(String name, int low, int high) { + super(name); + this.offset = low; + this.valuesCount = high - low; + } + + @Override + public int valuesCount() { + return this.valuesCount; + } + + @Override + public int indexOf(Integer value) { + return value - this.offset; + } + + public int low() { + return this.offset; + } + + public int high() { + return this.offset + this.valuesCount; + } + + public static IntegerProperty create(String name, int low, int high) { + return new IntegerProperty(name, low, high); + } +} 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 7df09003d..7efa2ef80 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 @@ -29,118 +29,118 @@ import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Direction; public final class Properties { - public static final Property ATTACHED = Property.create("attached"); - public static final Property BOTTOM = Property.create("bottom"); - public static final Property CONDITIONAL = Property.create("conditional"); - public static final Property DISARMED = Property.create("disarmed"); - public static final Property DRAG = Property.create("drag"); - public static final Property ENABLED = Property.create("enabled"); - public static final Property EXTENDED = Property.create("extended"); - public static final Property EYE = Property.create("eye"); - public static final Property FALLING = Property.create("falling"); - public static final Property HANGING = Property.create("hanging"); - public static final Property HAS_BOTTLE_0 = Property.create("has_bottle_0"); - public static final Property HAS_BOTTLE_1 = Property.create("has_bottle_1"); - public static final Property HAS_BOTTLE_2 = Property.create("has_bottle_2"); - public static final Property HAS_RECORD = Property.create("has_record"); - public static final Property HAS_BOOK = Property.create("has_book"); - public static final Property INVERTED = Property.create("inverted"); - public static final Property IN_WALL = Property.create("in_wall"); - public static final Property LIT = Property.create("lit"); - public static final Property LOCKED = Property.create("locked"); - public static final Property OCCUPIED = Property.create("occupied"); - public static final Property OPEN = Property.create("open"); - public static final Property PERSISTENT = Property.create("persistent"); - public static final Property POWERED = Property.create("powered"); - public static final Property SHORT = Property.create("short"); - public static final Property SIGNAL_FIRE = Property.create("signal_fire"); - public static final Property SNOWY = Property.create("snowy"); - public static final Property TRIGGERED = Property.create("triggered"); - public static final Property UNSTABLE = Property.create("unstable"); - public static final Property WATERLOGGED = Property.create("waterlogged"); - public static final Property BERRIES = Property.create("berries"); - public static final Property BLOOM = Property.create("bloom"); - public static final Property SHRIEKING = Property.create("shrieking"); - public static final Property CAN_SUMMON = Property.create("can_summon"); - public static final Property HORIZONTAL_AXIS = Property.create("axis"); - public static final Property AXIS = Property.create("axis"); - public static final Property UP = Property.create("up"); - public static final Property DOWN = Property.create("down"); - public static final Property NORTH = Property.create("north"); - public static final Property EAST = Property.create("east"); - public static final Property SOUTH = Property.create("south"); - public static final Property WEST = Property.create("west"); - public static final Property FACING = Property.create("facing"); - public static final Property FACING_HOPPER = Property.create("facing"); - public static final Property HORIZONTAL_FACING = Property.create("facing"); - public static final Property FLOWER_AMOUNT = Property.create("flower_amount"); - public static final Property ORIENTATION = Property.create("orientation"); - public static final Property ATTACH_FACE = Property.create("face"); - public static final Property BELL_ATTACHMENT = Property.create("attachment"); - public static final Property EAST_WALL = Property.create("east"); - public static final Property NORTH_WALL = Property.create("north"); - public static final Property SOUTH_WALL = Property.create("south"); - public static final Property WEST_WALL = Property.create("west"); - public static final Property EAST_REDSTONE = Property.create("east"); - public static final Property NORTH_REDSTONE = Property.create("north"); - public static final Property SOUTH_REDSTONE = Property.create("south"); - public static final Property WEST_REDSTONE = Property.create("west"); - public static final Property DOUBLE_BLOCK_HALF = Property.create("half"); - public static final Property HALF = Property.create("half"); - public static final Property RAIL_SHAPE = Property.create("shape"); - public static final Property RAIL_SHAPE_STRAIGHT = Property.create("shape"); - public static final Property AGE_1 = Property.create("age"); - public static final Property AGE_2 = Property.create("age"); - public static final Property AGE_3 = Property.create("age"); - public static final Property AGE_4 = Property.create("age"); - public static final Property AGE_5 = Property.create("age"); - public static final Property AGE_7 = Property.create("age"); - public static final Property AGE_15 = Property.create("age"); - public static final Property AGE_25 = Property.create("age"); - public static final Property BITES = Property.create("bites"); - public static final Property CANDLES = Property.create("candles"); - public static final Property DELAY = Property.create("delay"); - public static final Property DISTANCE = Property.create("distance"); - public static final Property EGGS = Property.create("eggs"); - public static final Property HATCH = Property.create("hatch"); - public static final Property LAYERS = Property.create("layers"); - public static final Property LEVEL_CAULDRON = Property.create("level"); - public static final Property LEVEL_COMPOSTER = Property.create("level"); - public static final Property LEVEL_FLOWING = Property.create("level"); - public static final Property LEVEL_HONEY = Property.create("honey_level"); - public static final Property LEVEL = Property.create("level"); - public static final Property MOISTURE = Property.create("moisture"); - public static final Property NOTE = Property.create("note"); - public static final Property PICKLES = Property.create("pickles"); - public static final Property POWER = Property.create("power"); - public static final Property STAGE = Property.create("stage"); - public static final Property STABILITY_DISTANCE = Property.create("distance"); - public static final Property RESPAWN_ANCHOR_CHARGES = Property.create("charges"); - public static final Property ROTATION_16 = Property.create("rotation"); - public static final Property BED_PART = Property.create("part"); - public static final Property CHEST_TYPE = Property.create("type"); - public static final Property MODE_COMPARATOR = Property.create("mode"); - public static final Property DOOR_HINGE = Property.create("hinge"); - public static final Property NOTEBLOCK_INSTRUMENT = Property.create("instrument"); - public static final Property PISTON_TYPE = Property.create("type"); - public static final Property SLAB_TYPE = Property.create("type"); - public static final Property STAIRS_SHAPE = Property.create("shape"); - public static final Property STRUCTUREBLOCK_MODE = Property.create("mode"); - public static final Property BAMBOO_LEAVES = Property.create("leaves"); - public static final Property TILT = Property.create("tilt"); - public static final Property VERTICAL_DIRECTION = Property.create("vertical_direction"); - public static final Property DRIPSTONE_THICKNESS = Property.create("thickness"); - public static final Property SCULK_SENSOR_PHASE = Property.create("sculk_sensor_phase"); - public static final Property CHISELED_BOOKSHELF_SLOT_0_OCCUPIED = Property.create("slot_0_occupied"); - public static final Property CHISELED_BOOKSHELF_SLOT_1_OCCUPIED = Property.create("slot_1_occupied"); - public static final Property CHISELED_BOOKSHELF_SLOT_2_OCCUPIED = Property.create("slot_2_occupied"); - public static final Property CHISELED_BOOKSHELF_SLOT_3_OCCUPIED = Property.create("slot_3_occupied"); - public static final Property CHISELED_BOOKSHELF_SLOT_4_OCCUPIED = Property.create("slot_4_occupied"); - public static final Property CHISELED_BOOKSHELF_SLOT_5_OCCUPIED = Property.create("slot_5_occupied"); - public static final Property DUSTED = Property.create("dusted"); - public static final Property CRACKED = Property.create("cracked"); - public static final Property CRAFTING = Property.create("crafting"); - public static final Property TRIAL_SPAWNER_STATE = Property.create("trial_spawner_state"); - public static final Property VAULT_STATE = Property.create("vault_state"); - public static final Property OMINOUS = Property.create("ominous"); + public static final BooleanProperty ATTACHED = BooleanProperty.create("attached"); + public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom"); + public static final BooleanProperty CONDITIONAL = BooleanProperty.create("conditional"); + public static final BooleanProperty DISARMED = BooleanProperty.create("disarmed"); + public static final BooleanProperty DRAG = BooleanProperty.create("drag"); + public static final BooleanProperty ENABLED = BooleanProperty.create("enabled"); + public static final BooleanProperty EXTENDED = BooleanProperty.create("extended"); + public static final BooleanProperty EYE = BooleanProperty.create("eye"); + public static final BooleanProperty FALLING = BooleanProperty.create("falling"); + public static final BooleanProperty HANGING = BooleanProperty.create("hanging"); + public static final BooleanProperty HAS_BOTTLE_0 = BooleanProperty.create("has_bottle_0"); + public static final BooleanProperty HAS_BOTTLE_1 = BooleanProperty.create("has_bottle_1"); + public static final BooleanProperty HAS_BOTTLE_2 = BooleanProperty.create("has_bottle_2"); + public static final BooleanProperty HAS_RECORD = BooleanProperty.create("has_record"); + public static final BooleanProperty HAS_BOOK = BooleanProperty.create("has_book"); + 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 LOCKED = BooleanProperty.create("locked"); + public static final BooleanProperty OCCUPIED = BooleanProperty.create("occupied"); + public static final BooleanProperty OPEN = BooleanProperty.create("open"); + public static final BooleanProperty PERSISTENT = BooleanProperty.create("persistent"); + public static final BooleanProperty POWERED = BooleanProperty.create("powered"); + public static final BooleanProperty SHORT = BooleanProperty.create("short"); + public static final BooleanProperty SIGNAL_FIRE = BooleanProperty.create("signal_fire"); + public static final BooleanProperty SNOWY = BooleanProperty.create("snowy"); + public static final BooleanProperty TRIGGERED = BooleanProperty.create("triggered"); + public static final BooleanProperty UNSTABLE = BooleanProperty.create("unstable"); + public static final BooleanProperty WATERLOGGED = BooleanProperty.create("waterlogged"); + public static final BooleanProperty BERRIES = BooleanProperty.create("berries"); + public static final BooleanProperty BLOOM = BooleanProperty.create("bloom"); + public static final BooleanProperty SHRIEKING = BooleanProperty.create("shrieking"); + public static final BooleanProperty CAN_SUMMON = BooleanProperty.create("can_summon"); + public static final EnumProperty HORIZONTAL_AXIS = EnumProperty.create("axis", Axis.X, Axis.Z); + public static final EnumProperty AXIS = EnumProperty.create("axis", Axis.VALUES); + public static final BooleanProperty UP = BooleanProperty.create("up"); + public static final BooleanProperty DOWN = BooleanProperty.create("down"); + public static final BooleanProperty NORTH = BooleanProperty.create("north"); + public static final BooleanProperty EAST = BooleanProperty.create("east"); + public static final BooleanProperty SOUTH = BooleanProperty.create("south"); + public static final BooleanProperty WEST = BooleanProperty.create("west"); + public static final EnumProperty FACING = EnumProperty.create("facing", Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN); + public static final EnumProperty FACING_HOPPER = EnumProperty.create("facing", Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST); + public static final EnumProperty HORIZONTAL_FACING = EnumProperty.create("facing", Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST); + public static final IntegerProperty FLOWER_AMOUNT = IntegerProperty.create("flower_amount", 1, 4); + public static final EnumProperty ORIENTATION = EnumProperty.create("orientation", FrontAndTop.VALUES); + public static final BasicEnumProperty ATTACH_FACE = BasicEnumProperty.create("face", "floor", "wall", "ceiling"); + public static final BasicEnumProperty BELL_ATTACHMENT = BasicEnumProperty.create("attachment", "floor", "ceiling", "single_wall", "double_wall"); + public static final BasicEnumProperty EAST_WALL = BasicEnumProperty.create("east", "none", "low", "tall"); + public static final BasicEnumProperty NORTH_WALL = BasicEnumProperty.create("north", "none", "low", "tall"); + public static final BasicEnumProperty SOUTH_WALL = BasicEnumProperty.create("south", "none", "low", "tall"); + public static final BasicEnumProperty WEST_WALL = BasicEnumProperty.create("west", "none", "low", "tall"); + public static final BasicEnumProperty EAST_REDSTONE = BasicEnumProperty.create("east", "up", "side", "none"); + public static final BasicEnumProperty NORTH_REDSTONE = BasicEnumProperty.create("north", "up", "side", "none"); + public static final BasicEnumProperty SOUTH_REDSTONE = BasicEnumProperty.create("south", "up", "side", "none"); + public static final BasicEnumProperty WEST_REDSTONE = BasicEnumProperty.create("west", "up", "side", "none"); + public static final BasicEnumProperty DOUBLE_BLOCK_HALF = BasicEnumProperty.create("half", "upper", "lower"); + public static final BasicEnumProperty HALF = BasicEnumProperty.create("half", "top", "bottom"); + public static final BasicEnumProperty RAIL_SHAPE = BasicEnumProperty.create("shape", "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south", "south_east", "south_west", "north_west", "north_east"); + public static final BasicEnumProperty RAIL_SHAPE_STRAIGHT = BasicEnumProperty.create("shape", "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south"); + public static final IntegerProperty AGE_1 = IntegerProperty.create("age", 0, 1); + public static final IntegerProperty AGE_2 = IntegerProperty.create("age", 0, 2); + public static final IntegerProperty AGE_3 = IntegerProperty.create("age", 0, 3); + public static final IntegerProperty AGE_4 = IntegerProperty.create("age", 0, 4); + public static final IntegerProperty AGE_5 = IntegerProperty.create("age", 0, 5); + public static final IntegerProperty AGE_7 = IntegerProperty.create("age", 0, 7); + public static final IntegerProperty AGE_15 = IntegerProperty.create("age", 0, 15); + public static final IntegerProperty AGE_25 = IntegerProperty.create("age", 0, 25); + public static final IntegerProperty BITES = IntegerProperty.create("bites", 0, 6); + public static final IntegerProperty CANDLES = IntegerProperty.create("candles", 1, 4); + public static final IntegerProperty DELAY = IntegerProperty.create("delay", 1, 4); + public static final IntegerProperty DISTANCE = IntegerProperty.create("distance", 1, 7); + public static final IntegerProperty EGGS = IntegerProperty.create("eggs", 1, 4); + public static final IntegerProperty HATCH = IntegerProperty.create("hatch", 0, 2); + public static final IntegerProperty LAYERS = IntegerProperty.create("layers", 1, 8); + public static final IntegerProperty LEVEL_CAULDRON = IntegerProperty.create("level", 1, 3); + public static final IntegerProperty LEVEL_COMPOSTER = IntegerProperty.create("level", 0, 8); + public static final IntegerProperty LEVEL_FLOWING = IntegerProperty.create("level", 1, 8); + public static final IntegerProperty LEVEL_HONEY = IntegerProperty.create("honey_level", 0, 5); + public static final IntegerProperty LEVEL = IntegerProperty.create("level", 0, 15); + public static final IntegerProperty MOISTURE = IntegerProperty.create("moisture", 0, 7); + public static final IntegerProperty NOTE = IntegerProperty.create("note", 0, 24); + public static final IntegerProperty PICKLES = IntegerProperty.create("pickles", 1, 4); + public static final IntegerProperty POWER = IntegerProperty.create("power", 0, 15); + public static final IntegerProperty STAGE = IntegerProperty.create("stage", 0, 1); + public static final IntegerProperty STABILITY_DISTANCE = IntegerProperty.create("distance", 0, 7); + public static final IntegerProperty RESPAWN_ANCHOR_CHARGES = IntegerProperty.create("charges", 0, 4); + public static final IntegerProperty ROTATION_16 = IntegerProperty.create("rotation", 0, 15); + public static final BasicEnumProperty BED_PART = BasicEnumProperty.create("part", "head", "foot"); + public static final EnumProperty CHEST_TYPE = EnumProperty.create("type", ChestType.VALUES); + public static final BasicEnumProperty MODE_COMPARATOR = BasicEnumProperty.create("mode", "compare", "subtract"); + public static final BasicEnumProperty DOOR_HINGE = BasicEnumProperty.create("hinge", "left", "right"); + public static final BasicEnumProperty NOTEBLOCK_INSTRUMENT = BasicEnumProperty.create("instrument", "harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling", "zombie", "skeleton", "creeper", "dragon", "wither_skeleton", "piglin", "custom_head"); + public static final BasicEnumProperty PISTON_TYPE = BasicEnumProperty.create("type", "normal", "sticky"); + public static final BasicEnumProperty SLAB_TYPE = BasicEnumProperty.create("type", "top", "bottom", "double"); + public static final BasicEnumProperty STAIRS_SHAPE = BasicEnumProperty.create("shape", "straight", "inner_left", "inner_right", "outer_left", "outer_right"); + public static final BasicEnumProperty STRUCTUREBLOCK_MODE = BasicEnumProperty.create("mode", "save", "load", "corner", "data"); + public static final BasicEnumProperty BAMBOO_LEAVES = BasicEnumProperty.create("leaves", "none", "small", "large"); + public static final BasicEnumProperty TILT = BasicEnumProperty.create("tilt", "none", "unstable", "partial", "full"); + public static final EnumProperty VERTICAL_DIRECTION = EnumProperty.create("vertical_direction", Direction.UP, Direction.DOWN); + public static final BasicEnumProperty DRIPSTONE_THICKNESS = BasicEnumProperty.create("thickness", "tip_merge", "tip", "frustum", "middle", "base"); + public static final BasicEnumProperty SCULK_SENSOR_PHASE = BasicEnumProperty.create("sculk_sensor_phase", "inactive", "active", "cooldown"); + public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_0_OCCUPIED = BooleanProperty.create("slot_0_occupied"); + public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_1_OCCUPIED = BooleanProperty.create("slot_1_occupied"); + public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_2_OCCUPIED = BooleanProperty.create("slot_2_occupied"); + public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_3_OCCUPIED = BooleanProperty.create("slot_3_occupied"); + public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_4_OCCUPIED = BooleanProperty.create("slot_4_occupied"); + public static final BooleanProperty CHISELED_BOOKSHELF_SLOT_5_OCCUPIED = BooleanProperty.create("slot_5_occupied"); + public static final IntegerProperty DUSTED = IntegerProperty.create("dusted", 0, 3); + public static final BooleanProperty CRACKED = BooleanProperty.create("cracked"); + 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 BooleanProperty OMINOUS = BooleanProperty.create("ominous"); } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java b/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java index ca5f62daa..0c4713124 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/Property.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.level.block.property; -public class Property> { +public abstract class Property> { private final String name; - public Property(String name) { + protected Property(String name) { this.name = name; } @@ -36,12 +36,12 @@ public class Property> { return name; } + public abstract int valuesCount(); + + public abstract int indexOf(T value); + @Override public String toString() { return getClass().getSimpleName() + "[" + name + "]"; } - - public static > Property create(String name) { - return new Property<>(name); - } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index b31c9aeb5..9fe70c0f1 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -27,9 +27,6 @@ package org.geysermc.geyser.level.block.type; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; -import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; -import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; @@ -37,6 +34,8 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.BasicEnumProperty; +import org.geysermc.geyser.level.block.property.IntegerProperty; import org.geysermc.geyser.level.block.property.Property; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; @@ -67,6 +66,12 @@ public class Block { protected Item item = null; private int javaId = -1; + /** + * Used for switching a given block state to different states. + */ + private final Property[] propertyKeys; + private final BlockState defaultState; + public Block(@Subst("empty") String javaIdentifier, Builder builder) { this.javaIdentifier = Key.key(javaIdentifier); this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops; @@ -74,7 +79,10 @@ public class Block { this.destroyTime = builder.destroyTime; this.pushReaction = builder.pushReaction; this.pickItem = builder.pickItem; - processStates(builder.build(this)); + + BlockState firstState = builder.build(this).get(0); + this.propertyKeys = builder.propertyKeys; // Ensure this is not null before iterating over states + this.defaultState = setDefaultState(firstState); } public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { @@ -167,9 +175,11 @@ public class Block { } /** - * A list of BlockStates is created pertaining to this block. Do we need any of them? If so, override this method. + * Should only be ran on block creation. Can be overridden. + * @param firstState the first state created from this block */ - protected void processStates(List states) { + protected BlockState setDefaultState(BlockState firstState) { + return firstState; } @NonNull @@ -194,6 +204,10 @@ public class Block { return this.pushReaction; } + public BlockState defaultBlockState() { + return this.defaultState; + } + public int javaId() { return javaId; } @@ -213,6 +227,10 @@ public class Block { '}'; } + Property[] propertyKeys() { + return propertyKeys; + } + public static Builder builder() { return new Builder(); } @@ -225,11 +243,14 @@ public class Block { private float destroyTime; private Supplier pickItem; + // We'll use this field after building + private Property[] propertyKeys; + /** * For states that we're just tracking for mirroring Java states. */ - public Builder enumState(Property property, String... values) { - states.put(property, List.of(values)); + public Builder enumState(BasicEnumProperty property) { + states.put(property, property.values()); return this; } @@ -244,7 +265,9 @@ public class Block { return this; } - public Builder intState(Property property, int low, int high) { + public Builder intState(IntegerProperty property) { + int low = property.low(); + int high = property.high(); IntList list = new IntArrayList(); // There is a state for every number between the low and high. for (int i = low; i <= high; i++) { @@ -283,17 +306,18 @@ public class Block { if (states.isEmpty()) { BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size()); BlockRegistries.BLOCK_STATES.get().add(state); + propertyKeys = null; return List.of(state); } else if (states.size() == 1) { // We can optimize because we don't need to worry about combinations Map.Entry, List>> property = this.states.entrySet().stream().findFirst().orElseThrow(); List states = new ArrayList<>(property.getValue().size()); property.getValue().forEach(value -> { - Reference2ObjectMap, Comparable> propertyMap = Reference2ObjectMaps.singleton(property.getKey(), value); - BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap); + BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), new Comparable[] {value}); BlockRegistries.BLOCK_STATES.get().add(state); states.add(state); }); + this.propertyKeys = new Property[]{property.getKey()}; return states; } else { // Think of this stream as another list containing, at the start, one empty list. @@ -327,11 +351,11 @@ public class Block { Property[] keys = this.states.keySet().toArray(new Property[0]); result.forEach(properties -> { Comparable[] values = properties.toArray(new Comparable[0]); - Reference2ObjectMap, Comparable> propertyMap = new Reference2ObjectArrayMap<>(keys, values); - BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap); + BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), values); BlockRegistries.BLOCK_STATES.get().add(state); states.add(state); }); + this.propertyKeys = keys; return states; } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 4fed30e7a..44271bd80 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -25,8 +25,7 @@ package org.geysermc.geyser.level.block.type; -import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; -import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.level.block.property.Property; import org.geysermc.geyser.registry.BlockRegistries; @@ -35,13 +34,18 @@ import java.util.Locale; public final class BlockState { private final Block block; private final int javaId; - private final Reference2ObjectMap, Comparable> states; + /** + * The values of each property of this block state. These should be treated as keys to {@link Block#propertyKeys()} + * Of note - the comparable part probably doesn't do anything because we occasionally use strings in place of enums. + * Will be null if there's only one block state for a block. + */ + private final Comparable[] states; public BlockState(Block block, int javaId) { - this(block, javaId, Reference2ObjectMaps.emptyMap()); + this(block, javaId, null); } - BlockState(Block block, int javaId, Reference2ObjectMap, Comparable> states) { + BlockState(Block block, int javaId, Comparable[] states) { this.block = block; this.javaId = javaId; this.states = states; @@ -49,23 +53,97 @@ public final class BlockState { public > T getValue(Property property) { //noinspection unchecked - return (T) states.get(property); + return (T) get(property); } public boolean getValue(Property property, boolean def) { - var value = states.get(property); + var value = get(property); if (value == null) { return def; } return (Boolean) value; } + @Nullable + private Comparable get(Property property) { + Property[] keys = this.block.propertyKeys(); + if (keys == null) { + return null; + } + // We're copying the behavior Reference2ObjectArrayMap uses + for (int i = keys.length; i-- != 0;) { + if (keys[i] == property) { + return this.states[i]; + } + } + return null; + } + + /** + * @return the {@link BlockState} instance with the given value. + */ + public > BlockState withValue(Property property, T value) { + Property[] keys = this.block.propertyKeys(); + if (keys == null) { + throw new IllegalStateException(this + " does not have any different states!"); + } + + T currentValue = getValue(property); + if (currentValue == null) { + throw new IllegalArgumentException("This BlockState does not have the property " + property); + } + if (currentValue.equals(value)) { + // No action required. This block state is the state we're looking for. + return this; + } + + // Diff is how much we will have to traverse as a sort of offset + + // Block states are calculated in a predictable structure: + // minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=none] + // minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=low] + // minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=tall] + // minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=false,west=none] + // minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=false,west=low] + // minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=false,west=tall] + // minecraft:cobblestone_wall[east=none,north=none,south=none,up=false,waterlogged=true,west=none] + + // The last value goes through all its iterations, then the next state goes through all its iterations. + // West goes none -> low -> tall, then waterlogged is toggled as west cycles again. + // Then when waterlogged goes through all its properties, up is toggled, and west goes through again + // If we want to find the "up" property in order, then we need to find how many iterations each property + // after it goes in. West goes for 3, waterlogged goes for 2. Adding those together, we find that we need to + // add five to get to the next toggle of the up property + int diff = 0; + for (int i = keys.length - 1; i >= 0; i--) { + if (keys[i] != property) { + diff += keys[i].valuesCount(); + } else { + break; + } + } + + // How many times do we have to jump by diff? This depends on how far away each value is from each other. + // piston_head[facing=north] might be right next to piston_head[facing=south], which just one diff'd hop. + // But piston_head[facing=west] is further away, requiring more hops. + int thatOffset = property.indexOf(value); + int thisOffset = property.indexOf(currentValue); + if (diff == 0) { + // This can happen if the property is at the tail end of the block and there are no other properties to look through + // If we have minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=none] + // And want minecraft:cobblestone_wall[east=none,north=none,south=none,up=true,waterlogged=true,west=low] + // The above for loop will always stop at the first break because the last property has already been found + diff = 1; + } + return BlockState.of(this.javaId + ((thatOffset - thisOffset) * diff)); + } + public Block block() { - return block; + return this.block; } public int javaId() { - return javaId; + return this.javaId; } public boolean is(Block block) { @@ -74,7 +152,7 @@ public final class BlockState { @Override public String toString() { - if (this.states.isEmpty()) { + if (this.states == null) { return this.block.javaIdentifier().toString(); } return this.block.javaIdentifier().toString() + "[" + paramsToString() + "]"; @@ -82,14 +160,15 @@ public final class BlockState { private String paramsToString() { StringBuilder builder = new StringBuilder(); - var it = this.states.entrySet().iterator(); - while (it.hasNext()) { - var entry = it.next(); - builder.append(entry.getKey().name()) - .append("=") - .append(entry.getValue().toString().toLowerCase(Locale.ROOT)); // lowercase covers enums - if (it.hasNext()) { - builder.append(","); + Property[] propertyKeys = this.block.propertyKeys(); + if (propertyKeys != null) { + for (int i = 0; i < propertyKeys.length; i++) { + builder.append(propertyKeys[i].name()) + .append("=") + .append(this.states[i].toString().toLowerCase(Locale.ROOT)); // lowercase covers enums + if (i < propertyKeys.length - 1) { + builder.append(","); + } } } return builder.toString(); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/FurnaceBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/FurnaceBlock.java index 2b898e089..25d54ff2d 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/FurnaceBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/FurnaceBlock.java @@ -28,29 +28,14 @@ package org.geysermc.geyser.level.block.type; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.physics.Direction; -import java.util.List; - public class FurnaceBlock extends Block { - private static BlockState LIT; - private static BlockState UNLIT; - public FurnaceBlock(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } @Override - protected void processStates(List states) { - LIT = states.stream() - .filter(state -> state.getValue(Properties.HORIZONTAL_FACING) == Direction.NORTH - && state.getValue(Properties.LIT)) - .findFirst().orElseThrow(); - UNLIT = states.stream() - .filter(state -> state.getValue(Properties.HORIZONTAL_FACING) == Direction.NORTH - && !state.getValue(Properties.LIT)) - .findFirst().orElseThrow(); - } - - public static BlockState state(boolean lit) { - return lit ? LIT : UNLIT; + protected BlockState setDefaultState(BlockState firstState) { + // Both furnace minecart states look north. + return firstState.withValue(Properties.HORIZONTAL_FACING, Direction.NORTH); } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/HoneyBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/HoneyBlock.java index 73c4d02aa..642240915 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/HoneyBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/HoneyBlock.java @@ -25,21 +25,8 @@ package org.geysermc.geyser.level.block.type; -import java.util.List; - public class HoneyBlock extends Block { - private static BlockState STATE; - public HoneyBlock(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } - - @Override - protected void processStates(List states) { - STATE = states.get(0); - } - - public static BlockState state() { - return STATE; - } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/SpawnerBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/SpawnerBlock.java index 2103fe6e5..968499d11 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/SpawnerBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/SpawnerBlock.java @@ -25,21 +25,8 @@ package org.geysermc.geyser.level.block.type; -import java.util.List; - public class SpawnerBlock extends Block { - private static BlockState STATE; - public SpawnerBlock(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } - - @Override - protected void processStates(List states) { - STATE = states.get(0); - } - - public static BlockState state() { - return STATE; - } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/WaterBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/WaterBlock.java index 801a7f9e7..9d2d23116 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/WaterBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/WaterBlock.java @@ -25,17 +25,8 @@ package org.geysermc.geyser.level.block.type; -import java.util.List; - public class WaterBlock extends Block { - private static BlockState LEVEL_0; - public WaterBlock(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } - - @Override - protected void processStates(List states) { - super.processStates(states); - } } 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 ce89689eb..2be4e7a38 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 @@ -39,6 +39,9 @@ import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.Blocks; +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.session.cache.PistonCache; import org.geysermc.geyser.translator.collision.BlockCollision; @@ -405,7 +408,8 @@ public class CollisionManager { * @return if the player is currently in a water block */ public boolean isPlayerInWater() { - return session.getGeyser().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockStateValues.JAVA_WATER_ID; + BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getPlayerEntity().getPosition().toInt()); + return state.is(Blocks.WATER) && state.getValue(Properties.LEVEL) == 0; } public boolean isWaterInEyes() { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 1d40386d4..6eadbd0e5 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -50,7 +50,6 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.Block; @@ -433,25 +432,13 @@ public final class BlockRegistryPopulator { } int javaRuntimeId = -1; - int waterRuntimeId = -1; for (BlockState javaBlockState : BlockRegistries.BLOCK_STATES.get()) { javaRuntimeId++; String javaId = javaBlockState.toString().intern(); - BlockStateValues.storeBlockStateValues(javaId, javaRuntimeId); - BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId); - - if ("minecraft:water[level=0]".equals(javaId)) { - waterRuntimeId = javaRuntimeId; - } } - if (waterRuntimeId == -1) { - throw new AssertionError("Unable to find Java water in palette"); - } - BlockStateValues.JAVA_WATER_ID = waterRuntimeId; - if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) { IntSet usedNonVanillaRuntimeIDs = new IntOpenHashSet(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index f618fde46..5c4e835e4 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -90,6 +90,10 @@ public class BlockMappings implements DefinitionRegistry { return this.getBedrockBlock(javaState.javaId()); } + public GeyserBedrockBlock getVanillaBedrockBlock(BlockState javaState) { + return getVanillaBedrockBlock(javaState.javaId()); + } + public GeyserBedrockBlock getVanillaBedrockBlock(int javaState) { if (javaState < 0 || javaState >= this.javaToVanillaBedrockBlocks.length) { return bedrockAir; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java index 2dfa2a85a..4476391c8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java @@ -31,6 +31,7 @@ import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.holder.InventoryHolder; import org.geysermc.geyser.inventory.updater.InventoryUpdater; import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; /** @@ -40,17 +41,25 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran private final InventoryHolder holder; private final InventoryUpdater updater; + /** + * @param javaBlock a Java block that is used as a temporary block + */ + public AbstractBlockInventoryTranslator(int size, Block javaBlock, ContainerType containerType, InventoryUpdater updater, + Block... additionalValidBlocks) { + this(size, javaBlock.defaultBlockState(), containerType, updater, additionalValidBlocks); + } + /** * @param size the amount of slots that the inventory adds alongside the base inventory slots - * @param javaBlockIdentifier a Java block identifier that is used as a temporary block + * @param javaBlockState a Java block state that is used as a temporary block * @param containerType the container type of this inventory * @param updater updater * @param additionalValidBlocks any other blocks that can safely use this inventory without a fake block */ - public AbstractBlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater, + public AbstractBlockInventoryTranslator(int size, BlockState javaBlockState, ContainerType containerType, InventoryUpdater updater, Block... additionalValidBlocks) { super(size); - this.holder = new BlockInventoryHolder(javaBlockIdentifier, containerType, additionalValidBlocks); + this.holder = new BlockInventoryHolder(javaBlockState, containerType, additionalValidBlocks); this.updater = updater; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java index 705fac362..40ee28362 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java @@ -45,7 +45,7 @@ import java.util.Objects; public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { - super(3, "minecraft:anvil[facing=north]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE, + super(3, Blocks.ANVIL, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE, Blocks.CHIPPED_ANVIL, Blocks.DAMAGED_ANVIL); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java index 9aeeff007..ceae1b640 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.inventory; import it.unimi.dsi.fastutil.ints.IntSets; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; @@ -43,7 +42,9 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetBeaconPacket; @@ -52,7 +53,7 @@ import java.util.OptionalInt; public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator { public BeaconInventoryTranslator() { - super(1, new BlockInventoryHolder("minecraft:beacon", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.BEACON) { + super(1, new BlockInventoryHolder(Blocks.BEACON, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.BEACON) { @Override protected boolean checkInteractionPosition(GeyserSession session) { // Since we can't fall back to a virtual inventory, let's make opening one easier @@ -89,12 +90,8 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator // Send a block entity data packet update to the fake beacon inventory Vector3i position = inventory.getHolderPosition(); - NbtMapBuilder builder = NbtMap.builder() - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) + NbtMapBuilder builder = BlockEntityTranslator.getConstantBedrockTag("Beacon", position) .putString("CustomName", inventory.getTitle()) - .putString("id", "Beacon") .putInt("primary", beaconContainer.getPrimaryId()) .putInt("secondary", beaconContainer.getSecondaryId()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java index a2c45384d..e425342f3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java @@ -32,11 +32,16 @@ import org.cloudburstmc.protocol.bedrock.packet.ContainerSetDataPacket; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.session.GeyserSession; public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator { public BrewingInventoryTranslator() { - super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND, ContainerInventoryUpdater.INSTANCE); + super(5, Blocks.BREWING_STAND.defaultBlockState() + .withValue(Properties.HAS_BOTTLE_0, false) + .withValue(Properties.HAS_BOTTLE_1, false) + .withValue(Properties.HAS_BOTTLE_2, false), ContainerType.BREWING_STAND, ContainerInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java index a115bd953..b0914e5dd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java @@ -30,12 +30,13 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemSt import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; public class CartographyInventoryTranslator extends AbstractBlockInventoryTranslator { public CartographyInventoryTranslator() { - super(3, "minecraft:cartography_table", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CARTOGRAPHY, UIInventoryUpdater.INSTANCE); + super(3, Blocks.CARTOGRAPHY_TABLE, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CARTOGRAPHY, UIInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java index 2a2f5beb5..8b0a0ac44 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java @@ -31,6 +31,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.updater.CrafterInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; @@ -53,7 +54,7 @@ public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator private static final int TRIGGERED = 1; // triggered value public CrafterInventoryTranslator() { - super(10, "minecraft:crafter", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CRAFTER, CrafterInventoryUpdater.INSTANCE); + super(10, Blocks.CRAFTER, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CRAFTER, CrafterInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java index 521db494a..4a0f1d7d9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java @@ -31,10 +31,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemSt import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslator { public CraftingInventoryTranslator() { - super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, UIInventoryUpdater.INSTANCE); + super(10, Blocks.CRAFTING_TABLE, ContainerType.WORKBENCH, UIInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java index 8fee2a391..e1407346a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java @@ -38,6 +38,7 @@ import org.cloudburstmc.protocol.bedrock.packet.PlayerEnchantOptionsPacket; import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; @@ -47,7 +48,7 @@ import java.util.Locale; public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator { public EnchantingInventoryTranslator() { - super(2, "minecraft:enchanting_table", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ENCHANTMENT, UIInventoryUpdater.INSTANCE); + super(2, Blocks.ENCHANTING_TABLE, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ENCHANTMENT, UIInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java index f47a367d8..80040e375 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java @@ -41,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; */ public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator { public Generic3X3InventoryTranslator() { - super(9, "minecraft:dispenser[facing=north,triggered=false]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE, + super(9, Blocks.DISPENSER, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE, Blocks.DROPPER); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java index a32b97b70..5344d27cb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java @@ -30,10 +30,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTranslator { public GrindstoneInventoryTranslator() { - super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, UIInventoryUpdater.INSTANCE); + super(3, Blocks.GRINDSTONE, ContainerType.GRINDSTONE, UIInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java index dab1ee972..fdcd7bf57 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java @@ -29,13 +29,14 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; /** * Implemented on top of any block that does not have special properties implemented */ public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator { public HopperInventoryTranslator() { - super(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, ContainerInventoryUpdater.INSTANCE); + super(5, Blocks.HOPPER, ContainerType.HOPPER, ContainerInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index f3bbc9b87..c6c3c7dd6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -34,6 +34,7 @@ import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; @@ -56,7 +57,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator private boolean initialized = false; public LecternInventoryTranslator() { - super(1, "minecraft:lectern[facing=north,has_book=true,powered=true]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.LECTERN , ContainerInventoryUpdater.INSTANCE); + super(1, Blocks.LECTERN, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.LECTERN , ContainerInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index e8571c8fb..0694e2ac6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -45,6 +45,7 @@ import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.item.type.BannerItem; import org.geysermc.geyser.item.type.DyeItem; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; @@ -101,7 +102,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { } public LoomInventoryTranslator() { - super(4, "minecraft:loom[facing=north]", ContainerType.LOOM, UIInventoryUpdater.INSTANCE); + super(4, Blocks.LOOM, ContainerType.LOOM, UIInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java index 201c900d6..21fe9ca21 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java @@ -37,6 +37,7 @@ import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InventoryUtils; @@ -53,7 +54,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator private static final IntFunction UPGRADE_TEMPLATE = InventoryUtils.getUpgradeTemplate(); private OldSmithingTableTranslator() { - super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); + super(3, Blocks.SMITHING_TABLE, ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java index 72f5260a0..464bf07f7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java @@ -35,7 +35,10 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; @@ -43,12 +46,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator { public ShulkerInventoryTranslator() { - super(27, new BlockInventoryHolder("minecraft:shulker_box[facing=north]", ContainerType.CONTAINER) { + // Ensure that the shulker box default state won't be trying to open in a state facing the player + super(27, new BlockInventoryHolder(Blocks.SHULKER_BOX.defaultBlockState().withValue(Properties.FACING, Direction.NORTH), ContainerType.CONTAINER) { private final BlockEntityTranslator shulkerBoxTranslator = Registries.BLOCK_ENTITIES.get(BlockEntityType.SHULKER_BOX); @Override - protected boolean isValidBlock(String[] javaBlockString) { - return javaBlockString[0].contains("shulker_box"); + protected boolean isValidBlock(BlockState blockState) { + return blockState.block().javaIdentifier().value().contains("shulker_box"); // TODO ew } @Override 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 730e4a451..c68347fd3 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 @@ -30,10 +30,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator { public SmithingInventoryTranslator() { - super(4, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); + super(4, Blocks.SMITHING_TABLE, ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java index 54f2f447b..b977ee1a1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java @@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemS import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; @@ -42,7 +43,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator { public StonecutterInventoryTranslator() { - super(2, "minecraft:stonecutter[facing=north]", org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.STONECUTTER, UIInventoryUpdater.INSTANCE); + super(2, Blocks.STONECUTTER, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.STONECUTTER, UIInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index 4c49c8e5a..4bc727397 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -40,6 +40,7 @@ import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.ChestType; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; @@ -51,7 +52,10 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { public DoubleChestInventoryTranslator(int size) { super(size, 54); - this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt("minecraft:chest[facing=north,type=single,waterlogged=false]"); + this.defaultJavaBlockState = Blocks.CHEST.defaultBlockState() + .withValue(Properties.HORIZONTAL_FACING, Direction.NORTH) + .withValue(Properties.CHEST_TYPE, ChestType.SINGLE) + .javaId(); } @Override @@ -96,11 +100,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); - NbtMap tag = NbtMap.builder() - .putString("id", "Chest") - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) + NbtMap tag = BlockEntityTranslator.getConstantBedrockTag("Chest", position) .putInt("pairx", pairPosition.getX()) .putInt("pairz", pairPosition.getZ()) .putString("CustomName", inventory.getTitle()).build(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java index e18096862..264b2eb29 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java @@ -30,6 +30,9 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.holder.InventoryHolder; import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.ChestType; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; public class SingleChestInventoryTranslator extends ChestInventoryTranslator { @@ -38,17 +41,17 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator { // TODO add barrel??? public SingleChestInventoryTranslator(int size) { super(size, 27); - this.holder = new BlockInventoryHolder("minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, + this.holder = new BlockInventoryHolder(Blocks.CHEST.defaultBlockState().withValue(Properties.CHEST_TYPE, ChestType.SINGLE), ContainerType.CONTAINER, Blocks.ENDER_CHEST, Blocks.TRAPPED_CHEST) { @Override - protected boolean isValidBlock(String[] javaBlockString) { - if (javaBlockString[0].equals("minecraft:ender_chest")) { + protected boolean isValidBlock(BlockState blockState) { + if (blockState.is(Blocks.ENDER_CHEST)) { // Can't have double ender chests return true; } // Add provision to ensure this isn't a double chest - return super.isValidBlock(javaBlockString) && (javaBlockString.length > 1 && javaBlockString[1].contains("type=single")); + return super.isValidBlock(blockState) && blockState.getValue(Properties.CHEST_TYPE) == ChestType.SINGLE; } }; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java index 6cda03a19..8991ef787 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java @@ -32,12 +32,14 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.AbstractBlockInventoryTranslator; public abstract class AbstractFurnaceInventoryTranslator extends AbstractBlockInventoryTranslator { - AbstractFurnaceInventoryTranslator(String javaBlockIdentifier, ContainerType containerType) { - super(3, javaBlockIdentifier, containerType, ContainerInventoryUpdater.INSTANCE); + AbstractFurnaceInventoryTranslator(Block javaBlock, ContainerType containerType) { + super(3, javaBlock.defaultBlockState().withValue(Properties.LIT, false), containerType, ContainerInventoryUpdater.INSTANCE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java index 0b6e0c674..185cafc51 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java @@ -28,10 +28,11 @@ package org.geysermc.geyser.translator.inventory.furnace; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.level.block.Blocks; public class BlastFurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator { public BlastFurnaceInventoryTranslator() { - super("minecraft:blast_furnace[facing=north,lit=false]", ContainerType.BLAST_FURNACE); + super(Blocks.BLAST_FURNACE, ContainerType.BLAST_FURNACE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java index 95a79a93e..bc96f7105 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java @@ -28,10 +28,11 @@ package org.geysermc.geyser.translator.inventory.furnace; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.level.block.Blocks; public class FurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator { public FurnaceInventoryTranslator() { - super("minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE); + super(Blocks.FURNACE, ContainerType.FURNACE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java index 2f87f3b13..380446f09 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java @@ -28,10 +28,11 @@ package org.geysermc.geyser.translator.inventory.furnace; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.level.block.Blocks; public class SmokerInventoryTranslator extends AbstractFurnaceInventoryTranslator { public SmokerInventoryTranslator() { - super("minecraft:smoker[facing=north,lit=false]", ContainerType.SMOKER); + super(Blocks.SMOKER, ContainerType.SMOKER); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index ca8679319..350ce8c3e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -26,22 +26,24 @@ package org.geysermc.geyser.translator.level.block.entity; import it.unimi.dsi.fastutil.ints.IntArrays; -import it.unimi.dsi.fastutil.objects.*; -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.level.block.type.HoneyBlock; -import org.geysermc.geyser.level.block.type.PistonBlock; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import lombok.Getter; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; -import lombok.Getter; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.level.block.BlockStateValues; +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.level.block.type.PistonBlock; import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.CollisionManager; @@ -53,6 +55,7 @@ import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import java.util.LinkedList; import java.util.Map; @@ -99,7 +102,7 @@ public class PistonBlockEntity { static { // Create a ~1 x ~0.5 x ~1 bounding box above the honey block - BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(HoneyBlock.state().javaId()); + BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(Blocks.HONEY_BLOCK.defaultBlockState().javaId()); if (blockCollision == null) { throw new RuntimeException("Failed to find honey block collision"); } @@ -224,10 +227,10 @@ public class PistonBlockEntity { private void removePistonHead() { Vector3i blockInFront = position.add(orientation.getUnitVector()); - int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockInFront); - if (BlockStateValues.isPistonHead(blockId)) { + BlockState state = session.getGeyser().getWorldManager().blockAt(session, blockInFront); + if (state.is(Blocks.PISTON_HEAD)) { ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront); - } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == Block.JAVA_AIR_ID) { + } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && state.is(Blocks.AIR)) { // Spigot removes the piston head from the cache, but we need to send the block update ourselves ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront); } @@ -353,7 +356,9 @@ public class PistonBlockEntity { playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() - shrink.getZ()); // Resolve collision with the piston head - BlockState pistonHeadId = BlockState.of(BlockStateValues.getPistonHead(orientation)); + BlockState pistonHeadId = Blocks.PISTON_HEAD.defaultBlockState() + .withValue(Properties.SHORT, false) + .withValue(Properties.FACING, orientation); pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox); // Resolve collision with any attached moving blocks, but skip slime blocks @@ -562,9 +567,11 @@ public class PistonBlockEntity { private BlockState getAttachedBlockId(Vector3i blockPos) { if (blockPos.equals(getPistonHeadPos())) { - return BlockState.of(BlockStateValues.getPistonHead(orientation)); + return Blocks.PISTON_HEAD.defaultBlockState() + .withValue(Properties.SHORT, false) + .withValue(Properties.FACING, orientation); } else { - return attachedBlocks.getOrDefault(blockPos, BlockState.of(Block.JAVA_AIR_ID)); //FIXME + return attachedBlocks.getOrDefault(blockPos, Blocks.AIR.defaultBlockState()); } } @@ -633,7 +640,9 @@ public class PistonBlockEntity { if (action == PistonValueType.PUSHING) { Vector3i pistonHeadPos = getPistonHeadPos().add(movement); if (!SOLID_BOUNDING_BOX.checkIntersection(pistonHeadPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { - ChunkUtils.updateBlock(session, BlockStateValues.getPistonHead(orientation), pistonHeadPos); + ChunkUtils.updateBlock(session, Blocks.PISTON_HEAD.defaultBlockState() + .withValue(Properties.SHORT, false) + .withValue(Properties.FACING, orientation), pistonHeadPos); } } } 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 25f9f5497..878d326ac 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 @@ -56,8 +56,8 @@ import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.item.type.BoatItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.SpawnEggItem; -import org.geysermc.geyser.level.block.BlockStateValues; 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.level.block.type.CauldronBlock; @@ -295,10 +295,10 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { - private static final String[] ALL_BLOCK_NAMES = BlockRegistries.JAVA_BLOCKS.get().stream().map(block -> block.javaIdentifier().toString()).toArray(String[]::new); + /** + * Wait until the registries load before getting all the block names. + */ + private static final Supplier ALL_BLOCK_NAMES = Suppliers.memoize(() -> BlockRegistries.JAVA_BLOCKS.get().stream().map(block -> block.javaIdentifier().toString()).toArray(String[]::new)); private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers(); private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(AttributeType::getIdentifier).toList().toArray(new String[0]); private static final String[] ENUM_BOOLEAN = {"true", "false"}; @@ -247,7 +252,7 @@ public class JavaCommandsTranslator extends PacketTranslator CommandParam.FILE_PATH; case BOOL -> ENUM_BOOLEAN; case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc - case BLOCK_STATE -> ALL_BLOCK_NAMES; + case BLOCK_STATE -> ALL_BLOCK_NAMES.get(); case ITEM_STACK -> context.getItemNames(); case COLOR -> VALID_COLORS; case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3a3a2d20c..aa68a0bc0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -65,7 +65,6 @@ fastutil-int-byte-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int- fastutil-int-boolean-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-boolean-maps", version.ref = "fastutil" } fastutil-object-int-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-int-maps", version.ref = "fastutil" } fastutil-object-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-object-maps", version.ref = "fastutil" } -fastutil-reference-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-reference-object-maps", version.ref = "fastutil" } adventure-text-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" } # Remove when we remove our Adventure bump adventure-text-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" } @@ -143,7 +142,7 @@ blossom = { id = "net.kyori.blossom", version.ref = "blossom" } [bundles] jackson = [ "jackson-annotations", "jackson-core", "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", "fastutil-reference-object-maps" ] +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" ] jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ] From 96bfda2ed3f53a90266876b8b8741d2052dfa8ef Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 21 May 2024 20:37:18 -0400 Subject: [PATCH 156/897] Fix #4683 --- .../geyser/session/cache/LodestoneCache.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java index 50cdf4b5b..f66daf027 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java @@ -28,7 +28,6 @@ package org.geysermc.geyser.session.cache; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos; import org.geysermc.mcprotocollib.protocol.data.game.item.component.LodestoneTracker; @@ -53,11 +52,13 @@ public final class LodestoneCache { private int id = 1; public void cacheInventoryItem(GeyserItemStack itemStack, LodestoneTracker tracker) { - GlobalPos position = tracker.getPos(); + if (!tracker.isTracked()) { + return; + } + GlobalPos position = tracker.getPos(); if (position == null) { - GeyserImpl.getInstance().getLogger().error("Position is null. Find out why."); - Thread.dumpStack(); + // As of 1.20.6, position can still be null even if tracking is enabled. return; } int x = position.getX(); @@ -84,13 +85,16 @@ public final class LodestoneCache { } public int store(LodestoneTracker tracker) { - GlobalPos position = tracker.getPos(); - - if (position == null) { - GeyserImpl.getInstance().getLogger().error("Position is null. Find out why."); - Thread.dumpStack(); - return -1; + if (!tracker.isTracked()) { + // No coordinates; nothing to convert + return 0; } + + GlobalPos position = tracker.getPos(); + if (position == null) { + return 0; + } + int x = position.getX(); int y = position.getY(); int z = position.getZ(); From f7b026d61b7f07459542928bdd3766843724a43b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 21 May 2024 20:56:13 -0400 Subject: [PATCH 157/897] Remove old sneaking/crawling workarounds Since Bedrock implements these natively, there's no need for extra checks. :) --- .../type/player/SessionPlayerEntity.java | 34 ----------- .../geyser/session/GeyserSession.java | 58 ++----------------- 2 files changed, 4 insertions(+), 88 deletions(-) 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 e10adb134..ca541b5d3 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 @@ -31,7 +31,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.item.Items; @@ -60,10 +59,6 @@ public class SessionPlayerEntity extends PlayerEntity { */ @Getter protected final Map attributes = new Object2ObjectOpenHashMap<>(); - /** - * Whether to check for updated speed after all entity metadata has been processed - */ - private boolean refreshSpeed = false; /** * Used in PlayerInputTranslator for movement checks. */ @@ -120,9 +115,7 @@ public class SessionPlayerEntity extends PlayerEntity { // TODO: proper fix, BDS somehow does it? https://paste.gg/p/anonymous/3adfb7612f1540be80fa03a2281f93dc (BDS 1.20.13) if (!this.session.getGameMode().equals(GameMode.SPECTATOR)) { super.setFlags(entityMetadata); - session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING)); } - refreshSpeed = true; } /** @@ -150,7 +143,6 @@ public class SessionPlayerEntity extends PlayerEntity { public void setPose(Pose pose) { super.setPose(pose); session.setPose(pose); - refreshSpeed = true; } public float getMaxHealth() { @@ -199,21 +191,6 @@ public class SessionPlayerEntity extends PlayerEntity { } } - @Override - public void updateBedrockMetadata() { - super.updateBedrockMetadata(); - if (refreshSpeed) { - AttributeData speedAttribute = session.adjustSpeed(); - if (speedAttribute != null) { - UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); - attributesPacket.setRuntimeEntityId(geyserId); - attributesPacket.setAttributes(Collections.singletonList(speedAttribute)); - session.sendUpstreamPacket(attributesPacket); - } - refreshSpeed = false; - } - } - @Override protected void updateAttribute(Attribute javaAttribute, List newAttributes) { if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) { @@ -226,17 +203,6 @@ public class SessionPlayerEntity extends PlayerEntity { @Override protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) { AttributeData attributeData = super.calculateAttribute(javaAttribute, type); - - if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_MOVEMENT_SPEED) { - session.setOriginalSpeedAttribute(attributeData.getValue()); - AttributeData speedAttribute = session.adjustSpeed(); - if (speedAttribute != null) { - // Overwrite the attribute with our own - this.attributes.put(type, speedAttribute); - return speedAttribute; - } - } - this.attributes.put(type, attributeData); return attributeData; } 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 c85c0fd28..aa256df55 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -317,22 +317,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private boolean sprinting; - /** - * Whether the player is swimming in water. - * Used to update speed when crawling. - */ - @Setter - private boolean swimmingInWater; - - /** - * Tracks the original speed attribute. - *

- * We need to do this in order to emulate speeds when sneaking under 1.5-blocks-tall areas if the player isn't sneaking, - * and when crawling. - */ - @Setter - private float originalSpeedAttribute; - /** * The dimension of the player. * As all entities are in the same world, this can be safely applied to all other entities. @@ -1283,21 +1267,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.sneaking = sneaking; // Update pose and bounding box on our end - AttributeData speedAttribute; - if (!sneaking && (speedAttribute = adjustSpeed()) != null) { - // Update attributes since we're still "sneaking" under a 1.5-block-tall area - UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); - attributesPacket.setRuntimeEntityId(playerEntity.getGeyserId()); - attributesPacket.setAttributes(Collections.singletonList(speedAttribute)); - sendUpstreamPacket(attributesPacket); - // the server *should* update our pose once it has returned to normal - } else { - if (!flying) { - // The pose and bounding box should not be updated if the player is flying - setSneakingPose(sneaking); - } - collisionManager.updateScaffoldingFlags(false); + if (!flying) { + // The pose and bounding box should not be updated if the player is flying + setSneakingPose(sneaking); } + collisionManager.updateScaffoldingFlags(false); playerEntity.updateBedrockMetadata(); @@ -1340,30 +1314,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } } - /** - * Adjusts speed if the player is crawling. - * - * @return not null if attributes should be updated. - */ - public @Nullable AttributeData adjustSpeed() { - AttributeData currentPlayerSpeed = playerEntity.getAttributes().get(GeyserAttributeType.MOVEMENT_SPEED); - if (currentPlayerSpeed != null) { - if ((pose.equals(Pose.SNEAKING) && !sneaking && collisionManager.mustPlayerSneakHere()) || - (!swimmingInWater && playerEntity.getFlag(EntityFlag.SWIMMING) && !collisionManager.isPlayerInWater())) { - // Either of those conditions means that Bedrock goes zoom when they shouldn't be - AttributeData speedAttribute = GeyserAttributeType.MOVEMENT_SPEED.getAttribute(originalSpeedAttribute / 3.32f); - playerEntity.getAttributes().put(GeyserAttributeType.MOVEMENT_SPEED, speedAttribute); - return speedAttribute; - } else if (originalSpeedAttribute != currentPlayerSpeed.getValue()) { - // Speed has reset to normal - AttributeData speedAttribute = GeyserAttributeType.MOVEMENT_SPEED.getAttribute(originalSpeedAttribute); - playerEntity.getAttributes().put(GeyserAttributeType.MOVEMENT_SPEED, speedAttribute); - return speedAttribute; - } - } - return null; - } - /** * Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display * blocking and sends a packet to the Java server. From 6f4c29c834b4f111ee9807da89fc3aa83d93c83d Mon Sep 17 00:00:00 2001 From: gecko10000 <60494179+gecko10000@users.noreply.github.com> Date: Wed, 22 May 2024 02:26:32 -0700 Subject: [PATCH 158/897] Match Advancement Packet Behavior Towards Java (#4684) * Send advancement packet regardless of current tab * Send advancement close packet when single-advancement form closed --- .../geyser/session/cache/AdvancementsCache.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java index 6769b4330..be1eb3a5b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java @@ -91,11 +91,9 @@ public class AdvancementsCache { builder.validResultHandler((response) -> { String id = rootAdvancementIds.get(response.clickedButtonId()); if (!id.equals("")) { - if (!id.equals(currentAdvancementCategoryId)) { - // Send a packet indicating that we are opening this particular advancement window - ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id); - session.sendDownstreamGamePacket(packet); - } + // Send a packet indicating that we are opening this particular advancement window + ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id); + session.sendDownstreamGamePacket(packet); currentAdvancementCategoryId = id; buildAndShowListForm(); } @@ -188,6 +186,10 @@ public class AdvancementsCache { .content(content) .button(GeyserLocale.getPlayerLocaleString("gui.back", language)) .validResultHandler((response) -> buildAndShowListForm()) + .closedResultHandler(() -> { + // Indicate that we have closed the current advancement tab + session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket()); + }) ); } From ec3327efebd017f43966299f5b6a528128ea2f50 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 23 May 2024 11:41:26 -0400 Subject: [PATCH 159/897] Minor minor changes --- .../geyser/level/block/property/BasicEnumProperty.java | 2 +- .../java/org/geysermc/geyser/level/block/type/BlockState.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/BasicEnumProperty.java b/core/src/main/java/org/geysermc/geyser/level/block/property/BasicEnumProperty.java index f55b85d7b..c34392504 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/property/BasicEnumProperty.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/BasicEnumProperty.java @@ -47,7 +47,7 @@ public final class BasicEnumProperty extends Property { public int indexOf(String value) { int index = this.values.indexOf(value); if (index == -1) { - throw new IllegalStateException("Property " + this + " does not have value " + value); + throw new IllegalArgumentException("Property " + this + " does not have value " + value); } return index; } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 44271bd80..a312a7d5a 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -35,7 +35,7 @@ public final class BlockState { private final Block block; private final int javaId; /** - * The values of each property of this block state. These should be treated as keys to {@link Block#propertyKeys()} + * The values of each property of this block state. These should be treated as keys to {@link Block#propertyKeys()}. * Of note - the comparable part probably doesn't do anything because we occasionally use strings in place of enums. * Will be null if there's only one block state for a block. */ @@ -135,7 +135,7 @@ public final class BlockState { // The above for loop will always stop at the first break because the last property has already been found diff = 1; } - return BlockState.of(this.javaId + ((thatOffset - thisOffset) * diff)); + return of(this.javaId + ((thatOffset - thisOffset) * diff)); } public Block block() { From d5fdbeb49c5b304aa18070ae4abae1e3d0f36763 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 25 May 2024 13:19:59 +0100 Subject: [PATCH 160/897] Make allow-third-party-capes default to false (#4690) --- .../geyser/configuration/GeyserJacksonConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index a55e4af8f..81ac824e4 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -94,7 +94,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration private boolean debugMode = false; @JsonProperty("allow-third-party-capes") - private boolean allowThirdPartyCapes = true; + private boolean allowThirdPartyCapes = false; @JsonProperty("show-cooldown") private String showCooldown = "title"; From 0ea01bfa4876fd9722698f096dbbfefbf5ccd7d1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 25 May 2024 18:59:37 -0400 Subject: [PATCH 161/897] Allow skull pick item NBT --- .../geyser/inventory/GeyserItemStack.java | 2 +- .../geyser/level/block/type/SkullBlock.java | 36 +++++++++++++++++++ .../BedrockBlockPickRequestTranslator.java | 7 +++- 3 files changed, 43 insertions(+), 2 deletions(-) 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 fa62769fe..744ad70b6 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -69,7 +69,7 @@ public class GeyserItemStack { return of(javaId, amount, null); } - public static @NonNull GeyserItemStack of(int javaId, int amount, DataComponents components) { + public static @NonNull GeyserItemStack of(int javaId, int amount, @Nullable DataComponents components) { return new GeyserItemStack(javaId, amount, components); } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java index 76b532919..c4aae46a2 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java @@ -25,10 +25,20 @@ package org.geysermc.geyser.level.block.type; +import com.github.steveice10.mc.auth.data.GameProfile; import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; +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 java.util.Collections; +import java.util.UUID; public class SkullBlock extends Block { private final Type type; @@ -55,6 +65,32 @@ public class SkullBlock extends Block { // It's not an empty skull. } + public ItemStack pickItem(GeyserSession session, BlockState state, Vector3i position) { + SkullCache.Skull skull = session.getSkullCache().getSkulls().get(position); + if (skull == null) { + return new ItemStack(pickItem(state).getId()); + } + + GeyserItemStack itemStack = GeyserItemStack.of(pickItem(state).getId(), 1); + // This is a universal block entity behavior, but hardcode how it works for now. + NbtMapBuilder builder = NbtMap.builder() + .putString("id", "minecraft:skull") + .putInt("x", position.getX()) + .putInt("y", position.getY()) + .putInt("z", position.getZ()); + DataComponents components = itemStack.getOrCreateComponents(); + components.put(DataComponentType.BLOCK_ENTITY_DATA, builder.build()); + + UUID uuid = skull.getUuid(); + String texturesProperty = skull.getTexturesProperty(); + GameProfile profile = new GameProfile(uuid, null); + if (texturesProperty != null) { + profile.setProperties(Collections.singletonList(new GameProfile.Property("textures", texturesProperty))); + } + components.put(DataComponentType.PROFILE, profile); + return itemStack.getItemStack(); + } + public Type skullType() { return type; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 0a721e4b0..94368a6d4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -33,6 +33,7 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.type.BannerBlock; import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.type.SkullBlock; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -65,7 +66,11 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator session.ensureInEventLoop(() -> { if (components == null) { From 5f7a31a1d837048a147258f3caf2f750c7738fb7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 25 May 2024 20:55:05 -0400 Subject: [PATCH 162/897] Fix #4688 --- .../org/geysermc/geyser/entity/type/InteractionEntity.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java index 4e7a805b4..06035a47c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java @@ -80,7 +80,10 @@ public class InteractionEntity extends Entity { } public void setHeight(FloatEntityMetadata height) { - setBoundingBoxHeight(height.getPrimitiveValue()); + // Bedrock does *not* like high values being placed here + // https://gist.github.com/Owen1212055/f5d59169d3a6a5c32f0c173d57eb199d recommend(s/ed) using the tactic + // https://github.com/GeyserMC/Geyser/issues/4688 + setBoundingBoxHeight(Math.min(height.getPrimitiveValue(), 64f)); } public void setResponse(BooleanEntityMetadata response) { From fa6808a62029373af4492329bbf2cbf80bb51e7f Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Sun, 26 May 2024 20:00:47 -0700 Subject: [PATCH 163/897] Bedrock 1.21.0 Support (#4687) * 1.21.0 Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Deprecate Bedrock 1.20.70 and below Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Strictly disconnect on all exceptions Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Remove old version resources Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- README.md | 2 +- .../holder/BlockInventoryHolder.java | 1 + .../geyser/network/CodecProcessor.java | 23 +- .../geysermc/geyser/network/GameProtocol.java | 36 +- .../geyser/network/InvalidPacketHandler.java | 4 +- .../populator/BlockRegistryPopulator.java | 13 +- .../registry/populator/Conversion630_622.java | 217 - .../registry/populator/Conversion649_630.java | 64 - .../registry/populator/Conversion662_649.java | 187 - .../registry/populator/Conversion671_662.java | 205 - .../registry/populator/Conversion685_671.java | 205 + .../CustomBlockRegistryPopulator.java | 9 +- .../CustomItemRegistryPopulator.java | 118 +- .../populator/ItemRegistryPopulator.java | 30 +- .../populator/RecipeRegistryPopulator.java | 5 +- .../geyser/session/GeyserSession.java | 4 + .../inventory/LecternInventoryTranslator.java | 19 - .../inventory/PlayerInventoryTranslator.java | 1 + .../chest/DoubleChestInventoryTranslator.java | 1 + .../player/BedrockActionTranslator.java | 5 - .../java/JavaUpdateRecipesTranslator.java | 7 +- .../JavaContainerSetSlotTranslator.java | 4 +- .../inventory/JavaOpenBookTranslator.java | 6 - .../inventory/JavaOpenScreenTranslator.java | 6 - .../bedrock/block_palette.1_20_40.nbt | Bin 158101 -> 0 bytes .../bedrock/block_palette.1_20_50.nbt | Bin 170466 -> 0 bytes .../bedrock/block_palette.1_20_60.nbt | Bin 124510 -> 0 bytes .../bedrock/block_palette.1_20_70.nbt | Bin 176502 -> 0 bytes .../bedrock/block_palette.1_21_0.nbt | Bin 0 -> 177397 bytes .../bedrock/creative_items.1_20_40.json | 5787 ---------------- .../bedrock/creative_items.1_20_50.json | 5995 ---------------- .../bedrock/creative_items.1_20_60.json | 5787 ---------------- ..._20_70.json => creative_items.1_21_0.json} | 2033 +++--- .../resources/bedrock/entity_identifiers.dat | Bin 7951 -> 8314 bytes .../bedrock/runtime_item_states.1_20_40.json | 5570 --------------- .../bedrock/runtime_item_states.1_20_50.json | 5846 ---------------- .../bedrock/runtime_item_states.1_20_60.json | 5998 ----------------- ...0.json => runtime_item_states.1_21_0.json} | 1300 ++-- core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 12 +- 40 files changed, 2325 insertions(+), 37177 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_622.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion649_630.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java delete mode 100644 core/src/main/resources/bedrock/block_palette.1_20_40.nbt delete mode 100644 core/src/main/resources/bedrock/block_palette.1_20_50.nbt delete mode 100644 core/src/main/resources/bedrock/block_palette.1_20_60.nbt delete mode 100644 core/src/main/resources/bedrock/block_palette.1_20_70.nbt create mode 100644 core/src/main/resources/bedrock/block_palette.1_21_0.nbt delete mode 100644 core/src/main/resources/bedrock/creative_items.1_20_40.json delete mode 100644 core/src/main/resources/bedrock/creative_items.1_20_50.json delete mode 100644 core/src/main/resources/bedrock/creative_items.1_20_60.json rename core/src/main/resources/bedrock/{creative_items.1_20_70.json => creative_items.1_21_0.json} (78%) delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_20_40.json delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_20_50.json delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_20_60.json rename core/src/main/resources/bedrock/{runtime_item_states.1_20_70.json => runtime_item_states.1_21_0.json} (95%) diff --git a/README.md b/README.md index 9257af9ac..dd2d096ec 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80/81 and Minecraft Java 1.20.5/1.20.6 +### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.0 and Minecraft Java 1.20.5/1.20.6 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index 9c8e5de15..cdda4fe4c 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -163,6 +163,7 @@ public class BlockInventoryHolder extends InventoryHolder { ContainerClosePacket packet = new ContainerClosePacket(); packet.setId((byte) inventory.getBedrockId()); packet.setServerInitiated(true); + packet.setType(ContainerType.CONTAINER); session.sendUpstreamPacket(packet); return; } 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 6bd767fb7..4c459573a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -224,7 +224,7 @@ class CodecProcessor { @SuppressWarnings("unchecked") static BedrockCodec processCodec(BedrockCodec codec) { - return codec.toBuilder() + BedrockCodec.Builder codecBuilder = codec.toBuilder() // Illegal unused serverbound EDU packets .updateSerializer(PhotoTransferPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(LabTablePacket.class, ILLEGAL_SERIALIZER) @@ -236,6 +236,7 @@ class CodecProcessor { .updateSerializer(PurchaseReceiptPacket.class, ILLEGAL_SERIALIZER) // Illegal unused serverbound packets that are deprecated .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) @@ -243,7 +244,6 @@ class CodecProcessor { .updateSerializer(SubChunkRequestPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(GameTestRequestPacket.class, ILLEGAL_SERIALIZER) // Ignored serverbound packets - .updateSerializer(CraftingEventPacket.class, IGNORED_SERIALIZER) // Make illegal when 1.20.40 is removed .updateSerializer(ClientToServerHandshakePacket.class, IGNORED_SERIALIZER) .updateSerializer(EntityFallPacket.class, IGNORED_SERIALIZER) .updateSerializer(MapCreateLockedCopyPacket.class, IGNORED_SERIALIZER) @@ -260,22 +260,25 @@ class CodecProcessor { .updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER) .updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER) .updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER) - .updateSerializer(SetEntityMotionPacket.class, codec.getProtocolVersion() < 662 ? - SET_ENTITY_MOTION_SERIALIZER_V291 : - SET_ENTITY_MOTION_SERIALIZER_V662) + .updateSerializer(SetEntityMotionPacket.class, SET_ENTITY_MOTION_SERIALIZER_V662) .updateSerializer(SetEntityLinkPacket.class, SET_ENTITY_LINK_SERIALIZER) // Valid serverbound packets where reading of some fields can be skipped .updateSerializer(MobEquipmentPacket.class, MOB_EQUIPMENT_SERIALIZER) - // // Illegal bidirectional packets + // Illegal bidirectional packets .updateSerializer(DebugInfoPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(EditorNetworkPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(ScriptMessagePacket.class, ILLEGAL_SERIALIZER) - // // Ignored bidirectional packets + // Ignored bidirectional packets .updateSerializer(ClientCacheStatusPacket.class, IGNORED_SERIALIZER) .updateSerializer(SimpleEventPacket.class, IGNORED_SERIALIZER) - .updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER) - .updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER) - .build(); + .updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER); + + if (codec.getProtocolVersion() < 685) { + // Ignored bidirectional packets + codecBuilder.updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER); + } + + return codecBuilder.build(); } /** diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index f9292671f..1c58288c7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -27,11 +27,8 @@ package org.geysermc.geyser.network; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; -import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; -import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; -import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; -import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; +import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; @@ -50,8 +47,8 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v671.CODEC.toBuilder() - .minecraftVersion("1.20.81") + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v685.CODEC.toBuilder() + .minecraftVersion("1.21.0") .build()); /** @@ -66,20 +63,11 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v622.CODEC.toBuilder() - .minecraftVersion("1.20.40/1.20.41") - .build())); - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v630.CODEC.toBuilder() - .minecraftVersion("1.20.50/1.20.51") - .build())); - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v649.CODEC.toBuilder() - .minecraftVersion("1.20.60/1.20.62") - .build())); - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v662.CODEC.toBuilder() - .minecraftVersion("1.20.70/1.20.73") + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v671.CODEC.toBuilder() + .minecraftVersion("1.20.80/1.20.81") .build())); SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.20.80/1.20.81") + .minecraftVersion("1.21.0") .build())); } @@ -99,16 +87,8 @@ public final class GameProtocol { /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ - public static boolean isPre1_20_50(GeyserSession session) { - return session.getUpstream().getProtocolVersion() < Bedrock_v630.CODEC.getProtocolVersion(); - } - - public static boolean isPre1_20_70(GeyserSession session) { - return session.getUpstream().getProtocolVersion() < Bedrock_v662.CODEC.getProtocolVersion(); - } - - public static boolean is1_20_60orHigher(int protocolVersion) { - return protocolVersion >= Bedrock_v649.CODEC.getProtocolVersion(); + public static boolean isPre1_21_0(GeyserSession session) { + return session.getUpstream().getProtocolVersion() < Bedrock_v685.CODEC.getProtocolVersion(); } /** diff --git a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java index 3e836711b..1b653891e 100644 --- a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java @@ -47,7 +47,9 @@ public class InvalidPacketHandler extends ChannelInboundHandlerAdapter { if (!(rootCause instanceof IllegalArgumentException)) { - super.exceptionCaught(ctx, cause); + // Kick users that cause exceptions + session.getGeyser().getLogger().warning("Exception caught in session of" + session.bedrockUsername() + ": " + rootCause.getMessage()); + session.disconnect("An internal error occurred!"); return; } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 6eadbd0e5..936935306 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -38,11 +38,8 @@ import it.unimi.dsi.fastutil.objects.*; import org.cloudburstmc.blockstateupdater.BlockStateUpdater; import org.cloudburstmc.blockstateupdater.util.tagupdater.CompoundTagUpdaterContext; import org.cloudburstmc.nbt.*; -import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; -import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; -import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; -import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; +import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -125,12 +122,8 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { var blockMappers = ImmutableMap., Remapper>builder() - .put(ObjectIntPair.of("1_20_40", Bedrock_v622.CODEC.getProtocolVersion()), Conversion630_622::remapBlock) - .put(ObjectIntPair.of("1_20_50", Bedrock_v630.CODEC.getProtocolVersion()), Conversion649_630::remapBlock) - // Only changes in 1.20.60 are hard_stained_glass (an EDU only block) - .put(ObjectIntPair.of("1_20_60", Bedrock_v649.CODEC.getProtocolVersion()), Conversion662_649::remapBlock) - .put(ObjectIntPair.of("1_20_70", Bedrock_v662.CODEC.getProtocolVersion()), Conversion671_662::remapBlock) - .put(ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), Conversion685_671::remapBlock) + .put(ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), tag -> tag) .build(); // We can keep this strong as nothing should be garbage collected diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_622.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_622.java deleted file mode 100644 index 398eabc3c..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_622.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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.registry.populator; - -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.type.GeyserMappingItem; - -import java.util.List; -import java.util.Map; - -/** - * Backwards-maps the blocks and items of 1.20.50 (630) to 1.20.40 (622) - */ -class Conversion630_622 { - - private static final List NEW_STONES = List.of("minecraft:stone", "minecraft:granite", "minecraft:polished_granite", "minecraft:diorite", "minecraft:polished_diorite", "minecraft:andesite", "minecraft:polished_andesite"); - private static final List NEW_WOODS = List.of("minecraft:oak_planks", "minecraft:spruce_planks", "minecraft:birch_planks", "minecraft:jungle_planks", "minecraft:acacia_planks", "minecraft:dark_oak_planks"); - - private static final Map ITEMS = new Object2ObjectOpenHashMap<>(); - - static { - ITEMS.put("minecraft:acacia_planks", "minecraft:planks"); - ITEMS.put("minecraft:birch_planks", "minecraft:planks"); - ITEMS.put("minecraft:dark_oak_planks", "minecraft:planks"); - ITEMS.put("minecraft:jungle_planks", "minecraft:planks"); - ITEMS.put("minecraft:oak_planks", "minecraft:planks"); - ITEMS.put("minecraft:spruce_planks", "minecraft:planks"); - - ITEMS.put("minecraft:diorite", "minecraft:stone"); - ITEMS.put("minecraft:andesite", "minecraft:stone"); - ITEMS.put("minecraft:granite", "minecraft:stone"); - ITEMS.put("minecraft:polished_andesite", "minecraft:stone"); - ITEMS.put("minecraft:polished_diorite", "minecraft:stone"); - ITEMS.put("minecraft:polished_granite", "minecraft:stone"); - - ITEMS.put("minecraft:chiseled_tuff", "minecraft:chiseled_deepslate"); - ITEMS.put("minecraft:chiseled_tuff_bricks", "minecraft:chiseled_deepslate"); - ITEMS.put("minecraft:polished_tuff", "minecraft:polished_deepslate"); - ITEMS.put("minecraft:polished_tuff_double_slab", "minecraft:polished_deepslate_double_slab"); - ITEMS.put("minecraft:polished_tuff_slab", "minecraft:polished_deepslate_slab"); - ITEMS.put("minecraft:polished_tuff_stairs", "minecraft:polished_deepslate_stairs"); - ITEMS.put("minecraft:polished_tuff_wall", "minecraft:polished_deepslate_wall"); - ITEMS.put("minecraft:tuff_brick_double_slab", "minecraft:deepslate_brick_double_slab"); - ITEMS.put("minecraft:tuff_brick_slab", "minecraft:deepslate_brick_slab"); - ITEMS.put("minecraft:tuff_brick_stairs", "minecraft:deepslate_brick_stairs"); - ITEMS.put("minecraft:tuff_brick_wall", "minecraft:deepslate_brick_wall"); - ITEMS.put("minecraft:tuff_bricks", "minecraft:deepslate_bricks"); - ITEMS.put("minecraft:tuff_double_slab", "minecraft:cobbled_deepslate_double_slab"); - ITEMS.put("minecraft:tuff_slab", "minecraft:cobbled_deepslate_slab"); - ITEMS.put("minecraft:tuff_stairs", "minecraft:cobbled_deepslate_stairs"); - ITEMS.put("minecraft:tuff_wall", "minecraft:cobbled_deepslate_wall"); - - ITEMS.put("minecraft:chiseled_copper", "minecraft:copper_block"); - ITEMS.put("minecraft:copper_bulb", "minecraft:copper_block"); - ITEMS.put("minecraft:copper_door", "minecraft:iron_door"); - ITEMS.put("minecraft:copper_grate", "minecraft:raw_iron_block"); - ITEMS.put("minecraft:copper_trapdoor", "minecraft:iron_trapdoor"); - ITEMS.put("minecraft:exposed_chiseled_copper", "minecraft:exposed_copper"); - ITEMS.put("minecraft:exposed_copper_bulb", "minecraft:exposed_copper"); - ITEMS.put("minecraft:exposed_copper_door", "minecraft:iron_door"); - ITEMS.put("minecraft:exposed_copper_grate", "minecraft:raw_iron_block"); - ITEMS.put("minecraft:exposed_copper_trapdoor", "minecraft:iron_trapdoor"); - ITEMS.put("minecraft:oxidized_chiseled_copper", "minecraft:oxidized_copper"); - ITEMS.put("minecraft:oxidized_copper_bulb", "minecraft:oxidized_copper"); - ITEMS.put("minecraft:oxidized_copper_door", "minecraft:iron_door"); - ITEMS.put("minecraft:oxidized_copper_grate", "minecraft:raw_iron_block"); - ITEMS.put("minecraft:oxidized_copper_trapdoor", "minecraft:iron_trapdoor"); - ITEMS.put("minecraft:waxed_chiseled_copper", "minecraft:waxed_copper"); - ITEMS.put("minecraft:waxed_copper_bulb", "minecraft:waxed_copper"); - ITEMS.put("minecraft:waxed_copper_door", "minecraft:iron_door"); - ITEMS.put("minecraft:waxed_copper_grate", "minecraft:raw_iron_block"); - ITEMS.put("minecraft:waxed_copper_trapdoor", "minecraft:iron_trapdoor"); - ITEMS.put("minecraft:waxed_exposed_chiseled_copper", "minecraft:waxed_exposed_copper"); - ITEMS.put("minecraft:waxed_exposed_copper_bulb", "minecraft:waxed_exposed_copper"); - ITEMS.put("minecraft:waxed_exposed_copper_door", "minecraft:iron_door"); - ITEMS.put("minecraft:waxed_exposed_copper_grate", "minecraft:raw_iron_block"); - ITEMS.put("minecraft:waxed_exposed_copper_trapdoor", "minecraft:iron_trapdoor"); - ITEMS.put("minecraft:waxed_oxidized_chiseled_copper", "minecraft:waxed_oxidized_copper"); - ITEMS.put("minecraft:waxed_oxidized_copper_bulb", "minecraft:waxed_oxidized_copper"); - ITEMS.put("minecraft:waxed_oxidized_copper_door", "minecraft:iron_door"); - ITEMS.put("minecraft:waxed_oxidized_copper_grate", "minecraft:raw_iron_block"); - ITEMS.put("minecraft:waxed_oxidized_copper_trapdoor", "minecraft:iron_trapdoor"); - ITEMS.put("minecraft:waxed_weathered_chiseled_copper", "minecraft:waxed_weathered_copper"); - ITEMS.put("minecraft:waxed_weathered_copper_bulb", "minecraft:waxed_weathered_copper"); - ITEMS.put("minecraft:waxed_weathered_copper_door", "minecraft:iron_door"); - ITEMS.put("minecraft:waxed_weathered_copper_grate", "minecraft:raw_iron_block"); - ITEMS.put("minecraft:waxed_weathered_copper_trapdoor", "minecraft:iron_trapdoor"); - ITEMS.put("minecraft:weathered_chiseled_copper", "minecraft:weathered_copper"); - ITEMS.put("minecraft:weathered_copper_bulb", "minecraft:weathered_copper"); - ITEMS.put("minecraft:weathered_copper_door", "minecraft:iron_door"); - ITEMS.put("minecraft:weathered_copper_grate", "minecraft:raw_iron_block"); - ITEMS.put("minecraft:weathered_copper_trapdoor", "minecraft:iron_trapdoor"); - - ITEMS.put("minecraft:crafter", "minecraft:crafting_table"); - } - - static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { - mapping = Conversion649_630.remapItem(item, mapping); - - String replacement = ITEMS.get(mapping.getBedrockIdentifier()); - if (replacement == null) { - return mapping; - } else { - return mapping.withBedrockIdentifier(replacement); - } - } - - static NbtMap remapBlock(NbtMap tag) { - tag = Conversion649_630.remapBlock(tag); - - final String name = tag.getString("name"); - - String replacement; - if (NEW_STONES.contains(name) || NEW_WOODS.contains(name)) { - - String typeKey; - String type = name.substring(10); - if (NEW_STONES.contains(name)) { - replacement = "minecraft:stone"; - typeKey = "stone_type"; - if (type.startsWith("polished_")) { - type = type.substring(9) + "_smooth"; - } - } else { - replacement = "minecraft:planks"; - typeKey = "wood_type"; - type = type.substring(0, type.indexOf("_planks")); - } - - return tag.toBuilder() - .putString("name", replacement) - .putCompound("states", NbtMap.builder().putString(typeKey, type).build()) - .build(); - } else if (name.contains("tuff") && !name.equals("minecraft:tuff")) { - - if (name.contains("brick") || name.contains("polished") || name.contains("chiseled")) { - replacement = name.replace("tuff", "deepslate"); - - if (name.contains("chiseled")) { - // chiseled deepslate bricks don't exist. just use chiseled deepslate instead - replacement = replacement.replace("_bricks", ""); - } - } else { - replacement = name.replace("tuff", "cobbled_deepslate"); - } - - return tag.toBuilder() - .putString("name", replacement) - .build(); - } else if (name.contains("copper")) { - - boolean removeStates = false; - if (name.contains("chiseled")) { - replacement = name.replace("_chiseled", ""); // special chiseled - replacement = replacement.replace("chiseled_", ""); // plain chiseled - } else if (name.endsWith("bulb")) { - replacement = name.replace("_bulb", ""); - removeStates = true; - } else if (name.endsWith("grate")) { - replacement = "minecraft:raw_iron_block"; - } else if (name.endsWith("door")) { - if (name.contains("trap")) { - replacement = "minecraft:iron_trapdoor"; - } else { - replacement = "minecraft:iron_door"; - } - } else { - return tag; - } - - if (replacement.endsWith(":copper")) { - // case for plain chiseled copper and plain bulb - replacement = replacement + "_block"; - } - - NbtMapBuilder builder = tag.toBuilder(); - builder.putString("name", replacement); - if (removeStates) { - builder.putCompound("states", NbtMap.EMPTY); - } - return builder.build(); - } else if (name.equals("minecraft:crafter")) { - NbtMapBuilder builder = tag.toBuilder(); - builder.put("name", "minecraft:crafting_table"); - builder.put("states", NbtMap.EMPTY); - return builder.build(); - } - - return tag; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion649_630.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion649_630.java deleted file mode 100644 index 70a5e1ad9..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion649_630.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.registry.populator; - -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.type.GeyserMappingItem; - -public class Conversion649_630 { - - static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { - mapping = Conversion662_649.remapItem(item, mapping); - - String identifer = mapping.getBedrockIdentifier(); - - switch (identifer) { - case "minecraft:armadillo_scute", "minecraft:turtle_scute" -> { return mapping.withBedrockIdentifier("minecraft:scute"); } - case "minecraft:armadillo_spawn_egg" -> { return mapping.withBedrockIdentifier("minecraft:rabbit_spawn_egg"); } - case "minecraft:trial_spawner" -> { return mapping.withBedrockIdentifier("minecraft:mob_spawner"); } - case "minecraft:trial_key" -> { return mapping.withBedrockIdentifier("minecraft:echo_shard"); } - case "minecraft:wolf_armor" -> { return mapping.withBedrockIdentifier("minecraft:leather_horse_armor"); } - default -> { return mapping; } - } - } - - static NbtMap remapBlock(NbtMap tag) { - tag = Conversion662_649.remapBlock(tag); - - final String name = tag.getString("name"); - - if (name.equals("minecraft:trial_spawner")) { - NbtMapBuilder builder = tag.toBuilder() - .putString("name", "minecraft:mob_spawner") - .putCompound("states", NbtMap.EMPTY); - - return builder.build(); - } - - return tag; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java deleted file mode 100644 index 041afdbc8..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion662_649.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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.registry.populator; - -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.type.GeyserMappingItem; - -import java.util.List; -import java.util.stream.Stream; - -public class Conversion662_649 { - - private static final List NEW_MISC = List.of("minecraft:grass_block", "minecraft:vault"); - private static final List NEW_WOODS = List.of("minecraft:oak_wood", "minecraft:spruce_wood", "minecraft:birch_wood", "minecraft:jungle_wood", "minecraft:acacia_wood", "minecraft:dark_oak_wood", "minecraft:stripped_oak_wood", "minecraft:stripped_spruce_wood", "minecraft:stripped_birch_wood", "minecraft:stripped_jungle_wood", "minecraft:stripped_acacia_wood", "minecraft:stripped_dark_oak_wood"); - private static final List NEW_LEAVES = List.of("minecraft:oak_leaves", "minecraft:spruce_leaves", "minecraft:birch_leaves", "minecraft:jungle_leaves"); - private static final List NEW_LEAVES2 = List.of("minecraft:acacia_leaves", "minecraft:dark_oak_leaves"); - private static final List NEW_SLABS = List.of("minecraft:oak_slab", "minecraft:spruce_slab", "minecraft:birch_slab", "minecraft:jungle_slab", "minecraft:acacia_slab", "minecraft:dark_oak_slab", "minecraft:oak_double_slab", "minecraft:spruce_double_slab", "minecraft:birch_double_slab", "minecraft:jungle_double_slab", "minecraft:acacia_double_slab", "minecraft:dark_oak_double_slab"); - private static final List NEW_BLOCKS = Stream.of(NEW_WOODS, NEW_LEAVES, NEW_LEAVES2, NEW_SLABS, NEW_MISC).flatMap(List::stream).toList(); - - - static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { - mapping = Conversion671_662.remapItem(item, mapping); - - String identifer = mapping.getBedrockIdentifier(); - - switch (identifer) { - case "minecraft:bogged_spawn_egg" -> { return mapping.withBedrockIdentifier("minecraft:creeper_spawn_egg"); } - case "minecraft:grass_block" -> { return mapping.withBedrockIdentifier("minecraft:grass"); } - case "minecraft:vault" -> { return mapping.withBedrockIdentifier("minecraft:trial_spawner"); } - case "minecraft:wind_charge" -> { return mapping.withBedrockIdentifier("minecraft:snowball"); } - }; - - if (NEW_WOODS.contains(identifer)) { - switch (identifer) { - case "minecraft:oak_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(0); } - case "minecraft:spruce_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(1); } - case "minecraft:birch_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(2); } - case "minecraft:jungle_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(3); } - case "minecraft:acacia_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(4); } - case "minecraft:dark_oak_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(5); } - case "minecraft:stripped_oak_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(8); } - case "minecraft:stripped_spruce_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(9); } - case "minecraft:stripped_birch_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(10); } - case "minecraft:stripped_jungle_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(11); } - case "minecraft:stripped_acacia_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(12); } - case "minecraft:stripped_dark_oak_wood" -> { return mapping.withBedrockIdentifier("minecraft:wood").withBedrockData(13); } - } - } - - if (NEW_SLABS.contains(identifer)) { - switch (identifer) { - case "minecraft:oak_slab" -> { return mapping.withBedrockIdentifier("minecraft:wooden_slab").withBedrockData(0); } - case "minecraft:spruce_slab" -> { return mapping.withBedrockIdentifier("minecraft:wooden_slab").withBedrockData(1); } - case "minecraft:birch_slab" -> { return mapping.withBedrockIdentifier("minecraft:wooden_slab").withBedrockData(2); } - case "minecraft:jungle_slab" -> { return mapping.withBedrockIdentifier("minecraft:wooden_slab").withBedrockData(3); } - case "minecraft:acacia_slab" -> { return mapping.withBedrockIdentifier("minecraft:wooden_slab").withBedrockData(4); } - case "minecraft:dark_oak_slab" -> { return mapping.withBedrockIdentifier("minecraft:wooden_slab").withBedrockData(5); } - } - } - - if (NEW_LEAVES.contains(identifer) || NEW_LEAVES2.contains(identifer)) { - switch (identifer) { - case "minecraft:oak_leaves" -> { return mapping.withBedrockIdentifier("minecraft:leaves").withBedrockData(0); } - case "minecraft:spruce_leaves" -> { return mapping.withBedrockIdentifier("minecraft:leaves").withBedrockData(1); } - case "minecraft:birch_leaves" -> { return mapping.withBedrockIdentifier("minecraft:leaves").withBedrockData(2); } - case "minecraft:jungle_leaves" -> { return mapping.withBedrockIdentifier("minecraft:leaves").withBedrockData(3); } - case "minecraft:acacia_leaves" -> { return mapping.withBedrockIdentifier("minecraft:leaves2").withBedrockData(0); } - case "minecraft:dark_oak_leaves" -> { return mapping.withBedrockIdentifier("minecraft:leaves2").withBedrockData(1); } - } - } - - return mapping; - } - - static NbtMap remapBlock(NbtMap tag) { - tag = Conversion671_662.remapBlock(tag); - - final String name = tag.getString("name"); - - if (!NEW_BLOCKS.contains(name)) { - return tag; - } - - String replacement; - - if (name.equals("minecraft:grass_block")) { - replacement = "minecraft:grass"; - - NbtMapBuilder builder = tag.toBuilder(); - builder.putString("name", replacement); - - return builder.build(); - } - - if (name.equals("minecraft:vault")) { - replacement = "minecraft:trial_spawner"; - - NbtMapBuilder statesBuilder = NbtMap.builder() - .putInt("trial_spawner_state", 0); - - NbtMapBuilder builder = tag.toBuilder(); - builder.putString("name", replacement); - builder.putCompound("states", statesBuilder.build()); - - return builder.build(); - } - - if (NEW_WOODS.contains(name)) { - replacement = "minecraft:wood"; - - NbtMap states = tag.getCompound("states"); - boolean stripped = name.startsWith("minecraft:stripped_"); - String woodType = name.replaceAll("minecraft:|_wood|stripped_", ""); - - NbtMapBuilder statesBuilder = states.toBuilder() - .putString("wood_type", woodType) - .putBoolean("stripped_bit", stripped); - - NbtMapBuilder builder = tag.toBuilder() - .putString("name", replacement) - .putCompound("states", statesBuilder.build()); - - return builder.build(); - } - - if (NEW_LEAVES.contains(name) || NEW_LEAVES2.contains(name)) { - boolean leaves2 = NEW_LEAVES2.contains(name); - replacement = leaves2 ? "minecraft:leaves2" : "minecraft:leaves"; - - NbtMap states = tag.getCompound("states"); - String leafType = name.replaceAll("minecraft:|_leaves", ""); - - NbtMapBuilder statesBuilder = states.toBuilder() - .putString(leaves2 ? "new_leaf_type" : "old_leaf_type", leafType); - - NbtMapBuilder builder = tag.toBuilder() - .putString("name", replacement) - .putCompound("states", statesBuilder.build()); - - return builder.build(); - } - - - if (NEW_SLABS.contains(name)) { - replacement = name.contains("double") ? "minecraft:double_wooden_slab" : "minecraft:wooden_slab"; - - NbtMap states = tag.getCompound("states"); - String woodType = name.replaceAll("minecraft:|_double|_slab", ""); - - NbtMapBuilder statesBuilder = states.toBuilder() - .putString("wood_type", woodType); - - NbtMapBuilder builder = tag.toBuilder() - .putString("name", replacement) - .putCompound("states", statesBuilder.build()); - - return builder.build(); - } - - return tag; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java deleted file mode 100644 index 29ab3f2e5..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion671_662.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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.registry.populator; - -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.type.GeyserMappingItem; - -import java.util.List; -import java.util.stream.Stream; - -public class Conversion671_662 { - private static final List NEW_MISC = List.of("minecraft:heavy_core", "minecraft:mace", "minecraft:flow_banner_pattern", "minecraft:guster_banner_pattern", "minecraft:flow_armor_trim_smithing_template", "minecraft:bolt_armor_trim_smithing_template", "minecraft:flow_pottery_sherd", "minecraft:guster_pottery_sherd", "minecraft:scrape_pottery_sherd", "minecraft:breeze_rod"); - private static final List NEW_CORAL_FANS = List.of("minecraft:tube_coral_fan", "minecraft:brain_coral_fan", "minecraft:bubble_coral_fan", "minecraft:fire_coral_fan", "minecraft:horn_coral_fan"); - private static final List NEW_DEAD_CORAL_FANS = List.of("minecraft:dead_tube_coral_fan", "minecraft:dead_brain_coral_fan", "minecraft:dead_bubble_coral_fan", "minecraft:dead_fire_coral_fan", "minecraft:dead_horn_coral_fan"); - private static final List NEW_FLOWERS = List.of("minecraft:poppy", "minecraft:blue_orchid", "minecraft:allium", "minecraft:azure_bluet", "minecraft:red_tulip", "minecraft:orange_tulip", "minecraft:white_tulip", "minecraft:pink_tulip", "minecraft:oxeye_daisy", "minecraft:cornflower", "minecraft:lily_of_the_valley"); - private static final List NEW_SAPLINGS = List.of("minecraft:oak_sapling", "minecraft:spruce_sapling", "minecraft:birch_sapling", "minecraft:jungle_sapling", "minecraft:acacia_sapling", "minecraft:dark_oak_sapling", "minecraft:bamboo_sapling"); - private static final List NEW_BLOCKS = Stream.of(NEW_MISC, NEW_CORAL_FANS, NEW_DEAD_CORAL_FANS, NEW_FLOWERS, NEW_SAPLINGS).flatMap(List::stream).toList(); - - static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { - String identifer = mapping.getBedrockIdentifier(); - - if (!NEW_BLOCKS.contains(identifer)) { - return mapping; - } - - switch (identifer) { - case "minecraft:bolt_armor_trim_smithing_template" -> { return mapping.withBedrockIdentifier("minecraft:wayfinder_armor_trim_smithing_template"); } - case "minecraft:breeze_rod" -> { return mapping.withBedrockIdentifier("minecraft:blaze_rod"); } - case "minecraft:flow_armor_trim_smithing_template" -> { return mapping.withBedrockIdentifier("minecraft:spire_armor_trim_smithing_template"); } - case "minecraft:flow_banner_pattern", "minecraft:guster_banner_pattern" -> { return mapping.withBedrockIdentifier("minecraft:globe_banner_pattern"); } - case "minecraft:flow_pottery_sherd" -> { return mapping.withBedrockIdentifier("minecraft:skull_pottery_sherd"); } - case "minecraft:guster_pottery_sherd" -> { return mapping.withBedrockIdentifier("minecraft:shelter_pottery_sherd"); } - case "minecraft:scrape_pottery_sherd" -> { return mapping.withBedrockIdentifier("minecraft:heartbreak_pottery_sherd"); } - case "minecraft:heavy_core" -> { return mapping.withBedrockIdentifier("minecraft:conduit"); } - case "minecraft:mace" -> { return mapping.withBedrockIdentifier("minecraft:netherite_axe"); } - } - - if (NEW_FLOWERS.contains(identifer)) { - switch (identifer) { - case "minecraft:poppy" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(0); } - case "minecraft:blue_orchid" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(1); } - case "minecraft:allium" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(2); } - case "minecraft:azure_bluet" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(3); } - case "minecraft:red_tulip" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(4); } - case "minecraft:orange_tulip" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(5); } - case "minecraft:white_tulip" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(6); } - case "minecraft:pink_tulip" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(7); } - case "minecraft:oxeye_daisy" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(8); } - case "minecraft:cornflower" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(9); } - case "minecraft:lily_of_the_valley" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(10); } - } - } - - if (NEW_SAPLINGS.contains(identifer)) { - switch (identifer) { - case "minecraft:oak_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(0); } - case "minecraft:spruce_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(1); } - case "minecraft:birch_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(2); } - case "minecraft:jungle_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(3); } - case "minecraft:acacia_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(4); } - case "minecraft:dark_oak_sapling" -> { return mapping.withBedrockIdentifier("minecraft:sapling").withBedrockData(5); } - } - } - - if (NEW_CORAL_FANS.contains(identifer)) { - switch (identifer) { - case "minecraft:tube_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(0); } - case "minecraft:brain_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(1); } - case "minecraft:bubble_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(2); } - case "minecraft:fire_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(3); } - case "minecraft:horn_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan").withBedrockData(4); } - } - } - - if (NEW_DEAD_CORAL_FANS.contains(identifer)) { - switch (identifer) { - case "minecraft:dead_tube_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(0); } - case "minecraft:dead_brain_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(1); } - case "minecraft:dead_bubble_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(2); } - case "minecraft:dead_fire_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(3); } - case "minecraft:dead_horn_coral_fan" -> { return mapping.withBedrockIdentifier("minecraft:coral_fan_dead").withBedrockData(4); } - } - } - - return mapping; - } - - static NbtMap remapBlock(NbtMap tag) { - final String name = tag.getString("name"); - - if (!NEW_BLOCKS.contains(name)) { - return tag; - } - - if (name.equals("minecraft:bamboo_sapling")) { - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("sapling_type", "oak") - .build(); - - return tag.toBuilder().putCompound("states", states).build(); - } - - String replacement; - - if (name.equals("minecraft:heavy_core")) { - replacement = "minecraft:conduit"; - - NbtMapBuilder builder = tag.toBuilder(); - builder.putString("name", replacement); - - return builder.build(); - } - - if (NEW_SAPLINGS.contains(name)) { - replacement = "minecraft:sapling"; - String saplingType = name.replaceAll("minecraft:|_sapling", "");; - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("sapling_type", saplingType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_FLOWERS.contains(name)) { - replacement = "minecraft:red_flower"; - String flowerType; - - switch (name) { - case "minecraft:poppy" -> flowerType = "poppy"; - case "minecraft:blue_orchid" -> flowerType = "orchid"; - case "minecraft:allium" -> flowerType = "allium"; - case "minecraft:azure_bluet" -> flowerType = "houstonia"; - case "minecraft:red_tulip" -> flowerType = "tulip_red"; - case "minecraft:orange_tulip" -> flowerType = "tulip_orange"; - case "minecraft:white_tulip" -> flowerType = "tulip_white"; - case "minecraft:pink_tulip" -> flowerType = "tulip_pink"; - case "minecraft:oxeye_daisy" -> flowerType = "oxeye"; - case "minecraft:cornflower" -> flowerType = "cornflower"; - case "minecraft:lily_of_the_valley" -> flowerType = "lily_of_the_valley"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("flower_type", flowerType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - boolean isLiveCoralFan = NEW_CORAL_FANS.contains(name); - boolean isDeadCoralFan = NEW_DEAD_CORAL_FANS.contains(name); - - if (isLiveCoralFan || isDeadCoralFan) { - replacement = isLiveCoralFan ? "minecraft:coral_fan" : "minecraft:coral_fan_dead"; - String coralColor; - - switch (name) { - case "minecraft:tube_coral_fan", "minecraft:dead_tube_coral_fan" -> coralColor = "blue"; - case "minecraft:brain_coral_fan", "minecraft:dead_brain_coral_fan" -> coralColor = "pink"; - case "minecraft:bubble_coral_fan", "minecraft:dead_bubble_coral_fan" -> coralColor = "purple"; - case "minecraft:fire_coral_fan", "minecraft:dead_fire_coral_fan" -> coralColor = "yellow"; - case "minecraft:horn_coral_fan", "minecraft:dead_horn_coral_fan" -> coralColor = "red"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("coral_color", coralColor) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - return tag; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java new file mode 100644 index 000000000..250fd9d9f --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java @@ -0,0 +1,205 @@ +/* + * 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.registry.populator; + +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.type.GeyserMappingItem; + +import java.util.List; +import java.util.stream.Stream; + +public class Conversion685_671 { + private static final List NEW_CORAL_BLOCKS = List.of("minecraft:tube_coral_block", "minecraft:brain_coral_block", "minecraft:bubble_coral_block", "minecraft:fire_coral_block", "minecraft:horn_coral_block", "minecraft:dead_tube_coral_block", "minecraft:dead_brain_coral_block", "minecraft:dead_bubble_coral_block", "minecraft:dead_fire_coral_block", "minecraft:dead_horn_coral_block"); + private static final List NEW_DOUBLE_PLANTS = List.of("minecraft:sunflower", "minecraft:lilac", "minecraft:tall_grass", "minecraft:large_fern", "minecraft:rose_bush", "minecraft:peony"); + private static final List NEW_STONE_BLOCK_SLABS = List.of("minecraft:smooth_stone_slab", "minecraft:sandstone_slab", "minecraft:petrified_oak_slab", "minecraft:cobblestone_slab", "minecraft:brick_slab", "minecraft:stone_brick_slab", "minecraft:quartz_slab", "minecraft:nether_brick_slab"); + private static final List NEW_TALLGRASSES = List.of("minecraft:fern", "minecraft:short_grass"); + private static final List OMINOUS_BLOCKS = List.of("minecraft:trial_spawner", "minecraft:vault"); + private static final List NEW_BLOCKS = Stream.of(NEW_CORAL_BLOCKS, NEW_DOUBLE_PLANTS, NEW_STONE_BLOCK_SLABS, NEW_TALLGRASSES).flatMap(List::stream).toList(); + private static final List MODIFIED_BLOCKS = Stream.of(NEW_BLOCKS, OMINOUS_BLOCKS).flatMap(List::stream).toList(); + + static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { + String identifer = mapping.getBedrockIdentifier(); + + if (!NEW_BLOCKS.contains(identifer)) { + return mapping; + } + + if (NEW_CORAL_BLOCKS.contains(identifer)) { + switch (identifer) { + case "minecraft:tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(0); } + case "minecraft:brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(1); } + case "minecraft:bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(2); } + case "minecraft:fire_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(3); } + case "minecraft:horn_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(4); } + case "minecraft:dead_tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(8); } + case "minecraft:dead_brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(9); } + case "minecraft:dead_bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(10); } + case "minecraft:dead_fire_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(11); } + case "minecraft:dead_horn_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(12); } + } + } + + if (NEW_DOUBLE_PLANTS.contains(identifer)) { + switch (identifer) { + case "minecraft:sunflower" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(0); } + case "minecraft:lilac" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(1); } + case "minecraft:tall_grass" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(2); } + case "minecraft:large_fern" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(3); } + case "minecraft:rose_bush" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(4); } + case "minecraft:peony" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(5); } + } + } + + if (NEW_STONE_BLOCK_SLABS.contains(identifer)) { + switch (identifer) { + case "minecraft:smooth_stone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(0); } + case "minecraft:sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(1); } + case "minecraft:petrified_oak_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(2); } + case "minecraft:cobblestone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(3); } + case "minecraft:brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(4); } + case "minecraft:stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(5); } + case "minecraft:quartz_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(6); } + case "minecraft:nether_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(7); } + } + } + + if (NEW_TALLGRASSES.contains(identifer)) { + switch (identifer) { + case "minecraft:short_grass" -> { return mapping.withBedrockIdentifier("minecraft:tallgrass").withBedrockData(1); } + case "minecraft:fern" -> { return mapping.withBedrockIdentifier("minecraft:tallgrass").withBedrockData(2); } + } + } + + return mapping; + } + + static NbtMap remapBlock(NbtMap tag) { + final String name = tag.getString("name"); + + if (!MODIFIED_BLOCKS.contains(name)) { + return tag; + } + + if (OMINOUS_BLOCKS.contains(name)) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("ominous"); + return tag.toBuilder().putCompound("states", builder.build()).build(); + } + + String replacement; + + if (NEW_CORAL_BLOCKS.contains(name)) { + replacement = "minecraft:coral_block"; + String coralColor; + boolean deadBit = name.startsWith("minecraft:dead_"); + + switch(name) { + case "minecraft:tube_coral_block", "minecraft:dead_tube_coral_block" -> coralColor = "blue"; + case "minecraft:brain_coral_block", "minecraft:dead_brain_coral_block" -> coralColor = "pink"; + case "minecraft:bubble_coral_block", "minecraft:dead_bubble_coral_block" -> coralColor = "purple"; + case "minecraft:fire_coral_block", "minecraft:dead_fire_coral_block" -> coralColor = "yellow"; + case "minecraft:horn_coral_block", "minecraft:dead_horn_coral_block" -> coralColor = "red"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("coral_color", coralColor) + .putBoolean("dead_bit", deadBit) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_DOUBLE_PLANTS.contains(name)) { + replacement = "minecraft:double_plant"; + String doublePlantType; + + switch(name) { + case "minecraft:sunflower" -> doublePlantType = "sunflower"; + case "minecraft:lilac" -> doublePlantType = "syringa"; + case "minecraft:tall_grass" -> doublePlantType = "grass"; + case "minecraft:large_fern" -> doublePlantType = "fern"; + case "minecraft:rose_bush" -> doublePlantType = "rose"; + case "minecraft:peony" -> doublePlantType = "paeonia"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("double_plant_type", doublePlantType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_STONE_BLOCK_SLABS.contains(name)) { + replacement = "minecraft:stone_block_slab"; + String stoneSlabType; + + switch(name) { + case "minecraft:smooth_stone_slab" -> stoneSlabType = "smooth_stone"; + case "minecraft:sandstone_slab" -> stoneSlabType = "sandstone"; + case "minecraft:petrified_oak_slab" -> stoneSlabType = "wood"; + case "minecraft:cobblestone_slab" -> stoneSlabType = "cobblestone"; + case "minecraft:brick_slab" -> stoneSlabType = "brick"; + case "minecraft:stone_brick_slab" -> stoneSlabType = "stone_brick"; + case "minecraft:quartz_slab" -> stoneSlabType = "quartz"; + case "minecraft:nether_brick_slab" -> stoneSlabType = "nether_brick"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("stone_slab_type", stoneSlabType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_TALLGRASSES.contains(name)) { + replacement = "minecraft:tallgrass"; + String tallGrassType; + + switch(name) { + case "minecraft:short_grass" -> tallGrassType = "tall"; + case "minecraft:fern" -> tallGrassType = "fern"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("tall_grass_type", tallGrassType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + return tag; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java index b2d238ddb..a43df3f52 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java @@ -53,7 +53,6 @@ import org.geysermc.geyser.level.block.GeyserCustomBlockData; import org.geysermc.geyser.level.block.GeyserCustomBlockState; import org.geysermc.geyser.level.block.GeyserGeometryComponent; import org.geysermc.geyser.level.block.GeyserMaterialInstance; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.mappings.MappingsConfigReader; import org.geysermc.geyser.registry.type.CustomSkull; @@ -325,13 +324,11 @@ public class CustomBlockRegistryPopulator { // meaning of this version is unknown, but it's required for tags to work and should probably be checked periodically .putInt("molangVersion", 1) .putList("permutations", NbtType.COMPOUND, permutations) - .putList("properties", NbtType.COMPOUND, properties); - - if (GameProtocol.is1_20_60orHigher(protocolVersion)) { - propertyTag.putCompound("vanilla_block_data", NbtMap.builder() + .putList("properties", NbtType.COMPOUND, properties) + .putCompound("vanilla_block_data", NbtMap.builder() .putInt("block_id", BLOCK_ID.getAndIncrement()) .build()); - } + return new BlockPropertyData(customBlock.identifier(), propertyTag.build()); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 10d87a8a9..a6fa164c1 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -44,7 +44,6 @@ import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.WearableSlot; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.mappings.MappingsConfigReader; import org.geysermc.geyser.registry.type.GeyserMappingItem; import org.geysermc.geyser.registry.type.ItemMapping; @@ -260,18 +259,11 @@ public class CustomItemRegistryPopulator { } private static void setupBasicItemInfo(int maxDamage, int stackSize, boolean displayHandheld, CustomItemData customItemData, NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder, int protocolVersion) { - NbtMap iconMap; - if (GameProtocol.is1_20_60orHigher(protocolVersion)) { - iconMap = NbtMap.builder() - .putCompound("textures", NbtMap.builder() - .putString("default", customItemData.icon()) - .build()) - .build(); - } else { - iconMap = NbtMap.builder() - .putString("texture", customItemData.icon()) - .build(); - } + NbtMap iconMap = NbtMap.builder() + .putCompound("textures", NbtMap.builder() + .putString("default", customItemData.icon()) + .build()) + .build(); itemProperties.putCompound("minecraft:icon", iconMap); if (customItemData.creativeCategory().isPresent()) { @@ -427,64 +419,56 @@ public class CustomItemRegistryPopulator { // Make bows, tridents, and crossbows enchantable itemProperties.putInt("enchantable_value", 1); - if (GameProtocol.is1_20_60orHigher(protocolVersion)) { - componentBuilder.putCompound("minecraft:use_modifiers", NbtMap.builder() - .putFloat("use_duration", 100F) - .putFloat("movement_modifier", 0.35F) - .build()); + componentBuilder.putCompound("minecraft:use_modifiers", NbtMap.builder() + .putFloat("use_duration", 100F) + .putFloat("movement_modifier", 0.35F) + .build()); - switch (mapping) { - case "minecraft:bow" -> { - itemProperties.putString("enchantable_slot", "bow"); - itemProperties.putInt("frame_count", 3); + switch (mapping) { + case "minecraft:bow" -> { + itemProperties.putString("enchantable_slot", "bow"); + itemProperties.putInt("frame_count", 3); - componentBuilder.putCompound("minecraft:shooter", NbtMap.builder() - .putList("ammunition", NbtType.COMPOUND, List.of( - NbtMap.builder() - .putCompound("item", NbtMap.builder() - .putString("name", "minecraft:arrow") - .build()) - .putBoolean("use_offhand", true) - .putBoolean("search_inventory", true) - .build() - )) - .putFloat("max_draw_duration", 0f) - .putBoolean("charge_on_draw", true) - .putBoolean("scale_power_by_draw_duration", true) - .build()); - componentBuilder.putInt("minecraft:use_duration", 999); - } - case "minecraft:trident" -> { - itemProperties.putString("enchantable_slot", "trident"); - componentBuilder.putInt("minecraft:use_duration", 999); - } - case "minecraft:crossbow" -> { - itemProperties.putString("enchantable_slot", "crossbow"); - itemProperties.putInt("frame_count", 10); - - componentBuilder.putCompound("minecraft:shooter", NbtMap.builder() - .putList("ammunition", NbtType.COMPOUND, List.of( - NbtMap.builder() - .putCompound("item", NbtMap.builder() - .putString("name", "minecraft:arrow") - .build()) - .putBoolean("use_offhand", true) - .putBoolean("search_inventory", true) - .build() - )) - .putFloat("max_draw_duration", 1f) - .putBoolean("charge_on_draw", true) - .putBoolean("scale_power_by_draw_duration", true) - .build()); - componentBuilder.putInt("minecraft:use_duration", 999); - } + componentBuilder.putCompound("minecraft:shooter", NbtMap.builder() + .putList("ammunition", NbtType.COMPOUND, List.of( + NbtMap.builder() + .putCompound("item", NbtMap.builder() + .putString("name", "minecraft:arrow") + .build()) + .putBoolean("use_offhand", true) + .putBoolean("search_inventory", true) + .build() + )) + .putFloat("max_draw_duration", 0f) + .putBoolean("charge_on_draw", true) + .putBoolean("scale_power_by_draw_duration", true) + .build()); + componentBuilder.putInt("minecraft:use_duration", 999); } - } else { - // ensure client moves at slow speed while charging (note: this was calculated by hand as the movement modifer value does not seem to scale linearly) - componentBuilder.putCompound("minecraft:chargeable", NbtMap.builder().putFloat("movement_modifier", 0.35F).build()); + case "minecraft:trident" -> { + itemProperties.putString("enchantable_slot", "trident"); + componentBuilder.putInt("minecraft:use_duration", 999); + } + case "minecraft:crossbow" -> { + itemProperties.putString("enchantable_slot", "crossbow"); + itemProperties.putInt("frame_count", 10); - // keep item enchantable; also works on 1.20.50 - itemProperties.putString("enchantable_slot", mapping.replace("minecraft:", "")); + componentBuilder.putCompound("minecraft:shooter", NbtMap.builder() + .putList("ammunition", NbtType.COMPOUND, List.of( + NbtMap.builder() + .putCompound("item", NbtMap.builder() + .putString("name", "minecraft:arrow") + .build()) + .putBoolean("use_offhand", true) + .putBoolean("search_inventory", true) + .build() + )) + .putFloat("max_draw_duration", 1f) + .putBoolean("charge_on_draw", true) + .putBoolean("scale_power_by_draw_duration", true) + .build()); + componentBuilder.putInt("minecraft:use_duration", 999); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index d3a4bed84..5fcea504f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -38,11 +38,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; -import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; -import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; -import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; -import org.cloudburstmc.protocol.bedrock.codec.v662.Bedrock_v662; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; +import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -62,7 +59,6 @@ import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.*; @@ -91,11 +87,8 @@ public class ItemRegistryPopulator { public static void populate() { List paletteVersions = new ArrayList<>(3); - paletteVersions.add(new PaletteVersion("1_20_40", Bedrock_v622.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion630_622::remapItem)); - paletteVersions.add(new PaletteVersion("1_20_50", Bedrock_v630.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion649_630::remapItem)); - paletteVersions.add(new PaletteVersion("1_20_60", Bedrock_v649.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion662_649::remapItem)); - paletteVersions.add(new PaletteVersion("1_20_70", Bedrock_v662.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion671_662::remapItem)); - paletteVersions.add(new PaletteVersion("1_20_80", Bedrock_v671.CODEC.getProtocolVersion())); + 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())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -602,18 +595,11 @@ public class ItemRegistryPopulator { NbtMapBuilder componentBuilder = NbtMap.builder(); // Conveniently, as of 1.16.200, the furnace minecart has a texture AND translation string already. // Not so conveniently, the way to set an icon changed in 1.20.60 - NbtMap iconMap; - if (GameProtocol.is1_20_60orHigher(protocolVersion)) { - iconMap = NbtMap.builder() - .putCompound("textures", NbtMap.builder() - .putString("default", "minecart_furnace") - .build()) - .build(); - } else { - iconMap = NbtMap.builder() - .putString("texture", "minecart_furnace") - .build(); - } + NbtMap iconMap = NbtMap.builder() + .putCompound("textures", NbtMap.builder() + .putString("default", "minecart_furnace") + .build()) + .build(); itemProperties.putCompound("minecraft:icon", iconMap); componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", "item.minecartFurnace.name").build()); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java index 928ab8df9..4c6d53518 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java @@ -35,6 +35,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtUtils; 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.MultiRecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData; @@ -173,7 +174,7 @@ public class RecipeRegistryPopulator { /* Convert end */ return ShapedRecipeData.shaped(uuid.toString(), shape.get(0).length(), shape.size(), - inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId, false); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId, false, RecipeUnlockingRequirement.INVALID); } List inputs = new ObjectArrayList<>(); for (JsonNode entry : node.get("inputs")) { @@ -196,7 +197,7 @@ public class RecipeRegistryPopulator { inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); } return ShapelessRecipeData.shapeless(uuid.toString(), - inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId, RecipeUnlockingRequirement.INVALID); } private static ItemData getBedrockItemFromIdentifierJson(ItemMapping mapping, JsonNode itemNode) { 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 69f61b181..9d2a3ef06 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1546,6 +1546,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setRewindHistorySize(0); startGamePacket.setServerAuthoritativeBlockBreaking(false); + startGamePacket.setServerId(""); + startGamePacket.setWorldId(""); + startGamePacket.setScenarioId(""); + upstream.sendPacket(startGamePacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index c6c3c7dd6..8fe1e96c0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -35,7 +35,6 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.level.block.Blocks; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.InventoryUtils; @@ -44,7 +43,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBookContent; import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import java.util.Collections; @@ -152,13 +150,6 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator } else if (lecternContainer.getBlockEntityTag() == null) { Vector3i position = lecternContainer.isUsingRealBlock() ? session.getLastInteractionBlockPosition() : inventory.getHolderPosition(); - // If shouldExpectLecternHandled returns true, this is already handled for us - // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet - // TODO: yeet after 1.20.60 is minimum supported version - boolean shouldRefresh = !session.getGeyser().getWorldManager().shouldExpectLecternHandled(session) - && !session.getLecternCache().contains(position) - && !GameProtocol.is1_20_60orHigher(session.getUpstream().getProtocolVersion()); - NbtMap blockEntityTag; if (book.getComponents() != null) { int pages = 0; @@ -205,16 +196,6 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator lecternContainer.setPosition(position); BlockEntityUtils.updateBlockEntity(session, blockEntityTag, position); - - if (shouldRefresh) { - // the lectern cache doesn't always exist; only when we must refresh - session.getLecternCache().add(position); - - // Close the window - we will reopen it once the client has this data synced - ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId()); - session.sendDownstreamGamePacket(closeWindowPacket); - InventoryUtils.closeInventory(session, inventory.getJavaId(), false); - } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 36752e582..18d6a22eb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -550,6 +550,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { ContainerClosePacket packet = new ContainerClosePacket(); packet.setServerInitiated(true); packet.setId((byte) ContainerId.INVENTORY); + packet.setType(org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.INVENTORY); session.sendUpstreamPacket(packet); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index 4bc727397..06531eff2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -152,6 +152,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { ContainerClosePacket packet = new ContainerClosePacket(); packet.setId((byte) inventory.getBedrockId()); packet.setServerInitiated(true); + packet.setType(ContainerType.MINECART_CHEST); session.sendUpstreamPacket(packet); return; } 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 index 1ea686536..959797d41 100644 --- 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 @@ -42,7 +42,6 @@ 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.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -331,10 +330,6 @@ public class BedrockActionTranslator extends PacketTranslator1zWLFM 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

g-=;VUl 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⁡z#A(DebW+` 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%0D8NL_yw6CPSm^x#@W)*%Q+? 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 bpUvdU1E#~Pzl`yiv-g&@bjG3vY-s-jSX!9v diff --git a/core/src/main/resources/bedrock/block_palette.1_20_50.nbt b/core/src/main/resources/bedrock/block_palette.1_20_50.nbt deleted file mode 100644 index 0eecda74f72dcf026d3f665c050d04a1f8485bb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170466 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 JkFhIPadz0t*h z|Jmi^JGA((N*e@k;JRB*=KKWUD>epcW53M@qbMw~5&h3vg?2Xf%^N1T;Y-j9hiFuI z8;CBUE<}Ji)>6>r_&*Gn+YyCYl?B4suf^5kRoM!>^Vk>k>Ho)0|FoR$S_xt4#Z1j> zjQck4`U1r#XKxFx$E&xGVCL6L7@0J9-fT4p3c>rz3O43?iWMwYfzm5_i3tlbQa3w> z1PoZ>+(f1ROEm(bE91vAVtDHIeoZ#i?ZekD(I$2L56n&x%OtR%YpMQ#hLYj2B68vd z0tY?>M50{qANb7Cftnrs)VO#UozsxH1RQ9-Gg=|#^!@1YM6?AO(21RWm!3WZaIIagt7Qblip*Q4S@ zbP7#tfArn_Gt5wwO;x@ZGW!4TjC|30w>l~?{rgNM~vOh+%rlQ9Ak2?|Ttu^~^1-a1b&hn23;wezF%1-fF7_ z^i${=}p{ynyr%Wlk089mwWUVxW6^A3#8Ad;^=HG0Pw@|0v{M5Kmc|S0ww#`= zw9{`S-rvp-<$R_J8j!CgP7`)&MtDw3Jpi z_q_Hr)8X!%)d`i$i7%34B{`g;=+mb_EPa=BeVEZSx&Fr~`K!nVI=I2I!e?5a3H$s* zS&GhdX-rS?HXGUXFr(#Z!&U25>5wOz0Bu?Hbq5)rTVRUYZw1#!EPr+Sa?B*mjcA-U zf~@R_&(J^0p=bKfFhhyUCEoLnqK&_MiQv&w#Z(d21S~32+ zTU+wU4+U4#1GMPp^3YhNSj(&Og)c_ZV~o^7b`pHGN?-o_Qmg#)-#bMgwQ*ml%(jEi zbWN87 zz3u)GTd%M@A^i3gM$5J(XB)KM-jeimeBIWCObt93FV2JN(xwnc(Y-irdyOu z=pwW4nK`fcv=APIJ56Kq#nBdLKxNk7!IU(mkHI(p--U*mgYP;`Me{nM?-dB*aGIluUJGw`)|=JvlpP8z|E z4JjVD?Z3ch=6`ry4dp|9e}1q_Cnv;=y*rwDZT*|i-B7*|+5)|FHLM|}yeV=L3sy>R zugLpXzNmCm0?3^QxC#{rj4+^CeQsGNYmJ9zr}7At@S8UnP$#5W>I@T$z1!cCRZ8!z z$m^!NU(Vz8G?jN}owvPvSEQ}z;~dSItE*SLV2a2=LU}-;Tg3dQ`J&rn0-__-kP27W z(U#F@K5D3;G=Cz$?=FlWAKdRzEE3E+vE*(fU;*aji>`*t1J}j@9hi4X)_(C%g=%izC8Pz)k`llzq-cH+dX+0M)72YNeK9xxEu>_I$VuB&H#pE| z=@Z9D(rYWTyVXM+a`|kGCETIL`m63t zd~D*ZXKm`WRL{rVLWc2MnlK$Wqn2YSJPMNz!zFa0hmNPkHhm6`qg8fC^);0Ch2CpA zXv5-a@gArKmmaLXY3(Mn)Ufx1#qXMWum1*&s?5g&D0P-Ck>n>&83AOyptZ7b1q#L* zO6w~50VHr#l6o^k6;dwVz2uA9r4igLQ>F{)^*=0WT?jZn#wq^%w3MU2cg$B+v8x8f5OcbIOw?O*RS7Z5-89o7nWQ~tG1KEs+uI~RoLtvkE7&%TCjh?CVjg7Mar`9eyM z(9Bb3+-zUxPh6yw7nwG=L#0O=Sgrr;!0lPVa4&E8E+T5G;w3JX+wVldyg(WIAD=#+ zQ6KQ?h&xL_kP~2iZ6A;Bg?xMtA{#1XS+xZ>^%TbTBR7W@%t*Pj)HLw$j;b6rt9;mzexd2Nw#^i zfui*VOxZ%6P5ts<)N8#~b;tIS*fYOp~^egnsrGWP2<;8psN`Nq<&fUfYM57B~G5k+=!(wPwlL|y;?v8BKP zJ@Q~0J#c9H_jr{EZvSnpTz^oI5%{Pia}}~a;MoFa7bCsL5m3(sp@02{_j=x6-Sy*p zc_8=6dY7`oj8RH)cHKQ7*_M9(?059*3j$9Y?9t{(Z!5LR=-s!mZ2TyFWbZDhL8O{P zh$|sCbxQ?<$x`cBT)KjIov^`%(5CiKvea}4gaB(J_pDb*AIr|`mi@o49wo;aj``PA z)$(d|s0THa;4chs40_TW2=Ly>m?c)5ZG26s8PF^n1MXhmfX3v9 z_sDE!s}-p#r;8Jo{|oO%6*q<&pX?11YNHV~>z(u|PtSg;sKnp4RQbVK$6|fxRdpaR zenFzh;S!l2%$Kv1YHhs`o6s_TA^++62(zwo_l}mx(_`+QZ0sUkn&bM~CJPLIwwj(F z2OHG2%$B6?-kC+}j(LrRs7RwLz0%F=l0+TpVlUMH^nzXS$=Z`^biG1pm_LGc`BpOi z7b(s3sa@`hUgu|Kfg918{bMZ228C+XoR=-H;*gq-p&KV9ZMgTzEx%}`q0kb8N2-*w zjxWkHmC5qWJ8Q$C$1LgWq_!;l`=&Helf*kkW)2!;66YXxlrty2Auq{d6KjoS3F9u> zkCc(SDgr%&{00?*44JjlTx5JDNeEh)KOb6h7-Jszv9fY<-o~$J-oz}TgdwD2{(SPu zF8ao`rJ;6SFXX1+svo7c<#SSM7NX#LDQ8GetN(46FMG)N`V$%bL*JhyteFx9-mWil z(1JFRkOkbT#wX!Bp)0YUee-BW^m)Es%Xm@&V_v@x>s$3J5){2c9Oe59GIK1OBz zdc2=1Qot9z@T*$!_8iUrxZC^a(wxi2c$B!nzNu!v#Rz^c#aH5C}mYVe{9evB^Tqbrfrtm6A6Yos?SPN z_o(DB<}9f6E;BQl;?@+@u#IHeu5B*sI6_xl8*6$0nj=L-;VI?_Wzd)PNTtb1U^)R3 zM^!YIepp#{m=qgPQHPnPA`d;d4WGV_bt<|$c{7FP5E#82N?Y{o*X%yuI-$OcD?-dO z%1tpw&ABXKR%5YcA3>ysj2`*|y30M^G|H(Y4+ZXy+(*s2`=WqxoDm{LSV&@>odQuH ziz3f3AKAV}+VcGyr5i#Pk?UL+dc4&Bn`?bWw7MP$4D3AL*qlIO3rJ5!^LfHia&jqs zKQgbtrG(qDsiGGdIF2a%%Dft+`+|vYRa_0hIB5{_7D%hh?NM`3E9+FGzEhsF3 zvsZKVH@&Vzu(3CH~%mU(Bsd9GVVd6U#=X@gDuG?b`0b zF51(tp^8Zx!8HIji2e>F4ezVVZm8uwlz-f%2o6&uXQ)Crz@eZ1k%;&~ci4b!h>F@j2vo?M%L`A$K23p&~;^S|@(gTY@sWke`7M zmaWL2C-y#;LMC<)*FDCOd>)(g7V|61e6hiq7EjRv?nEW!k93Vm9lg%Q6mppsS1M^| z@mgz|V%`VP>C_C1Ga_3ChT4t`ve68Sqn%Vmo6_n-y5#Vc;;E6%my;l^Cl9HMds%_& zv8i>UB_~d#Ujmc!>ft`cm33J)!+;?4Oh-5J4@3|^^d@S4y1VIS-a?P zW^ufFoh>czkVjnO<6c{?UGN9*yeZc4F4Y5@q!PWa*!a-c%5<`;v1jp>}YM(uQ0|Bpxw)ewkXe>-eWtMv~TpmxU&iG*SsthPhp-rUJMWDCTed_LM9 z0*n2oawMy^Hx(ZHN=s(zG`5`#k7pT1*@MT!E_1ca_PU~GvK>n2W%5_w+>5{Y_n)nS zI3Kic%3po(EUS%f;S~XC$}8jhj&{q!%aiq>?lP|ZIevJn+;_v+0|pUa-Db}#=frWq zJ#-Y++wU;DT&WJq2R6~U0klAEJ-<{;4`sk}ZnuO*Q=b^!hUeSy=dB~t-LBQu4A&4t zZ4@xI(l;t%iAy$amAN-_*lNSSq_dcAB=3H>TG5}TKw~7|xL8`DKM+2EraaHh^Z4A_ zDCSy-_3Xj|ErQ?L<27;JZ0^inEm~^l!sO7*sK{!+gyYV~3HGYW((t78>JC39+ag!_ z$)CF3OX-W^3U{*)->x_!t&Ks(J4RIYn>g+f-Zc@{Ms^n)E8$B<+lV;c(4pCZU#{1E zuSR)l(3pHc?QWJ=szd#qt}a7M>h+c>Rj29RPgQpq^1z(~b2P`>p%d(mEqr`^<&`!z z_p=^u8c;WReAW{U#R~fEEe)q|@5+qdpWC!{d^~@kwPh^7zs8upCWRaetr$xp6FiaV zv>XbQ9O2tk#i+hf-0fYETb@DE_nzcyU_<&x9>#lBo{ZC-57-dm zbXxCp5q>Fl&4-+&C)ao!2=V%j6wwgK7K_RCzGTw`^!5{J&qns zalqV=DTy1tAt1Lrng`-tnv#sEIn?w|JPG>6*VUB7(nygH`AjLTbt_1ae)xeFTyf6Y zyj_yrto5==aQA?i;2E21kTbXnod0Jzj9gmlx_ZWyfD)D+yQJlLP1jmXY8KDG!=$e% zwnrym~cGCwU?mZ~NGgw?S(({bgW_V_cPw(Hwx6R-kZVWzX6%xKmEb9%Mg5IK0gDVybc zr3L!0A}^!^$6{6H z)kr!eBqC7Ttjz@I%(&^r!o`n~2aWM;&#EZ{0x&*nUnfN$pvr|Cqye>Wz7>!ut(POW zc->yp*Mjjb9;9*iTV1wkpP4{k88Y?wu=2Eb0;#9xMaDbQ~KvF?%O_b zY(iE!=>fBdw4V7^hr~9#KG%`95(g||KzN`7wP_sVb2KI)XH|Fo!eD$}t=sF@$UlF; zd<17~l{g$%od*C`wkYxl>%Arv0K`jScwB3OLPaMMTL*>-t$=(x5P805RMu|g&~c$Whql89CpYUhJL(5Z{uordyz5|Bw!KU=rtGR zwqXaFur$rBMbE&uI+7LNZka$_u0;8gd-`#Tk&Kpe`IsU;4cXUSv$+`z9o=`Z%CteO zb2oWEHECYYjE}}0%s%8~w{fJZh^ss`uA6 zXfQUYZ#SU(5F#fh;w&@NX7B0Zm*wvT+drFMk>{=wu>sKobzM6om?&2%hk4!cxt|Hk z;}o9M0vtR!U3vIZ+PpC(fhT0n2khO81k+1gT`^I-L&$NphX=-ttirIo%oKb%3R_kN zmOkv5bY^iZh)^=5{gezf{s3mTy zP#RBH3iyoSlPpM6xC-y-^NcKT)*2n(naqprm3wFL6idzGvCx~zvHh2NZv+U( z$vF{`dSn(;RpSS2f1S9q$Qjchx$g;8B?|Zse~b)7i*p0=e!N&@@+sXE+OKsTr_dIR zl{Z?kkMmeOI<9^mT_Pbgy>W&FBlo*F=`Jqbp~u+T-O)a6R(P@b%!dEeKIY|ilWB(Q zwdCeZ7ZuC!TyW3uFO(y)R2-04&1VUuernY?^DeP)z4ACMR`S*Baw;GBUu%F?~?qVBIXVJfjFbxO(z=EZ1Q5c+`uYuT5=@yvkl; zrj>tK!RKV}KffW-PU5qg?iSK_~hhWd(4Tn*Z z(1JVosAz_v6^eO-(YH}Urj_?2u{B<9^y}zYXH|Y;E7hJuS&g2y#?W%?C3mad^Xc&_ zS84%;x;eiasQrn(_10HheddR*)~+*dr?hsxNBHOhoErJm)ta;AV7+7woKl>=uO68h z6CF6bSFjSI>>@qTh&E0ZJimGVow)t!i__`3LuIwY!&$v;6f%RgfR`8l{Re)LwZ{cU zbN6RdWSHQFAn@ZsbQ=HSVW~ii(Niz86`mHCZfOihWiQFMe>I<5=;#7{TJ3-Pr=|wC z*T$#H$N0C_f}_>yDUtRiawM#Mz>kK~J{YNg=Nfu-QCO#f(m4=TF^~VM6I>~591uhoKo5{%J{e;@07LS&U zl2rmXGjLLQz?P&33~~y(ZIA_ZgF#=&@I&S#G8NZ)%myY($!wMTBvjCVJp)ldG1nTp zg2J&$U_ZaFr~vgArpiDhvdj1qrz6JV_Xd^VG}3sN%Mo1y^Bq>BsbFJJHp-!Wg#)Q0 z`Udf7{YoH|N5S!%eSNrqQPeb-o@VJj_Cu=ANlX$d>ia$8jpNO&wVhLa@!}s>GXA=; zQi6RRPezlZ9MLyd^1iKY;mw)h_2H!p(TbcXp5;)SHs!y^cREQ@ZJb7tt7GPyqi#~S zEW7)PE=0^a1@EGzvzu9OVt zv;~1mu}t58iy0ZUiLP2?M06;wWJFfJn9&;JR=DLekJo}L0n3$>ue+)gLR_hEAyEA^ z{?bA>kjnV#kUT_D{ocu6xo;!Mp{y_lznp5VrHf&@h~kUI;5D83nvlc(4kM9GlL_Le@A)0 zNH}`25Ca2r&t^+h`3m>4nwH)&5#FaF#Kct4ov#c{%h+BQ*mCuZ*wtBJeUYBUeainf ztwASl)Obxjk2mgT!I2m)V}yr&-Q${LNtkLrRJ@ZRzL340Lr3UYNXPODwV86^M{w7l zy!?F^m9*$j<%q(fof)$v=C?^7uxItj2TG{)$$!UGFim*RF;#FrKcA5b=Yu?3@F(~6 zjJVQWk>4(iOicMEQ_Db0Xd*65VW|Etmn2SezcMnaUZRvM!Be;*rh>Iskv^;PFt)|x zQl^F_>RxAD(y;XHb7 z-aoizDM#CVYhmkTpRz*yE85xShTD>pKa4|6Vi$g1rZ@Bk7Wzm45_#)~|#`d+p>m90^m02a9(yRc|O1 zkIfHxQfug`55v^*6Wij519KN_)*!b_M(|)BM`oC$1)9fC>UN!*{&~Yx_Vj$k-4t2T$oMPs5T+we_XT|qHe-j6-iE+*CA>&DrHXQyW# zio)viyzE#08LzY!J8X7DrG#S{o0jc0>ce_>c+Km}MEN8WBI7EVq^Nfvs1GAtv~3qB zG(`c?h!W6O>{+Nuj)*e376(WR-a;$#EZ#A8! znd_y;()uKTjE2hBbz^jY&nsIdTNSCar8a{JFKBh29Ow4Y&=72v?WwK0*AYVoU95BT zbZ+VEYAD@((!jlG?=vv}c)R@Lu-N_{OV|5>I!Tj^ybU%3=~)8ArOA>w_uQPFNTsFv zYL@4)$TuT=2%Q|aOy>aO{T~W|>r0PvgD9xP?s`xi5~e!ZKM!V-F_zU3-g3$GN0x3} zCRinzEUYj3M8AFst2?5gXLtH_D5|r3m5q{>sH8)FM;Z)z7dYYk+JIG=G^(W zIf^a60Kj)!zD7(M;ui&=txdhM|*E@j&vEhis#4k&VNMyQK>Z?GkHaWzQ~@ zv)Vda3E#t;w#BZ{~cwKr$9!vGuM*1aD`MPb{)%(a=}^c&8j)uv;s z#WOI#F;a{fjT+*1d(JYoZ1=VV2XJaJC*ig(8?8D3OqirO7O}v>HB#9OL-mj?m93%= z=Mi8PfwS8Ci*Ywpa+d1%g>^k^GCiDn=rk}!HPS4y>$^(O0AgPMJLKGmAT2$MlY_^Z zQdnKm1msn|UeP8H9?P_~cST#=ew?KWS`AkLGC(dQbFtV>Ry#?mNhYq|-)1)1LS1?c z`eMR7Wb=VcSLT>bBEDfZS&SdiI{H&>4QRt#37WMQgF%6K*1}6(e*nhClDd|BFTMu^ z2vky3I69`AP5_m2Gk*Hb2@56r^VO)+Wr8%UB=y26C1BeA}o>118E4YP9%Pq*4!QvPr2NCgE+y#u0spPc5gw0gPD z&rTz(PDR@x{apuryBO07wx2|Vu75=PCnZHLMWfV*UJ;LD(PcA62@>+fp3hw$Kp%*K z&pSzM4uOw%;h%SE68N`6jfvZho+9zr34}&_@Y#Gun))((Kekcq+)jzztb~KSs7B9- z;N;rB5hJ1O3|j|?lX&ks)z4=%5-t&eQ>E}4N^;yL8%U0!RH>${o< zX0)>gl_s5lPw*63G3i)Q?CktAPkMij3QgblQTE(5#)QzlJM?l*zNQPgh^N3(94oL- zFgfEFVb?=uU{b?HYNU`IuL1(3d!Wq9G7OVgC4eQo8 z&p2jl}x#neXGUql4r1-JPhAUeC;5R$0$cEsGdKrR`_XO*Y zQ{;yP7%iX5#f8Mu+KB@Mx?*`at;PVUauh?beYR3p)8)rp1K*%YR_#w&nG`e+AJa0Y zvN)g6Xb-{mjUv%ez+)rdAS*D5#~3&!<%z&{WY<_xNR03r)SwQo=Xyf3n9E#Sn?%$D z1dV-z@+rEI_CV5L2pa1_1eu(WSWrU-#fn|9e4Ac|tq`QQZ@Uj_3avkK_v|C|cnV_f ziqygj=e&gIaIsU1hb}@gvL05jcek((q~h-UZXUejuQUj?-`(5Ul12;l-W6{~qmX>H z1}(TDPdOSTRES7r@Xyj@h-^GAo%Q)gq4UliC`Qvk+{W5KzQr?E07x7bTG(+FnOwvaep9Dg(+Oby=*zDIs+h>}{4a9SwdW|B}#M}V0ss$aj47R0`b<^R(1TCRq<=KVS&#L z`p{6q!NM889=CsDoaMXGCp$G^noj?rSICY7YWihVgXKWdM<41k_rNN4;XPltOxRWq zZT+sG&XN@M?B{i#kh9C_y?WJIv5FVb9mC-`ajmXa5rVE_7^`#3lR2Xrf+B>)3SL0vHv7jqT#Z+&S=7@A}MybvK`0!Mk!9T zg!N@}gVDP3X2~e8oY=dj`XytZ2g#gsLzQWxs!O8Ck-)IVqW&v84$(ihOTfRh=@?&4 z3%|Ey=<68o_retXsTubpC#&#sjh0}8e){kDu6P^MoMcfz4r0-YA)dPln$a3F-P?4z z6c0w@HRgaY@ZSB4#ZJwJ01kVq=mjxxzd!MI@kVjjls1k)Zm&TU#*LJJcxnPK zbf!lH#?%pCgAC&ZcE%|NHMn0>B>8`QUtqAtY+n^rN`Pv&#%yBQczxmr49r_>|S)?Z-Pk-*>*KFBsp4A zWP^VA8x~GaC%#2-0OoWYqf@lyqrUt5&84+18=?YJUz$={=UG{hNnVe%3>rUC_x(0T zY|?W|jc$4Ojrmi~@gEv1a?}VB6r^hYmW&c$j-A03jh=!HSTKr`|2^E%c&zfaMIM(8 zd8Ju1iu$;`ku*2VwHjgG%v=WfVGo$B;HZ1=K)e79ybei3f<~UXalKA@PipgH96*EI z@WLT$R@%1)A8$0XN3=!W zYo}+l%GP)=^>0CpQ_DkL?Oy!-HO$69E!>7n{n0|4>zwklzc-WgmP^xIYrt;(59W#W(%>FK4LlnY)cV}`7>=rj=|PNPyT+`8j8<4l3mQUu@tKSH zJ3krj_L{jtn;PG^URX$up9~T1vVK%(PAmb4dr%`TEGLWS`jKa@Oe`im$B+PTjf_IR zcYO8s%7RzADl&&+|E|hH#+^4x666#;sY`vwO-Oj)y?tPc%0rln>lz-{sPZF{7#%!5 zk%K>==ExzM+RGPX_x>&2jztHr1$S~)=+-84h}PvNDn(hWw6qs;BadP`Iea{?e{CC* zU~~Y338lp|xxjb=hKWHaH}l1-oBV~LRHBT<8=L%yc!hcT>YW3cyU*`; z6r)cz`H6P!znn8-b`NOIHh3S&PGj{rIO6ed5T%_IMZ{OX8Fao{H*g={*Kj_pO7#di zRLvvLs>A|~4u*d1TX#HU4X<&`o~mphw&iy%&oy^u{_wi~Irl)=*FH)d$1TFSZZXvw zUc7`g*{WEITBDq)%2}`d>!6m$tq?%sAM;6wc_^UUo>`q$nu&qAMs%QC;6=w~jabE1J7& zd3z&?^s!_nuf=hbC^F*cZYb~ZI#QCR#2|7W-hKAsW(GRX)}M$X$3myR;^v}q6Q*I5 z-XFyoubP{<5Vnj^%KRN4bJLv9jo(={|CTqssG$PuK21*J?SG!(jXH|P-gh*W!)ZbL zK&b2m3@_SIo0Q=Qh#K6AWLK0Hud}te72OZWb0$ymMn&^Zhm7d5SkeN+AGf$0EYQ( zkZ)r1r{}jZZaz_ZU25qj&=!QtQ_*E8Xn?jbv=+FaEfXrz*EwO-ENeRW_`9}qs8T+tSec~4br^u6$3t_qTEEo|*E3mJuMAR$%avom|EX7-lZ9a1Hm|*d|hiBH2xpEB7>OBB&L7 znR^8QWY9Buj}HeJ%=6w9N}0_d!T_R(nMU**0K+fJDSchZYuk(^$59i~HrMLkXXU_O zl_N)QF7ZEcpK}ub`R-a>!LV$ljsOS8QB9(pa^R^g9=rRisG%YlJWx|`q=U#2-MJLm zZqNJr>x$-EQwQB=((s@{YtNdv<4*~lV@iU4emVOZ9ix;wkSlBP(eA22Zs5j9bA3u% z;5|{ARx9@E^1h#gT=IMA0Iy=HJgx8JbKUdx9;!bcnM~g1tn63r>8=jQ$3jX;vp9BM z$I)nGldtaoCHOk0DLv(M)ldA+p}76c3w6v$l`wKcXYf?c#+V)V+$fD7b{Q#ozFFfy zT@g9nX#5yfM&u&@7od*jQk2IxcC9*al7C3V#mni-Bh7N)>4L#;6k#*^3QYtEL9?V~s zy`^jEX@SFeTSWb$KJOGpf0#|jpsQD=r@a{3WGmauVhfAE$X%AV)085i1BqN#?1l_~ z=H^jcT&a0xQfP$+^gO%stL+aj($WG)9P;VenX&r@G*1I==2y#LEy;4PK7yK>LrVbi z%|ka`otZHvp(MQPO(}+?xgEHCO*wn&Z^O4Lv`1~Y=!lD*E?<3F(h$pTgB>HV-8bLS7AwwOqGD0zT2UoOjzyS5~X{r|c{KH+Fe$Qab{ zzDstX37Sd7EyW1xb=n*rz|NWayZbMtKCf&MSS!5Y@r}+HMVL8lD`4F=49P_O9jv36 z{IehVX#X0thOOKnCuaY8rxDjzla{q9u=+b2TB8f;a;Ikh)>-1$z;f|gMM&p3dl zI=9t^()<&E-X!|O%37TDBe1$dGro*YQv$WK)7|!PKf@#3ZjFD$zw?+&xwBJq*K6gH zMiTcm2=V8kC?dP4Om*O-62dRjqvKRu@^TNHf;C3U&y~Mf@6K`ty40Ru_{=Y(hT=Kk z{(WorHSw*24Q&}^aWON)FE?+24`H zAqDnjQp-l)bR>8=$-q@Os~e2j3?M@dm4KMy{yfW4pRMNvjbUz4Gm0{js?>4=YSgNr z1%j$Ll(6_}VvV;WUO_FlJ&ule;^TJ{5WDkkIXfJ{7C}3BXnub;<%=lGC-t zSO0dOYn!ry<0e=E<+x~Vli7{d#ZIbMU6_YQ@#uGqXnrmak4{2!lqb5huR)9>x1`H5 zsGmy3@GFMY_TU}{hH?#Ylw2}rz1HBFBR7ZCc6#%Bnc=nBe-G?|*3T*Xhu0dcTiNrQ zIXHuJCfl^m65^JKqs9|z_4{ejuP} zByA2%rW2Tcu^8=^{ZL%XK)Dl>cv97Lv^rd$|^QFzG znHlgew+J~MhUeY<-1|1M<_P2kM3cD$EaGoR&G#MLb$0w@*7d_~edRaaCwG?lRx&Cky-D6d$vP8mNuK{_RZ&HUe)n2h|8EE4NujxC7Y8;y4+||F}9mkX}JA`pR zRw6?pj8DJf@XGMf+n3Z3Hm!*WepZPJ>(14MdHka54DWtj+IXFs&PEm-Q2Tn1qvm0| z$D?40x~T?&R7rY`{^hNvhYuH$R#zP?!hp7%e}a$+pwr^RmktT$YYrYsF7s(G%i_B6 zv9fj>#n2#Vve3S^z;^}dk=maZ8|xDQa3XrULgC@}?*Io=EBdz9@F!$4lSMnNKQl9m zGwiG7ioPk2s(Zb0`o=&E&W%3eq^$WPk`!M{?nHLq#l{_02HrI(-T89 zBp|K7nW+F#uL@6y`CFb4qEDYaS){8Tf5(B+BtxzeQm!%}L^5;Or>f}@NeBeJv-P`D^u*xpkLJbUx?uC zp^Y1U89MFqu$=)-8+T~?B!7U;D-yj5mV9PJVUJJ!W6eUL& z66e<9NcZ}vh=~i>RWWWSl6qRoVW?FK;N*`&!GyW9T9ir5k+pfkjSnG}t}m=uu7#1h)ep58>@0jpTwK78XVO z`(k|pVXh8*Lav+AvGi}>D+oNy=^Y7+mFWZS1>{T39i+Nf_=BHy?-u%=F%f^Uc+ z=N%){cMEu*{#Sglifhk5IApOpOe&)zZ9%+r5^h4cpf7-(m{D8)SRF*n-y#Hjq7+x( zK`usNV~MJ@JqL0zK8BB3yTQIxes$FBRWL}yok@zvkLCg<)$gE=RkMZ{7kJV`ubJs( zpoimi?Rn%Slp|orebj=?o!qUa^%$YtNuhbg*-945o#LKU{81HzI6I0ZdncI}Akj%# z5Oj;LoVx=OFR@wfHExh@@_{o-Q}LgI;s6bIi#TI4h3!2ZKRS81(s7mZz(ZM7F#XAe zdAhn3N!_XGhQ+($paG7rEA<6O*xnsFQLuOHz$emq8L}VA7V%#SWe_)uMeO;D7~<@j zitV2w$vYQHd}o~Rt-4JW7oxuCE$$~UOznXm!FvlLrtRk1^w>AAfDNR*L7e*{Gq8oI z4Cw|GRKVl$|8Ap1y88qcfYPcOmYB9^}# zv2(D<>Lk+=R-D|)C8j5SVOIxnfiZXI4KejqCDo(un@7=iPwmk#r!gsFwIklK-Yquy zMPhpAL6blHMe+fA!F8Iy#c|QIr|K~Qtg_}^QCRR{$&dvlKl&kdIRR{>U$aOMSr3u({Z9 z;!@Ev#Q+bb+7&!Kz+xiK4yzP-`7z=4K%FA`JsF7vMtz)@)`|(i`F@Cok!OWO_%gRo zmfeoYofKh_isg6z`ow9#?u}gS=?=J&`y0USg)4RaKKlZP-5bpq_cEuS7kHSrlX&nf zsd&}GC1|YlAswQBV%&y3F1td2;l;qjHyx3IEW^Cm{AIaAKG#+QdKp?5##x7&za+>g zScJ(TMRB$Vih^ebr;A%1Pyl+QoNS)kNVz+aaH(Zi`uu>hr;C^u92X#W+L%th{eL=- zD?Sw;8P~AhHa-S)9$N^i(-;qu&f6ou@}Pt;>N4YsZ#Epe2jO|#8%@5G7ZhLn!*aIF zk;OD4!~8b;{!d-QIw37`;lIp;Uk0K83s?8S=~>N5LK7hGIP%j)Jg6A~;Wl)jMm8|& zh6;GNPXce5R~V4wT)^jT1Or7LApA-^s$X&|fSX9tYfl(slRII6ntLxDWh-yka~Is| zuP!u#-{MyE3Eaw~yr3UL?EhZ6+$4AQ_)76@D%k5%WGFAJ>;x{L3V*q5P4vMbi7?EH zmE%yO4|to|MiC242%gerwf@p~Q(up+4PaJJ%aTIP%>2 zn@<7O1u7-s-y8VH=GAo`lJZF5Lu_7C8-=WUlq6(d;k&+!tan}m8%m2#mWHW95lzP8 z$5nq8i2LoW;N0&$WzXNZr#n^k&9a(?2BP3Bb~WJDOVgBwzLDIZP~PlFo-M3r3`upz=QJ4k|NV-*Qk5*liF znr-Qff=mvpWKbpPOULmOY@5Rk=1F~PAww33=7&zvLx@4^+h*RUyeW=F!5 zuXkP=0O|l1g9(47wPIzCLAjuEV}Z(hB*5dz*oNcp=M1h?z#pYJ?N%Iqh8)gzYEe%K zxXxi1BiglmlM=ST-o&J5e&rzn6$(z+ zzP)23#xn)=DEaf3PYltp&HYTi?O=NP;{s;_?~~eOm=xjy&P3_;+i-n(U^kgtq_Z<+ z#>*lL%r&-{2_yldNhD)V&$-Jq^=mZmBMCViQ=ayC0>IK0TL0x^FYL)NdELxs@htTv zBL~0^1)WrOZ+d`8e!5dn^OD{JCXh*n(bbRxSy3`7R2<+k4ua^x2EQ)bHL&j^qUK0H zr2tHEF~mL^8v>Ld&7_D_NvEuh^?O!4wn>*JblcC$D|Vz}w7; zkMxS`MEM0?ypCeAJAV%_1-4o1=HoaQYaOHMP z8pZ!hD|+aQxxUoYOLaWOxsUq%;W75V28fp2S6z(v^`Elbj7`y+pw#U)df8}IH_5q$ zsg%4emtiWp);Q*2K|!se$Y4}iid}eH_pr$eE*`+|Ly-4lCztt9bvuU%Lpyr(vTd3J zE5YH{E!*FJ{Pw>8t4B)J;yo>k0FkZJ(nSPY^c@J9+U5$WSAX9E4kg@rP=lr=suZKB zIk^=dijEx(1RryPiX?nes-2ehHlTbM&%FovYSck^e3C#vIuX*ACJro8pm3Cp-Wx>> zm`v&k|LDCV_6)R0nG+1%1mK5+W+Splw4fS-t9^DNlIKf1UisxB$$hhM?CJCvhC4A= zoc1J{)XFG?y@0G9I5jdp;h?Xw~*YB(dlF={}~QGhReuD5N)-BEz8o)>qF zL7{K?M}hLhxL8$WH#JX5LyXNw7ATVv@!5?tii+;eO`Xc|B9#-z?e81z^~ZTnWDPQ@ zGFd95d*)D)m&d(N${}|hV+}l|7c-uw94aosGAV>Sq*KJIYS zw4*AI5~lLH5Rs9Df(Lns4tJ?}$hN!e_sHAT zkr`BVYnXOCK_zbAx?+%f7N|dUeTp!ev@JtsQj6@$nQ;&qX!`2sA6ZL~D%tD^+%u$u zh`kuijuA~Hv1i$|hxUJBkCB(BAPyq-iu4A|dFB-zK*mL0jz`Igh}6QkUB|{S?TyT% z@)XjW@sQ325B;km(%G;j8{ndYIONYUw?h5|c*Bb25(?>`ps;o@>QeeS6bH{a*EX@d zS{7-a!l2wmTH2ri`=vU_p%@Enqv?^fp6)<}!Mv?-MpBX!2qWy&uud0aj1l>wJI&$?8=M@wn-&C>coc zkQ54h@?(X?I903E>KQdp6-~yx9mNRRTvJ#GfA*sc<%p1Oa`4X8%ZUYf5DR5K>c{Y21}slnaCT)dGpJsw*^L=K)9wZwu*fr~$cXB9 zAb1jAy{$i$ys_q>dGOf;H@-9j=LK$miT8oI#e|)p92+PpgC`Yv2?|OsVZ+;`W`^O2599ONJnOF25n|DU$9Ajkg3b1ZW z_Up%MC@k-DYhzN!Spza&xe4%SMn=}GJQ7k#9l3N4XMMHBW^>l8AM+oX_Z!VSjOF!~ z2xa$c&0%657ZPdrdo%;(cVQCdU6Z_YmlS9?nT!IaT7GCO4}`|hEGYDA-q6J4*8cR| zPriI76g28@AwMZv1aWYK%bJK^4i$TVO_N;e=G=%OoWVsmb5;u{MUr}T&)Ukb*PCt^;iB{kwn7BuS;BLO!EIwKV9Lz{-z*JaPcd4cVQqZHN-Ttqh6SyYVtwD`Z)4?fgK16=QbqbV} zC50PF1R+mi=~FL#6L1~pGdo(J)Wfp?xtQqQyA3k-wrFo}aPJ#cFY0YnhZZeNtq z7&n{QDaT(ZyqN1GQ&asj8=c_bL?U$C(3An&6G;&(6nDhY2R#SHg2+x z;a3A<@hb7iYtrD}O?Y~gIWe{R<@c$^ z|9QNQcxKA_`rSMOQJF6j5q<$9KEb>(z0e)7Gt;{_dXL~6n0sE0F-7$(Mhv27@_Zvp z&yj9rQn8j26)H-0=)RbL2Yg5Jx>_UxBJs>ocnf?xPoNZ=p>=G&r>_*KF21+a!pD^F zgD8fu<1eOe8U>W6EA0s;wRwp_03>B!_~#B(mn=)h>jWhOHVcj{))a9}z|Yh+*(pEM zggCq|7LEd$&^n03!^ro!y>11nL!pN0!UGWW^aqo0(n|C!f0D%Ycx(_B+8xXNHp?sk zMjR{wDBGJSZ%Bi?dALkl)@$G}+|jhfM1P>GEUTK_JwF3*ouvB!$~HV@+j(N;Izbl z44$4K3m(}Z9sm~?)D3>?DByxDyxbn-y^BAoqp>y zyyUaFP*Wu42r3P!{9zy>0a#P0JR0`2K(ai*u~fg1KQ)?>LysJ1I1poYAOOp6V#fk* zkmMT+;STsiTtZT%@&L#vUO5EODJ(NF127s6AecpbsiOhd zHvWBk-Cf5R;7;Z|`qDrM{SnytPQKD$S{^BM5I7T6Q9+gwLpAN-b#zc7EvNNb)eNdF z8GrL)ON|Z&2$MR|j~hpQeV=4hqDU#aZ=7UQ-Qn?11z}`nB)eG#5A{Uq9K0vaTaalq zIbPn^&k$G{Z{x)(>2pJIZf;*;4Kk6&648LR}rvK7R9MHPDNQV7p-8Vt>^3dDdL_J(OH%nO-0m112J(yZ}eDp6IG~C@Y(0{dBP5Og?SIDCA^TL zmkBioag3WdRsOIVgp3x4fc?Dr=wRWO+O+AONS@LI0er)CNkt*lxs>)vb^)nDRM$Z21Q5TwZZp=pb7nqAq0 zMJx4f*^0%T!tg+8X9i&*_wh|sf3f)7&(RlX02lb;=w`km0nW6hZfCSfH?;Ie)#{qR9LXnXfSrkw}I$`r3wf+I{tJg%` zj+7o$nUpoyH<hW5{Clx~?#Z=4l|W!b<{ciF ztg*}|W$$_By@$tKZ>z2(BJWh82s>XVb-H@We#q3q+?CzH%Xp__Y$dzRDp*XL6U z8I9++wt+>VGwsnBcRbY9xryezvsbDiB8 zD%86Wy0~n1I??yEK}Gp~;?=kb1>{&hvce3|77)6h_>T8HVUUM$VRyAhgF;pAhQXS9 zNDouD7wI2=}$Z_zJ*s)McjwBXLdR~uPp)MH6Nsm1H zKE@$En%F})>wJ0_#jT1i-Lp75i#T^v{e0GTC2Uj1Vu;^0m3tW zgMyIU6FxDfJr!xAS7buidA%}KSqWxar=1h4D1E~;oCBvS=u-UwE)9RMkBKx>@>g@Y z&vEJ!Xtq5php}zbYfK&eOn_1F zsMVCNilx>5B-+k1)+CP}+o@xBmveFz5s>JwXJJ$LdbBmwn5D0tSGkIk*1Gmap}8fh ze`~QtuE^>_Xvndzmv0$v#gtZE`+V?)6}4wk*zzu$g^y5bWY4)P313w+L%Zsy8QpL2 z(fZ8>td3FCVwJz*@NWD&Mu27LWa6Bq!|tB}@oJWPv7bCxF70pdfxA43sXj?a=MWlF zK{GPA5iWlrgq^vD5^Y$%vdi|)>!1u?0yg>dYd`xUX?RCOPxI+m^ZsqP%%^tiGE9iZ?Lxxe*dQJMI7}53vz2#>{umK~IniqEHL7Z>4`6P> z^)QjF=hQIY3|G&XbJ`~UkjA^3Iiy6ZD!H9-$y-T`D?jX4Q~brEHI~08*C~}JW$wrG zG=DhTCffs+JTS8Gst}52{MbH2)bql!X%~YVjNbE>E@;+V`HDkV4O|?w?E8CFGs~K* zz#q)gYgivXMw_Vn{>3sN2HaZ1tkY6o^39F-=o|U>=lpfbufQ_q2<7?fY7m4ty>j%B zz&QS=k@2n8sJ#U_8B0CyOB_h)Q0tGza)C+ESf!u06>e`((x}idUg|l6dt4YgVAK7nW!K$ z@e>~SKxYn^WOJWi&tziMXSWUp;taRCmO;QSq$kLY6eE?W1(P|QTOMo8oQ@S@h6gK z{K_(CA%P?Tv-5|4I=8=%q16oY#j$e`J5S}JQfk)?p`&U#j|o;x6Ae?R)PS?ui1 z%)y#QQu~JF_1~Y9{hqy9{s_cM7^bGvue*`1r?c4}wA#@MotTx|*WOCvRTQMVkCowP z?b4Lmc#1O#hr40pj=u)lJmIe?x^WH)40Fp=Bc7cXKt@*AlzQr!LNy?_^KKc zR*tdhJHxjrnF6@EBBLGA7a<|#!DiYw;~jY-22X_wIhqy-N|tv}2EDxG6+pyVjAcGJ z0vD8G0=%vIQjH`76zkUX&cuvrLannQH0`bXe z)MemUj!-F297aD4yMcmqdsP&Z8*#f-QUXymkT`ttXi11)UUqnOM*3Ho0v1l-D8RLD zcD0^tyy5^~^yOn?mFZm`ho3XWYPMWR$mOFv$XkwV05z)aT?h1<< zovl}nUcUh9JDDhx0rls8fS6-2n^)tx|DpmUNSH?H@fBor28iXm^sG|>BGS^39Hwf{ zbbuyK2c$?_TU!IIAVoqogD;S*aq|E|<(+4<-MOv@;L+4CrQuXi2(vxDteDrD!yHm5 z-)Wt$0rF#k$H$4BRZ;OLr>MFxMYlLV$ZT}YQqoo-+J%7KI`)#AN_q5i-*vSZT!#*9 zBwE3GD*qM7A7Wl?l^?e~3#9HsVuvqnMGG9vAcry7 zdCKx!>xPiD5^xX~32Dr9Kvfrunf86*xi~mNJhYfO3FTZS@!qP*BFL2MWs^lJRHAy2 z;e#KDV37wUsICD;R@e?3C_&*U#jFmW5J1|yin<44XJiDF;AW=D)p2IFOt;hgiDRNot4Zc~S;aT(;UXbdS)icpZrm z-(g#GlJCOGLyCU1b*-T#qLXUlD>P>$%?A!Ng*mVlDH*Vj_i0K_vF0`WX|W0 z;UcAXvl{M3F?Xr8V@Iajh!GWE?>qqFyV03JssD@bik&6d0T&BWr1{6Z{}FZKn;QoZ z4U;Ny@S8OcI2(pVzlmT-u&MYaxJ~^C_#vh0<-~#iRCl6FhM<1}q5I>`ukv#>NUzEF z%;wCU9!iqL#$p+Pjs{IhG4!1;7LZYy6XpMg|1yUG9~ECYpvKdIItVzJ=7W;#mud0c zn$791j`XR62#h^#w-F)~G;D_~I(sk?AaW0VnnL@mvPcL}Yq&8PlsM#Mk*kU&C!6N`D>(?t^aIJYp2%+>SvBpxKB1arb zj~2D=HFP}!gGRf2pQC%3XiDL*T5M*Btdn;akZV9g0eHjFEi{~x|33GG?yh;0s|KXJ zI~ARjuQ?!y%B}s;?0h*a4TU`;%b%YN)TA>7jZR{jthY~wfd^!Z_xre&L+Mcq5DvXG zL@Mu|kosm1MFGX!l=I(}86-)kQ|W?WXRHGJLd$9Q4#82vP#Rf%2TbM$ zv7||kceus|Hw#QshWL~x+0Ny$BjTrEPRGebRJ`Gb7&s|_&A>-%@Ba}XklImhJK}{V z7f8X2yS{NKK;|_PX7d^zN)2+P?U>jq9j(WZj_S#8TqzK}kccmh4dW0`l0`y%oycL{ z?c@+h^Ok$fLE;vA2u7rbaf_A&OMpbJcOTf9KrCO{rAFfrH^qN+opAP|eJ=108LAppt_7`-{7%kfkm8mBVM|1sU<)AiSW>OXBVIsy7)cB_8ih$@4*{*NKjPpFQib=gx^5;w z{GM6nhzB(_;6JvHs3!4|ptKojsIBqQf#P|&T|$iMvIG6$*~`;ERNCFk_akSYyeY)N z3%>BW&KHWHMASdW5$mJ@eoj|k%-k;^A^7i*acm@2msFeuf9!R{ zj~iUF_4?WIC-IV~?upbFJrN>11e-u_w_)$uAs!dg{n7HML|VdA8aJ5n{QfTPi$qwI zYNVxl8(?;mZilZ4hs_`pX>vW?&8JX|+idkJi4sbr*@U@Ux!a)l<%?%ND}+KvmiGm2 zBNJ&+5BCfxdMWNa;{T7TYk6z_H6r z)bjvivT%(phqrwkw{Y$7@k%-glOku0j)MXAjfu*go@Yi(2LMR&-PN(Ta-jf^;y6l} z{$uPEuZB4=kSIhZ+7-_Bn~@1naq{|vtM#Dd)b))mqDAHZl--(D{o*m0{1H*xA;yRs z3UG>c_3{YepbL=A!mIJmb3-M}C@qZq6BmnnJjQZ9;F&q*mJD(AjsJw;RqFw~gCLm5 zRYE^Uw7dnHsn6@Plhd3K793KlnFj+6)dH#SXoJ-;w>wNX~tMcy78&LAfI`Z?K9>t9f`Mz z4E8kK#EvUr>12ZCi=@kogMQoXV_6mT)w=D8w9aPF7j*N6^#ujET{k1~nHC3+jy_n) z{Aud?33Z=15k?q8+H8K9>kM}sRsRX87qzUd@R2xeQ5ElC3k?N;pe-UJSWhe z6w{qtr&$QKCrKbUA`+nXq=skquCj5UJ=W4>P31q$o$qEcR~*Z-#k(SRZ)FNHq@Y16 z_oG4|vOTtMhE?+s)MrAJ;T9vpgAQU1x*RiYk#X>{htJ)^5#lL;=oQ~MzG{Plcc~#S!@BxSs*h(qu3>g`L zqG71_4f9q@>&oYEA3nX;8j=qR!~z-xf2SXd7&Y@{<6tk}n?@}m*(lJ<Rmw87-HiZ~@xqfc1~tax9|uyD_~mG!PFdwgjqVF;pn>Vgb90k05a<_V2)c#p ztjogOPo{Q--B-yVrKTsj7Cix^x#N3kcR>tE?S?bHMpe~e|C|OAg<4I{8l1RA&>=fm za(E9BRrUZhTo>&WM>lIi&9c~!rs}jmwR&2y3{yyceJ=jfE{kNeFr6Y8SlAi=(EOoB zSF7h|6zQp<5=i_qYgDvvO}(gObSm*Re|~QwplwVk$AeY2-|fij|Gl!S70gzks0{k44~5O> zkSe=C)pz>YFMmKzrn+T089151p_4e>-=L)pI|V)RMHLXtk?@$aMKd-Wrub{%*k`gq zkoJMOvv42B6!I_o6M=|3R75}mN9$9C)SzD3W?qZ0D1r=8(hN2i8+wqu zPRZkl72b*~#t{`%xb&?M&di?66NSz=TU4}w6xbanCda(~ZR`q*RBj}aNK!a<?8Ro=@Op}M|2he!6Coi*#R~9AOljwef~X7 zgk1_?2p2WSlSiO;KxOJv1jY@rKj~iMVm>k+sXQe_Y>*@C()w*J@k&LYtbnGR*=&?l z0!bi56kFry_dr>o*toxT@DLgCB3RLun4rYE=JAdAM%pr9ce4~cwc>NHRh364Rc`#u zN&Yp>es@-4VG{<5x|n@GGO{(vauY}HS-V;}WuSZ`oxI0!NiS7y;zwp;BA<*!@L)Sg zioyMvLQQCJ2@uY)6nn9YvT=gLBe7hpv5)78=!m?`UXh1FEwe01l$S5Gz%8jEd)kQq zT4o~_dBWHNn4p%~DD~2>iS#n%CMaI^AAaQ^`ybV+R;I%NBB}5UjI?@#;3aS<7rT4` zX)4nuvF1R*VBXCqs{CY7>;fI&QSS!Y>=y|rpQblit(pZQJre#>83xkXkBVaAn~fR| z%AtIEJH7ieD(HWcfB!a9R_pF(u!|3aR3}F1)@xudqbrI*0U&xIdETCXuR3g7UwY(G zP07o}JXh^7NZXdP9u$j4umtpOY|24ZqyKbv5;vQ%?l=#D`mVolC?T#9*(@6|`{6f5 zD5SDWu${+ZCz=Fj_zYd`;vTOP&VljsNy@<3_6@>uFy{9hdPc#K2NZX&unaPe3}u1d zZh&owtVK%$jDEOmwK1lC0xh~nx*e}f9DNSW1mm`{HrOvi10cB*g{ad(Bm_bvPX}8m zAper`t)AYV_!iJMDI5^Lp#};l=UJZW7x-`>=jQp@CSwk+5K}L;CaVb(i37d-JMfE$ zy~lV!7i?4Yq+IXzLaQf>Q(KG7qNo^A?=C2`X-FjKG zK85a8WZ#Br7!G{diAO_paIR04q7hcQwk}vQhxv& z8ov1RS_KI~mRZ-zSP+&s=A%E^BMrWzM%MWBqAI3jXKF1x*-T^NPRNL z1Zj2`eK6@(PoSQXn9Xv%(t_Tc+QQyim?~RIecnI0H%G6$N-|PX_j`D?ya1Bakxh1| z3|A3Cjj!|;Gr=Tr06#uyFlDwEBPDgcK@II}kfctjMnM{G>w%QivAPvAl<$W{iuD^i zSA90DnXCE)$?8aWuiO%d1EQohw%3UC=>h6=>6$DA{9jgQyu&>YWObX8<&(cRk*c~E z^|#YrgP0_#ZCAUpJ~n#^t9ZvWZT#z%E}YPM`(Guee3(nL(w);L&KHBJPiSuRpNhw$ zqR0Q&Dm$BX)e=*-xf7c@v+@On8mo#TO?o{YyWG2qf_&9#5iXp3N50AHUB;6|s`)a1 zB=hnc%k;h0EA?pA@sPuQ$fGED@CJB8aAdl)PkI{)TNHW2&AE}NvQ|^!4K-HF|MBNU zMYjVA&%%F=|J5x$U}bQBPJWNbUWKF~*TF-01jqsv7J(2l`-I4PQI&;|FBDP^B@>{hkb*L*MvKBs{2q?u=#s(I?}4NSD7|rq7?sr^r8ilM4?8yG zR@koGe%%J|SbaiMx*i$ien{S)>;nDx`aw689TH&BH9hr23%DmX8(f)hZ?vG}rc5t` zZB)V`Yx#;!%uvn*^p+~dF0Zv2p~h;HxPG@P0`NT<@Bv#q31WA%Pn>sHKt?Be`e zTtjoe=DdR1c9e30%0mW<%l|e@dN+l=LU%bhW}Bd?qDiqv<2Y1k3oVy5v*$G8DHO{G zEM1@b7Wc8gd_Z`4$ojY9z3lf8OK0$TqY10dkr>~!`C>sA64Py3t~0_tB_lJN<2DXtiiXxN&kj@MwgW47U+;E=FR>1lUG zAtbDW_0uQ!E1WtDh-$06|C#_b$qq(TDQj^AaJwX(gzIXe$5>`T!a584-uuV5h(S$h zzy>?a>kd?&j#|+Ba0@C=ix`3?N~k>Dcd&+1!+sYkPk(%-ydbqA_9 zUit328X>g|A8tA#LB&a>BH6M!odpnd87r+}GwMLxa53!bu~`oZ>q`7)lE42G)(Jkf zZ#8fOyjk93&XcuxNLaU_G;K_~)>9wghxmATVI>EcIQSy5O@bJbbCV`CkKY%Q1QNT~ zi0#L9IY6?&C4kGnJK+5~3exA{1>@*2aaWN?C=0Ki>B1o?9+~GA>;L;>PZ8SjzQR&~ zpIi3yDz<-*?2zqxNdp6ZAuDfUGh*qVL^tEvvOmPrv23)vU_tDQOUAP`S|t0TV=`z6 zWG~FO+D^eANtgT!Jj?o*Z>yVtz#$Rn_3wy%(ghU~EM_aZGZVp_knTw!c@HGSQ_A88 z`aVBkAL)di&l-{P%ZjU-1w*7pw=G?QkvnsuB-G?>Y}cQYFik@WIhM$)HV*nC(C%uZ=!+f` zxI;JxX2quuZ>0X;980wHbH4!D9P8+^&}<|NZWvdzS}3R~0qoucCWo3$$|o>Fk>9Q5 zs06XD`l_4j77S!H#ShFoS<;cA?sSpVXCyFX{@(o88oOO8@|u?HGa4lIzaDmus}yzx zMFEYVMx(WIWG!H>67@e_9U5$3(ydVj($z)P&ZHu9X(=tyRKUG#@_)ZRp+Yis2dBx( zCD6yF^e8yxNZ;dcr2w+dj{HFr$iBL%_1YiT`axtJVUzs<6GYaTl~rp>Gc$nZ^XYf= z@TwRApsX{|zmVsGnqwU=MR+ulBD%X$_mli8q&XM+mhTIaM_REc0YNuT<@YF?PfVlz z%j106HG+|J)WIf%ADXZ{#aX@%EdTsorZb@fNxC04EzqZln*Opi0MAbZ&n_D6iDhOmfm(dP#VXgmsx`FqMBQz%t_ zvOZaxp}oh`*{X?zBFx#{NwrzfQPkB`FyPBqoB&{g1A&c4b8^%JN=1HT=Fd0_k-Bd5 zAv@c6q^`TGa;CZfEPizKxC&tt7=tF6J`8u!BFVZsYwlMK$P=yJ?>fN5DBoy_2?5GT+rCDN-l0f2VNdbood zJdad^zv>jOf_h{(JWniD5k@M35>&x*B($F1nX*;K9SX?_|9^*UX|enNJ7jyYo$et!WSQGWg8%D~wQO~ew&cF5 zgr%YPGX5g8TpC1qXyNSAM0KeZHL{?YIB-_4x1cY`+2UGal2F4C!!!@(mL6z?^5r+#*6>__Lf{B<@c~KC zTYywssq6iS1%3CW8H7{+^~lDV?k=QX0N$mqX|({sLW4MXN4upZ;W4PjOtNR3z0hwte%+c*2RUf*ATABibIQ8BKv|hr=V#HBAoTT!J1PeS#V0>~=)#cXo*0yYm%+5W6bttfX$(49TsdS$^=@>y+zL4kjy1g;*KKdh?S)smOK z=~VjJvEsHgyCKJK7MQ8oT*Hlr+8=OwYR%qAw{BI9UsGW8^X!7|)Uk{*n7-qgp!34N z0^{kC^U>EjF|{_uR#?x|t>d(ujK%nAI%t&S$Ef@*?lfn}TF=n7d_1%WJfi|Et2?iM3iSks*hyy!9?!N=gIV5zR9HudaY;w~az)!S z)dmdNOK_^lJ6U%ZW%m#+Ac3Y8Er_cAj+6Dwlq z;Dxt+zjQSJFbu57)3fXwlUHq=1Ta2s-IF%bh0!=EFy<|dvX(MZ(Deml)^#lrolKlE zhlJ)-{nptTU}>v9W^OMcT@blg{f^gU1ngcGib(6M%TA+~Mp|0Li{$&h?NsT&{@lV8 zFVyP-#F3^}Xtek}x&kXX{pmuWRNxD8f`L~F+;X?XVrS-&vjylY`qSa9-e15&?V2~)IT(D zWfq)T6JQv9i%asfhPgToW*T;lK1{m6o+zON{>P9~a{ggH2eZaFGua|>zF>~`8Ed-| z=U*^qH9B@hb9IEfTa9p>L(fxw7!REhT+g3_$%{S~93(QeG4k@LDM6^2$@ub5VqDIw zF{z(y{fr?)$vXSf-b7u_UcOgp#Rb^K7Q7uWy?H~s&#t(G4JC{RLN)!KezHB zYbyr3XO0OqU`ws@)yw8*A{D=cs{X9TP?Q+$tUe3e7_WMBMQ7m>t3pt%)9apYOGFM9_^-eByE?4nAW;*X zmOyEDK2*R3H?A2ldvfZXfzj}{jYuNbyKypL{c+`(=|MUhc=&AU51t>Mz{{yIZ1wf| zuD4x;bA^xCi-r<7>o%%_8 z8>Z)jsuOS6zaA#hw}x8&WauVRfaV!YXU;VIxR%%z+|<=`jy=>=JQtxYm`*L;@>7M$ ztF5L8JG<{9Euk%^HE$Z(W|bmXN~+M;plP#*$#3>Ce?dt z+1BTGe0pJn5H?<&&{Kv%D7n(%Cg%PRC4Wy1y7BdbeP(eoN9GsPU{tug;A&nn2#|Fo zfd)@1a&>tZj8!`uGizgre>kOQV5jR<6qJ4fzhhGkZOQ#m6a|N7B_-u-%Dkl&e@g16;n+JAn$FO7RN*0PEcKC z6n}v^3F+e2H?<|L?%0LQAh!Omqcj7MS9XZIo1fFTqHC^_9BJ)ICFG0Hdre zWyOt*0WFUTfwXg|Y^+*ds$nl(vpQpyZ=>@w2NGsN=PWqHb4bvGCX zPWQ_2_#-u|xpqzs-roj6x_sx;m?i9ecIdU3(jKBZ?A*r@mS(FlWP z%vYmw?61aDHZWKC{oCSUM!W&{pVj^e^P~S$P5kcuUpwZdJe(u)H`SbXZb^7_Z?fI$ z)aFF}G>CP!PIhZAvgLX1PqdY8?{W=4^vLbvH%8-F_Ag`Pc!`Ssu31VSGx)wL3Mo_= zmUYVh?IVgJS9D?Y80~Rcd&0xXrRj@r1*cPFkuA625665JlxxOAloZb{I@d~Zeok!@ z74@qW&g~lAd0U|Jl*(iwJbBprO|4NgHWy`*n8@zW?JV$t7H%==gd(G9<{RRNnbo>` zeG3t(b0d^yB;LEu$?llO!Wd@T(KM+$& zfsm42r}%_FJkNPw>(C&|#!Su2ZBRtQ1Krlv07trAh-=*CQPjM?Tb*Or@9Cu{=H8RC zIb2@~1&?%Sq~#@YLu9dBpwJD6*|PrkJn$C0?kG*&D@KywCu=bxJ`H>t;pc&%x>xlV*`8Y+PIlHE-(#V3 ze4H*XF8DJB5Om;QZC>T$lm>_QjyCwl-}B z%#q+5tNAyg@R z4s;?Arek;9+e)mzRsWeJ`=X@ZX;G89i1<#={@eiqy#x#%pN$xzLW8I3!Y7MjJ$3%? zJOXAq6yE8HJ^xPA-7WD>?{%<>h{)d#Z)nPgxkbzHc_kH96@@S}UXIrN`@#n2`nRA9 zXkWJ3qgbJ#INn&FC*8IRd@6dhSIO$39hd@kkqXvYJb<=$rizq5Lk{djV$N}CpnuHH zBkSL&&`D<7!mf9Ev8dTPyaKZKpi2*F_&slfrK3N))-AW7J;^x#$UvO*}c z%%W7b?41TOE3!u@vXi}w5JHlyjFP>w#kI1^E_+?8Y%VUY?f0Cc??1o)KCknf^V#FL z_r4$g5r9~$p|*B}MDczc>j|p>{Ceg;fARj=H_!XT4r)cFSGG+6IK^mbPE`B9wnSKT z?eNq>UXAaD;_yn@F3YTi>?(J{rT%*T93apkX}PiiSS&S-O=bWV%N$-E;Q$1>{F4&v zjXcEwb>vMor!d)PdPq-BnKf;V)udigL z4QWjgt(ctGJ0!s_E#{xA|dTOZ2^SM__8u5VChpk)rI#$Z}N@0)S;uuKZoj4_AkMNu}+|~qXZ7^ z33QqLCor+?FBUkh(6a!q7)iB&3Dw<1i9Dc#8?Lja3J}{r;x7J$ghRgU0JQz((-se? zi<4aS7$Pu4eH7#PpF^udPd*2`*77%;m0$`)YHp!i&j=tIhV$sp@B-JkDis!7PSN^u zaW2((fbSgegXfo}$g_ZOwe94m2LzW_fdnBSC~FHmp|6&u>`RegiF!>@3wXO9XDIP# zW*I)%DG!@43$APto1h)vck>GHO@1Jv~Lb+bsEo?W~Dj+ z277$=homjFCqpZAYQhm4<&Q|Yrv}2pP_u{U50K|AK8b$=0prn>%Ei+_k*&d9nG@i| zAV-I)5i1=$QAu1Z-LO_r$7ZMb2;ZKkV-7j-k+aN6n+fpCajaU+Cxsg`B8=s>OwXQ) zp|Ey24Qv*5OPs3q=ik+SbhbdOcls*Oy|8Q(82*t4TQV+1a(a1V1nyI$TivXZ--~4-!Ek2c0cQuGu)VgVQu#$ zHrYTlHWHU2e9T9Ox7H@mQ4JsVg^1pQ5+t+wQsD|FX^e2E^Zg64nf_v1kT*_k?I}H{wM$xoH!o0_V?pSf;~7vm8mchP=8cN9z7bJdAT0J$4M+Y&fO` zahraNZYYdZ@B{jsiEYFe1IkgC@u9u%C&%2oW(9zQGOnI$_mqhMrnnt66Byg$Zz2Zp z4x6!HvL69kST?`z!csOW;s_bI_#W=ms?Yf^udj7ko62E?{<~V6>Ddrrp(>uLIevr1@Q*yRndC+o8!{Xq5W6L_-zlIgls?hOBLi zf0{tx_fbp2M!uqu1BIhDlF7)9ZnQGS{mXHVj1_W!nXM(0aoFOcelP{h_0`vmAHWNS z+#9C_Q9d_eng%c>tx32;+hx6e)BVOKzt|oMzv}_B%CJ0i?O#^Clyo&X0SbpNS!T7e zN^n;@B};$h!?D>V2O;g0N{CleHor;IR2a@^ z&4(HIPIb)Sidr4;m&{;!1v}X9uppiGFUSr*DN{>fmMWJXz8$AxyMW#>6~ZvT0#qlbSkf&GrB40VObQ?v%Bs6}AqC0X#eqtC=&^71*>;4$bss6b z2|dj&KP7C+e(mMJe2?qu%(h1o4jIA`>K{|TGu6v@kRX|le9HFc1e^`5e}_px1&>SH zx}67vZ75MM;Az^iJrN3r>9+2|z51RODrB@*ObwwUU|Tk6d*J7}0oKG6YlrE;NiJK< zG01{ZdXRU}_@W#a(`vAORT`btGKU=UoYJQC-AS;q_Oax3xDmgLcaZ`V;4~(85mq8T zYGE7S>W-4vRG%PYKQt*O;5jAm(o}%^tT9}X7Plen629AwtSPx-NIfDTd6O|vh@cmg zaHwZ57o6GZffiLHfIn-3?*SAP=EF_5QScTxFRDMF5>Dz$BUeI0oy$)H*kuZNx74&i ze@vPj561;3fg}*C9e9e)hFLAPr$LFn;sGP-*VWAQ!DsZ3h6?MC)>zJlXx z(F|sC?Al`_-Wug{5pJ$#un$Kpq3f$Oe!%jourNfA=^(619v0@^zlPig!qibuG+FBT zu!_L4EUY|M<`+yP(X4Zw`oge)W`{iz{^{j55R{F2NDcE2r^l#%(keg@Z!I-`7GzRI zV9h0r+C}&S2t4$-(op2%u`^uriEuj+#89%#K{YG|lqeuTN$1>dGGFS^v zm^mjz4dPr*#5yY-eB4d4GOl1OkGqNgFFH? zFVj1Hu8uIxe*YCmG50_(hkuhgmW9l-=<2!=0XUzQ9A_!)wIzU|YhwnRw#e;)Jh|fG zTAVC&gH;DL>PjK(Z9T4xt)9bSz~GAE`m+C)uXy1mq?el!%Uov64|G^T8)*rf){YlN z+8k2d(#FzfkogoQ*3tGC_KD;k=>RVar5jAWj%P84u(jYHZzkev<(V$?d-H0VoSvXipV$#gD2hjUXgm#XC`(P&vwBXQw7a?>(#b&z&ec zOK{xi?XU6mNg#wZv)F$?JP^8|G2|AwJai{TjMHdC6@0xs-r_pQp(~d|Tnpe4Z6<7_ z>k*t7Vvob||43?_oQk}1;0jMv(XVtf!dryP%uhO~fFxH1Hc19)baiaugJ{dku-&%t z8Mi?X3@k}r6onnT2hX?#;gOOz9gp|V%r06r+Y94yRA(qN2c;x|>l~X3vkc)}^ETJ~ zBh3dQzBR+)#D+<5g8BD7UhoclUcM(h`WkWHme+pD!FlLf5d}&GXhJfhMz$;zTDhok zLHdZ~wIsP=y&X$-YA zbn+aNuzL;%XaUS0=B7~U8!&;43u>qG;$etq>9&5p0!i_4#C%B+v8rS?B;564?d97y zK5lKQ{_7vJA;sfvuB5O|$3M6=Rx!3g%gW0luRya`DVnUIClrQMrk7)3a9r}9#gua; zf>hYn6UMi15duY+G5?O-iq6Nt8$QafUsT}YiIQPpX8-CpFG7X3T$Vbh|7#pX6fOT1v%XMA$G>7m z30ZOeD`p3lpe|L&p=ZFe;yg&Q3iVHT|5a@lE@rU96t?656t|z&eZ4{ij z)JdhDi(T)@p^@=OERbJbv=B=5?wwU>po|WW#aLIW`mBlOrG`1C=%wCYplv-kqLQ}CT~W!;8`8W_kAW&h)mc#(JYPN zQ&Ho=<$xHqoP$Kw00E(UY4@&?%WIrT)cX50YE$;;l~#u6Zt&4rf8MKy5&NzmAN3tg z4-Qux?oz*$@E5S7CEZO?WN_+9wKZ;i)a^$f@kLI7F}sX_vBbZ=YeW6~m*KpgoT2CE zgl+Q2Qe}(-^(W+ejyU`^%fodN)QS89J2r~P4oioKcxv4KUY@uU^M{Em=zhbD$Asy@ zgNplY^53nOhevej8Uj1Y!Um?#zOXjnV5_M$4#A@;hB3beg1j!0WEW(?J#24wv7_W$FzK4-!*vei%i}UX^?s z9KC#(Q8@Qv-|)kR^0r6aU*pgZ^LQWSU8Bdt4EUU!==3w7*{{p1@q9fZlzVZgOhHNV zC$QLP;G(wJe3{?FOM7=p9R;8dTNIX)6^AoT$g}L+MOD4epJov0=?TJZT^xJxHAK^x z^lFhDMQUKjW+26oC6rl^llaN@XJMd9ZPFOQs?dqssbiQ>0@1!Sq5}dciWj0*6W9~R zryKXKYDF%UuI#-QeUQsG68|XXdB5|Y0Jfpa98O-`&}h3~{B<`qM6TCVbe^rVB^;XD z{wZ>2PjBQCeTb8!cBO+R%XDCetDd27GlhGRBOlGY-LDn$X@}RBSdgIj@>YKvuMDrb zcgb@cZCd>o1dsJJpJRP%C$cu8c61?zJCHnK*&hG5;pMSMUqc>i-)H7M&IRYW5-Ba0 zLqwVQyRLlDGj=r0-M@w@>h68<{8Kg>`d7ei(93@D;iHu3#Fw8GaX}O@>OX)7^PdX( zM3*xAeNrr6yT7dC{)SOxT+p6aw761(pN0gpzw@yl9gCn$kBPP9>06O2>0GFWKR_(8`N0o2t%N11(|0P{ z-WN2uX-NhLA(nV76O9(;vkTDtRLhbUR|P?F4q_|I$Xil5eWxhno9$0FkcN9d!sFU< z7j=*|W;!8nc9{JeT9UF{lJvJCm&_c?Y~D3}H7RDM+wY8aNky{S@QG;{KFsQICb!h$ zqGAD>d9+)#hmY=QMiHd@b*g^NpGL%X>i7%_i@#wI8OV?owNa>SdBprP>8+2I72KC) z6EFRF)bwlkV}&Pi!U|Bm%BFAf`UB_VjIn-RMUK7SLSZ2{IBLGcj=r#LVOMl64q=~A z5j~?oo?v~{Q(dJquyf8&lit^fKkqaVdBVKUP6WRl!#n2ii;B*h3-jk)Uq`w0e*I=w zvxQc*mOOv!?NXseI(;OtNBU`ig*%tzIb_XyTAJvGNpBsdh<$PR-3q79t?ags$zLDB z#uWEc`}M&?q;@R7e-8%4z?H4B$4gc0duJ$ovNiaU8wVf9eeowc^cd-%{4#d!w5m8k zR*m7Fj*0G<=Z}%^dit!dSbbS__s; zlAwFB{>a^Pevf^}pa0SZ?apQCvHFc^lATjK{lbeUyygF-{voS!G8Z~bl_b3N)=qu; zxqMU$lHjZ5Ngp0ESUm}Pbn2bA^#0Cy#P8dlA9IStbw)@KhUKzzjMreef4!Iu$Xz;d zTCPaDeIHxNBu}2O$g0o9SCWtABgjH~n&0+>HJvuH^17_30a@#RNb-XNq(!A};D@-p z#U(Pi>=v(5+&j=em+w85f5IiXee>-?rDgo-sD{j!2bvNDzU5^ad^CGgFM~v2@AUbd zBa;^s^6-*p-`w32HBPO_#g=L_J^g_=dL(`eA|ClLeoFy-M7l#Sk+t#6#PUq2oF%TD z--j+~0fmT_-2W;F227k9tL)Rn47oJXgSb~_hk`-sv&ya9NytBZIyd~)+)uzF?1+Rl zEkc^}FJO;h(uz9kjXGl<=Ac1b!D>=nfs)blM$$ zP;lYi+nVTFV*O`?FN?f1DBaEKX$e~2ZS7B4BD?Or*RSLwPcxSDyBas`+p?iRF5i=y z_dT=6b0-e(uS=Xr{=+zd83mi#EmgO3eA5NBY1{NF*%$I^`<>3$kMrX2NoO#p=UwM1HOLby0$7!#f3XRSrqajTam8p=+ z6F49VD3CvIUa9kjv)X7rO^_kl{9Kv>cY$Sr1Ajwo#ZJd;t-zA)??bW+D@SLh)t3*O zI3lR_%=M<)TgGJxp})juQ9@t*4Rpsov&g=l5N2ck5;Zn&&32*evGte5 zcxBfexikHW5nH0ktNs^q&)O#h73|0n3@E0%y}eP|FKegYs9bP8yIriaT1;Er(>?OM zf46R zIp7A5OAZP#y?GA_08!-~JHP-4jhe(kntP%T?(rv=9{9jbj$6`u$dY1g8>NpU9Uy9B z<{}vZVc%z4Ne&3>9omo+z2wBCGeJ?T+z3TAlVLv+MhJ+lVzOugKqwU7LIFL*_qwmp zLxqO-O4?31vtK53oIYSrz*`_9!B#E*DhGz>4iyb50A+cZ@~@Ht6XWQN5>Ejl(j6yy zvNueVrhOibHYNm13Zax;#DGw~8Ttf>H-AE3r2$;^F{>#!1`tfkS#M7Ek}JG(jW=WS z2O_>HM7X1@Z>b>q^HJ`#dySucp)xV!#m%{HQzd}0m zCc#w&4_L#(IIu1g3XWj+ZI|7Xcbc3K_glVPN0mm$B5^FxJ4`GOqy?wTd(x{3d&7EZ z+S|5H+dzf0v#Q*1HI2xTZ+mB%F)XRz$T%r?M^y}0I${SI=Jd>%AcA?LGLMK~9>H4( z6eM))P2*XFetTABfWi!e(?f%W_!vo50mM=0u}Lyal^Gyw=8pVv%+-J=E3>s3;(dD3 znF-E;kHBo?CrU=BYH3r%CkA}JGH4b~aKtB7vTG!V1IV5)pLh2>3C&6K)g-<#_AKpD zjYrnB84SnKg)8=ag^+bZcWAkVK5$iwkxk18BOf?Th#|rz$(;dq_arj6;4R2Akj^j% zX%NHk)@O2~EMkD>?i14@D2qnug89WeD2p|?>hy*S6Q=-;=;zlyj|fkFlt1|CnFkOq z^X`BHqiYGCs?ln`#i>*RJrrD7TRpdofgWwIj3+mBpl~yNGqs6r`%@kzI_;=$dOtsb zBtV&E`r(+*q#hBm6i zy=IpcOgF~s%w*m@F;@kaBn_4j*!waAMX>Sof*w;qR>q>y9B+!U6|CU18_$Mx9USC(0XP?pLSGbroZb*LLz3$;0G9O4y=vXxruMb(et9ea&(>(#FMWU^{Qhp-O3y z08I&t+2Pxhx6L80Ge|d{wn9$57Pe`>hORMydSCX&cgNKr0?v4zv|pYYGkXkpbq*b} zV2pTSs?Ej-qC97yAFayAEr3sbKKHHGSet<}Xiauuq?#eu!)k`r8cB1= zs@sG8KPSBpRP}@oII_`x$_he(^^e(c_w)qv2joj{AoUE-|6UHlZeYlmJA@WmjmDy+2|yNfPXhR;iF=~t7^LStB{d%|(tEP#V!)Ig$pmlP72 z3tP=x2dpsLi62(=lf#6*-DHZgNJBJOja_v8*6PWTh_GEV&|lR>7au{kF9V+$MGzu( zHTry6nVb!XwdGkKufv{pcUf%oR5OPL`!MFSOg~1Hzp>A9Z&SorEDmxk=hPtGH6rB~ z1fD3s9Z9^4ibL4{5=C=dKt`U;wb&j^91|R(Ww%1;;G}wywCD)yd%M1m(7WvN95NUD zm_FU3@Tbjv*1HN}$0Nb1cljR%K+6mym)8p{n_e7Vj#rk%7RN{f`jiA(XrUHb2&@7Et#x*&F%qY#|n=9r4B=$|wCY+{U zn<#xwF36LT&fxTwkgo)gxq!oB22KLmu2udqU@YvEM&0Z-lk-C)4a`NAN&%4(qXuRa zDRyG__(eC}FAla`1zcl1%4n9_qEnC(k6Fo}UmE%VNI{8q`hB%ZpmB}lSS$(DD*aYNhmhbjQ5n!6+^h;YO+zcq%t(X7`x4d=>347 zK4&1>H6juTS%kY$dos%N8_Wo@t`GDZxsZd}nC4m7+^0RM>(OpN5d#ysTXGS`B$bo5 z>vKcATK3eUAcLtW6bcg#^P+41<02eM^9mO6z>mc;2Nf4#x8WK%OPgZ%CH>J>u5V&_ zPzXHQ5F?4Iwt}+r9>`GdbHo5ov3#7jUYoqExec25(KwNkYa%pwaS}_E*C&M+s1qA+w&0(D62U0Ok1x9*yam zbHhD{O4AGHUzpQ{sX?aI>U0JO4AqL|n|pE*1ePy7@c|MOgS$z0GI;)aXZ%D;-VL2y z=Ye)bKFCMAEyGiQ_XJ zMs)Q_Sn1k%18W`=$gG+Wn00%9g%Rn3pChc>m!H8&7QeuVd|Qt65@m`VXsIhd6#{hmDph-zz$jzJ>o$attTJIrPMxd_u>TP7{e52r#79UUK`IkA}w z2h57D6c2`l9S)eOO@4Is@h}}3VZm-0!5Pkqss6WbYp6v-r}DaeBKmJq z&I!`Hk24<|&oYF!UZs4gJwJn3y#<+5qqBT2%fPErGeyy(7i<0B#{0RO1h1i_HDN&n zp1$nv*#|ENEw!;No@MVrv42yG<3L%sLE~nRmIP>_7T#^T9l-Ci?xVEmBwG;WS&J$S zRP`Fd>NT!jSc3yz0SCg${%$V7OMu$m?jjp-@ImE(Xg<7#)jH|5SGB-lEQMX;{m*X6 zwB%I}3plQ2t(H3$?>B?g%k4zR;}XiCsw=FFZ-7Z&bYX4{#|>?5>{Tc|a_5Itu^H4b zj7YfP6X6rqLIO>8rWkiSAcfZDbQ+IBXMRg+qx#@teoo8WwWtDv78)f;UQGwkUi|`|F^=e+7 zoKvT+Z_hhdzIY{T{B62C=DgLbF5$hM{0_(WDjTzo%||Hh%m+EEzb&gbI8&9*W|D1b z&3E`YMYvmzZ0|fSz93mE6d(Qct<({dKls$6HROKU09UnB`lYxgT^C!oziK-S2~FZ} z3vQ#xa$dx<1S#CAH= zwQ$~hX<-_oJ+)PYgz>Kw(pJM6%}0H2`nPHfj;o$(70F7G_tvXcJk`pZm16MV6(yBl zkveB4s>8!5sv=#-ZtQo;O8>Bn;#B;1|B%YQgMdci0Agp(mgo?w0UDOxcWZL4I{oi? z{@$!TxV|LR7S9&2ThUxV4u}QD#6r08AWw{66=9%1_l@^MJDY>*q@1lRs_8!9Is9!? zhc(zbByIS2Kx}sI*V=DXQ<`xfIx47zfcE0;X@`8I`VSK1)a=*d=3LT6Wk zldAB~rHq*IPJOmt$(`%0O|~iWS(~D<2ZuF-C2F{uFCyi7WYR-P8Sk)~i`DxyFFm5` z&wSBtx+4%z{&}I7QCPM@GEbOn-ODx4faLezbZvLWHxhXZ+Pb;DuW5BY1o|wGWTv=1 zttT|GoWsrQMW3PM(b3Um*q!cF``dJjjPBuwz{BhZT4#~vd&qJ|LS-4U+qCs}w~M5Q zFcoDY6_=AzLHCELPZ}lxGSrW-ic%%)T65SqCgYGGm+z$BmcGL}Yu#CeH;p&D_En`y z1hwW8SlpMIZdE-Bs3|U2v|8)V*ZIVn+4hB+GLeXDgBqt4hdd++*m_NAyZT^vdrk;# zl~FYJ;|F;ac83H_!dmOIy7`qju z?(F_tFMN?jV*gW1SF@u5u6vTqDONUqx-y7D_Lr;v+3-apey@Il$>`xDS&nnjR@Fm9 zH%f&X=!Prhg+*(3)ecnL(6h$+&yb(q`aiU)E)QQ0$h>@Y{N{s>Nd>vMXwgpv@~f$* z`mrBU8fW&z!ddTpttlr+GpKO{rdlcOpngtA?tW^E>GsQrO>jM=nmb*e(mR?d{MJ>WP@HZTb?J z4!Mh*+gzxts~}=|@*+bmW3_h1WdL>brRar8TGC(F*5oMC_~rDwfXKCq%bhRqo{;^(alx9^pA44;+v}82u@H zX+ecB@uV`p!WM{e_kD}$?9oWw-Bhuq`=V;S`6kgnCxLKHI!6`tQ@mc^TQ*T9 z|EF$2Z|uQFFmtx&{7k11CU`#Xo9}1Y#ECqgOr_Lcghyj?wp)9mOnRt1{!SD{1UN^d$-iC=y zC(~HW@gvWvmAd;3PyC32aVbOOq(a_1tsc#*Rtw|z@%!|A2U9NNm=}26Y!_~7eya1& zt@6>ZtCx${)Y{vVts`1~&KIV3^{Gdg9(8v2&ebXm`B)hRuQaWNb}2GyVAWys0b5 zFGSg*GY^+NZ1Ku%@Ln%y=JvlyKIO>VcdFnX>oa`%7n!YNRKnZA1OxZ|yz7$W^o+xl zzR;&Nql5j;Hi$dQbsQy22002}_Dl`#ut_YPjp!&E;o@=mq!!XZr7y-4ZrF~-eQ~ov zdBqsyNb<4hKfBdAHTXo5z&Lua$+R%S{8$`GsC@%d)c0^$o6EBN6>M>O{tuN1Cb^(-Xj<;^38JXP= zU8bsofy~jVLPF6$&##D$en0rd4KtNOS*k?;;x!B8@hO6`~H=?e&0DX z_9^41&i5H9h0SBEylftLEWD9VoZxu%_ktxO4QtCuQ~O@R>o#xPt^71k66af+dq0yp z+P^c_F`in64K6SZ@EJdlMb{-9tPh^f+H&O`Y+Z`EGLqL7`RI|IgRjP#WPNRGizb?r z^~u}jQw$r2v$w>X{3Q0`lBk?(;=6Ci4*ueG;_21m{#tEm_=2c+#NPJ`9sgg9f^8s? z|G32_A;W2_e94U_@zwMy-KBJw!)sJhVZ|=jSBV)8E?JQEs|6C+vMKQ)-#=xY(y|gd zTECw45H*;w-$&Xd8k%afzj6EIwW;T*ub1p@6qnCZ1&3Zo*F_lTU!sahV-AwccR>D8 z((S3D4NHfX<^4^!+iVVm$>Ti1Bi{4h@`4*_y9a5wj1{W*E#;UWXm4$@}+&F@);RMy)3fp_mv+DGa%_zAT0cuiL{ z>e0P1F+U0=zT98(=(O@~O$B#h8KIfZvz2o9&7SBf%P+6Pu2OeZ7rAO;9`U@=m)b74( z8ul^8ghO$W*($_#mF)L+!omY}!`HeKX5(HVooMfoeGZ2&gZsA^zcZ~}Jn76(IvKN< zEIIbMw5oJ{M@X=r(z@l z+eCdZSwcb@Wz17&F1z=1kVCbfEw00-40m~Km7q_NGp%4@K$%-1p~P4CthJ^RtA^Eg z&Gh8m&7;lmoQ~^gXJCx4&jcLvP4Zt4}SwVKhHMeN+AOp1_^LqZ=iq z@5qL-*2+iyuy>5?>T>o(sB@nJE~oh)+BupM4O?9WSCXRhof^IavF z+}=C7@1CmRwD)`V&6xoI=8c3Ug_29`sB1F%rzQ(jEu8|Lc4P-v^H0^^GJA0GK~5lU z%INF_&9~9i!1cUSZm)VtPR9*u5r{QZlpAKOA=|KC4=#SU_*2H94CFaT}Z40tBM% zX{M;r#L{cBffGsJG~YZ?X7W5K60Fpuv(eN{_EiwsIjkOcYg?dhpgDWS(sRx1RDKxS z+PPY3ZU2W#smYxA;)h2M_E}vroOzQOug~|n_@5sdOAuM3i#WaKP~-7ruHe44s(_cU zlK;@eqT0{3%ZRbbY)$dPLB4=X%iLT^W*he3`uO z#GQnT?pENFwuU|qkLfWt#7E&2XWaB1e;L*#L_7{3%*aVPf%d-S=#^BoCOolxWm0$i zg!5=;Si$$qjo#R5k*x93Z|Qf(id{Rp@<%+Jl{K@dg*Z4W3JzA3g~oi^jivh{map^8 zZYS(@d>6uqe;544Pa;7He(80RZS>hLdYHB~JVI#iKxK1Q&gqffjc2o!1x-Gp8nunuW%BZ9C4^E!zl8O2u{-Za-VC>+^cPCLP-;*HCTnREH$pvHO|t zHuov~9`UCYQrTr$^-dHF`HQn}(;i6>lj9Z^G-UY`{R6oQTRK@(W>Y4W)UTsVj2({- zMVPWr5x0x4zw_=m+t5*?QAx8G&mK53vmQhS2xFdBK`CBh0Pa1$vw z2W08QO6c^Y+3$WPywQZdy$>(vnMzI-oTt(vQJJl?-#6Yx69Zia%he@c%rgm%zH&07 z0lH}0wPvaVBF6WjIVDhPBu>=Zmp{>Lh?i26v3g&{_u2}6;7paTZ0pk`T!+06uiF9( zpE1_fO2j0Z>8p49?h+eb+{YIDO*tdeL%gu@=D^%g1K%d@uQ|nSGX%kJ=jz#c%A&3} z=>^Z8=Lui_x;b)vZIGKq>bL30H&ikoOG1;sg5Hu%LWqL0RQXefrFONQh~O6UwTVbN zNq@FIyx>_Hp72B$<-kO$t}A*>dk_EotfA_hXkM}AWb&SjkgQ`R zF1lE;Vu3r=~sREJ%)w%1=Y$XR)ZxcMmz;s-X3f1um27l&||sj7e(9l8I%K!}nVxivdp- z=P@m*k9zFmUp7_{vKYKGsoKdo;@z-f z*UDaN-WSs9WM1o%xcTyTBk}L6o(arrRt!F07i$jpI>=*U45Z?^!+zgMU7`K5rRA1$ zGR((R)B-I=7RnrQCYasr)=XG&`j5?9Yz_qW-%$=)rz^hdUkaZHixKTi_vz{iZaj+` zT5k>(^F4Z{$W+hBZU6B{@wi<~Yfx1Ek=jG+Ip1 zOoWdHIhm^b=mI;!&8vtIF0gCdr}tefs<+wa=Mlr-)o zy`rDFRHm*s)n*}@B_6DCiDxa_a7$M_nEBm@irf7L0AYxLSyAdqM#t#EpV(`F@cQbJ z!vToVyvmNV00n|R+RzaOMCXcB3c&14QYY)^y9om1j6(iMFDXDd#L(1?Bfy7KuLV`A zJ&6EeT%Jh{(Wkqm(s~FiLt3VAYj9#7$~gEj?F^-g{B7g`gp?#k3t@fcOqao;J4AUV zS}nIBklJgj!4`i|4px;4G}9mj_XQ%}3_ADfAx4wM$9_!(SfGOAVteNd@Ri1sA9Ymacdf0g$ zNbt(ljc$iPR;GAI92XE^SD3?Xul@-@l4V^Y7|1|OeCgi&Sq`HG>QWfvyZ}VWwETIP z6`oZ9nao;fvt$GmdQhI`j+=u*FEp$OLjlW_7HC&hDD;AdiyDw%bpQE?)Q!Anm*@PP zhM6G-**MUAW-OH+2nbg%tAhRrGP~n8E*uQt$lFa*dl2l>(tWWFfg_X4C2D8)K!2>% zm|Xd%E-|JfnhJQ_BDcD8gpmt)oRU_05g--|$5$qUAaZ6~VeH!$P|aY%hy$H;6MA>C z*BqvSuk~PXxu_O^B-_(%@IZ(aMbZ<1Jn^HrOGl-Sd{KZSAcNS3kgVuXXm-~e0}-$* zX{SA~eAfa1Lwt&!aseQTX;_E&4SJC4>;R*Jm~}4zZ0a!zM}O5WVnmKcNQ# zdEe5o*uzcse`J4pR^C+MT3QX(P_JnoIR-q8UTOVLLd~p*H!nQh^!mXu3{?5yb}Tu7 z5x6zb;D!)DoH~DtYnKoLmZ@XwEOXhifS?iN|6^_u0I*q(niV<@t+BYL>A2Pjb!vrG>M=2@WwtlwL?;(8{d6 z&q{RbQiiCq2+p{4M)7s_4$At7{YlR*@3la9i-8^ea}I1vaU zLF4_)?@^urtnzfPWlv^(mjuCbrOZ2|_MkAwxE1CZ;&m4+gqcNbv-liCldYdUc7`fO zv72L8j*)GY*gV%`Y=`1CVWe;Y7AEogS@jD5;vzM2uR;haXoF=DfG(O`C_+gG0Ld6^ zpilM-fQ>;3N3q-6b0b+7&tfdq_7C1VSU9T8hm=wCmHd5+h0DOxo(Z8W>s!a@w*v0T z`w+P#HYog}{1^r&78-gfu(Mum=|N4yaWf446 zO7%C(p-7w|3~nK=Y~~nnrPCN8&{{6aW#4R|rWuVQqN?ywfTS9^C7zMX;*^VkjMZgjJ_D-kGgG7IBFJdn+mudg1< z92PD7p!EX*aw3yAM#aS!J{=PDrFRmJ1c1@9EkbK(Lc%BEPG~}o1kM$#tVP$%y9YOw zfZ^K~u;F(|3xKh1(+UZFKyj4M`t^Eg2)y-D*tz+Y%g_&*9|I(cO`b6jjK%x=TOThR z!d`!Rt1f~wOj6iC^1v(#U)JaF?F0CWGI~&@(8TMf{$XBCORca}p_X?zy{3dl1_of~ zDx_T|tojWBoK5*$oY2KSGx5|=6MlP{e-3uAHI%Opw2V zT=j~9lpz#N_Jo`f!e{eo8Of2Z7vh{tJ_7=K#cRqyCc}OF2CQ}0kKbP6c=$m03f2E` z%N>!zSanN&J_V+~f|gf1H26l9ztafspa72?*Mn*5qhGtE{~F|4R13zfss&=-wC_~w zk%IUP;TNCU)rOc@S=VfWT1qwmCdO4Kv@3I`({^q*YH(6a{6n=-RDJ$~{M8N8*@)lc zZHjLIND-IZSzb3PWk0QZXXwv$9ILRn)+s389jWH0RWU)0%U^8xhs!m1^ic2^SI0f| zn{W7(gorXg<4z~jpYl0S1aT{f`{POs25B2>ax+jNf4fmy>;05B{!h@lz05EK=yDXS ziz>Ai(n=D@V7_ucA4FjP;I8PubR+pN!;ak8*vMtpn27n%ouK=1Pelc>|K|eMfkQiZ z!yw~q$H34RKE#PYz_(8`J?gmjC;~iIT~uIwVwftE{=@X4zpMXC!@;jb%cdZc!ha6N z;dmix*5Ir1)jyIw1Q~O`_FvibtiWdF6F<{_0yZlVvfX3oq^S7&1YGV(&|57u64&R! z0IJCzY>A3FMud*3W{|^d?e5za^o-Ch(KoV@da_Z9v@0Ig3Bh2FVgu(rX8rjQ0! znpPdO?!$v}!p}S5K|6OJM_oj^&{S97EQA{p3whUh`UM~jYq?FTVbmS@-5v6Z0@oIs zMcDUkwm%yHNadD+$tXVHFSV)rcNQ{TOyB%leLUqdSg< z_%EzdnPY{=5wr^r`VSJy$7J314-z`M@KDQW9DvTbO<6~%EI>HX>t(S-^E>J{MtvGD z{;($zpQLuR7kP~%hicImiXKjQw?RND%E<)l1!b4+dRIfI?u)nB{MWGKDj7Us_Nd37 zL?s?0;{&?5rO=0j%a$c=8;M)ls{HoFDWFbtkqhQ zT55V;6Hc$qSu4CdpC!oPjF-vnI5MvH^E>$FiS*^;H%H1w9?mc1EGk2sB&v0nRAbB} zdC${W(n)%l+nCiW*Y|U%jz(PFSD{blT-g;qpjR+VQQ8{-zXc)6-XK*E>uft3@bybi zI9KT9KOy}7kJGIJ?(>{(YnR2x-f?s7oiZxDt0w9-Qgh03vGc@BfjUEuyEGf2>>8=w_q71G)_<*>=N@Q$i>{`~SjwhLJYyYEWC38N$ zR<=LFd+dIX>U?*`mA%T;bPbf0w()RfsvGGKC-0=75@!Xu@?7_-&ENgZgoZy~`13$L z3uP%)PxMGW6F%(i^1Tk^rKv_0aswiilx#2S3{9Ps@4q)IL=y?6_f;uD-Zv^yG`X_4JvbM3Nh0 z8=M&9s{Gom-e`uxYTFlc8A=r_XClJIx8}}8m`(j6bZx-^Et~lf&2Tk=oKi7OKW7*XC$O}IPdkZ04sPD;;DTazTXxCUf;pKZzAuEX+Eg4QP7M+#$bcbi+WDfauu5RKnr1eXh zjD84J`!cV4?dU!>aH+dLh!G~`4qC>3{AYO*UlExj7~*8yk(3R~0^0*wu>BwA<~>E`zbi@)PdMric3(yO$X5fBpQ9s<3-L)So)+s*d8_U>)v1 z&6&5^N&D3wuzhIVdvx>jS;Dq-g1ilnG`%Q(y&MVus?tr#v3~C1H|}B7b_8F7_mpkQ z1<;Bb=m844u*T;^FR%UHFHdZ^!(PaA`%#EchRLGI=SYGAQM6*)BJSg5hP$g0(_tlU z;j@o_Df$i2+kbH`{;u^}o(h%k#-8VqXMB}`WXWTA{rQF#^1O-y6)Dos%yg0A?z5F{r;b#bIc z)prvF)UBs4Z4|g^2g{ z-2z4EEbOmyWuHR%EW|^+w9EpZiN9fH$Gp^*Z1-cVYJV(a>bpQ(bWTcs=IFG$2ko=I zHl;a#S}f@glcjU++M-7@b#77Aj4@0BHJQc@isw%=vo9JO+x?^zafCXmvjk8cgLkWe)qYr z&-;7MkH6;3&Q9;_a_&64t>qHFT|peLjoF!kkyT({KzbWt)hhl4BMOeB_&4zAA*dx${+Kkn~5#-C#;1&C)ElR2TMYXlmHD zG9$*s-I>u5y*l|fsBkp5lnvWxM#obxY(Vt^cmFwcLMDo2y z_*wE6hiBvxPhCqvUF~Oa=MuLeeSv(aJ@z+W=PC}@AS`42N>o1rEFXp?$&+>F2PvC- zrH@J%)c}V-5;Y_@lpmf#=-|RtQ{O?|I8%`ARep2{!OjylG35jqTkn8CBYnV~PoP9PChkFVj>Nyk zy*A;|5u68eb7ow0C*G|@MzK6mUAjfij_#Z|u*cz8rM02kJ*0>OVc2_u;RZ>ZA5RY& z#BVV%r$}k?82g>_WdtE63qNk6XCTEd!FPy^b=lK?bew+JbLAsA&lVEIJ{TqgJB0mc zNPhat%>)t}13Bvk(xjhQh{l^N@Ld=xHT+85we~yfl?T^;$B-c;B7O^J z7O%EVfvNS+F|E)H>rrntFg7WQ*u&{CdORn9xF#ID%s8hu>(cq1^-PlPC?XM>+KxAY zuCp%Pdviyhezqyg&;Nb@mQQMS*k-k;p>|W!*kW#+=jgvhV5c2Hf5@jNk#tS`bhK;& zEM~KE!R5uFX#BW>HodrhY>40?+v7`5xAJ3MY^{y)%4{wLAjIB08XBD!&gVGy83_C^ zS%nG7Q#bq?t<5f(jPK+gDvuka2EXjR)go_bxPQgOuL6;PpFHp*x#yp9J9lx!@83!s z$^}ms#YeN(Fs!BJH%gz2LK8{p@^J5N$km5|g0x!4V?t%cFDH@YzPUXs4D}t@7VOnM z6pa%{)81iwAp*FVFyA}jZq_yWJM)?1sA*kd-x|mJ4#Us1ouvFtVNdy~128v7TZPxb zwSABlA5ID5lA9XhCt3VJX%B*jgBTKZ*C5EuDALf31i*Fe_YVhLv#!1noD$d#3{BE! z`^tbwuNmWk&_6iY-Rq2-{NX=IA?2;ZMs9VfSrHTBsG+4EPN?(9|J?INB$ARsTo8MH zr3f*E9=tA0R^L#WAZ~0SoIK{!0xdHc+*R7k$tlHCzGY67We>0fYAaEPg|>CSImL~` zR=Mie-L%ljs4lXnuidRoq(lDTybKJW&up=~Mz)%v{h1nVRz#00c)GXGzJ!L>pw%1n zcPJVSqRMSwsu`3n#zO#_1R;8E;p*k(-(uf!e+yO1 zwk~Uodmr|4tCjoec@kr--Cl9FUM6D4Gl8Ho2A2gEXO1*t5{Y8nb2Umnh%T*B7p7uhyDUPs3%sakq7vj-;*~sJ`W|X^UC} zci8>bwYFLEdzouAc&x~DI9z_SqEm2b+NN`J@E@C|4t(uI_;I7K zz%~_q-gGF$aH1Qf0A)CP!vGS1GURk8RooKA-Uj$Mid(uWLC1$~dXC9QwWlI@UQkvI3Yq|Yxj_Cu~kYM3g1v>M;*ZWqXw%fNV{+uJW zAnKr)E|`q3hcVkkqKGNR) zeLG}6>|DMa)_-QSlZfxy)G#ro7+l*f`cTYeO^>qTcYmP9cwFU{r9HiRHADXzQ8GuR zO!m)AvuaZ@xgg{C`^_OfQ;)|8f?N@g4LAhIf7pQry69~xWgnjByk=(;rrIr>j}Kig zu4@B^YW+v?Ur8iCxH2OCvw{(EW-HfF=u}60m8Ua#Ap0m0;Ku#x-GeonFYE{HS6BrC zt?y}sv3K}nD;C#=l!BU~r;O+0zGZ(e7=HJu;z}bW=r8peU%ql`>`#Rusr2?tU(k4@ zv3vHl3GPfw`OB>jTfwYO{`;q%RrybgBc!I~_gW7l%$>jaXK)qU+oX(NI^#i<22$j= z(j-aTS1wi@+t5J1W zp#p#CykgoRBuw$L<4jtZ{^WT)n?O$2$j|rxyO;cb7ma_SX(y%Peaw-4J;V`eR-$*? zZLp-mCC2WJe7{$eiE(X;fhl|+LSE>Ci%uRQbpN94Hv3J1`S8K+0G35Pr_suR{^Ud* z^^NSugu2%X30NhRean!)?X{B=m8E4pTkSEyQP}hm>lL>&@0Z(UCotGKd;F;N;mCB0 zP$|2G@cXuhPBy=!{=*?0^U5u`AEcqpYMDI96m_Uu&s6J^^Mvs~7QGaS(oew&ZN26A z{(-~_KYp)=Uxp6LN%kr@4Z&f> zU>ov*86tImSqV+t278k%BS9!}RexN&&~FjLnFDgr)Gym8cawL=XNwZ$$zqAE-=ALc zmo1}oO|It~aLh_8b$NwIu)Q)GM$P=zdmM~oIPW*>^}RugM-DicGo_3X7?k0;CEwOQQy#x?$R6NLZQVJW zqy$>HWA!O(*b-@0zl)H9eFN)UF%jO9?5s& z4Vm#*OXwJTM$2yT41RCuG#F<%1cZwh>8|Istu=p{EX}`27rkQ^@?W8y%~Kgj z(XSKl=cGJ#+u2Yoz-0Aq6_}BvVT_h@p>Lu6`Lr$bV&8G89o_cTu}mQTc`uo#sr2sx zeHf0c`Q&8#<_qhVak*-MeymKS-H%h`w%ZppEKvN6SGiVI)p8cqJX7Nq$e^M%;)Gt{cTZP=d9TyLB*)nIO^3s~+R#xy@s#>#8CftX#xouLOU$SmNMiKcC zlF*UzDblIjE}@I&)_fE7{b^J%{4RaX^yhFT-PFHaI$bpD(>Kd4M!IrUr6WqZt;dTRj2;$BPU`(KcjdciUZHPh zYFD^suR820O5bJsY|(#MY%FsDC*wDUO-@?FK76!>y_CG3yCA60>k~D{{&w|I#!v1; zzKNii^Vkp~4&?Wl+ACyjJwiMbSTNdxC;UuY-a0jME7ZUI&v(bj>GKCuX9|Yx5bPb~(hRHQR6b2LJ5_&rY!Wwzx47g0}NI#Fhdd zwtt79`ygm!;XZ4KM7vjq*!U-DUTF}tQ>SN;NBifPSc+3$Ld_U{)4)3hcR@vq;_Z~*{YJ5~ zZ9S(Id>B(jb9wL%QWR=iM>3w2Kw|6dX+J(Q+*TeMO_3G63+Md1RPzZ;xQ{45*wu7! zhGyHwqR*W$C?I+MDNBVVimT1pp5E#43jGmZ3+h{n6Txhpm;_HUAl;45O%5LXI%fjzlc>u^Fl**<7JLx+l z@JOYocl#K@^IUong7p3-Joh6DThqnM{VfRDRfu^=vx~zHr!jg?8 z%qUIbM0>gZi}nOAqnPx=5AX`As1m)cfD&Sk92ppASy;c2si9J)8; zqdKLn%zG$(()?vFD@2#1L;RNtQM2XR`f@s;y_H;h^WZ|+@o(+o>l3cmPR}s+7{TIY zs{11!C*0^swB<}JkN{xeHx)*N$SQ;yPmtCR-Y2v>H_EeC8V*XWe`l`@CHh52CngFI zjizr6V%}qHOLE>}mrt9&R%y~K*^zL7AGl=UWqH<>#xST%OI6tj4~n!=hP>@VF(@V6 z%`7kX{%H7>KFiALIjz^ki=I;|SN!Qf+VEO?8MScqU*|P?&mj0EPUX5fZyQ|#D z{ShzPNGVbT1?q=Xy{1O?<)Y=(X}>!8dbiXf%)Qm3i6v&wc_9`pxML0r?s*YyegsI1llEjXImUlGW% zmJMI&qtd z9(H2Z7YH5nUaqo97kJ?2S0Jec)vnDuk%Sd*+PNyXzILEUgLfM?I>um1h-&i-W8R_| zSzc;5xr}H7AwN8|f~S`(r$aaA5Dh<+i;XNC?fAr%(9;Eb2dm;WgpNjm=e$01!yWj6}TPU70leX5Z8C zS`T>#(z&j8SUCS001%L*b|ItYjShs`C0*VaM2b&GUHt6Xfg#iQ|2`3q>~^-ySlPWz z85iw2X3?sG^B4{L*M7^-ucxo5?-aT2y5(Ff1^`6MOaC%jci#3$Mp?NUXpVBYpCReJ zP1k}z{!V;9Q(4M)-gdHFJxxdh7+jNk5c$Y%jsnPREIjWcHNFn2k;qCmRS zkl54UXtn*L1bw4VqWenK45?ycW>fDIwJx|`E~~uNvlZ76K|Un-1?RBvVe@ZnrAgV< z=$k}0SZS~2xp3bX3mrdGEcCyH!Q2-U;%Dk)=zq`qg4_0T-2cZneLV2v5MyH8sQ^u~tggAPZu>Mz4PJ@q)Y z*X`5>`|`)(*E=CLwnq!)DUuusS86Y|2PoWoQLF74Wg5q2dmc5@WG8u{?G-1ft>W(= z?>TFvnCAAMM_Y;n*cI7_YUQGE5OQNlh(CtbHcC`P1bq59=2Ik|y4o?tAWBa?&@r8R zM8B{siiJAJaOzC2gZoYhO>8}C{Y|6_k6+d7jXals?U?=6S>Ysf1mC4QBD z8yKQrPK)V$_67$ob{|QFlm=weaJ>bhOFErKZ>;Qu$cj|gn%pnmgB^v@u6iDxt3%Ax zstQ8kXE9Nge$VpXqm+}sA?vU!i$(^3K7VBmnFHzG(kvaN9iNq#jN!grkLklVRpfky zuu6vIbYM?62tzF#t)iUHd(o2J!R3=PAu#>{Qg9LEXM`$p?PBsbSz1Pc?sM2W#pL=~ z&V}j7E;uxF!F?1K3uC2-*MyWAGGwGH-$ZLEONzw_Ps?rN|U&|#L1K_Zbh4Ttl)>CToLg@FxFszSgIIKf%>5D zY6Y9leKpCZ0#p=3x=QSC}g>=WoYZ0$Ip;g!!S^JDqCAu%NMGV@uxXMR(3K50UrJ-XPZJtoBaWf) zpEuOEsuyN|N`-s>Q)>_&7i)SNC!Q`V3W34RUh%#n5I%NyAeI3ihU7K1D1+EmXw&tA zx$=rPil&VHX8lQ#3GA=&+(h_np@Vd-N*E^y{AztTORyUK%LxPfo$75p;=AsgNO^6+ z+-Pn!%tK~Du*3F-Vf4M82cKO;HY)G)?ZmnaJnG@f_3h>_BpwH99K_L7<0%n;&37TG;#r&O!>U{Q^2R$Fzu!X&q}DubN)SMiX} zVBzAtFAE+TH$AT@p1x_Y?NFx3$=j@aK0XuA#edW$=doeQQlts32a(QftigtxdnM z1#c9t?ml-L{HXGN*c`>puu8UcXF<9ParghhOVr2$E=#0Z#TtKGX@APGk^%SQRD=k$ zn@cG8ho_e_WcZZ6EW0`lH$_$qPUB88nYi0B8fJ-BZ@&)!G8&piIlpobyi!ziR0XAs z$9bntb@q8-dcXsxldtt&7dz^?K}b`bq$zYOC;)C(vNi!YC=hs2iYo&Ll?cMgGEU%t z!fkis@g4w1AL@FNTX$Zm?3k}1jtPGb1r8={D5=*;0B}6d55n{qQO1J&uN z2!j|CP>vImZ~PT-R*8HqCk#DTjhEr>0%w(s!82-^U#|t6F0q4?D#t(9t?8e9oK8+> zcyK^gr`)^L4yLsTcw9y9TXp4?s*AZ5D86YsUh10@SCrk?Sk+;;|Dx~u{7+=1;8s0+ z=&#S+FKmyw?H3y2v+<`UY=@HwNB!vIQN8%`lPiP|DWag^Z*U^GY>9budn~y5!ac=OTla? z>En<&+dZ4zdB|8<`3*+nXv6PB+@pom+gOaLI--#&hNq z#+@4aZHAha+WVzP?m4b(3`podk0SZ;{$eq-84ey^eFF7Qmb6^U21sT`GVq~RoP|6- zx8a|SU&oOecsh)$=oIc#*=r`6GD~2k{cW0+I*+k0G@lU{Gde3`LdeA{cRHlGLjrx~ zin`zo=R^$}vp^ARsi9C@`-#n$HY~y2cLy&&xnok!jqVq(g0--Dy^Ww4F&*iHEXEY; zWX$u3A}eYxczAcxlb!V@=sL$K4B<;VVuU)ahDkVQVbIuD6tQ96)}T&F;XQLC4Vxm6 zK{&%g#kd{YnvyK4Sh^ES%1sb;BZG{n`Qc5YHC+{Vp*dzz<7$6)^qU~s`}H(5zxOIw z+V=Z&txEJusz0lllr&*4iI~3Xpi%p=dHgjB*{oqh2V=i4MCom$y7#4xc61pG^6?U^UPWX@_;U8l@&@lg&e& zE6v~bi~6iuH(1v())w2eM3{uM!C|^G6R_c50qdw6A9uq|&($%{nDgh~?^Y(;AViQ3 z!lk#!UAyT@|IxP$MdL==>JayePR1M`uijQ+>|n?RK?rs7M?)=qYUba6sfm=CUcbiD z6bFd}dOMy+Q=mjS{6;meVk8ImR!oqXmHAiR7Fo%uh>!R;*DYzK{R~Ng;bxwSx|wU9 zpofe~d?WCn8w@h#)j{B@@crJ>Nz@IKMmW(H+DWv5@P58wWtn2~VABtCQngM`@BUwE z&vsMUx8Lfzc4u@y2g9n~%Pdum7^UjkNql&IrCuEAmzV4$R`+J0|MywaVN+Og&#XRA z6v@pU+a!oVLOPG@<_rUly>wd8@8T6T(wR2Qgz%O-J_HUu(S~9FckImyz#nvA*y}eN z7It9VHC(%1jX1m78k70E@e-hSf|AX)N8lPaVC8k6D#JZq@#y-~MDvP4P@AyK2FfC) zWSwvXU&czgSVrO8H(;6fVj2Dj_!F>p7Mjd#jKKZuLb#=?)+fJsW#Is$j&vuThIHDG zpb7q@Z$;J_is|n(5unbbkrwX4#BQ^E=y}6M!cmn_C7k~K$pxixAIt{Y&In^6*ZPFN zPCwVW&$|*(OBH?24^H`lHlzp|B1iHgHy52Jl-AOE?B_=tVg(Hikk4pJDlZxj)L=2V zt$>-(1wDN~SL%Qaj_n5_)oR6R@qhy*(%b7GW@78x&!JlxulPu1*7mae z4q{1Oixg2ka5TMS^HCSUOzcZArwSe^k>*7iTUJOgU?dbr5@08d)BCK1Lp5?LBn`!DzzCiHxcHW z#H1Rjz7DD7?FPuYRoe;Csk=A@vOYeoKWqXiShw!A=N@dy%fJL;!iYzpv+09};LdtB z))UB%GN4*g73c7|0d+&Hl5L=prc}qL1M9w~uMvq6LJvDP=2;WA)0Cl7&`xcX#ER1! ztZRTmiPWzJP&p{d@6M^OvgudqGU)a*QCEDH*DlSEAMRb34U7I|Nay%+Z1-~HDm<7= z-1tSFE+RqvPDR4--81>(V|Iupm9m3r?z?d$4~f4FxWn~lc74-2Z{G8|PT#)BQbpnP zGf7ah)XHmz^javYM#Wyakh- z&6ekcC)bDL&K)5|@iBs8ae}e+wcu3~$&^};N2b5`E#*{&NB-7joX>i*D4&1J540kT zUb7712z$(xji8|r zbj~?EO@r1dSma6^OkHW@ayHeH*h93$GT+cT@mwA$QG1I( zFXNCEa)d4yb-xfd>97eK6)fGVh)T$$t?lioUNL1cn(r!wf6?{;J88w^SCZx2_S>f$fwoI5X~Lw+xLbLz`S z{HD_fQ6ymnPK!&`^l`$HVq|5?blWm=ukT+79!F^mzy#M2cCVSENq<8SR^@L`*y@Tl7e+O%QzIMieJl614s_n6gV zd+VCG(I%AMr}<(ZY%Q2KF?aqDO%@WDIi7pR213v7xs**C7yVUPGTiQ>`MoDOgCsb4 zqsYNu-vn=1C#J#Y)$$NylC=KZJD4X3P(%#2gdrVfOzLDdaD3&Nq{dv4w{i>H3;{;3 z1S%T+FZ zN9e#+$?N=@JhZGoXNF#DIWAtjOlX73VQR=El0EOi#JbB%d}B+tfG-4Fre>FI0fk8| zenj69Lm|-0p<5O&DgU{*T`o9@ky)lDecKj|QB4#5*rX~%OfJzH&i;Hq&yVc7kRMFs z)d1!>Io;VeBp^<2<$i_n_$JcvR^w9NvTj?;1$B{7>=A3Zt2XI_CvZcNQ3dkaB%JFU z{JCbC@$VI0ggO|`W;+JYmS3W%g9p`Ann1eUnMgBpBO2w``5Y~cN?jF#JBkVCD#g7V zI0fe~4@@kk=bB-^c8sqMO?UokZPpbxTz^k3ah?T@f$3N_dK?U6rmrI!nsB{t?W<+) zwnOHE5gaPMYV|S<;=UB5C$~)DCh6JwNcm(rx9CGyzfpkVc>~$IBojxqS!lFdk4GbknKJV#?$!5G`c=$WE)?qAfFK{UxfbX&HGDp@_gKb zDQh_Jm&SJP!5&4{u;?!h8N*>?cKknHm#~Yz(KIEQqxk0De7JUBgiBOxA%`mdstlO6 z0LV+!tZX~5o(OOop%xdIaF?ivy>JmoEQkQWqDSTip+@XoUG;T-BFk#1ms`I`hGqp$$xwPooPl%_(i>JLm?H%hj9S3eKWD~L3Q?t@HQfBi0h z_eisQApmGxnjxtN6meLJqg#g3j9Ek+!gvOA3OO7Ogf>8VpFFLu!T`Km_^K??_wdla zXLnqTp#lKULr5f4+xB>bV2CuxYoVuuVWa@3v)0yuLpVUUW}0?3sBXff>Q_*;2P|ct zpklwzZR`5$L!Rj-@pzIE6{-3nl3{ijt_c83U-S!S03|_|1L3| z0O0Y=`Gp5M?Py>d1Ia78Ea#0Q45 zOD0Vbb2NT-(b@7Z`w2j$o$^f+0KC1+4AR~MyxkqYG^qnX<4db79@LZVIN83io|4+$ z8*D|i(a(0shg=M^;JIGZDsYS+l z%Uw{kcdLaqdB!8;%h{IAtf><u;YD%>1hOk3E+H0J} z9zO<5yWJ{#symE9xqz@-ZHvkw&8GvjU8yzQk%F2q<`Zb)Hkp2bYUaHWsn|{gIJUKL zQDxy$79z6FKp}*!4kZ_=?z6_tM+ZPRBRST5g=k8EQTyAM1HK#$$QR9_Hr5j97P5ff zm@Cro99i(;HhfcOTcOLh<*7XhYRxrs1}`EIP9;B1-ER=vuMzLCUh$d@`D+SD%ctwh zK;~cTc&1Ar0vV#gjFsI9IKg)&Psj$J8nE}QGcVozW+~+YxN3kGPHxgP4QB`968^Bo z$x1F7Xe`odMvS4>(NVFASN0i-WbDh25CW!=%(i*ELWiCU^3CT^uz{&eW~xIGKpebn z9^XP2P{ygD90-WuS?05g#l?UA8wksK-8EPxLd-yd_t6Un9_szuGyxi@Q{X;m{9N{t zhv@$SGydeW2UJLG)y>KV5U^btZ?x1qaG26jf?ER*g!95s;Rpi8IxyCO4CX?jgG3GV z&cJ1X`6CeOjah{UVTiEKch5zp#0&7$PS7PgC-gB0swhQ2I}BvXaf7qpKqNGC*d%$B zprYm~wKH9BIH1}!2e8%^1*TnubDiCx#{>lbxkRdbk1**GH-^NH(xIP|hK@G#b!x$pO z(8bXZ!;~5t4@J9Q44Jitjl#By1u12)nsb3M>|lVUWEwrs4Xqn9%f9Wv;%anH(x-xA z3_}rHTbAM7A-j=XkKIKUJ547O$ywMgs{k%Ek=ZOIUIVqK#?V)41ux-Ee|{$VBn z+?{txb8AR{1ytg%PC6^SrZD>JkxChF^;_|w^)mOZ5EiiHZaSuu-FkKWA%%9fJ;D*X zWwL1a?CKd%0(`2P1v1>|l3rEWchP12`#b~P+?2rT%>V5K-)!!5XSfN(Wq{{fT93 zwdjVr@oDn?$_OpQZ={d4TcR#N??lZfK?9IrmwH?q)?6 zMTAH|iHq4<;6$HbYCR2W8TA(bZ>r={Rc6MGHx{6Mqx+_0os$Ao`vIvBTcbdJpnsPJ zTV0R=K_$@Yu;qqs%tCJKM8|1jK-K16p_CK{T<0K}iFCZ63E;rt8)1D==l!~hPKEk4 zf`~T_2C_LLuHqfqO;j>ak3hakXQ^n{MgTaIC-qNMMnMaz{^BE}oo_IZVy(_8o6TA`}nH7{o%1NNF_z5vS< za63UcuMc*P#_byJoR?F&D<)9h7x;2pvZ|ok2 zDLv``to48rPk40&3#}zh84D99$+QqJ@Hd@@XSm`)H=LRc>3uoKxOvf=+o*A%)=0J* zeU*XaYxyv+19BU7YD1Y1il_VaK;^x^T;l~wEzigGuXP?`P!9yNF27#`%DtJO_qUrM z20-!etCeK!xIn$VHQG+Cv!#K;EnvB^5DrC-yUnaASpQ}Pb{q4J z-?C7oh7Qfte|A4qzQq#f=a+(3`#X_50%$$2F69`5Iv~30RwP{zI@+qF9N|iv3DNEN zuR}va5!93S@^SveAzt((`$ups{#u*%Cj5A=VvVRcHBigFysP(+|^SLlD)Q#BN04Lt!Z z+4v6QL5<1{EP8~ht*(Zdy9@^$%s%kX7M5!89i=8Zwns~7K-3%WC0Bvda%(TI z%6Gg{_9jI;)r7%qqRgp3oiK`3!`RLyU&v47?)NMGU;LLzTe(mRRPylT4DtAolu4p@ zhJG!yx2DyA(hBriv(7F1FDy)DC;yhbmaWmRNR+a#)4t*55!$rJlO8UMa;ywf-`VQG zd6~SjMO6DKOPU{mSG7=?^G#%lx8EJT}oIB^qUFp3x4^lKtQEoZen>t@Rn$N&oH%U;^MU3zI=!9)1$PXCz&)?Ru_R@=;Q?` z_e{Rs!zqxE4Eyjt_0#&4tS4FPJt61g-*-^J;bFqslWgUl<8C6(5>J`0UY3MbLuPy9 zbXCYXuczmV{E5+ZxAL2n2J7}E7abC&V%T?*);Ej}krE~Htk(I3+Eg!UTOh8E2wv-=ZZ+ z2-}Tt!>`+(3g@9UMazkZmnTWf#}TycKhFY3FLx0y zswZD$EBm4pd=1THu-Oj|@l?X5ZX1T!k>)sLh^BB`IcmWRWSEXBOQ779NnqUxQq z7pT08dc5-DQ!QhE&S#L3S6*Hddam&RQSIkRB&Rf;%?jVEPpdhk@3T{TqZ@olXCTY$6?r~%gTzIvS&9z={IdTT@U9^dgCaP z;EDX>{gG?(DoNyN&T@g)73&w6!%+~cpV99Z|0~+kynM)Dn11+l%0XX$`6++gzhC&$ zRpQt3m@GmIw6>KKLk}GbC`0 zG^Eickhazpf>4o0wjLvXf1tA!S8U6VrFpI0Z(P@pFxK9nXh~j?oCtR5nkC9$2X_=py5##eVk$ySL3@zVYQq^m2=3I zDoS`O!BVhl;To)1cSWd!=adB!R!2sgFU64NwEezZL_+DKiR5S8e7gvc;jV9g7I&)V zdqU8&8unM5lBF&!Q`7lcmwU{cA{|TR)yYo&5|hmPgb4cz~&w1cDM{i)gvD zU+*NC$37*0j+`sN*%HfscsSdoD-ZIX&Rd?U<;{b9BnOGTrY4t&b8!lGM!t851g5^P~(symJ7c$J8*?!)AI)HFy zg9~KvDch3w_r%zWOlc)}$mpNOmQDS@J8Jx`!x>@^r1G^Lnerf#_Z(fbF(kPoFQ{%6^8bwdo7t6FuOw3&YuaYJ1M%`G5K|NKPPamErqW9+IC`L z2N|x0rs>Qg!~v-HGx@%nU+f`NX|Nu|37n@ZNW#;jhT2hQu$~nX7cJlVc$V(O+q}fJ zF+_LBjp|KTG&6S`fIZ}oxSre!Am-3s=zdu;a#ycc`Ccw~;*yLp9u zz}oQ(UxPTceRmK6%;2P*0Qf)ob%q)*T}sP@oVZ&z+|Mj~_28rKq-%e2$5 zoe>DU+s!`5LK;KuyZ9eWXFgEvVX)p(SSnL-29T`<%>B(DO2xi}CurU0DG4VOWwY

oYIzSyh{iiN^y?}E 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 S3Ddm$_?t%ZPkIIGv;P4hJo(K4 diff --git a/core/src/main/resources/bedrock/block_palette.1_20_70.nbt b/core/src/main/resources/bedrock/block_palette.1_20_70.nbt deleted file mode 100644 index 8f4957b95013dd748bac4ed50c3e370729664453..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176502 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

bkIWg`I^~cgV&?1^)kY?)Q07(A8SpTQ2lKpk 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νeHj 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ⅇf_;0AHH<-@xezNx8u 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 D9);gD diff --git a/core/src/main/resources/bedrock/block_palette.1_21_0.nbt b/core/src/main/resources/bedrock/block_palette.1_21_0.nbt new file mode 100644 index 0000000000000000000000000000000000000000..57366fc57f4456dd195497c435f5e5c7b397075d GIT binary patch literal 177397 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�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

<8kA1=h z9UZ82n+fuLdk42aX|)(t-Eo`yfSNW_dEemsI}aArt(@)&y3xaYywcm{J$fd(bC{x2 zg)SrEEf;aG>XL=641&`ogHKuCO`d5kGT`lN|1K5sFQg-Y8#l(xS+hPFoz8&fgo~xTprb>OfnRc8%P)deN!5TbU zAvUzCQQtLDRY$a#zuF?RqPB6Sjy{QhMD@_5u;duh?$HLHv*uWZ*noN-#c)8v+zT&0 zLcaZC!AJF(iq(JnN?#j!$|XNBH1@gyQ>I*8Bg!EY__h)P`CkErn%UJgddS<3AjNwl z*m=czY@V9&XZcf2L;c@3l1>dp0n*gpvmy6rS6 zUUZvqy+QGhv%A^w)q`y&HD6;kQJHPnTwFD&Rpns@nf!hxWYt4vBWa?RoirpN^|^z(>MK`*Vv=fv!vQm zF-M1}F?+A)%lVHXIZjUVhicXx;p*ZJoMq2U?x?-3)Hob_gBx9|TT&_C?-s4hIHb{h zH^g(>V2$#-dM9m*tc!4Elzk?(a8!`h*;C@$dojzg;_lWVLfEn;Hc=6+E|RyDqVi&I zYAb&JdmBT_fSWzald|j0x`$Zw^44S^+Tgh#LuY|0>3+sBh5|ta^Pl(Y9!+*B57`N< zA|DdhJ~xY^bMn+gfg9u=FNUe$hO+=VS->pgX2_S*kJ*ri`p+_Q$q0Rj>iz=ph!W@i z6DzuN=M!DJ6h-sExt~WFpK#Qm;J0lNm{?K0bpgirspsn4hPm;E?R=5ixpTCIdLf-& z5jqtFbKB;pDBIyd}f^NT8UKf?r=S5ts%!sV`-B+aom9@WrE_5p- ztPO{!COBnvnoTHV#rj6mOpmrcAggj%h+K<`rTDp-AUEW<_8+q^TfPy-`B>*mGstBJq!ZJDN7$YGQYrh%1>c-7>RW7Y>T2|`@kKwKTF3%k0ewr=&jYlZ)Dltn@ z^M_7j>3qzDRRE*=L0$tB;yw+>)|c+u$jOnu^XFkPsaI~yDmsmQDi*`vqO)Ju|HVgr zhZ}#UfBJ&o0$Xe8ulRgih=0ytsYzH?~*x1QOX1@fgls zjAZEB4?B}TMb^xVYWWkQUTEv4hPyY`HV^aZ`t1?1uPEH!j0-KOkmx**+GrX!_h8D4 zuc?dNVzk*Myv23ZF%T2sr&Rm4dU$o3Y5u{vf@Mp^TxtkeBNpjEsZF^j`)Vt5&?~9A zdtHSO{E9Z3x%-9gJLWWQ*9YPRKAD$f4OQ0v%U2{+AHwP<*H5)j8&Aa@CmBL~U+E>6 zxb8>M+Pa+>y^9o9qOF?c2Z4yo2RN-1%JQ{A>`tRzlc<+8;^;zq&pyVvFVu3Iuk7Hb zk4v+SJvg9VX6JvX(HlQaM1V;5<*_j!NfgURTl7%2w^XUCNxZVc5!r2MP+X{CcL-8X zM_HsepBRgu_P>ehbf8wTw)YvotzgbLm7o<%i=)u9O!jR!NhQa#8Rnr_mzp9`-803I zjPM#W8rHK3Uv)C)M$ELM3Vm-%rkAmkIm2YI{2)*Gqly z`W=KdkQpI9l#9Nz0RS+fl?X>1{)N(rt!=8E)p= z^|@G{w}jTU2YvOaUd?(I_H5#u)jB=D##nOgNx2`J=NvLbIUYxFtLcqd}KYcndS=+?#V z+alj7v23=Yc|zht5?L{m$m_#~%HCi+_q_>K7hO*TZR|7R_G7pckLKxIa2i%4R!7RI z_zfSn*SFcy)Ef6+z~c>OD@Q}ntMF=&)|{}22^?sgkxiGHvGCxA)#LRRz^W~&vlYE6 z@&*FwSKJnYwPjUo7bU9C+Ts2>)NoYP+KYy{j}N{^+4c?X^`A$JsV_U{7llOc%1pGR zq+vbv!P=#Ie1Qg&irlsu+hMj12`9Q0uxM|wL`H7F>sjiwU_9WZQa-MuxH-m5_tZU&bFJP<1BLuumH8b=fO(}Fl z)}GVbX$QfJB_J^V8)D`|Vqm6zdJk?4*e4MD6FFTtqAdn9n|{&03bCi$4H4Wfs|6s2 zjz2ADfXCyxIsP;O-XuQT<_XYDvKNv9YAw4^pg_LEi0}?beYS9IcYr(qfU&58do*<^&rry(-T`GCaQ93?%NGT&aYstE+` zb#7Gypuf4+Rzg76G@!{>@)1|~1NX?(X8jI&J!!)|0Q!!)=Hchmuk4|vkv(ni2U?fT z@(?-v@gILKPFrELF;!v+bjxX#3moc%zV3l@F#aP@u?{cN`#YNK-SuTGWQ_6Y+G9Sx zQ!x>g`y@|~GNRd0>E<_IqFH0ntU|qr+@6U5FyWb;TlOz_g7X?#=sC4`4+#oEQAQ`n zv?WoCI}J55MSWg^2%|o_wD-$ifv12q;>XApPBPrdC@?#3VhK3z@@kaa2E$82|i(vj|OI6wq3JL@Q;0OHT?xklv@CpVzESCNNJ zi3PzBnA8t0ST~CS+iIeY4S`B6=ZuR&9eDeYu!FEZ`L`qYYrL&qRS84R)HjdPbqu|u z6W$E&;%C)^oiHlDFCIkc|6V}rsoyWd1hTfgj@%R>aDE$aw>V7u7h19{qp+p@4F8Q_ z^-F*dPt(1u5rWJ~n|jzt`XQDl1e#(&1PbM{e41L9Brq<4@(?`Lkbz68QJGJ7&+ z01(cugh{es(6Jf)wxFvs!75>1WQjh5pUZ7%^+L*2H z4}924R3cBvvA_!NdNiF!1NMkstG}VZ6Y>Mt-+`!SSp6hg00WAHXE)<*kMGdJD~b2C zrxgcH1V)gfZvdYs4*3yeOvC)8O8Ec`4##C5#We9X!n{JbJP!##f81MkyZvWC`f|in zFp%z}#ZtT`jsmo+fyG*b z&Ioq$cl}@Ko})k!+vVKnHCW5^9rgBq?xok3sF0S#cmmW8m+3K zN4~EIIVQ5q)}5DHp~gkjNDy4iZXSWUIP%EA^lcI=b35@;wCle-J#n^FK>Y_F2*2+<%oy2j%=tSB9T~2m)x9u*ytK; zsOvt%iPIa)`Gs9st00#;0?N^`Z|w!)83z5?(>y@vOh3O94ZMF8iK!5&AZ$_zm(YS8 zT{Q77rd8u63zQxk`uAzYK$@4#)grDR&{%+`pm6aAg20g8Te}EzL)wvQe^@|L(gb~< z2yOXK&l@}b0$62glUK!NKvSi@TutD--`6UpK^Wzmo7(q<<(fTwbN&I+*cWS{ciq7c zCXK6q%>$uaiBN;&I%V{18QZaE!c0XRga?f#L6h3>^6MQaEura%q^4}e-+|L5S%%yZ z2n?qi9Mgwh#CqwyIcGTQ$%^86%N!IIBJl3B=Tbp>^#^^yg0#h4*n} zt1#|AS@RQd6^I-6Kxi4(D3o%cmL{1;B6+ zhm6ox0=5f0)WC4MfeIiQI2^OBNQ1Yo$1)2Zx%dF|#UZrUy@HPzL6UugcwbFQ2pGH{ zs6$NI0d+&eJ}y|_gwR1DNb{J&bK+-%cnz0!(eZ>xO=>QPkv5_c<{G93!fS?JQ;zwc zFf13WC2LWD$w1Du_%se4fc0XVe(@i7l21%%5 zv=wgxi|MZ6`1A%ma!*9;kOTzHO)pQ3W9Zrk9KngMWM%-z6Vj#7a}PNBNsA;;Xv%oz z1d>vf$JmP1eW0T=AT^$@ad01dUfwiyN(_txERN&*^Ss zHikf24GSt+P;Y;F3av=C6AcMQC;QMq4`3PAU0K868AG9nZ0v#Iy ztr{o>z$u7nz7Z(x`)~X0zD-8|xBUzhi=AYEkk{Ye6lQ|7qkMoj-Kh&{ z%|w>0M&;y60la-e@`g;x2Xywdoq^MTn~&AOI`}$)3mQf&0^2((4j=rBGa}W~`L=;E zkV7lo(Oxs3{}*S-!~X{Jf0cl@3N`!pR8e5Wk5qdd$OzF|taq|>F3iwzh|ETRNwE;l zeYIG+9sliogO@qC|BF3c`P&zfVDZ%{a;d;t88r3NBgm+M8|dUG_*J8!0o@nxHQVxt zz(o`vb zA84qR%XjzA5bqtFihPcJN~_#ps( z%h=!f=P(i?m-mn)z7id^{<)ofVSpDhz1 z|7Dc<;O$M1qSDt_;~86|2UfY3a#$or^#&v=8!K|T-(p!*8_n~%GShVm1|QISjcm@$ z_xXJz$$DhYe7}8FH1`4DM=efMtzLsn9d;ar$}Crz$S6(gUh?{j?`d?;DotkMdL>!b zl$gqNj!NIQ&1I^S(WrOPUoP_v84XDY(QYK$s6{Hv@2frS_)7NJ{Dt|igSW9lnN*t+ zj-=T468BOsuUIBIHmH_`!!er&EiVj@>i3ki1MnO562J86Vr4WH>62E!%;Bhe!yzgg zyhjztM1LccCtwzx;p6wP@`i@*cHO_EN5pTCYV6oY$ae3P@1h_{MUV6RzJCj6zRbl# z;DYd0m>_v?NX_qNaxPq3uICOkZoFpX3ucs`32j!=?2NpIH=k!dNPGrW&Dyjm9rFkY zzi|F~vsUB#=v^C~;^IiL?wU3JBM%{$?WWnD%>*Y!f@rtd?zF)NuiqBSQxu$SJ$?4m zwo;5m<<+!}gEV{ZA$BX{iu2qTF<1B5z@w9|o5v3*ehw*kqAo_4%r!em&#mB?H;6Hp zBnv4FpxvC0#vJ@ss92sG`kYxJRj7Y1@1f8Gw^TmYtSI8sBrYAcL9)5eFO>co+$4<= z#qMZ;o^7oe3-(?R*JbN)-jTkwvQr`B6vlS}z2wc^mlk*V_$c>WU*x{%`?^q1uCPnY z;<=kG?+J9tC=BYw$Z5ULOlI-E5@g<&wzvpxd!IL)wn;nMsm50phs?<*J4X9_(cq^1 z%%PazWf}RBUSpg6YG^rc^t05;)HJxg=G! z!Fb%&R0NrIISJh4iIb0X3Wlace5X50I0CS_47{f2s^1cjnl&6TMgEXsJ;+keDSKi_ z?K1rCJ6`%t%Sa(;r2C2&Q%tv^xM4YrD^^M+H%J7L^`I~?D zF~7o>g%0(LI+M&}Hy%)I1h2Y=q*}ivfEI>5uWV8KDG|-p|wGIQn?Oz_#PP)`x{TC=@@8qNA)*t~F^NVfaI03Uxz8lNYxNbMeXhdk3R<_?i#DIwUq7Qfsdi>QHHth)qAjAE^dYML zom2KUK_@WgFITmINfk5Au;--E>e!@`!mk@vUKi`GJW;9`d&)ywU88c z`HD1_xq~_Ei5>3qoS$h!WcgCxpJX5W6(D*27Nf~QP(O-WFxh=VTEc*?PS~@~n6~&9 z?ZngFL-!{Hw>YBedQk8o zDZ@`SjRf8;KFd{h9v8NNs&?|+43IHzpWkPGE0Aomnc&~lTo?L*{CPDG8AHY{?~T3E zf_kHem=Rcb5&A=VtV+&0@114)c7Eddx8nqTTMv9vrsVt>X^+r+_A4f41V7&M-mf%Y zm;@+A1V-*1$EWQ&qwJ}E%Egda=tOT(xzaUrBcx<^Oxe#7I8`8?F;`)b`)VGm%EE(d z$o<02`;TsM(MODlPPgs#$`5h`cQJiQT}fu=WH7mxsC(}sMY&Y9 zg(qYxVau69zPC8x<7Yqn*m%9B7;k4T?gYOm8Rb`x=&30caTvZF7Wrnv?dLcQhOHmP zVmY9;64Z`3pL~`;fEST{Gg|4Otvv;mLWa)UZ(DO}=?TH&qY(oFqxLIw`gLhB>Fhz5 zV^p7TIzK<1=QxOnCoRq28|hRN*~^_p(ug23s>eb(u{~d&Eu9-OUCqVtTQpHA0x_|1 z?{`$_d{KA=DBXnQG6Ns|B9*qL#6#>z)OjId9o@}Z2AF%1y(@{rz(;b_$lWYSlj&z- z0(JNLR0aFwLGL*E?8G8I5t#D*VSmWEnYcj9J$WBRzD6V7a!7i|*2P9xtE~wOd8aZG zMh1h9I=%y)DBbYZX>b}X2F=3T=(bv*MS=X}G9U0Zi9k!r zslke_WvQT%4*MR-x)jXA)_k2bL`q9z0h)uz5e|Y)KDZ|@HdU3I2{@9-9#%tm>Yzmq z*oJX#50UPzTX0|uPLV7?CM=BE*8ATlva>O5St@L#JE*xEWbr-dmVvK~*>Bobk5U@S z_c#nRMqQ6X*4DHZq^(h;J2ov&8y>KbLxB89YMZaKq^0!3VQ5_0bC~8)Ysn~D$nvk& zZH8wC;8fJ?nvza02rt@=8xY)6W!Fhcqcz485i3|zMCiNVMYIGY`C+h!@zVr5Gd)T0 zn+%??{pOD!(Hfw={EO0;|7nCX2Son0BW^4Fk(x3LhhbqRhrR+rvl@wD)^W;zN;;_h zm9GqMl@a!~ly=LFl194WoR@cxLl_tFCkzP0Omu(=QIKC>{=%C!rVDC+?JI+bp`(%? z_$YuHS+v{ZF+I{0BxT&}!B_v3z{!wo(GZ$Q?3ChNU4yrWu;jo9ix6zoT@H3OfHbih zDqLhMlN5MNw$0M7%oFnMLUTbn1x5NKPLRx+mWDD35+rZ?a=P_z&@EG68I7u}8{1tj zEg3%+^vZ8pHNc>xKtrmQ9H+M+)uADXszM!NpYRyS896bZEo}2i35b!&i=|p7+ww@? zr%Z=--tvJdVoDW1V(@0Pt*491bZ=A8tv9|h>#Iwl)y8CdOjZb|ugjW=kcY%05d?UA z03K4>NJodQ>qB<`y>l9*c;49?1O|4HlzH=(K4SPD?3>vT`S}g0rM5|G%3KK9!M}}Eh#i5hd&=1=-hWUCcR-6Up6KP;CSFp$AOXRl$R(4 zreu1%xIl8>%P`rEZ9|Vjp-xYgy8LulmZ5rFF2Z6TZy#pUt?q~py44EL=L=LMd!$gJ zl{OAbp#QI+?!4%bf0D)aoRpma$ARZM?(slX&n5PGp-I5!>Hnob zi?q#~>qrJ%xG;2T1HcUEO*t>`z{bgIAMW1;a!Kr;a1C_AQf(#u_n`6f)@wGNh%mnd zNY%#t{E7rHGcs498VrlfG-I5WA~S-qva1Zh$$(5c)?xZY`w@&A%8l<~gm-#}AoSk- zNdbThcXYi~CT#i_DLI^NJ~cp;bK?Fj4ujRSPsWNl2&)kJW*Y?xelP|_+H0hupm!WW z9taHY7*vRW;y{m-4;lY0&%W#4uQvl<{epoGN~yVX{3{gJ`pbepDq!Pt&WaFjtxd*< zp^Ve>ucRN8i^ z>9Fk@@A&|MiCgoye*rVzvauT2hboG;rg5hW1)!k@1V_(98U`y~^wotcAIUvBM z@Ao&2*)gtxX*#vBSjTrT0FIbs)zC8sh=q6KybrYfVGiVs!!4I)A+Qdj!wSCVt#^O} zmUImM=WUu)HjTQ^eBcp=<^c*s03<}c3+A@DA%rmE`C4bZ9Z5OODuj-+MlR*{A29%Y z!EyHz+aI9YuHmlPbY?khoxY3u4vmY?*KbG!M={a!PY7VmP>toD!}}gq$R~oWMfYh0 z060|j!}Ur`p-1=QLl@qF8NbGEC8xp5yzogIZCZB?Op`rlZJVJE23W4o^G;jASQ-#8 zP$q;|Yu<%yvUXZHPDW^#L#WKpezY!Me+G7tuY9{L*mTz4tjtWO@i1VMo{sF@w!L!~ zTBP|S_RZ3EDE6$-UI;UgpsjQ($Fl%MxYY!m7bgCP(leFUjNO|E{i>d z5g$|l0?93DQv+EM$eFNKtv-F>%ep4lx#`S6hXaTy1>v@B!y-Nbly#+%FkCoi+MpZ- z@8j8(?V9_rhwpCuD)$E=Ky;( zJ86m@>_OE&>$!M%zTrm7Z{lNTC=-cEpKxb~d;-KjC78tZf1nJAiz3Z*XX`!i3tL9% zqmF5iT@6hwZ!nmA~gHD3Lx!Y>9D8RyYB+@#PgTvjqYxRG^w}(5XKft)t z)QR2>VZ_p2kS2u=b9PN#(?Ik$f~Z#jSx?upd*ZN^f$tZ`6rhjl!%D9rOtO7wx`qJ> z)l&)-JqIJ@xRnC-Vx{TKRzC?w<0$-DnTup=q%Ie;xx=p4Z#D)k3Ci0sUB z-v+`6YPHI#VOL#0r1|+Cp8Dk~aK8-nUD)S!fh8Cy_RMC4CK8G?ZP#M`mu@=Or8WR8 z>eGduAkopd=m~6R;J}+qtWLB_0q8C`LwN{o22!-hqKT<5j{q#i@}_aX4~8eX*+YTC zHjSK*!73N<#A{=(mcdJ)r{qF9hwJzesaCCY#@Nq2Ae0xt1|VSgemvAE<>Mx0u6ikSZKYdm+;ws{>xhyB03DbM zjzeMX0zO_0KRCMcFXi>toG)<2E zMCvWRNYgZb<$s|isKW@6biG`vQ^ZfMPaSHW@wWfA_w>8&_Meb-WX^h97JIJ^J)xY1 zbr-WWS^)kpCW-BNV{b2z$+32tOAkyPX8RRfy-5z)w4Jd<0S>V6l6aQodR!l%tYnV= zMHe57mgXxk$>B=vm=B<@SzR3^Ao>Cw!^J(K51ia+OmpOkpA)af!zuUt!)+3<*tXT> z2h1?sXxObww#WRmaKgQt`s#+YJ2JFh(?gZvi`al;2J^!=A}|O(OP7ZKj#vvD-cq-L zS7|J95%Dm?>RJyUrQ!YCYfUX*J(YoGK1vfPyLtB-^~y9N@zfLp>4lDU^Otq zipj$RJJYtd_8+%t1Sb&IIh5+~1)LB5w3h!fUvzY3`8n_qBdYSo-s=PKuAmvmKl6Ro z4cEFMt;gwkS7l|$G&zN|`$iLtA^5Mi%bh{facrErv7FS76xA5j$6jLgojERrPCz7H3kv zagf__b36al$_H}EUoW){dey7+)nh!%&_)}^9H*4eMu;_j2wcrJcX^`KS3Kh$!7VD$ zZ`9;}{eY$%ZtU}xscKCWk{8aiywLRcso`7tz)PK3xijYN&B^Eu3s=2Qy0Py^``>gD z+~JBB_L4vT_LL$os+d}x36%YLKl)G-qE2i+vQ|4Qm&2@Wk@HQY>y39O%55GKR zp=XmZHcwE5Y2XrGtm)-0)*&QM{JmI)?T_ZX+j@jKz@yCVMm$Ay-QttR#K1G(GU5-M>Sd~Sbtzw1>E ztluObnQ-%cdANu#j>7w0<)Zc_cIrfUMip)CZ{vPN%Rc3q;LCy<=-a;%-_`tn4Kpv* zGTnYft!j2IbecD$c~eZ}z0;f2Q{Am;?&~j6VT07h>&NdiHk$#bCAw#)j>+ynS1~7YYvuCQsq;V0 z;*noOtaS|sP-p7osmS`=RjaO;;Huht;Pq_e&ABzjBm88+ty}lHH;7&Y|2#2`ZFKAt zHLum9xY6D2IiWfq()PyJ4Vo3EbTVyX2JIh#O+r5M6bynzb@2 z)|$pOK}+!1>pR(BIrgi|!cPP}1y2th_ZJ>{p-JE*>L3qtoF!B~`tPMbkLrs2@5Oj5 zYuQCs31^ru?G)Q@Qeez}+9Qt~4& ze&Q3kjf%TDrS4R1?!>3f9i#;h*mJCnasTH*x&O+iCl1GqNiKSPbWt;FeLMV zje_gV(ajrV!mNj8?F}FFgm?HCbAQ(VIB}5=&*eu@i;jiM?74B2(w3rJ{7n8c>#Fk95$AYPCp?8D4IC1j7W;{3VZ1VD&Q9XXy zL3rb*kj>TQ8_w;ifZc-h;+`(UTl`1Hr!~osRsw^>iN52V3S&uMX~{>uSieni-0sq} zPAQa*9XB9Z9;Rnh_zFjE{ir<5bEzQjJ-x%Nsb>*eRrcTC)v^)X^AKzHH{Wp8wLP$E z6za~~c-J_%CiOf@V{F4Gon3T1gUcBjwWU2>QQ^ zg80&sVnq<9%x0}kH35ovNVE*xs2!WG7J?fdYoV6~>$O*Nl7}clQTKFH2?J+0p7;xi z=~vLX7ETeK88;6i9q3g&IH;Ik84TaN}1S&lCaN zg@W%A4#p(f`8(a&e;01U&-!A}KI=>OGC?A*YQBOdK~^l2g3Fq-r!N0|jpcpc<6k8G z@aF&Wt6jEQrEg(hN*zqGru>Ili1p) z*jH)fSufwCi@Q~4RZ`jueT0ywr1}{J+t}59#G4-q(^rQ$%t`18y>;^KqS=;54VLHn zdV6BV_DCjED&MC>;xsTs&#hE9|0HHx4qOtO@SLMDlR4C@>AWzcf*Z-%<$XrOWP$Z| zd7MlAqen)sLT(+tJt2EnUZtrUq5aEdcp`w0nAa$?UfGmv+CcIt%Vikf)FbhETDXy< z-)Fj?cfj-8ax&qYwfY%ZJHv=)j-{l+80k@T$T{iXpC@(MagssJL}yBNkvh3*9i+L6 zt2!GFbl*Go)q5J{CnRSS^m1!eh^ewRH3ymKnQJu&?yu>jNT%eR1Wiy>CZrXrENDk- z+dV2~@4Mf>tSyxFh~&=s7pz}WQo?aMLf9vwi9@WC(%#S+qq~3|kF2R{-Bze+dp-|CsBE3kQGO-*Jk&~1(_2~pUF8O9`JLhI3VZHlBnPsWYJurc-cN$d2LM4D{cIT`&5kf(Un8l*9eV_*bRr9 zO9nG1Hxl`e*IIV+D(&QxYp_3ayP14q+uVB`-tt!>?dxj-xtPy44AMDRIG;ak!EOF1 zAWmQ+mqnyDVaO|HBHd((uBVhj5#W(0M`)rqdPO>6IDV^A!qDV+6j9V{`!zh$PxBrh z-)(;E^P)JWo+c0RlH%r~2-D!E&wmj35I>tZ~PcaQKNDkp^0rdW&{jt3S< z81`9L7a9Z_QvD$CpJ1ID41%N-$r75J7vPjZQlxSu3~{%32j4?vXNc_8c7qinw`Ydy znZ$W(Xi#u6zNxc5k2P*iD0E4!OYxg*>WqIEfB8i`PD5sAV!6A@uCdoiDT(W}giX%U zi_H8bgZ^mMTny#tAVJ%_mS=bg z%vtF5NBh~&T*S7Lm%G2us5zhwo569{ot;t-7chwRmS>}J@>nDQi{?!-f79b@|<{aD}m+iGf&4GAyY*%J6y}%_f9Vi zA7tnIyK9d5O zcI?0iE6##@`r3}4>lcNWn~J7_Vl#TInXyqgUHwyG%+Q)u*F9p+$IPA!Y^9gZ_Zd0u z{HtPGS3k{lHq-AHl2Yrp0%VxEkJWlmp?Y@m<&#;#my2_;EXG{F|wCAaK zV&w}q_1Y2!{RibXi60CIHVa;6AFO)*vL{i{R4=u7iJ#%DI(GQDRKLnYkh9E(kj5xc z8G6MUhRLwjpFb{t@o`+CZ!A+D@>#uREZKi@*}SM!DPgj9Ha0iR665+xxlDGuOS+A# z93e)p{Heu-@7M564<=(|xsvgrl6!hFQ3qS zZRmVKk%zZPY^gLE`Qei62l;C?nv%Vw^tFka%6vQnZJySGWlX_*JVQ4g$%W-DOcuZK zafQKSJ(5THjQ+0>I^Vwa2(K5v!vAy|6CLNy#pKPOo{A#t39tXs`}}@|BGyuyOA+-( zke>R4%(b>(VxI>2%YuE2-)LznJ|3S@`J9gAAwDwA;#TvlZgv>GsyXYSluq<^qI-5Y zJ+*{D-Gm{}VKJ&-q`FLT$T~z)b+_Jg<}8Cq-UP-LAHXP88}~z0FsgwzqWvd@oJjV` zfU-?*HSc6@w2s)NOni;DZqjcJ6cKS;$+Unos3ArCCita8I|0&tEjoQxMXQI%4PKo^ z-zZ0lQN07??O9aQh2oF~lugus=|Q8W@7HC0;CR}}e5k4x%uHt-V$$V#Gayc4?koL> zzPd5n>YtcYli;bxZg;DFb^l#kXM?VS+~<$?`fX2#|B+yz&LxyU#k(U5HIGH5k}V6# zEs0=2W;upb#oJc_11hLAv5-d&e?p(O(#pgykF5BFp4y<@hX_?y8kKFnr_O2(6hOAM z#%qMG|7e2i_EiNr!9@ga9vA2*NvJN+o$PFk5pIm?>Z(Ik-B5XI2eJFgUAW|Lm*vF| z=-x#m)(PL&pZ1{C)VrnGh_DQK5we18BJBn=4~3-2ypKNQ+hb6`nqtcLBox+`mv}OR71qD#tyVG$ zD6Y*g($Iw2Q+wLc+xW08W3$bVoFwN0K|x214=Ep-_(Le+vI1^d;0X2-Q2SYxG48vPg5A+qw>}56Idiemg)ltSnGL|QQ~Cp zb2=0FdP2yn_yd58>+#2>y0DT;=;lk(REY_wRn;>l8wRD8k%Bc#(B+WF4PMI|WWMMA z0r1_9JS#^os3^A)%NCc{?>sgNrZFA0>x0VL@;>RGz$(t>sw2oXw&zg-9JYe~P2Jp% z6TS@_7Kz}aJZ7PXZ>QXKqm8D5X|@^L0lBa_4I>n$43O%#ZIQLl;u>`;yWxu}lq1!p z;2zJq2_mf8H5nGGdOMpd4pt>77{~oN3|)=0Lk^cH$sbgx6mjzAbZoUHv|jV_>Jbxw z^ScV@{=^snYI-9{94twgAzC3Q4`#LTi-Q&dsx@_{zigNp?1jZT@;{gYy+2SGm$L2^ z!9a<&zor6p20wup0SwWt&*-E46h zTfVM%)Qw{~1@(VsT!jfFpujTO>nUX#sO~ceS)&8v3xWdCfNTCt*|8mBo6zaN*J&uU zG%SQcLYk<34GL%pvEH2c1EJwAaf{oG&)`bO`Fp~`{DALiOzJ9haR!B8z*PGx5r9B= zN%%gA1=M^R3=gRF0ipoa39b_vF(_HhXzmlt0=iiDD_!69z-CMPsux^6egnovta>)%F1Za%^09|1mrwqx5whKxh`mqQ;)EVp92tg z5Tu4yFJlAl`Q8K4VEQJ@Ek~%Zz5u$SqFxYkP6td&Ti;zF2c~^maGkDDhO1qF9U4b* z1NJ)RSt-|bs-J?lbHP$6jnsvKxjtH(hU@OvC7dq?lWgby-PTC3*O7;O=r_X=e=ynS zFi?uzaZCXHE()*x06o$%77m0tU;)By+ebxy*NI_Sv+!#C7>=_S#S^Sn3aF-w>U1kaRS*G;xVH z(-bqH#(c76vK8F-u{}-XxBiX{JnefK%M5%SrHqtoU4sJ>nr#;4lY6F3K)o2tj!GE0 z>`*1~>fbeyKY^2nE#NXpEPrzCx7JrW57EIb9lXRh9R&Xd74%v>CI`1ihM#glC8E&& z!AE$T%7u4;$kJr3cpqdWN5dM3L7puX+L4FI!k~D+i}EMTu7tPN8cs=w%d;7Aa7)v` z=Dpl)Ft=aDON0FS*2eeJurlYGLO3C(ZDufqkWm9p+F!refW6tDpn?NspBo78(1msj zu!p;PXRfbx%%e%~Oqc$fZD8AMs}CzQzaAB70&-JMClwYHK&5Pv6_Qf=6+q^-=FFmm zL;gU+lK+2dJCU4dW6PJp=Zn&K(P+uLldm}nnj7jau>E*G_?^?nk3%Iw_U-0rd5 zpFOU1+VOp|cAWZIkl)^)f?_K|0EZ)QKVZ9q3ni3G3E`QwO365C6rh+q` zzlF(9U!?ODdpyLZU>xnUz|UelnAY$M?WOrO>+Xq8lb1J$VR@d`$q^#3JOSSF*;N-B zK;(`fwhFlGKV5`1&Sxs^3Cl*Z`qHaL1FNm>LYRy42y=m?=<(DT6DP3=1!Z`1&iPyC}?|zI|fH&XK z!QY#YFkK8tM0Ct7ei*Zcz>0TM+EoC=zCUq(i)jQ&nQs-_DFFO3ZV>zcMzw^iPt`<( zN)rBQVM`l2zM23G%~P2yez4wv*@$GmM7x$k=j%3M8Pk3rQY42A~C{;z&|0@nOBCB@p-@7>Pgotn3cw_x1A`G8fS4%;Vb}u>JL^$E-=eF0pb4$=}!8 zG2#k9Ag7hNi9ZZAqUK!M6p(hp^+~{tm|S(}0yGTngJYql!NHj$VVv!v1t6mVk<#lj!vXv{cCu zrw>8P9i#TmzN^0VrN3=$@N;#6_gVFL49EeZ7~O!)d{5UV$8%ObBa(qEn*(0Jkjb9! z$!#$Cp|HTmH7z$`4`i3gYey?d(lBnK2(-Lk zgDvAG%U5?J01S9Z@{RWIkwDTR6!_2H&;kLwspZLUqB$C_#1I9Dg7vmi>=0(mr>{r` ztUU8*!Mwa+EA0K@`<}@3qg|GIOHKK()LWmX4PDhyAPow7bn;&EK)h_NY)iwfu5EJK zMmN|VULvv8A1&hmT;$&-+WfP9#h*`gJP6nx+b?&V{)^pDrXl2Iz^hz*EIAH&S4JG7Y{|WQlrjZjD25A+3;^W*y%~I)WBZBwpi1I8exDjmuz? zmkc1g#K!Ra8Q@-^+09|qjRa5g#`o|g{wDV2Fs@9>LHoGhmATiGnN;XqqH3;&~0-aDrI-wHNR9I?B6QBEu#bX!mAt*q}fW zY?41P1E{H#aoYPHwC2_M&$zA?s{fW04EUXY5HNK0M*~lO7j{wN1qH8MeKGZYTX<#S9t z?h=5;XQT1PabtCSViU>XNPm_+A}hDqTFJ~>h>&nh{2X03#Zv1U>iX636V8ev4`Cjc zw4@RISmg?zfqsH>I;Yt1&C21j_!T=3qc(PQ#)~iCex;(eZep#aHvfGjCz#j7sowMZ z{?`|^Od8)uo(22h@ICF^4D^>YT5~^>c+BFZ`Sq{55b< zM>U=HQ7Oe!H?u~W#{|BnTQAO8>+Va5F=XQSllMR`0Igxkc=~(3z47zXPy;JzuW}$i z?keiL9|iqp;d~8t9LKM+*1AGhv&HY-ve!@HXX}E1vG zZJf>}VQ(|xS_|l!-oJS}(3op2ylXo8DNhFHr+pFQ?Z(`Ys?b#d<;3c#^_a&QPuW#h zt^4@tdd>RCVk>iP2+pCY|KsYL!YgaKZaW>@R>!t&+qP}9W81cEvtv6QclgG(&Q8An z>fDWI%u#dB!d^+ORR|p4C??hF1QeC(?wQY+0@bYHi?Y*;m$j7-k!UW^cOf2g#$o6c zZNBQ*FKAH<^bD+S%(BdYJ(Om{u#_K*vckp9SHMyWN?A_9)9@=Fj?$_fD@MM5y>C{( zXu}H5Sk7Op)x-#CMVshYjxfkT9Z_ujM~x;VZQcx3zC6F%K)B@HyPtEHW?b*N+lQwQ ze5$@Q&aG6t9C1J(=@NA9g<`dYmC#)xPzvUjk(!8O+wqKVSYH%q^wv)QD1j!$$v&)C zP3N35lmHiV?WQBCYxHfj+<0Z7PI0!6+CKZBiTO5m#=t>-Q+%uc)rSrxOf#%nbHDZ? zYFSI39ZQ7RRomWnI#-(!52C;D9>bw21%;bxJu?nV^W-O}PvFzqrJgt1?{6IwXZku- zs&lrTr}U<|cj=~bzz+x^ujOC2vB7ad4hSXc1q|0(R1GxxXrVLLir>A=2$wsDQ4aj+_mw;y_P^_-s!B)j zfBCv<1A7#lOn-oaLOuUM#+J_B@@@;bm#LLpx!UItuL1yoqqC&tsX{O=M z!J*6K1_Bg(8`y(1S3jbKfS)>HpPfu3%NC=SlUbKq4AD0kzPr1brrArBoYIjju)zAu z+r6A?w2OnbaGi$$nv~QoREAkrH-y)iG>e^HgcQG;haSF!744vz^}A9l70c)n-I6~C zjZR1T#~LZHc2h+s~uQh zUYCG_xu}>0iIEvIFBu#w~i1YJXq)QzhleqY^>0>SE!8MXH z>wonvtOk~JG<&$* z%ge*u$0)<@zyNc6vz7$L{-bBCH%twSya~m@Yz;<3z|x+BG+)HTU9ltX^Q2v z`(;dX^T!M{n|_ze$XZ5)ul`ijvbpPpx)yYHcC(_W6*D$K8r*e9J>|X~)6C)^H1cbB z-L z%ZQDIWwGRf;d+|c!KfLIcL)j?6G>Q8f@~_5niW>Fs-5?7DBvh3GYh+=eW+m54|UZ9 z?;s+=Qj_xF-XU=D!ub*p+aeO=d=^@=Xur%J9Ovb7SWgbHi8f(;s!X8_JrY6T1+dLsCR(sNAt-F#%WRK!k$iDNI*h#Gyj!STp=>1&L4jB| zdkDZnD~FL=!kZAYK;5695=yG`N%#T06<7aSjzZE`Kr2xBZve9T`ZMv&j-AaQN`HUSifVyAcp(`sJ-VJkA^{*#$?fFNW}`2kiDY`}qw{nYit&%t`w0u< z9CwPGxHX5XTH#1T^mb(R`{C?1JM;P| znva7&BEr?U`n2-5h0>#*d(c$F!!+VmzRc$DfAKBC=RUGKLRM>m{}5HxNvN?hRyy)b zc!(lxKqt%)3r*>)$bU{5AvU_!@R^}g`-wzhxiE=9OlfVxQX(e`k_ZKN7HG(zQiqDj zb&hK6K}?y=?Rj?C2BDeGEqG>sGDB^h@nc!ONH{mOR!)Mz>p3?9FV?vLfI;7?#rD)>e;vF=#q&x&4m6 zhpiB2%rkVxw&7D|2t~Vz6+b`Ee{Xrb5MJ( zJ+YJ?3f*elwMnpTkqkO&-8JD;nw~<~x%zw3D!q6lntrFD_V)IMwsrP{<$QlaE>$2C z_eVdJU77(+XMseqqfs8|KT@{t4~Oa&0!X&UC5MzFzp+=kn4fa(nk3Ok6ve(&AY%5(Y4dlcYIOi>i~R*+ z!NVRq<-~*O141wwKF49@{|X@(Cs=$a^YalgV@pe$KVSkU9P|+}=ohSER>`-OsP&C9 z;7gV_F<}Y-F2SH=aXmx{DZjr+Qj#vyz%LMpx+(e1ATd}0Hc&vw#B$0K^bAxH?C=I4 z6s`A-clLb+-Kq~D{AQ%XpAL3-1sB-j7L*+(iy-Xr1t8|B${u{bK*Q@pY8Sw&MEmeq z)FCoK(e8jqqG$z~Ox+xtemz4%n4T~j57+aD6XpV0%{M0~$o1@|3*2AjF0=~e?DIJL z;S#ZQwT6UF7Mkxp(%5n*L)3*FuK78QSD09>?1OoI+FpFoIfoK9^no7FY?;O<0w#}r zEu~!ju_ELwk9`M#;GxmB3fT_UUQg>T1@ESx*j7pGacZI z+P4NUyKD!P4ZUX*mseswpf84X{X*(1Bd1i}iCvu4XDZ+2##5_1!=u_KjacvQe?wnM zUc53-94`OZdy06{sk=7p-2&ukxNLHpY4RIQ53w=lPNpth&lCp$JF?HSaWw(ycGy$T zfqena`zv$4uXHOHx+OOAhSac@e^8a$F_L;1rFe7C{c`6EZ_up7LGMfG8mLqSBNmKb zv(Twrj#u2QSFj&(z-q=n4NImeC8z^)>AN_B>F=@^4#VADv*utmGmL zEum1*+N1iu{9)OmZ#YErLb$KNq(b@QF=D>!!dNo^wnif6Uv%OmhW=DZ3-@-BD-W}t zRPeZ7${t+g{RTE_CN+}^7T))EfM3tgH+w;ng$i)-=vvt3oJkU=a_!o~9{L-wkUlR` zeUwkH&FUdgJO#yKMcnIBCG@e?e%9-X%%j%$sOoA3)4Cz8b(ZrLXNy}_e^Ublh^)YX zYGeooLSRc74Lt8zmI0>^?+f0rL^S$(X+U$TDrnZ;!icqLO_4viACW?+;17 z{#iSlM4#{gD-)frL9jmpvLUDe4LM%!KKA^vI!O3Vrdqx5Dib?|I$vul7lc;}7?9Lz z?Hc4N6BC5`G~WGme@?JK-}oHWy5TC|z7KVcz3!vF9324FN?{IsmW~2a#edXQsXvo} z!!xOl=BDsr5rJK^j0jba+Tr3d%q{6z*UZ@7cDNcAS~rN!-EsU*#tpb7b7yV}F6$c3 zl|E36?Q%4LuFeRHyCZJ)XQ4qTtGjdmtJ82_jQ!Pr1CJ@WkX*Ck`l+oy((`|T~&6z!c2Zf|x!t&{&tTbCrfouO&@)J1Ez{kX)t?Xqnp zNl&2c)NU`*YFLiqSQ@Anx%cLSp>fH~V2*#xWFb4_5zWo0?Kh9^2_eGD+#sdLG8(to^NpX5*Yo35Zl_)qU}JaZGMFAro75wZ$Tz;+LK$BkY~&0 zD^LNhTUREOv`NTtZ4Ww^qFj!peK2yn7TaG@_EU+(MpKWnYY-el^=<1Hv844Krn=FO zEnU=RZg&*c4#~p3P;#0h9!7Kk1*}X?&4}!nhCxjwm+Qw})Lv|sDQgpST49%&67iu! zqpU%Y2_^#2smA%c8C`B&d@Shq(HdoKq#!VlMTZ4FywIpC)}POyW$k5`^MXSxI=npS z0LhSMSzCyyns)&}Vgiu-BDoI9h z1xcjdsgWe+pBr^AE38T4wW}+d&vfEsN>s3w6Bf5k;=BV!oc45`sUhHHE)mVS&G12H z05iN}C!pw~-9NL>zqpxsQ1h;FayJ}M0FrlJ=A4BkFIkX(`4pO=!%lgogAjmOn+FPa z&S0!29AMU#!`Htjf!Te)2?2lK1&KG4deeCcm=MmS?p$|Ow7mhG+;aoyb*)oce*hi3 zbIsku!~+SK9O{C^9{pW?4h2jOkA$w=FQV{!zGyrEEpTwX{zdb}P^dQOdkTq%k>58+ zQ+2XngXwr){7T=>?xLpjrhbQjuX@*GH#aJHX!h@Uh6cC!^A{I3|MG1>02`~R9PQ2q zU?g&hW>d_oU%w3wWM#EGwV7q}{+9*!Gx2Y@M<67`wd1%huQ^Hsne}Tiay79PP z=OukoV9+^UloIyG)Xf<0H5|Zb+}_ zmJ;++E}E0@zKz8OmY6wio5m{o6I^%{TD%b)9AuG5&`AQ1I_n-&jzl3~Myx&dxqq!ruxjvuKS}T`Pb`N(X z&xq{Ze;fQ*ONAip!+6>4HlPlO1FlMw_kI~x6Ka>LYJ}@J;6?l_9hoL$qvKL*_xpJk z4i8fk=~nR2mvi5@!|5BV4(v4!9C&)?E`oFR3A8Mn%V(4LB~MXFdvAAbR;%N<@++CS=X-ohsGa9%=lJ>*7jN zYgkzh;Is${a}nVpK{5ouMew>0U`j218RxXiZu&Z9zzQB}2nFr$GE)RiE)ZRg+h`w#{A^EF zipLUaBb7FYV3@a;3XpM0+1@r%mnJpWGn}xE^p4YmAYeU6_&DxAC0wW=x^sMaft%*8 zHd?kZ83^?B?ttZW&w_-P5dk;LkwtgI*B=m4BK?zI+Fy4ZnSLdIDdcce?&R`@L(0AQ zD!<{8p{LvP8xsDW7sV}ywD_>r5b*K>eki+Cub5)N+&zeWFZSsnt6kb%ekAw8%}A8~ zp8&3(XDl{T4kY}^(}F?3T3-;j%iFOci6H_q-r{ws2}^v`x9PA)dg#kU!Pz=Zf`td3 zbzM4pN;&rJ=`DH!2aqi12go%1+Q^rxT(NgXiTmLUtN(}~y zncwA5ou+5<{yF@?^jl_bNz0MN!EvlRQ zt?(@(sg;#B{)*g0-PuM78;d;swBWpd=J;)d8{ETU`U<_Kt)&zCU5oeetr%(dxY}Mx zJG<}d9IM?(^L-}@IQiP^I}D*(_Fc(8hha=Vu;xyL|Fy@q!HV6ND)!@50R0Qhq_NIO zeanaaeD%It5Bc_9^w(FTnf-|X4^F$9U5saCy+x^GN5_>RFAf@g+6Ge0CKpa`Nf#xw zdaq7ydU%~DZg?c})X34fpG%9vVky7#>uB=AU`E>8p1af>C|c{VpVE@2%)oLFQ$}=a z;ck{8*|(@_!G|mdkrZ({wCzZ*5av`l(MkRnH2LHK^4uU9A0i(g0moMD#bM~Oj?*gc zUaHF@%SR_*q3b?n%{zKy9w3N=Mlw$>Ew(Kj#HvlKN|g+?Ko%#R>s6A)+3-M_aGXJS z@7$q--zBVqY>aFkW*+n2M`~HeVoIT73PGo!^BCsgY$ehqTyxv$c)!GmD)T)8*sBiLG&B03m3x9}=|5?c z2||lDWhrtQ^xcGlvBL&%T3IcE4q3(y-<_LEe=<)i4URBVT0BB#$vyY@s&GSeZ5sPq zCJvjIIr$O7rVb=V|5dobE2&)I%W8}gkEP_so9qWR1Wh03wRnU1vCgT$njHK$O~>Eb z8T*ghf_48;CmR$qP2|&OuELi7VF^n8H|FMO&D+7U{TGZ$g*X#D^0l~i%B9homz1@~ z6NOUH;@`?N;G!uyww{Bi&smH+!r}pLqS2QlIp+}l?i7SmAY1+bQiEeV308ebSwzKb z-USMXjUu2=BxOsR!&jt|AU-Sb4-)b4$wv|hA2=@}Pb71+vsq%0qYZDQsYHLNex1-A zVPUzSw24Fa>`ig%I@NuvekO8Fzou9*0&T>OCM<$qf`#fujOW~ zpBDmfw|Dy*9bO$%)Xl5dnIEr;?BBKrh$=riwbyOW9;cGG55#plwekth@ylG&fcHAZ zk?I92Si|me2b~l61Pt30P3K;d=@H@(9MDwLW(ZxN&$k|N{Ni}1EaIRX{+S!ovl#C? zYEDCc6doz*xuDfKoOalD#Z>;vB=vuViFtq38R$Hw6YTSXPUwLx$VBPIi9 zG7Ba&w|xs|6Wa4MUrV)v&;mv?T9I;Is(F|tM6;Gm+}x%K8@TqKMpiI$;XlQfCDBEp z>ox0Hy3M?t+3_OJgyfq3?tq-7ETM)3Z_y95$q4<3=5v;2O~Vf9jl7k_)~DV39Gkb^ zt}}kd6sHxD3GC3f1z(!#gUeh(M^>#hgwclQoQyvaQKluM+0>DDv*xPC%ts?_i5_I6 z!*zs(91_FXRT$R>OjL{+OePy+P?zrYDX5rJ$BY-o_ewc9d8EiUch;=BZ!hdrjQcaD z(Zy;l4TM4;*2@+iW^CWo(6X3X{THSB>}(1Q@PjR)t4Z+c#nLV;BkMdYho@WQmCu?7uK9cjhi|H)lDlvZEAojYnZ4M>Zv z?+I9wX*I#6$FwAS&*5n`#iYkPfI3`}aP^|z@MA9*X)(F_PJmaNVgIH30yaXA1T3r1 zH26)vmuy?V(d;Z7|87_i&D6Ss(rgiyPQAYuVmG-*X1RKI!qv>~(m1XqOo1y0qS?hS zq+E3Ff`8dsOb+_czHFK!fK^gLk*%W^*+Sz>;E!4aGmTiO7xhei?hkUPE;Y&P?AYg=b;DX|(;scJN*4Yyjn=4OjEhPP8v=dIqeaOT+u6kNRrfh`WF z;K+GHTKjgPM(=#ApjqXo(h|B&OKJ=yxB z)z&NcT|*y3(&!o$*6hD@vz6Sj2%nT4qn;W_8VMEU%-Rp@N*`N?Ek=)1g&0U$0Wz(- z)rU7fMzdbzpe?r^Mi{lQ4O?_#>zRR~c@Ma>n9MvyY+{CCJ^85JTjmEu++t)|ftTn{ z0t*%QX%J>|lRmZ&Ta=|~Q49VG{;GF%-=BmRD!$25pEt$AxzEfYe1bP}f)|Qbd(9Ia zGj@0+ovG=osBS)x3;UxZamGx%aRmPj+B>1ZMN-^N`gb()SG zR6JpcP~`|KMHwA=us8wEbz8O!)CrX&D5PnG;4unPGl9Cr+K_m65ZAq#Osc&a@o(u- zqOMYGU@~T<#eccs7)-0ky4umiIo>M~282>7B@wa&}cZ(7fvR=aw6!XuoM#TH$&KYbg8 zF&dwOtvj57D^9KW2ReeUShr?k`>u~;Fx)nK{2u&+*IoY*2f;1oaUr<*wo||n!z5k1 zXE{gH?~(T~Rm|$+0mz({AD3!faS7|Qw-}p5$fj?*U^C=R&}xB$Y7IZP{Xs5$9b^n_ zYfB`5>M1=&^OZ2{xnc1f!K%Ia^Ys9K!~|3tEUjMfe+U&5M2c1`|FI7iQslUHyABCdGaB8)(Z2&w?fUnR7ieGK)+MSDM?BZ`6#0KcAMqx? z%>MrG0w;*^ETy+GgO*-M$IU0=dH4k!m@mk45IepYyqUz*NY} z^ME+lW#Nn6`7>#z4G%-J`Fq`e4?bdICF>2=qVM<4ivOTm%g^m35PVwcwUP5^<-c8L zz;LJXpw1oJdE{z9TYiLIYn%KS|F9=Fy%MRqnEJdRD4kbY$TA%99O}z0I9H`mDBrSg z8gCsQ+>p5gHGU`q(Fo$z>?7E?`)bCv-dhZW=d_C5|9!$k=7=})la-t7yh>bGzrBx> z(L)ZSkhIPQ>d zN>n#^=6}?N?g``f-+>8Vzy?o%>UUMOSaoRCXdGWAZVQWNOdeNx;;1xQoNNhMlH`Km zLvFwW9dyJr*Sk4KyW!Et4jh^~%#5=WbI<9z1Ul3nbM?7idbHMt#jDw?OzB(&tS3@m z3#C`1DjHv=*w41j9toK`N8gca)eeZTLI~8U_r3L`V$~C{lyzC!&Eu{rB7OAV7pk&& zl0`v)*Q{15g!P(MSz*N=>| zYB)YQ5@3cWL^VvkFmYdlgsxg_?rp7Oy$1;7L1}$W68$~T_t{6J<(ad8HQNPW|BEPa z>fE0u!vm$smVy&Np5_C)`@z;|6N#Pip*>`iv9FaO`5(*ELLW*gKCx0NlBBLl-LM$6 zQkSYD^?#ZnockN4zviSQ9uvu6{`<6u8;K#=mmH*loTJ8voNj5p-4|2mg~_rh&2l9l zxnZ!kv>=((0_jBvxVw-^bNz330eogm&VXel1DGae%Iy6$6Q(4Cp51bo4M%oHU}0L+ zh=hKuNwNG|hM0|fP?}EOg&5N0z{;l6dwM@oNpxtM2lff-#O#2imU&Z_5GvkstRVKB zBlXdA*^pR@tI@lo&o`uh?x~dS^rj)lfIX?CU!`al{+l9ty;#p? zXJ;?;0N393A=?~_zdMZgd7OgPTKoppx0iVQb~%Tgc7{V;ik5F4Qn%|9;MC-skNUDV zAp2#bGrKZ-nJ-#sOtiU+>$}n`QjzntFS2xCqQOnmx5aFz^SKi>bAkJ|D<_mB5H*Mz zTV5l-C=qU1ZvK-Xt+o2dNZ6mzIr&dw`ThBJ- z7I_Pp*Qab5ezMwgzt~R- z=0I)M<2YbcLTy|%A=n>$c!AE0Lx67fHfm(k9*$|+ANfgkbX_gw zjPhQ}2z#`a1}jI-DQki?4c<`MNbV_Zf+brp0F~KYXa1I0qKB?M?NF+RW_Fyb&XF5( zSJ^kuSMOMZp;|;D_4#L7%k>p=eRDK31cM%zcJCYjT@8^Dby4v$H)_~Fq$ye8Cn5EWEk7!V(tz*sL-K=q&d#fYB8BydRM z>XyhnZ>Z-aKf!(HiE~)K$cB|gLxJCw!dQYBNuEV0h-0B}3X1HdXa|HQ7!=YO0z62= zu_&PuB;pjTY!&;W68}h3sGI?Bk)lY@A7b+V*h^G0mE>SI*Ev$M{lN&T${pW4F3u9~ z@)GWeobO!;`7vD@NMQf;r}nPoD32l{-QsZ6)xHQ3l{$ri5fnI(20ir6o%~ zZG3iM5HgwAsKLf;H2R<3W;T*U(7&HTS`)D5^_nCKX%I5^f2g^N`2&@lVeN)-;1))Y zxnfVIaAHW!K%r$DZSBzy?U^~K)$M_e%z_z13&$+_10tVTBqjlh5m0DaYr%YaD0bCu zrM&*~%A`fc(80SV%S+WLL%7gm3tak|L-|Adw4CKFc-%FHFWW=r{#-H#&eTH3l4K&f zA~+M$@{S%GD{Q5UzqSfb3zUHe>*`&mUq&s%sI%kI6MOHY6D6EnyRyNF0b+6d!kLGI znS&}buh`HoIqNU{SVXXXY)Y^=<-$F5s->BE@#wY1o{=nu_r!cMAYAgTqSbOc776}) z+a*|_4VMjr;;qjaZ)V{N#*f;`C(INuHx>t;Jx>jMN!|kmqd2}H&B28y5YaTON03ja zO>Vdry1$;Q+zzDs>DBLT__ipgFuH$TUDy#s>&JIetNGh`so$baReyw6pIK&-jgr5? zLa(DtmB>;9fR=Nb91z+^NHEQ>&lYO`57IyH)W-Li=1jFT`{^_zVGFF6^R7GT=S82; zbo_pU)2{6yJLJ%QgE!R9PwLBuAGpE21_qrik?hU8Q)xl1HF_L9^njl7IKA&q$`s)KRiUjrKd?h!Sp|qFQY@ zrA~U`D)Z-R3C%Hp6Hn|5flOPK^GfIV_^txaP; z!eCyScgX|~7Ix|sk8~<1z^25B%MK>dR9ZL@asv)$un03=+l&|%R;CA?bZT}$1#Dqf zp3EH=Uqga81WTE*Sh+|6se*pKu&2}a({-tkG9Ldv|$3|H;;i6@RP$&Iwcsk#S zGqehrzMQ^C<-vX3Hp4tBHd`})uYLn0uMM2Wz&-ImT~^R!uI=oeH)y2VY1V8x~y%S~^Y1_ZB0kGbc$xYDkZL=wnQk70e zVq?$!+$ws{NPPAdx{Ct7P1oJFIDkA$eyr&P$gg3Q*a}}y&pTUw zJ5-puTGIB#!DEgql5Sf>FetMFq7z%$;*-fAI8sE2IRJOcO<`eqz2))l+DWoc+nUKX>&TTt}--C4o_wCh@T=#qQ z)=gWaS*9i#*j2L;2db5o4=9;eSNxTK4vB{eh)hKa%H=|TtZ*I{PYDrkj4u%MonPx5 z89>Kqxp0EC4Puw%@GE7(0nt)4JrktxiZ!ah0Zn`9!e)XWv?Z4a`M*At%b}<6hT_>S z#;*&hzux?ZS#{HR9Bk($9PB~A|_l%ce)))>_8sI$Qrn=U43`;;@5w1EP z9>G&gE8d$u@ewKPs$b>hS&rora#xW&{??1BSe%6MizL&E-f`g|*N82yQ?^}Ayq>-C z;Qv-;zUR_k8qA7IgEO1wvXZm6ZgbawM+iAhV}MO3X&9=lvkPt%F7Vne;K}1;%!Ri& z3Ub?6NfEwyQHFvryWPTH&n%maCR?s_R{)W&4pwoaTWFDDws1ZCiOkui;3f+060f4v z`*~W%W|jsz^a2O?^nFR9J}sTFM3_>(WB~Y*jA=L)uUs_Ro$*MiMu1T~)?mJp8C_;V{T9pSElu|hIfw}>IgY5=7u#7?4lZ{VGcvzIiz z1Koa{5x$Q{YXH^!r6U#8|Mw3?Vr`F#6g_TOZ~q@RgxbHg1%+Du;SqdJsA}MUf-?zJQza5o{%q&Q4_j(1|CD;w0&tM~i1?d)or*nOnf&HjQSvot9_(z#9xv;ZkSL?UgGClI%ED ziTeduN(xxfHcErsada{_2(jDb3<4^Sdh-arKtx&v2lRzfT3*Z{)Jxx1DFTOQFTd|+=&_8$NxprV(_oX{;dSEL-GG4V(axu=&&*ZS*vEF$Jk63;Qai-`X87`E@P zmImO63$ zfR~ATD)qDt#0B@ztR*C;x6eey2>&pWMi}hM!bq4ilKWAS(x~zra;ZTi6W`+-7|-DN zoGRqjXOFG0Hgz~x1c0U$Ca@-gjMc52;>dk4Nbi9@S4H^*B_+{FU}3jO$PWyK;^6cI z1M4zS;h3-*%)!&#mz8fJSQol^&!5F0pBlTIi16ZcR*XtUy8o#Ne?jtomN8Kw(rWZ-wevp8RvONQ}x%q)A7~(wz*s zS}+FiqVoO_$hL-iBj9hdl`Q23lqdd=G=G=MBxd}$(;kf-Tp2fyfU5hpBx5+Kyx4{@Y7!)>r}-aKT+;CGr^lkZ zP^w&Q`O-K-f2vM~H!GCv+Pc&^K%nlsO>f0CXr4!wR1v42Y8{d49|sz_RZ8sGFE9&M z#wV1hdX02zt2-^;ToNn6(`{IRn~s-9SF=@|R~kGtSL(E%RK7qZNX)b^+1dMa3k5p( z=zI{ataKVFP!&HRl^+-04TH-SlKQ~Da^h+z{%QUvge1zJ*o~D*WxhE4j%Ka4s!dVI zdT~!nyLuRb(d_VOTIuyy`&n_O^xkx@eIZ&(#gHR^J~PLK2eFEHDA}hJnd@>=>j}@p zuVzr4LSLK0wnc4J(ppYOz7#b)J;PIDZS#_(X7i}e`GzCdQ%j3O-THlB@*Ko8Dx`w> zzFfq#U=bIeEcse!6QsTRLwJo8^&qy$=I;F&@zhnZbxYAtko-#a9Wq+86nr%~l#^KK z@ZHh~Tu897CYX~LJEtaI5F6=e@f6{FOGbGhY2$&Ol>NQPtyE`fhlkU1Z~Jd|=02?3 zhXJ@yz=Bjp&kQ;kEAe9N(C32G$P`nRKTi~-EFZs<;Yj(`7CdK4{)0rf2i^9 z;&xcT8wD)L4d;GjBX1P~9L#gnyF{*jD-nu!efOlv((!91&q#x@{I*TMwYrhKmqQtH z4d7xF3(no0IxtYOa*&v3IX#NHk23b?%n|;?@(&Q4j?HQD;8xZEEVS}?zN6~i#5d6Ou z-N01VAAc9cv0DJyCnrYsNzvtFBW39_HXLOVs3%If?vRFJQS%u9>ckT3c<*afCDz8+ zo5_Bb%`x&_{iNxo|Dd;!wbQp{1pWMMjlU~@BfEYX_54Ha&@GAUwA*!kC~xNu#o)G3 z<|=1r{4K_je)Ti+yPw+W{}}Nu6MdC#5Kq8c?~mKLODGK1S>EI6Pk!DsmbRI1Mo4%4 zs@F=j+>aycxEOmAU$(#5+KBd+GpBL-Jb{j{EM43{Nk)SfvG}>Rif2wV?$5+QU)|+7 zm8Qs*s3LK5Nq$?19aA4E(0@!}g(}yoFGKP7cOkb;?@sA=77poYd(xzpN&DLh8Rl{a z4d227e6}B*XggHN``ao|rgUJdt^St^{l`>Jndj=sV-+ONZpnB-N^;*FHg9~(8K$E5 ziC>!=@ASe?{rd9h{)%$_62Y-;3LbOQX09{|$;Ne+^xk-TT33>K)~66+qlnfT%FusI z#^YQq$fU7E{29a8I#LVr?eE56Mf!45m36GQ(z@6FGS4RpN>)$e?EcM(v@#2j4;W^J zP2G2v$tBS*F)U-o=rsuq7XzlR7^qo23EU0!PhwQPIKv_#;8eeoe?t=F@MhunuP;~M9iD70Z}< zqYPkJwv!UWwtgoHS9_Q`p*@uJ#x-t`N)`(kt91_~wsFnK%hHK}-@{AJ`^MQ|8d;gTq1Lf74M%>)7-JP*r&`+o4AKlg@^7rH6_Snhwu zvdKL&PLnaIv5;Ka7EE_gW#Ym>E+a4Zh76uA-22_Er6=scbcyPGlG$a4QIVk=*GNik zZ5F+(9e{`_Y54ws%d?xFmOTK@Lyn7TFBwrw&?K%%U;pp~SAvh!@j# zVZeB*GLtvV?W-F9_;i0q$zX&x1^WCPc`bFa(5ot412ldE%W?3%awgBySSM>pN_w?z zf}0qHUi%aE_egFao_RY+ud)V^?R%?-$$)lRPJA4s1>Q0VI+v8~*(BEGg}WN3(hUVX zbpI^RlbSRnNNjBi&w1o7e*`%x8 z(DmK+&?4_ z?eG#Bj)jl}gt111uq@sn_V`FFh3XV3k+APXE3u-Lspcud_2;jcKXE#pjBoJfulCFA zCmB}{#XsGNqW-^ah*@Og+u=2@{N%XzmarrRO2ABp4|g;2fTiTpl=Ik0P_U2(Nz!R9 z<3-!VNkZ#RelL-N7843KEvRX>RO*#6^5M>ofsB*nyz00Tj8Ah;$G1WmuEc>shH*b9 z^Mt$_1$vzWg_-k{kWy6PCgqMj?WQNS_MIdM)V6G&mm( zW@%6yh{i>pRCH8W&rb*^hO$`;q@aHX=Mb5w&L3k&Sw#E+CBpQ$Q^<@0_a6mTxaUP-zP+&A+=$1E z78VrQ9SVY#0r|TuV}9_ zWY*^v_1@JR&jXHIOf(54jo+B}@Wq80N%9xMnS&%P#~l9C+zbcp$qFZOcw^)6Wxd-nkGgBuyS~ zg5OjK9iArNCD!99gO0|KZ;fZ2CW4N|kngRh*G!>YRL-vxH%{~<{EB^4 z0Cpy4$w+lFyaUM>vcPSr0xKkgz?J;`3$DfJ88Dl_n00ePSx6RUO4%_IrP%i~cveza zbI&UF?u97-z~y<~&V9O)nEBr@ZoR+Mp>d-Meq?(}QWhDPHm4Z=$lhs59Q>j&kC6w| zTHx#{WIeZb#XR&zlwVl_2Kb=D&h!J%D4z9EB_bO}0D}ir19;~NwVWZu@ILMsp7llq zW$G7g)BujWINrDjmR1RPYw_gBFjZ(~mG1EGy6y$?w1sJJU{4>nc6icYIC!Ktz%k{- zI&eawG)~;Zf!4-(n-d0bA(QISPFW5Bw5b%YOV z<7|4+3DI-+xSR_=d4%Y@zgf-tw5kJux3mJOJyU5r`qUPXRozT#1*k)YSN_k;Oge!H zi;G~Wv!^z*XO5|E`QJ-a?hl};?dX&>P`woo2aJz^CC-g?wQ&=GuU2Zyt)*H{>0bG} zNS_^zLH7Vkxft_wt1-tbKOkeS;ErHoQQg3}07b3u}eK08`xY8DH`F%=-F>x7+9(T8bwASIY*(X4a9O=`k20~6cC)-HgtBUZm21Z(L z9YTPcubFT^2SW}W57r1|w?eKYFp~TvpwR7v!j_%y;x)3mUATs5&$AzsPC-Q=rZI4+A7%Hv;d#E5=0=0fp_3Ja;fP^f%x-bukBs zbsiLuAz+^IT41dLetGV>!Y<|5OQ?X|V7!Cl_cbjcR;7-{~K zInrw?3ZxS=wK?DE;QvhWKC_?Jc-J!${9P+xG%gZOT!MwQKslwbgHE7gPGU*QM0%nA zqBb&+ZZtQU(`IyU*F+b@fi@)_!KM1tg-dv-&fG|Op+2$q>YCSwbhEEj=@sm378AVD zigstQ9>#&@xUIRn)=c6=ZMp5(W;@)VJ{pQlX>^AB3)P~@5|)68T;gacwkx-VdOKoh zLEO6WF~z=4pXqWMBl`K{9U)ORJ!!dCpI{1t{0bK%yo4APY2NS?%ePN_@dE_fqNgi> ziyjG24=Z!?9FiXCo)Q6Ve!oZ3s*repuDi7JxcWK4g_!$-XSgu6nQWR93GWfFSH_Tr zRzqxHZ;N4FtNW*DfrO)Tog;|0bl5%E{Q5p%<@#mOf&{1phOb75T4S0GSHKf3x|as> z$jX#??4izdzb@SI9VzDdTvrjtD)e3UHfJGEMmjFI*Rw0lWzrlTrym8e?g|rtoJ0rr z66tP50BDO^*;lFRjas<@G!7cLmq}RQNz{Wmk_yh5$`v=qF92QccXpMZ3|@1Ifkb(9*v z4?4{d_zKNv8z%P<c!p)6976A(l`%0HjC8Dch+C?Am-5KMGjkm_ZXk{mcn3flIX5EpLvuL4LE=&9K9SF+Uakpw$MFImC+)ik4*)zdH zO&K6jOP9$uQ92@=PcX+gs7i~C0jDUKoJf-|OWrHSi{cUx*a_oJXgT|C&9qJ@D4_;6 zcmUhJwrg@opi?KCNAvMBBInp&`pyXGNSN~4Vi>2>-YS#{qEL#|2~__4Posb6>Vb%i zb)8lEJ&Y5zh4p&D9M;ex5|U~Y<^QC4~j(~RMIZ!svIN%}4h^7D7!?1QHB zs3mFrnP1vg57Qpik^1;r_lZCD{>DyXJwEa>@o^0Jwr64?0MlVT* z0HtD>gck0I6vDvHQ;43p@FnPW>LFnMT;ozbG2dX_p`J3fLhV^S;kY?_jSY;6X2aZO%h>i=x{MgGfXVJ$ijTMEE)l;$ zd*77jDGz^&Kd+?)XrKp-zv;9x@v>bGzR+vya4i zrsEd+EEP(7K<{q~Z_vB#Zz=K(^jDl0#3E!a z*`LF&y;JiMpU9V=RqEwJAK{7)o11b{o^iKAe+Ik#C;r%)o}$_OiN+_E)4@-4$>CX2 z=JHzLO(@P!9zF+e+^<_3XK3U@8XC6C^ydBdC(*T=6Q0sL(AavlXx@rib+^W%w*Mx;BWyIZ=u>pfh5|M%P6*@iz!N)`yf>UTP=c;})Otw`b`|FVeHVv|b1tNOQ^C_*SuXV@5a`{5<9!wLh1rg+*{Hj&mDFH*Sm?%y%bg&-XYPewmg4r`#50^;#tnd zp|Rpv{ZV;GWO39R9%Z_X7%+VI1%&o<&U|8vX>MuyS8J7Fo`h+;{=;r!!>-eekAhyV3D^X|JD0}G=@05v2ClLs z0wecHV3scZs2N~gcK%yk-1x0yVSdV(MSlLq4CO`L=O&OO&rdRN3J~vxYCh~Q zTr#nJji^zLexX8`ZX;@z)qRg>mhM@^ez*H;hdeCE^0BN!%&e;O;XeImVzUC8D+jGs z?N`p9pT8g|9WPD6(jFPAglWp~%s7>FEr!}Z%y@rLkbYy6I&8T1Vh!3ex<`-IHgGVR zw3Mc@Q?kr25qvqe{KB3PEbhUF#Pe|S3FWU<6%s4A$3z~dnROMfvBR~SQLkQ2&v8os z{NQFRo7v8Z$jW>K|MJ$Kk<~jhMo-gWN9X4eL5~ew*8IcAOrPr+XtV4Qx7lVSd2!7e?JCx&-)QFZZwDah8KBL-)upeU?E(^|XhI*b`x=OSG z-!Bd7#-87YxkQgn9&0R5${PMbXiq~Dtd3E|Xyg?4^^rS-I z3PIDeZ>W{>av2|tHJW?YY8wHs4-iXiEr<+yg+$wF+UAF|`jz1-%h2?8gaGw5rn6j9NGVISpZL|GIm?*?@GbPA@ zFqE<8pJ?$;q*z(}d!*ID4v+JFNfY@8Y!ws8D6Sb!g8r{nxRQ8+pJW2VMDl6Qf2Vt{ zl-`adFmm_H;3VCzz$APdlf07Fq)hfP+D_H!i!rf1D@JjneUzHlIXpLxob}aKAQ_;w zHAu$kirz1{{n%Su+J~(Y8+xqWsenv}&;n>sc8*1j13Ul-_1>1!KC5E;r?sO6irY;n z?S4&V{Ax~*N^Q|JL-~H_S6hI^QHa7p>G%D&e|;{8bdlAoDvlMfL=Xyk?cp?ged|+bQ@+P2RxDyg2b?3W?{#%vn`yu}HANXx&MEHbIoY``J zG{h$yNnutAj<;c|1SSi8-@m(N%v^`kmf^&?!eu(2)~vl>6(ym-a(!x9$#UjsPo=Pz z5@FQGNh?zBt&YkZP`_}W`F&&;O%7{4nY{xL~2xxb^7HQS1MCd#?iw)M@Ua@ zH|^XMkLpj3l#=$ZULh^>yV!c?3Mn9sAU2{qOHZA9n&{a|fromc{t) zPwBtNBjxlCEa`}C8AU26yB+qk6qQ>zg`2qBmE_C)%}GRIJBL8}vR6wg_%wEZv=O&$ zxLU)1K=loQNY7Qj*ajnJuq6ABmhgokV{@4?z$U^y?2-18z4wN7L0vN1|D;?M3J+T` zBG87)jB}QwUtMA*8v4qj)Z{n4|C|^8iI3{b@$FCEZuRZ}f66>B7tzR1sJGbUI13Zd zhID_0g>jrlw9t((&=7+UHIooy$h&06XpQ z>{-hKYm{TPkOjWFSX-NNqydBE&P#fNf1ON@aUX&dFjuojMB`Bg<}0$2*E#&IDMtg$ zxysvlPu;bGjksrd_5J5oUVUZ`0X&KRBT-Xet_;9j`E~9w!MsQA6>qS{c_t%$z^f6` zW`}b)u-iILEfg@z&RX&09lB90E!ssce^jbFhRSP9Le>&B-uIFbWBpuoFeL|T97lgj zZ5=N%1Y)N-W91GHc7gRv)G4&;4@w)9!kSpYfiW0!Z-8iOxgA&%jv@ym#CE|ADA{ zzC$gbB?QBiBf?Di4}@tip&bxqJ~yrnr*bGI#@tu66z9h`lS7QJfQ73l+zaMiz-q&o z*G&HdLBA02KM)nWj~@UKNNxUJvgOhT|E3=}fhJ8$1&%~+g_FK!kH~8z((INp&)?EL6#-V`Q+q2-D+P{J_!LQRZR5Y7h_^~eubP8{ z!Y%1#teN~T#3g@0Ex=l$p%uOrNY>X35q))MXH|#$pF96qId9f7LvU2S>-`+9_4j{` z;96I=k#wm#*dfhwv$#;?r`B8SjQNK2Vq9>vncV~+L~&<(im;=uk7G>zx`I{dgTVmHA8i`Y zPzZc2LKNaqCOp~pCfPsJ2uqqb7V?_06GUp_oc-7Q9(P^wJEt?85+l^1UZ9llQjJAC zI4#Lt&awgvUd?QPuz|FMcmO2VRE*XU!G7K-68kq4p7`o@KPnaP&t)^U{tKBlB7;~=2pCQQ=B%7J7!LN68L$o8Uv;qVAE{tvUgb<9 zX;ksRRJ99H&t(+cT-%$)_(OqC0x;87o~rjitmXLSYj93AbP8P*>@7|`-ymMe#fz`=ogW1j!KtuFY+GgRm zMFij{`@5AI>AgC()~$U+8mfurqnhJ5J+cR*cjd611MZsyR_{-uI8bSwz zFRhm9`xH@W;(d{5js`9Q@_*N%3v^*#eL%%ngh{iu0Rnc^Z}tS>w{@ZbT+6cE{{@|= zVOylYO$lrlIq|Md1PrHiL!3#668bfVa&Bsuq}8~<2F#hN2_{uOf+L!hjRus4R}e>= z^%H)3G?-w>I@@kt&86d*ZT{DbB&`1}{5Q|FQML=D*F|nN|Hcdy0kFSIy)B^hgV(D@;M%^^@jpG?)gmw zlm@6*@%bBy4{$%gDbQ2%|0y6#+0)Tn8Ve8m*Dx_v^#%&OL0obZ2F8RRP~d=C#gvRi{zp#<{HBQe zkIpFD)*&&Zd;3@Iw6W@FUl-@K+ZWdD{C11sig<01)D;Bt8R^xbuLXPYtQH2`qE`h3 zI7V@+UYXxb$LIL;y2)_3*VOE67gFAXJEEi$T?<&WW69d%LHKoJyb*NlGS&GAHY#z^ zCg=-33gqN9Qh<*F!l`J?u;AL0@TOFU;MI*^b^XY;?mrDLVY35~S2J^3Pa>G$lK|?c zhf+X+l6VH*+R_Io3P2Cke0Ts(769zWi|r_IUq8LNm=*%d|K5M0fdZcdveHh0gGk01 z?VP7k)-Y=u-D{(KCipeKJ?{bzKrGtm9N)tT*=y~FIWwXJn}iidYXU={daF3LeMg2< z^(QFAQ(9>A)P~4Mb3r6IvRLRiMFUUZhHSh zG!yN`2sZeg4L=iDQ=qNh?3Ho=rxrdcu4V=_57}%7%;$w$FWg3PB6?cUR&5x zs~R@gV27945f}ie&5bK9Sgr&f%>?M1e5bVPb1YhFV6gyk9e%jiSPFU1QQ&|V>t(FG z30xGp8n>RoV>$ZcVH~_nK$>LTVjI&^JR^cN$R`BA$3XO?iz#ZbHCf9%s~Hn;j_oRN zlQDwbj_#Ch13A(RxIIy8oa)8UA@H1pfLGEio6dsS0kiIBTuKME_aza|Y zjqtBK;p6nMErM%jd~=TAodGiM%Wp18p(be0qT zUw@l}`vI1Ma>Bo((2iCsO17 z*|hW;8eVGG{Sn~qZ-6VGWwH30R@#Uo&U-viVCrMYwQCqSeaIBv4mG`VlV|#?K3)xE z{WulZS5@@yvx zeu?1U{lcR|$b^spbCgoc_~RXl zmRP-rPY#HyC#Bd^vATqkf2)>H&OSJG1Ske4($>*Nc3*{oWmuM(<;V+#4m6mC=i4stEuFowR6blzsC(t z-ronr8H-D@9MqRmQc0lZlizQ)6bef?kWuXExjtaX$7z3&=*;_j?H{-KSu&Ta$sL|b zf>bdMBbZlCSmKrJA1E|@>K9%bdC@8h;@FWXVPM2yX|Lg&70}T=Y>ZuF!zJH#)Aq+}d#L5bO|2zv z`gtBGD#xWY$1N>a*$B``(CbRrxIOX`B<6EekZ0E|NeWREchUAg5GG#(3R{VrPJi}@ zipZ~ADcoA=y+6=Mcu|Fs&xt8=Wr~&OY)+u3DVBg(P-KcBvYbBXXeTQ_A)nGAmLz!N zvOLC*vh88B&nlTa(QK@;4=B(S2dhGa6QpA!q&vIN<*0j$^xcPsx8OMh=3*rXXbaPB zDy9nCDo3GWWFo!t?ZON>@-itP^_lx}#4?c%cO! z5shyLoTw5x04EroeH*!djv@gPtFtd&P4x#A zU_uWt@o=qpr{Jny9n2@gmpFV;O|21#@ugIO+KIY&nr5SIY>(X{$iBLm?OD&aTy_|4 zI4hYCdd%ry>irvQxR3URpWiOxkwLz}#}mj3p=d+idSyAXTnlL(vod+|nYF|?t%F(XQw=LiX8O0T4B~o;j@f?e z8}p7fv4UVlXlS*WzhJ5S!{A`BRCLz-xc>t(GRde9c8G@qSl-pZ(;jS93to=4%L^_z z#?0)lA+ce!U2I;44|c*$L?x}r7!`Xun`MVfi@N0J#Emg|d#qz+vfGFmYGQS^Fm>_( zwx$=?!MBhm&*SsNbD_=k8iM2VyOBFw|36)ntV>%+s6TbylA&cc*(JZ&kFQgR5eulS zGn_E7J-~HCX&U`-EK4dnjSM1;Oj&-*Og$7&u>bJ7oh>+H}!*pjSk05 zfG{K=Y}GxD2?)C~x>>~CNGHoJejO(e5goo7b+Xm;KAEwrgb@&-Y>BRKs2(F%CDWmc zLsTldQa-opyFJ;QV8RALJAWHN$>1y3s?F!GZ_DtBg_BXPoh8>~&|%BS-I^$}1L;EU zOa4lD$0f#hGWG0OQP$)R@i(gcc^pPYo6qlkb3$YsHTBm};fh&^i^hvW4*o%cI!eL0 zvKP6Ns6>S4@x!IGn+!GTT@JymK@xNumPB#((+a2{b1bp)H6(~>4X8gx3WA@9b9r7*nbSfR>J-WMJpg?X6a?EjBl*u!G9_Hafd43wvRcO z3;#v93g%BoU$@f4A!QJ)6Jp|c?dN$r*kQYGsVPr(2Xz#f0T8u&NY8UY+gkAA!84Bs zOq`CEvX3{}(H}hIykJ9Nd$D}}bZKKkYsgeoGrFc&8j_YeRu6a(Z>Qn?c_*gw(hDAp zSG=O&8)9ev&MvsZ$BX7DgKX>~YvFv#G}|rYJV|Ty0nCb#LXlWAC=c^H^j4no2Add3 z{>qyj((nue%_)@UQ@88pW+Sc@o7{``<%-A47HiendA@ZYAUm#Z> z^SlS;?BNwhPn1MnGpRKxZ+UsPZ$t%kQ18cSY*!3&D;b0*jAXm4w^7y(jgk(>Ksy-fEvfc>3nG zW*l_3Dqr3B(n8K!!l=;Md%`sNK?gQ6-2)xhz_u-OI%?8VJlPLQqy5JHj_mwG6a-l6 zWpmw95Gu2TNa?^!P@wTl1F0813ii-Q>$t9G>W7EZ{GBdqK4J-Dd31a?gUxVc3F05$ z8cS(NT!BjaeQ}f$+BDiL?$UA+tWe)%?fEVFri?JMX{T2_SzTWN>v)8KWVwFQN2Pt) zXCp5ii**p!1vfgz=GM34likhV+uhH}_&V=A#EA!)IFlxoQ|vo_zJcE9<1A_yas+vm48s#&f z$&{mn&0%iCMo^=~upC0(z_PrFf(hgqATSZf8i2(>)JJ~@`v%3mc@kfNic^d#RM?!2 z6pQ5-&0omGIY2p6*c_P)Vn)FUkVe8N=_iF*!8nsk{V|UobS@NV!Sp5yIxsDGnb_~+ z=3L-%@#F{iMI)gZaagotX!kjsE$b!Ge}WWzs0a3 z%`u&crdk=n^V*uu-+M$P;ILYTv zNdpiE*dU1rO=g;EENJx#s`T1wXh8ab(I*XS`1m3$H@BvFZ~MIQ>|8r>rxgM|GncoN ztnQ_D-toQu35R0wj`j zvR~97`QCmi(CpaTSlW9;1SGTinKE=U*`!uD_`=6fax{P>MuewS*(@ahNN*JQ!t1R= zzr&2!-c?Xyf}|wvCS0lrgwJP=OslmaiT3OPH>0TxZiHKxaUSwI2dme77yUAhA;#xva zP6=YMJQ>!V)P|sd$TF4k#UhSXCobY#dNHK;1qD)B?pw)}Ndjj|?Xz0~aFtMKigo3? ztt-h?`_ngt%0F_g-oIPNuQq5)fB9oL z3gqiOZXJ6umO&-!u{HN|Y2tFAilKCnqWoIh-fd1#+|lo&wTz~$MHY)>Y_y)w z0*f?>9MV%L?sE_dl@MJqOcUj*% zKsDmi8Km1R!h9g0S_7y$pxqyfK^it_Vv)#$s4pP_ktRSyr3~8x3pRAiLBUgK`WQtp z01BqwHL&c+V^;FIp{?AajAbq9OV81Z=uq-^W@Cbov3}~#SU4T7vT?D3 zV_~SYzS$R$yE^et#V2{wygSQOw@wrT#G35b`&-OGHw2CpPH0tj(;x$Gf)2O~{%w6u zRlFoebStK8xf82V#4d;9V3h6koIMqF1NDiz$`10(Z24&HV2V5>f}x0-h=a<`N^%c_ z05?q=T~b=)LH^1){quJ#sAfS14cIsYkq>8u(17M~Xb+syZHh4>AQA;UGtDRENz?}z z_o3s!>xcw;-i~+XGH6Aqb;xg{6 zIK3v%=6+Td#1Lq`51ldBj<835EKg|H%Q*GnVW#%I@pQF@$UY~_%XMwMdfUH=pI$< z5?Yd+&Tu9feO!;{+Y8q2&1hV7hf15#q|)=)Nw(ROx*H72)3e*mtO>y>;r&yM^6h7q zD{nYWOYP}{PLz_+&7pTPwcNcZFhJS(y^t*l2ob;FMWd^CQ0{t6+fdX0%Y4)OcJpRq7wpRfOecTAl~S~ z!k;bvy&0U*C%8NYS^>8e$EzdIPvv*7D8>&*C@*4}9q#K+rq~2Yj#SoTdnmDipLwe%=97AL~ES~K@3_UBn`XAmA~ST1mIOtp4c z@uJ4+MG5)SJT)Vuaiit!jGk05GA&UJ0VxlMo3Xp*TThhd*mY&4Ob1)?vYa?uHi+)% ziiMx)XV)yG*L}lbI$)A*O$Bi_ z*JZ?HycB${@HFHm;eL_f`9;<5AdsX(4*yYLpa{NY^V!+WX%!x{hy1i!kQrA0AeiAP z{>k;t|l>^wyGEx)X9 zHYvV0hBtOp)8I!&E{|CPWy!LJvCKq054{w-PS~HFsjF|!l1#=0 zg8MxNw&bb5M&a9hYB^wT-{||jFW{>_&m#Va(es(bvt%>V=4-;+pSukQZRZ9T8!?>_ zKUmX8huJQaP$er0jn~^`o1@y2Xq~W#Qm-vJ%RbT^32D;}6tnKuBK{)W3(O$cO*=h% zQAeQph{$vGEi9>?Y`{T&5am*1u~E+cQ-a#q#X+#sA4Fv^w^Ed|DAE4-IdHVOd>wzds{E#|J{r!Ylf2W9+837IIP zGS?m4QY}LrdkcXRMnn2@t}^J*jOp36kZQwrtheoLiE?p1%_pCraHqS0sG=a7%$hAR z&)y=Vw%gn!%&I9rM=}e7HqN#!F}j|$j8J#NR^@RAvZQc3S)iq4Tvr2EJkn)gDt!47 z!cIqNSd6kGcG>N*r->Jv7rrkSYxRg`_;ORxBjj24G&`Q|qJi9PHtFMSF>D&)cWZT* zElVh1%8Z_k^5V6(3{MaDw`Ms)@}q7YUg)T)pv|9qQzp{iQv(*ovSndp^Y`KuaCQ{`AYp#ea?7@lqeQknKA?=stdb|07nE5^vdDM_$d2RCUh8;%lU;t zzs7|oHfTnwm|wy4c+#n>B*2?+7p-6{#Pk zvH1yP^^N>j>4UPVnS5@1=2F(wq}R=WH@XUjL?L)jVtE(54WhX;GxFEt3d$}HEl3Ck z*e3wHI+k6$nz^GQyK_|eK4+Db<6{zmd=)E27XCwERDS@|WJ9%R{9K9yrfK6k(M?zs zHJU*IZIzO44f7Vo5SE_6BNl;@K&Lc3{7smd(STga-c@lBYCSoe?xw~e`u6W2_i&Ab zt_UqzjPrx2zG~Dfi+@%5>?-tgYqodeZCoxyRncFfiB&D!h>R!_%=LMm<3_EFj9}*7 zYU4mzqasqt{(9-w9Csuvm&!>#7C$hg(@=Cz1d6*WuJ zVeRC%0>1_(sc8kOP)=JIzE^xz^+e@p$DN|nO8$9E&e6UzPFb9u`1}F*_W2Q&v2wyk z?3P3M=%PpR1!Mg{&+S2k_DMXD@!^V>E&Qb$>Q~HdyvJb9tsIqr;3~z5{39in-rtsv zEUIVBaK_uU$Ys_0m@f}_4`W9qfX&Xrt3%b*S4-(vPjd*gPkj!p?*0be^pizw)LX=9 zn|Ee!nXD-NBI(R{yGVp$&Fw2~Juii(6e<)L{X zR}b&=j;A56b3Ey4RUhj0_M*nAd(1AJu1!E$Z&c&6J8FKmwqhoHNNjOkYbKx|*Ffxh zrozCfy-gW-F%rXE6w`{j>HoE=$fsyMT_{u>g;RrJQF=9^b7ViuhVpFYUQwzN-u+}uve?6dcWg|mmXyA6u7Z{EEsbgsP7C~o~-_2EHf{fnMqe37N< zbB)f?9^HNQ;jkmj1ylM0fRvrnQ@6@#OsV=-WCVw{ zL4#8l67#!k!$`Xa>c((3l)w|PwU!}8G#uuooj7F3m4{ep-oUnHAHUi3e(Lid;D4f% z62Guq?=&Xj7LTA7ypthPl3Nz&M4Q9b`MNZ9MV0oMf|M(AzDgF1A5aU~9o4MRl89wP z#>XXJWd^z8f!GkzmUFKU-sT|7iBptW@_*I3vbBbwu-HPo_-1c2s$p-;U0~_{E+}Xk z617Q&)HLSkv%+}4t;HwWt%12st!);aj;z`PrE;?2XC5e~GLktu)T4BCZf4K>O`?p= zcEZ#!W>HNqV*2gtbJroABA)R%^8reu$XG2pd*( zf;GhWoOusb9#{&Q5pwx4p^|6*mlMA*l{Qtl{I_pcb%hcno9y}?sj^h_jTv_1^e*7K z7pBK=+)ilWx;q)J$5K(eVEx*xA4}NWsjm*|!}o4PNZTkysiwD|A%iPcwcxj)L#?l% zH_NyDE+O?-g>Xoshv4fcda?UODs6?v(Bz-D+P3bjpy_trEeWrG z15N1od{!BGT4cfG@O$n7! z<1;-pwOQ@g<{xp-LcS5@*lD%lAlQ0d_~?>PkKnlY;lq2ry8g^R!v^=bm!$8TfAtd; zTa@kIz^m#BDt}ocyhEQyA*QSlOmJ6aCS{OOVt^B#u9g;GW+>a!cDqJCVti-adA$W=u zS2V)Q4&k~fn$}-gXU?bop$`qIZ@%PAUS>!K#5{^yOfr2IJN1UEj0mTdnqppL0IRkOyQo}T(BBW^k7horQEwn=+4mC}P3I}MN^bSk zp130f@{DUGs+1dZCGm^(=dXN}iyq4ZWfRK-2nf*%FNK#-B}>DZ7w=W@W-&C4BJ!1e z<7V$Rc!@@3AQNn49;iR@>3vDR!5y7a_KkUC?!4zP$=Ev2DpYfm&Z>mb*A@OzrY3l0 zHV0LS!VLYLh;ph64hj9VGO@ek?3c>f)5wJoYxVB#1hej{M)l9);v@ybeR>tD7HsVz z*W;9Es}JP_?OkZUXKN=0j$B6;C~HpWvp^i4lvy>-i;c^@rp3eOAM@cS-QvUJJ{h}D z?pAH)KP-pcQ9?}^IXkHb&9%F*T+X+d8vH=~bygFsu%>&xu_i^qLmYzw3$wW7C>P_n zjb+6N;<*Z%oI**y42OMd1-+=3TWyGmG{j-LQw#BB|5uKck2GQmibNAmg7ridv?T3g zZ}r!ZkTRP<7f9O2&w)pOatlO%o)TcxWef&C83e6{R_-Oa3W#5(r+m{o9Xzwb$XyMs zIf{?G7QZC0uag_!uq3^Y;?iojaZ6gI?zRs*>GoNB-+v$aMhx`GL?H+Vy7HYki{5g4PlN4Ctzsk(bz@E}$azaj zPk;--uhyLab1XE=~Pi_$zD9<+{*{QK)2)f#fuP zLLG!;;?9idk`yMcA2lp9l{G9Ss%0}g84Y$2^|ZeH0vuIYX?!7bt|D`aq6{49$XD?; z@=zQ-u|z20k=0YqD@qd7VKsiPRG0Nxxdc%O(NLZTiRy^>uMet1F^e>{ukapW&Zf`i zuD2KkNs1zAz=YfBim#zf2znw-XF>@xl@3J0XT5vhTh!G0x6=K<*Nqq%@(ifQF-6M6 z1)GC8-!LAfQROf(5^35K9`O(3(oFfQkq0?D9d0IR5S4WTs_IIgQ-=_gq^k(L7=_}G=;kCy=F%T7&f*@=<3-=5%!pU|#}JgOkh z9xCZ%AnA=P82|w?ANG2uP)sac{4QWZpQ&`r1Tm;cnWSKIG=~jF{@u4ze?o;~4l!y{ z(ZMJ-nndV>AB_@v-0x|o{a+Iy96muLB;ziyNEx#Lt2-wFg6b+h`WaWD7*4vFCtyOM zGKMSJnj%*boMd}=IhT1d8>69;(*}}|$dY}Kpy=VcYY}C{KN{qtOsItDX#4)KB4reC3cQmq(K$Mh7XzW9gL06^l?W1P zkYN+TqXpjv7ENJ*@gqwcrpDFa}g%EDbC~PHm>wB zFUyiGfclPw$_XyPwB<3-y&MBs>D)|yAF6H%hH=U<3I`lH9Y|2~tTv##0PF`Asw*fZ z6C^<@zoIF)0_6bVVool`m+N0_xp9cO%B%r#Gew(9Z?(N<7Q=W1K7kbyp%PG&LWPO4 zH<>8(;6Ug4X*=Q}ze6PvQ{qSh6k&zFnoX)sVYL~n}gJ{++!ZB5r6&}vfQxs9)K)-z_?%rPkA6J+teBeNG z`uk%mxkX-Xj46ujaG+6N#rYs_;G^6t*a=)a(DkObhZu+$Je7(y$s>;j&rnG$Y3fkn zJ%W0v?}PB{$vJ4?bakhKR#rBt|n) zQJC58k+Eaw%gn_$Ogl5)Q#C*q)J5d$RV5KRY@StA$wdqW$Xouw*il(kaH+(>ci5cg z^f@HEJgr$DkB0r5u|8&tYnD? zSq2}p{83d8Zib36w4&~v0l+;>seT^shc?e;2cFvx-M724hg|XI+?j#sL|%38Bn81QlwZ-E6lkMIJp77CiT9X&uh05s_B>8i8oDasO{I}@j54G z`UOMXBupzOTWLm**Z~n=reC;T#MCTqITk6PaVLDz%p^Dt`Vzw;4EZ6AxKSm1LhI`<&id^o2)G7!hi&;?|GPnn;} zP-~`TvDRU(nY1$G-{J5Z6(=$n`k~yU!&_oxeX; z1xN3b-wwKpw)x;Zl_LkZ><18}uFku1cnp1UYVD|i^gSue{*ZMT;hb74nR=37j-4RT zFd6ri>_dEo-3Xsqz5U~*GROr(Xr@ZtT3<@DKw&VkUxygPVy&&or)va@wfDF|4{xl| zu>te#V0OQ8%lDL-m^R1Jb3<$pay?H_wVf}-L!gQfU4XG2aaT9rC=QUohgKB|@gd<4 zf(VDT?U`R_b2s89?NB|uznU}~ghZ(On=#l;1}1(BV#;cveyPOv(YD{t-SVX?Q}1Is zVUm1@OWL~yk3uLa7-K~+A@mJNdY9k>_tdJ@%KIOkScmlSrMscWO>C*3G&Bj+#@iZo z@lrJsK(O}ML~YyMIYYU0w2QTe>~eM=K5k*r7&&xYVC%WlEK9XQ8Ji3a3J9kUaUXJq zsSI=3OM4U_&3cuy1gu=T3-^}lWRoC_p4mvn2+JhoM-#3N&r8lq zvJFaT(C95IW3CijdiPMA-$d41sirO@`NQS1)9I99O(A=qymZ}Ak`s)s*632GmRmK+%TfTq2AVv2%Lf%zU%0X zq@#V|n($-N4+`ei?#YA?ge_J;;o++ASbaqTH$fN&zOPx-`qzgYz=_(j~qrL1$N9nzuyWVr`fw~xB z`{mtGd$hS|sF7~GVr-;iu-*l9!)Iu#$d=|Mn+(04ZU`Z}vsh7PQ>FSymyB)6=l2tK zp!?ZUgKf3SfY3A;Yk_sPB(SeIn?K$h7Q{J52 zY-}+Y9mIs8SA<6dwLlpJbbGW3*hH5JeiY$z*6>8NdSb@-OCJr|(SH^4SZ->8*Yc4L zytV5)Cf*gmS!|a!Pcn8%su>;6W_CEvaC>4SjAj?s@$BFnAaFu*a3|2O*Wv@NU2zW_k{ zD_z=}jB%|c63q9<)6c#C06E=UZ+6T8Ea#KIDgTq4mc99(A96FtErVl1=^ z(a}h>fmRE7Ee`K<_fyz_bAj@`3NvzC{`|*ZQ@QYF0X!mQVTupTcE_ABD(?!M3Z^S$+5ZobL-1bTpO1tiO^o;3{zz2WXw>RQK08TQ`nb;Kt(#g{Z? zDcWy5c|AX6D7H{lO_tmfRrKj#w=+7LKMw6#VB<+ybDLE<_#wU2B1Uelg|Vs+GmD34 zz{1I~Y@n*no*b%|wy*V@EOl^<*lt6?*U+#h@Xj^5Ty?AZoh{R-{YHK?#Kv1KbGQ=} zuq}hyXi{OgliyBN(f9m45aff^WQ&d0tin^Elec5TAx6u#kLPQy)f3xjW0V#!t8|F0 z37xg0Rn7NHcXq4u4|*uWAe$ATQm&S2>hB7MO*~gEDM2_T7tS=?i=%GEY3*#hg(lpE)S-u`B4ajO#7*RF3t??C~3uu6TP zWs>;AC5K+Y%RnEhfX)k+EfUEcHkaTTX^JCC5n-!2oI;C4+C8Scvg`UwX2X+$bH^`JpX^C>Pby zjd$HmAAk=!6&Yq`SbufT25Iu%cy@AQ8D0~AO~0?j{PF7d7twIFEH`0csgAdlob~cg z=4th;Z!iQWptGFBLN?)I|xl?KQmbur6TnRu4GUUH5lIbjNKkKhk zs<q~#rvgZo5%BKac;x-yU&;z^^oGPtq5i`Jxk-Wr{qKnRv6$fp*mW;KS2{vR4%8U z!md3x$-VSz1@GoCmZ@oa_pqGqUwvejaUa*y z1zUe%Q?HT{_%VO;6e760MJn;n`lQz{IE;+;J>^%j$$VT66@6>nOp4%2yd)kk1>Ov) ztm3Y24$2$*tOt%;1b5>O#fA?E6Llxb@392rG+@j&)wYAk?l9B*?HX=ewA+nJAN4BX zO{0mAVL#PG`QIEkwy)SNix7zNyVnI`nBBZ^;0iwoQ(+NHHf+!`K( z|3{(yW!#%0S(HttpwjKV*-yGS$8?M+Mn3|jH#u*mFZ^E!x&BLJZ;8vs|1+AJii~9n zdD}CPoCY(DY=U#$kagUnP3&(-x~Ieuj`N;!us|oEJ4kuoUicKvLEkeRa(O!^VR8cJ zxfvLY6L7NUP42`LJd@P$EPiAvj{3F2DRqv1CQh#9&v9cixOg|K?>D(%Xwq>n6KX|G zy(t+F-9g$-Ak+f#7T87M)iPsIAmb2jX3w)-_(==&B?by!rfC~A<+aE3OelebFL|2@ zSHu`axRo*xy`9$N)iK_dzfX`TAl#4x#s^`x68kirF_=4ZMz&Q0J7yQTrw!@>NJ4g**bN`~?^m?URk&5(q!yfLW zhx&IUjJX9?mrREqzS$Gh($X`p1C7Oum4rmb_Z&6f`d?9d5fFumpR)jc!UJ#g+VP@f zb-Mo=pD>Iwhntto-W9Rnfjw7nw6PmqolQL=9+1tx)roo@fUWD7IhhOgl@0TG!3t5p z=qS@JV~w>90*J8FgA-RTe1cT>)H<909AB7@qNzFhOHV2OB^iJQ4q7~e7mL@I9BY1R zxa1Djh#F3DnoG~TxoMjewJ{J#3R@d=kaFRHyC9xrMb6Pe7NEgmnteKr1|y2z1=J_X z7~Z5*`w_1**KaY=JK<({`Ua&YE;Hgm> zILHXiJnmx_ARUA>KG%n0cTny5$=D-j_`6{z^ML!Np7CX^)3IoAkPbe}R}JZ#T0JXx zBG*Dmi=AW$t6~9bXc9f-Hfl)uftuqTZk6bUQvX->0^2E#x*TuEpCDrTx$c6YSS_u! z9e|xb&eA4k;dwGV95A<{XIAzTl=GGQ>o>UTsrg^=&MdMrpb9GGj4kY(FfgO!Yl=U5 zy(-C7@-j_tXq_8gmQ_*M8>Kd0pK1HefC?Qw%H@(+mH}cuxLwci9#SKz>5|LOKR5`- zX+i_@5@12k)nRT1`eYe8Fy8u{OZ&li#tY4jSc=7}O}}6} zuJ9CXH!9@t9Duzgq;`EuP_bOa;{_5KNq7p-7+h`7= zlL=74jQe#o#uhbfj~r2XsMMZ3IwVh|7K!qYH}4?T+?uv&Eq877Gr0897eUMIYB5>G zss2n_rfG)j%ZTS=hGsI-ZpJ(61g=$b$N4J7Hm_w%@b@pnrW?UZ&4L@^d9!!Cog>NI79>JoojjmWiy~0{MU zDikaR(@ovVlcm?nbbE;hCtO1=z9Dzu|l`D?LBydt@qAo4tjgLu!yT zZFBz^HZxR+MMM-SBT2lM46u(`7Rf=%1qWZg-SO83tb+MYHBfdr*8J4~Y|7K+NrGbw zIyiG34ZbHy=URFmLW7s3zzRAB0r@i5rvht&qs0MuBb(o>?>Q?kTG4mbHeh4ak!^~w z4Z|3&Z`f2o#}N)x1#JygJyYwDQK^B*E9?nm){9KEeWZ>AjXp%}RE%(rv@jUQKjD|HUN-{_RADU=Rio1WkSGj>73n zF+oxM=byWbpLZ*JJOAGx5-0-lKpzn3XZDgZjIRfyzToWBSk%vcuKv!I=$&PJ!#i0Y zQJX6aP{i>Ay{PjyJ5kCo${q~w+($=KnUOxO{(o7@Xiao57}@skqgXQtM*FSoS7GO< zPdI(AKGLq3OEYIB;;YSGm`J<^{wXONDs+AjYv)&yJ@nX9KU0dl=lqnthCC5b+fhNf zWBIE>ah=b|P>zkkbI4Bji!_H8f_dD%kzQ8Cz$?k)`63DpTk}+174vPSd}*r(TR$0F zW?HYk&FVwrW@{w#I8t;fd17VmSQ5b}>ja5)p~m!CtX(R->ey5^TldMEE;y`OA>xrP}S>iBP^k@nyXUmUTbf3W&OiFewHVS?P^lwERfO>$kOEOkdHy zyie$^aViifG+-p*AXyDN`k2%;jhGUFGwf`;4I_=oI>ZuXd2iJzyVf=^D< zEQL5^sq3NyOL4QhR~Id+TjC?=B2HA5-ggp|lm50=x)!;DoJJ0O>c9BypEtMB-_5Pg zN$V8q;&hct+_bR_kKef2%vL?GD++X?B3W!LLiBDBg^_BLJvzpb7@4pPm%zO!B94 zeWwRPMta>M=WUWNQM%Vxq)3f#R-ZHz|OKOe#+zQNOta?5+#7CPv9n(-ld9bPF^EK;e?F$An zo>t5dU-V2Ve*GHIgUbD|x;HrUM93bpy~O9;b2Xav{tdaE`eBAX$%n1=-!mK)k&+L7 z`>PjTE9@vcOA=W@{7-;3>oTcsOhwW!@wzl|b4&OsXax^;54sFG_)q_#6jAKGwGrKU zs3RU|Oj5H@SG3YD18L`&8GBp(^0uGbYDH}PJhwEZN<)T>rGDl5uRMfm%$M$SV;(P<~g1(G|!SA%D6Pe?W$BV57x!8QL_4#(cVuv+0O zBFMGL_GwE!du4@gj_%pbJh_ClUB>ccrfrBnoeXy?;@LFwc_(7NzYVbfw~KQ0qbK$^ zk%Zy>>Sy@yK?o~gW+=w3&3Ky7h4|Jbf#BC@*Wt-e=Kn0E`uPe+pMV^vxS{urPOZ8%kn-YMEXk z-8){e;&?xw4Q3D)L|u8k=MRI+8GCS!(BQ8fw5Z+a`9U#Ys^;|*1JeA_y!~R=U*%~8 zzl3>$n~6PVLK27V7o;m@`O4apwAh6gLe_kvnLPK2m9~+FRk1o_8I40v40E=vSZ{qD z3$}AJH`cVL&#d`EXnk^y5%r5+v1OOVSw5)!qL7I>XE@T<#-R1#fn4l5pSXpS$<&D2 zbaz>Sc0sI18N9m_LV22zADbd=|M;mgVwPp?4CXK^5O&F7JBLoIh@wt*=ev}Pi^a`T z?On1%3%FQs#ZgTuh}XSe&EB<=XL9)I+YK(*RWb|sP~7^K9$Y_u6Hn{qw9$Kvvwn16 zBo9s=N@mX`yOrwUg)A?kk;mW~j`^4!@HJH0LLU>8634LuQGC1=5t5m1olnxVDXw*>xg-s`3D>m`T$jV~;EHi)y^(VlQa7~tuHHXUdNV6z!qy2N)hNZSQ9QPl{2 zBnZyGX)Ql{v_=oPI{{G?4+GO7rEczKcTIGM3$W_PW^f;MQ@d`PQwmF@NXM!Sc*NK8 zINpmWmdRwLLv{yUfpbMlazq%mo+l_UvS$p?-0+Ov_EXbKPce8~Oo3i^+E`vPeGu(h zChNq&6wXq>6-l7a^|v}=68318;qZ^a5Kdx0Pi$A>zZ+ZRNQLcb4dEh5bI%><$5nu# zaga^=%dN?WVK_gHxqZ5+nHaHH)*4y+nxF`wSTcS<$C6hM5&80x*MQ^yK#8d}iKK=;pNOHxFZdTSdgZIc0iI~EL{Hx0c;wwfBxzJeHAgtYsfY6Pz z*q_m~X5{aysJts2bW`@xzpv!-76|nF{p|qJBPpGj&YxGlDI06kbfz5arA+2p8m$ew z0Jis$Bs$$GrFP0=-1!1e&fuhivlDtonBk9&T|);0Hf!Qlrbss6^n#@9l@eKnI*mJ#qR=!;tRQA)gM<2R`Y>&QVh}!pU&(O z^T0Q$Kyq`u>U`DkobaRS(*YD~tggUQJ5C^rGd$=m_lB+=2@674j;W%)CHipDu*p9n zvW~SQfau%rQy9(9X2(8tEgOS$_L*B$4|c_$R^invz9sk(MhdKVSVA&>B3g@24y3quSnpv`{VNQ55iiNC-E}9`#XM0b96+y{p2P(cQHuKjD~3( zbC|(R3%ng6)iUget-z|NP(g}?t|tUsT4X|uC?@isve7L9|2yMeW;bO0uJ`IeBp$Ss zi97COAn+{bzrm0xK(-t1sBa)!cV}ZzT=CvKx_m&E#XnL8)t@=aOOWbrKu&CrRfHAtIxLu$zI*#i;Z zPy5Dpwq29*2&6Qw)~-wDk0)G!F=hWoUlNjsLm2UaEERA?*tG!&Y7K$6O zN=sZaen2$W)@~`z#ULc)s%zqBgvVcA8>F7}$g0O3nnrl~OLpgrjb&8JSA|ZLl!0=@x z`T5InwHO^nY$JK7^i|UhrH~Qtxawfh6vALh$-Ivo%E6iVj{-FUm86q3N|nE=V8LK! zgzx*U@8a+>u~3Ms3oliBzg&kPc1nd5u$UspOfhU00@M#Owz8!Z81dS%9u;Iqkgzy}Iz{7HnRHt-!Ks z^<>Qs6kY{``YjwONjIgF@DXl~4VrwsNS4+)hJiobu&*{4D$h?ZXR2H|F<9k9mFaSJ zU16VDa^&hO5V9Q#93Q~Em_kNRS`v7*Dasc)u#edZ)2^&l|qpbI)Uwlr*>9 zT_iya{fl=WZ`8p(v5L@0t?ICSI$+{*?XiIJFa7iAWx)^|PD~KP6v*PNd{^f-LBSw9 zz*a}(d74voUZHX2nUl!Yk%cVV1DXxdYaaIQ0b5o%iq9qH3FFdxA9kUi3%zka?Ozfi zP>}%p+P^H4|2*n&5v^+V!SUobw93U_ep)zg2eW(4`JZ$oJ{%b z{Q@z$;5!>FilIY!Lc)FileBrG7T6t5H0O(38$bUtH#1Y`zynR6ZlQ`-HJN#qf%){03lBmc@&ut7{U7uaDY=_qE99S}n|pK7)JVN`?HKb= zH#J?Fh`kaiaBV^bsq)xS{T$GGKa8}NYKjf3gf?3;3~56CCA+!+gE#D4>tfZt9}Hs} zMK!)=g*SgCwD9F((?y?31^$IRI(dz>&F(a)*X@X7k7+Y175~e9sw!cdT{yN;s6*fk z&1O_KUKYIIjA!E--Mr4%n66+mduUg#<6t;1tNEK-f6j#Ny}>Gb!&6gP43q4+Q;SwJJB#`D+)CbyxevR4n|qM- z@E(sTJ^%c7806i1m6p}Qy~?UeHQmCdIO~_7p+rf|u%Jc9+8ZSC6l4&5TvG1dOJ?MO z-8F;q>XJJz!=WU@%?hIbH&(lD7Qy|xu$paxO{-QBrD&x~%0*`6)T<6gLyx1&WHWCm zYDgTnj>95dX;^cAep}?9<>x}ubmEvhbA&Xl5^@~9#`GsTV_!rHH0DU8PugM~>sdgG zjo!7tIM%i3t1o#l#NmDeoti_E-g@L&oqqcc8^h@9{RH0fU%Oi;WbuO@qrJ?&#dm38 zi)|c>2nG_WSZ`f^AD{xaHD}^J-uTAW7BZoV!RF+}+JZh2|8d!pxo^Ch8$90jJw=35 z+V%4}Oa1jBltfG!_q$351#JWeX(XavMgFUDMV(?|0fZZKAS5x{Am>OxGnam1Kbvj# zBT)`okIl;gCB1z+#A0Zc7wL!R3->Iy^L{`X3c~S)j^*oLch x)mFzI|EyLQfAQQa$UlCT1MF!vEq%G(zQOm*8$SwLjMI9T${{SIyZ43Ya literal 0 HcmV?d00001 diff --git a/core/src/main/resources/bedrock/creative_items.1_20_40.json b/core/src/main/resources/bedrock/creative_items.1_20_40.json deleted file mode 100644 index b2c0bfe04..000000000 --- a/core/src/main/resources/bedrock/creative_items.1_20_40.json +++ /dev/null @@ -1,5787 +0,0 @@ -{ - "items": [ - { - "id": "minecraft:planks", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBsYW5rcwQJAG5hbWVfaGFzaA+7EGxL5oikAwoAbmV0d29ya19pZE/NqzcKBgBzdGF0ZXMICQB3b29kX3R5cGUDAG9hawADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:planks", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBsYW5rcwQJAG5hbWVfaGFzaA+7EGxL5oikAwoAbmV0d29ya19pZHl/r2YKBgBzdGF0ZXMICQB3b29kX3R5cGUGAHNwcnVjZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:planks", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBsYW5rcwQJAG5hbWVfaGFzaA+7EGxL5oikAwoAbmV0d29ya19pZL6SoXYKBgBzdGF0ZXMICQB3b29kX3R5cGUFAGJpcmNoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:planks", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBsYW5rcwQJAG5hbWVfaGFzaA+7EGxL5oikAwoAbmV0d29ya19pZKYD6L0KBgBzdGF0ZXMICQB3b29kX3R5cGUGAGp1bmdsZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:planks", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBsYW5rcwQJAG5hbWVfaGFzaA+7EGxL5oikAwoAbmV0d29ya19pZJ0zTHYKBgBzdGF0ZXMICQB3b29kX3R5cGUGAGFjYWNpYQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:planks", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBsYW5rcwQJAG5hbWVfaGFzaA+7EGxL5oikAwoAbmV0d29ya19pZOf6hVkKBgBzdGF0ZXMICQB3b29kX3R5cGUIAGRhcmtfb2FrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:mangrove_planks", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3BsYW5rcwQJAG5hbWVfaGFzaPvLtcEA0F8xAwoAbmV0d29ya19pZEvnlCYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cherry_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9wbGFua3MECQBuYW1lX2hhc2hNIvVh/lVW7gMKAG5ldHdvcmtfaWQTXpRoCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bamboo_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19wbGFua3MECQBuYW1lX2hhc2gYnjNz7SCCjgMKAG5ldHdvcmtfaWTi8ySSCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bamboo_mosaic", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWMECQBuYW1lX2hhc2izSEgiMKOp/AMKAG5ldHdvcmtfaWQZ/p8xCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:crimson_planks", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fcGxhbmtzBAkAbmFtZV9oYXNoJc5IKqNXJnwDCgBuZXR3b3JrX2lkwtJDdQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:warped_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9wbGFua3MECQBuYW1lX2hhc2g3yGXEWhe6LgMKAG5ldHdvcmtfaWStTABvCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSE4JosCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBjb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWTUvV6XCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9jb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWT4opb2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBncmFuaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQAMQTVCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBkaW9yaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQIbDOcCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCABhbmRlc2l0ZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSZKhusCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBzYW5kc3RvbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSp4zgCCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDQByZWRfc2FuZHN0b25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRbqVHTCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBzdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRr0ZT/CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9zdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRnLis3CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBQBicmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQNLzfSCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDABuZXRoZXJfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQ5h0xwCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEAByZWRfbmV0aGVyX2JyaWNrCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWS9J0B2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBlbmRfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRPbkJeCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCgBwcmlzbWFyaW5lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:blackstone_wall", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaMP8XppUSU1RAwoAbmV0d29ya19pZMbeBBsKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_blackstone_wall", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaP6SwV08YwzAAwoAbmV0d29ya19pZAJLsz8KBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_blackstone_brick_wall", - "block_state_b64": "CgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBBIDZbHxiEzAwoAbmV0d29ya19pZEbLV8cKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate_wall", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3dhbGwECQBuYW1lX2hhc2iECY5oKxeT+gMKAG5ldHdvcmtfaWRCnPrFCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:deepslate_tile_wall", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3dhbGwECQBuYW1lX2hhc2jz7N+PeuEXgQMKAG5ldHdvcmtfaWTqw4s4CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:polished_deepslate_wall", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV93YWxsBAkAbmFtZV9oYXNoHxjTdj9pevMDCgBuZXR3b3JrX2lkIvBYYwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:deepslate_brick_wall", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja193YWxsBAkAbmFtZV9oYXNoEs3EQrjroyEDCgBuZXR3b3JrX2lkwlrCGwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:mud_brick_wall", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja193YWxsBAkAbmFtZV9oYXNov9b98ATpUSwDCgBuZXR3b3JrX2lkH/1WZQoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:oak_fence", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZDvPEXcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:spruce_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZQQJAG5hbWVfaGFzaPQCm+aX1ZQeAwoAbmV0d29ya19pZD1QUEoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:birch_fence", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlBAkAbmFtZV9oYXNo6CJ2ATpANfgDCgBuZXR3b3JrX2lkmCUV2QoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:jungle_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZQQJAG5hbWVfaGFzaOX4cD9uAmsdAwoAbmV0d29ya19pZHz1VxkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:acacia_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZQQJAG5hbWVfaGFzaGjn+RlKVDH6AwoAbmV0d29ya19pZNVGubwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:dark_oak_fence", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlBAkAbmFtZV9oYXNoGPj0gCgM0c0DCgBuZXR3b3JrX2lk2w+gEwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:mangrove_fence", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlBAkAbmFtZV9oYXNowwAd7tPu9bsDCgBuZXR3b3JrX2lkKEcd0goGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cherry_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZQQJAG5hbWVfaGFzaFmtUfHfTxcxAwoAbmV0d29ya19pZPCBxAIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:bamboo_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19mZW5jZQQJAG5hbWVfaGFzaCKRbxfXsfkiAwoAbmV0d29ya19pZJNXKFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:nether_brick_fence", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0Om5ldGhlcl9icmlja19mZW5jZQQJAG5hbWVfaGFzaA6030ngawxcAwoAbmV0d29ya19pZLnjLF4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:crimson_fence", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2UECQBuYW1lX2hhc2jhUhKv1HGj9AMKAG5ldHdvcmtfaWR3OH3OCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:warped_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9mZW5jZQQJAG5hbWVfaGFzaJfb3/YuKmOWAwoAbmV0d29ya19pZCpaGC8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:fence_gate", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWR+T9kTCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:spruce_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoanTVB84HRbkDCgBuZXR3b3JrX2lkEnw5egoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:birch_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2jmfPklI8azSwMKAG5ldHdvcmtfaWQL77/BCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:jungle_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNobYVQkfBomIcDCgBuZXR3b3JrX2lkA1zgtgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:acacia_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoZnrLUx/XSekDCgBuZXR3b3JrX2lkHg/kTgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:dark_oak_fence_gate", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2j2PTvdJJHcVQMKAG5ldHdvcmtfaWTwjOCeCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:mangrove_fence_gate", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2i/kOhBKiI/dAMKAG5ldHdvcmtfaWSfweCSCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cherry_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoKWLgCk0z+PsDCgBuZXR3b3JrX2lk/9bTZQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:bamboo_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmJhbWJvb19mZW5jZV9nYXRlBAkAbmFtZV9oYXNopH1JrUgwdIADCgBuZXR3b3JrX2lkzIpPywoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:crimson_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2VfZ2F0ZQQJAG5hbWVfaGFzaHE3Gfd0Z2d2AwoAbmV0d29ya19pZDQzVbEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQsAaW5fd2FsbF9iaXQAAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:warped_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoy0oIBjDIG4kDCgBuZXR3b3JrX2lkkf+/3QoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:normal_stone_stairs", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hAEktZZOkGIwMKAG5ldHdvcmtfaWQeH1ALCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_stairs", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZDcCv+MKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:mossy_cobblestone_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3N0YWlycwQJAG5hbWVfaGFzaMVSTq5z9n1RAwoAbmV0d29ya19pZFIfrhkKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:oak_stairs", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19zdGFpcnMECQBuYW1lX2hhc2jk/HFzdXy0FQMKAG5ldHdvcmtfaWQJjyzBCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:spruce_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9zdGFpcnMECQBuYW1lX2hhc2iznygw7uBPBQMKAG5ldHdvcmtfaWTv+is3CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:birch_stairs", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3N0YWlycwQJAG5hbWVfaGFzaPfhbL619a3GAwoAbmV0d29ya19pZFyPlHAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:jungle_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9zdGFpcnMECQBuYW1lX2hhc2jodJsHUbOVxQMKAG5ldHdvcmtfaWR0z5d4CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:acacia_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9zdGFpcnMECQBuYW1lX2hhc2h3x1NmD43IqQMKAG5ldHdvcmtfaWS7Jwz6CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:dark_oak_stairs", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3N0YWlycwQJAG5hbWVfaGFzaMfwkbYPbNmAAwoAbmV0d29ya19pZCmBYKAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:mangrove_stairs", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3N0YWlycwQJAG5hbWVfaGFzaNpUDY+uGMpyAwoAbmV0d29ya19pZChzUAsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cherry_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9zdGFpcnMECQBuYW1lX2hhc2jMtr0v9JY4zwMKAG5ldHdvcmtfaWRQwq31CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bamboo_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19zdGFpcnMECQBuYW1lX2hhc2jFOzWL8PalKwMKAG5ldHdvcmtfaWTVPh42CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bamboo_mosaic_stairs", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc3RhaXJzBAkAbmFtZV9oYXNoNLPiveSHPaoDCgBuZXR3b3JrX2lk44PHjgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaN6tQViRo5cwAwoAbmV0d29ya19pZDMyMgIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:mossy_stone_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaIB/Zv5YBPuYAwoAbmV0d29ya19pZANTOsMKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:sandstone_stairs", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnNhbmRzdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hOyA0BoYUOPQMKAG5ldHdvcmtfaWSV/834CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:smooth_sandstone_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoB+CuCd8Ruz8DCgBuZXR3b3JrX2lksR+m8QoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_sandstone_stairs", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoPs0LpHPL24YDCgBuZXR3b3JrX2lkLYVt3woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:smooth_red_sandstone_stairs", - "block_state_b64": "CgAACAQAbmFtZSUAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3N0YWlycwQJAG5hbWVfaGFzaBvjtQv5pf+MAwoAbmV0d29ya19pZMHNND8KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:granite_stairs", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmdyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNoGzpvtoqKQjgDCgBuZXR3b3JrX2lkPkcB1goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_granite_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNo3PvbSfEQklIDCgBuZXR3b3JrX2lkMmEm3AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:diorite_stairs", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmRpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoi73T8VQuZmcDCgBuZXR3b3JrX2lk6i6nBQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_diorite_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoFKRJd5Wk5L0DCgBuZXR3b3JrX2lkbt2ioAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:andesite_stairs", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmFuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaO5w2FKBw76EAwoAbmV0d29ya19pZKhXEgUKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:polished_andesite_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaNcZZ/zmLInIAwoAbmV0d29ya19pZJTHrlEKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyaWNrX3N0YWlycwQJAG5hbWVfaGFzaMyt+cRDk5O2AwoAbmV0d29ya19pZNeMh58KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:nether_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om5ldGhlcl9icmlja19zdGFpcnMECQBuYW1lX2hhc2jRqIoOXgifBAMKAG5ldHdvcmtfaWQDiw5yCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_nether_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNogQvosSbcj7kDCgBuZXR3b3JrX2lkx2IMtAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:end_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2hmlAk+QhsUsQMKAG5ldHdvcmtfaWTN7KFaCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:quartz_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9zdGFpcnMECQBuYW1lX2hhc2hmvpvOqGi6egMKAG5ldHdvcmtfaWRmUTh7CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:smooth_quartz_stairs", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc3RhaXJzBAkAbmFtZV9oYXNoNZZ9rX0qZOsDCgBuZXR3b3JrX2lkzsgQyQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:purpur_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9zdGFpcnMECQBuYW1lX2hhc2ifwDxeezXD7gMKAG5ldHdvcmtfaWTT+rxiCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:prismarine_stairs", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfc3RhaXJzBAkAbmFtZV9oYXNooTHSZ+IrYtcDCgBuZXR3b3JrX2lkxTJfeAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:dark_prismarine_stairs", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zdGFpcnMECQBuYW1lX2hhc2hIciLmam4o4AMKAG5ldHdvcmtfaWTVu7TCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:prismarine_bricks_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzX3N0YWlycwQJAG5hbWVfaGFzaNIjq1oBlZMMAwoAbmV0d29ya19pZGEFwLYKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:crimson_stairs", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fc3RhaXJzBAkAbmFtZV9oYXNoZJqIzCBpCq4DCgBuZXR3b3JrX2lktXE00AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:warped_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9zdGFpcnMECQBuYW1lX2hhc2hOkY27jLD4RQMKAG5ldHdvcmtfaWQ+E5VrCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:blackstone_stairs", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNokdoUb76p9McDCgBuZXR3b3JrX2lk5fWI5goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_blackstone_stairs", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNolCFtFIE8MmADCgBuZXR3b3JrX2lkGTf7sgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_blackstone_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZSoAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNonks6UlfpOmkDCgBuZXR3b3JrX2lkgYeOdAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoHfoAXYq5G3MDCgBuZXR3b3JrX2lkeetf7woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:exposed_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2howneQGtZ9cgMKAG5ldHdvcmtfaWSg73zdCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:weathered_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSUAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaP+R5loXxrVgAwoAbmV0d29ya19pZOnbRf4KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:oxidized_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNo6Jeoq5rsPxsDCgBuZXR3b3JrX2lkmRjDnQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:waxed_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoh07CQj0/SR8DCgBuZXR3b3JrX2lkmYqoqAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:waxed_exposed_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2guVct1ilmxTwMKAG5ldHdvcmtfaWQgCPROCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:waxed_weathered_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSsAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaPXC8Sz/phCpAwoAbmV0d29ya19pZHlwHVsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSoAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoaqGdkuhxVZUDCgBuZXR3b3JrX2lkYQXzzgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3N0YWlycwQJAG5hbWVfaGFzaPIfa+TpyJcIAwoAbmV0d29ya19pZJUvOYIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:deepslate_tile_stairs", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3N0YWlycwQJAG5hbWVfaGFzaGFRFzB72mN2AwoAbmV0d29ya19pZJEOgIsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:polished_deepslate_stairs", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zdGFpcnMECQBuYW1lX2hhc2iNCYxVik9sGAMKAG5ldHdvcmtfaWSRVPnYCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:deepslate_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zdGFpcnMECQBuYW1lX2hhc2hIasOahEf83wMKAG5ldHdvcmtfaWQ1qEDCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:mud_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0Om11ZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2gt3qxK1NWajAMKAG5ldHdvcmtfaWSm9N3MCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:wooden_door" - }, - { - "id": "minecraft:spruce_door" - }, - { - "id": "minecraft:birch_door" - }, - { - "id": "minecraft:jungle_door" - }, - { - "id": "minecraft:acacia_door" - }, - { - "id": "minecraft:dark_oak_door" - }, - { - "id": "minecraft:mangrove_door" - }, - { - "id": "minecraft:cherry_door" - }, - { - "id": "minecraft:bamboo_door" - }, - { - "id": "minecraft:iron_door" - }, - { - "id": "minecraft:crimson_door" - }, - { - "id": "minecraft:warped_door" - }, - { - "id": "minecraft:trapdoor", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkyTAWkAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:spruce_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnNwcnVjZV90cmFwZG9vcgQJAG5hbWVfaGFzaOwlfbgBkUW4AwoAbmV0d29ya19pZPHy1K0KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:birch_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmJpcmNoX3RyYXBkb29yBAkAbmFtZV9oYXNoSLtLweOLJ7wDCgBuZXR3b3JrX2lkeJWDfgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:jungle_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Omp1bmdsZV90cmFwZG9vcgQJAG5hbWVfaGFzaDP/TnM9wyCIAwoAbmV0d29ya19pZEy2fJoKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:acacia_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmFjYWNpYV90cmFwZG9vcgQJAG5hbWVfaGFzaMj8xi3vmEKOAwoAbmV0d29ya19pZOHj8E8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:dark_oak_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmRhcmtfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNomB2GGJQ2aOMDCgBuZXR3b3JrX2lko5ZHTwoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:mangrove_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Om1hbmdyb3ZlX3RyYXBkb29yBAkAbmFtZV9oYXNooV3kQsQUUmkDCgBuZXR3b3JrX2lkkF/mxAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cherry_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmNoZXJyeV90cmFwZG9vcgQJAG5hbWVfaGFzaH/PefpfdHgtAwoAbmV0d29ya19pZOA7eNgKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:bamboo_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmJhbWJvb190cmFwZG9vcgQJAG5hbWVfaGFzaJrEOpsTwtKCAwoAbmV0d29ya19pZLvbPz8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:iron_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omlyb25fdHJhcGRvb3IECQBuYW1lX2hhc2gwA+IumsEiGQMKAG5ldHdvcmtfaWTvSVl/CgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:crimson_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNyaW1zb25fdHJhcGRvb3IECQBuYW1lX2hhc2jHXufTnwUkYgMKAG5ldHdvcmtfaWQLjMYVCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:warped_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OndhcnBlZF90cmFwZG9vcgQJAG5hbWVfaGFzaA20wG/+vkd6AwoAbmV0d29ya19pZHKR/hYKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:iron_bars", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0Omlyb25fYmFycwQJAG5hbWVfaGFzaPuefWSNAe56AwoAbmV0d29ya19pZN2LB5IKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:glass", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lk0hdLNwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:white_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iHubqoMbu9fAMKAG5ldHdvcmtfaWRndBrUCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:light_gray_stained_glass", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaKKa+LrRsHQhAwoAbmV0d29ya19pZEv2giYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:gray_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaIETy7Y/HZREAwoAbmV0d29ya19pZDomVrUKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:black_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iV6BCwpfDMmwMKAG5ldHdvcmtfaWSV7doJCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:brown_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2igsEiq5np8JgMKAG5ldHdvcmtfaWRMzE/lCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoCa2J12/lQoIDCgBuZXR3b3JrX2lk283lWAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:orange_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNozgjAuvzhxGsDCgBuZXR3b3JrX2lkW5CkhQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:yellow_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNo7EbHMd5WVugDCgBuZXR3b3JrX2lkkdDyXQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:lime_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBtZA1nZtwcFAwoAbmV0d29ya19pZDxX85UKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:green_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2h91ptDgbehWwMKAG5ldHdvcmtfaWTlDhnECgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cyan_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBkIYQ8nQLqbAwoAbmV0d29ya19pZOL1lHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:light_blue_stained_glass", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaLt05n1G0fiSAwoAbmV0d29ya19pZNbwulIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:blue_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaPhLocSfzduRAwoAbmV0d29ya19pZENsjFwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:purple_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoJk0DhRO0szUDCgBuZXR3b3JrX2lkD98ZxgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:magenta_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaFEDeFiJj3zSAwoAbmV0d29ya19pZG+iFRoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:pink_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaDijTX87ywxhAwoAbmV0d29ya19pZKdEricKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:tinted_glass", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnRpbnRlZF9nbGFzcwQJAG5hbWVfaGFzaAFZWSamk6KdAwoAbmV0d29ya19pZGSvWX8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:glass_pane", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWRGwixuCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:white_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaHgxQmgJVtRrAwoAbmV0d29ya19pZBEr/DYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:light_gray_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNon0aQw9lNkSEDCgBuZXR3b3JrX2lk9dp5VgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:gray_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNors74IIw+2MMDCgBuZXR3b3JrX2lkmrGO5woGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:black_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaOK/5ZRRd+M1AwoAbmV0d29ya19pZDv++oQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:brown_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaLHeGJyRFTIWAwoAbmV0d29ya19pZMz9L0wKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2gGr4x6JheAywMKAG5ldHdvcmtfaWQBjCTmCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:orange_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hbHxPD2gEbEAMKAG5ldHdvcmtfaWSt/7a5CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:yellow_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2g9tl4aOCyZBwMKAG5ldHdvcmtfaWTXRAS7CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:lime_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3CtUyLwoGegDCgBuZXR3b3JrX2lkYJDnggoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:green_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaJo6YP7IMy9SAwoAbmV0d29ya19pZHOnixoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cyan_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoti97c6QrbLQDCgBuZXR3b3JrX2lkUqFUeQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:light_blue_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNovDg/gQle104DCgBuZXR3b3JrX2lkFuy4MQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:blue_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoGc57tiexbQMDCgBuZXR3b3JrX2lk1eBLUAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:purple_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hDJHYdd0FdfQMKAG5ldHdvcmtfaWSNsdK5CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:magenta_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3pcOw5bs5XoDCgBuZXR3b3JrX2lkVbOR7AoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:pink_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoWRhSACMWgswDCgBuZXR3b3JrX2lkIR92xwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:ladder", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxhZGRlcgQJAG5hbWVfaGFzaKBhqheJVOz+AwoAbmV0d29ya19pZCgvzlsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:scaffolding", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnNjYWZmb2xkaW5nBAkAbmFtZV9oYXNoYrkevrqcljwDCgBuZXR3b3JrX2lkD13mlAoGAHN0YXRlcwMJAHN0YWJpbGl0eQAAAAABDwBzdGFiaWxpdHlfY2hlY2sAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWTkNl0JCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAc21vb3RoX3N0b25lAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkQJoxlgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNAUAc3RvbmUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWRHh04KCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAY29iYmxlc3RvbmUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkVRZB+woGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhEAbW9zc3lfY29iYmxlc3RvbmUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkBaobgAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUDAG9hawADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkhz9TeQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAHNwcnVjZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lk3HkwowoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUFAGJpcmNoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkDIBqVQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAGp1bmdsZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkL5hFYAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAGFjYWNpYQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkKRUHSQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUIAGRhcmtfb2FrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:mangrove_slab", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3NsYWIECQBuYW1lX2hhc2jYCcmhJPeNMwMKAG5ldHdvcmtfaWQx6U1yCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cherry_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV9zbGFiBAkAbmFtZV9oYXNoTt0MmVn/mqoDCgBuZXR3b3JrX2lk2VVsZQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:bamboo_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJhbWJvb19zbGFiBAkAbmFtZV9oYXNoo1xuFqINeLYDCgBuZXR3b3JrX2lkVC+0twoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:bamboo_mosaic_slab", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc2xhYgQJAG5hbWVfaGFzaNbVRBZ/ChI3AwoAbmV0d29ya19pZOLZHFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWQSiInOCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkoF89tgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAbW9zc3lfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSkoAE4CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQkAc2FuZHN0b25lAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkWfF7pgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0AY3V0X3NhbmRzdG9uZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkbKRChAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAc21vb3RoX3NhbmRzdG9uZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkBlrvqAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg0AcmVkX3NhbmRzdG9uZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkRWFXuwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAY3V0X3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkom8neQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxQAc21vb3RoX3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkd1ZaWgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZ3Jhbml0ZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkISH4iwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZ3Jhbml0ZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkqxEDMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZGlvcml0ZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkSYs86QoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZGlvcml0ZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkq6BU6goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwgAYW5kZXNpdGUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkTSXY8AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxEAcG9saXNoZWRfYW5kZXNpdGUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWQiYHKTCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQUAYnJpY2sAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWTk/0LfCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAbmV0aGVyX2JyaWNrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk/hXQ7AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcmVkX25ldGhlcl9icmljawADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkYJNxrwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMw8AZW5kX3N0b25lX2JyaWNrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWRlj0/sCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQYAcXVhcnR6AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkMae+2goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0Ac21vb3RoX3F1YXJ0egADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk+kMHGAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMgYAcHVycHVyAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkKOSOMAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9yb3VnaAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk8igLCQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg8AcHJpc21hcmluZV9kYXJrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkSFbyEwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9icmljawADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:crimson_slab", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc2xhYgQJAG5hbWVfaGFzaKZ+EfP0ZYOZAwoAbmV0d29ya19pZAxRUWAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:warped_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zbGFiBAkAbmFtZV9oYXNo/AT0e/Z9W7UDCgBuZXR3b3JrX2lk1yq11AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:blackstone_slab", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaF/DD4ZUlNgtAwoAbmV0d29ya19pZGy1DjwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:polished_blackstone_slab", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaDYnuUs86EWfAwoAbmV0d29ya19pZJj2bXIKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:polished_blackstone_brick_slab", - "block_state_b64": "CgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaKySLqvHc4xXAwoAbmV0d29ya19pZOyWX94KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaDsNpb2qs4iBAwoAbmV0d29ya19pZOTm2nsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:exposed_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNoahQ5OwIQb7kDCgBuZXR3b3JrX2lkrUlZLwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:weathered_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2hBIuGIOVVXogMKAG5ldHdvcmtfaWQgnaDiCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:oxidized_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaOptj9ycfpaDAwoAbmV0d29ya19pZMzFSRgKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:waxed_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaAlx6DZOCTHzAwoAbmV0d29ya19pZFRBvDAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:waxed_exposed_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNo3KqS5OnhtRIDCgBuZXR3b3JrX2lkHTGcTgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:waxed_weathered_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2gzZ1oX0HCFtwMKAG5ldHdvcmtfaWSgJR+XCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaMjjTnLu1KcqAwoAbmV0d29ya19pZIxsnFYKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cobbled_deepslate_slab", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3NsYWIECQBuYW1lX2hhc2gwJIVWK1TM2QMKAG5ldHdvcmtfaWTYAoX5CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_deepslate_slab", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zbGFiBAkAbmFtZV9oYXNoC/Adiz8k6RYDCgBuZXR3b3JrX2lkuFYMAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:deepslate_tile_slab", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3NsYWIECQBuYW1lX2hhc2hPydV6emzIXAMKAG5ldHdvcmtfaWQwlbFCCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:deepslate_brick_slab", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zbGFiBAkAbmFtZV9oYXNoSv62V7iw10UDCgBuZXR3b3JrX2lkWMoragoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:mud_brick_slab", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja19zbGFiBAkAbmFtZV9oYXNoq/tGBQWkv08DCgBuZXR3b3JrX2lkl4nnMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:brick_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJyaWNrX2Jsb2NrBAkAbmFtZV9oYXNo5Qc2E005S3oDCgBuZXR3b3JrX2lkqeGWRgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:chiseled_nether_bricks", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX25ldGhlcl9icmlja3MECQBuYW1lX2hhc2g31SBPTcUK1QMKAG5ldHdvcmtfaWS8TJ+TCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cracked_nether_bricks", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmNyYWNrZWRfbmV0aGVyX2JyaWNrcwQJAG5hbWVfaGFzaAdC6eKzXT5tAwoAbmV0d29ya19pZIUSejwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:quartz_bricks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9icmlja3MECQBuYW1lX2hhc2jSZO590dd8sAMKAG5ldHdvcmtfaWSc5xCLCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQ5kni1CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAZGVmYXVsdAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTDw813CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQUAbW9zc3kAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWSTvQGECgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAY3JhY2tlZAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQIM0OwCgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQgAY2hpc2VsZWQAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:end_bricks", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmVuZF9icmlja3MECQBuYW1lX2hhc2hIUFfxNLZaFgMKAG5ldHdvcmtfaWQ/vDihCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWSH021WCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBgBicmlja3MAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:polished_blackstone_bricks", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoIHgsgIdzKXcDCgBuZXR3b3JrX2lkUw9b3woGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cracked_polished_blackstone_bricks", - "block_state_b64": "CgAACAQAbmFtZSwAbWluZWNyYWZ0OmNyYWNrZWRfcG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3MECQBuYW1lX2hhc2jQIO1GQDk80AMKAG5ldHdvcmtfaWQ3UlRYCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:gilded_blackstone", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmdpbGRlZF9ibGFja3N0b25lBAkAbmFtZV9oYXNoNoWt1ocG0HEDCgBuZXR3b3JrX2lktL8gUwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:chiseled_polished_blackstone", - "block_state_b64": "CgAACAQAbmFtZSYAbWluZWNyYWZ0OmNoaXNlbGVkX3BvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2gzFa+kEjCJgAMKAG5ldHdvcmtfaWR2NJX2CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:deepslate_tiles", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlcwQJAG5hbWVfaGFzaGcLLx3NXAFvAwoAbmV0d29ya19pZI/G/xYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cracked_deepslate_tiles", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX3RpbGVzBAkAbmFtZV9oYXNo9zWgkFuMM1QDCgBuZXR3b3JrX2lkGwY6OgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:deepslate_bricks", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja3MECQBuYW1lX2hhc2gucvFmPdZxigMKAG5ldHdvcmtfaWSH4HDPCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cracked_deepslate_bricks", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX2JyaWNrcwQJAG5hbWVfaGFzaN40aqhh9WqHAwoAbmV0d29ya19pZO9GPBQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:chiseled_deepslate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaEU7/uRG8HSBAwoAbmV0d29ya19pZEqmI0EKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cobblestone", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYmJsZXN0b25lBAkAbmFtZV9oYXNoPoK7mGlSUz4DCgBuZXR3b3JrX2lkLm7RZwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:mossy_cobblestone", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoGJ67FCbkChMDCgBuZXR3b3JrX2lk/pYs1AoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoLUz9Y/ywmLwDCgBuZXR3b3JrX2lkNwzZ+AoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:smooth_stone", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnNtb290aF9zdG9uZQQJAG5hbWVfaGFzaMwf87/JaTNvAwoAbmV0d29ya19pZLkZICEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB2wApMKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUHAGRlZmF1bHQAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB7E+eQKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGULAGhlaXJvZ2x5cGhzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZFQnDaEKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUDAGN1dAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZPO4A3IKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUGAHNtb290aAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWRhNYiFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTqXJr1CgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlCwBoZWlyb2dseXBocwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTQRGkFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlAwBjdXQAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTvAHWDCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBgBzbW9vdGgAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coal_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvYWxfYmxvY2sECQBuYW1lX2hhc2jH8QQP3t5PiAMKAG5ldHdvcmtfaWRo+sR+CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:dried_kelp_block", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmRyaWVkX2tlbHBfYmxvY2sECQBuYW1lX2hhc2iRoucexkrl8wMKAG5ldHdvcmtfaWQQCCrvCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:gold_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdvbGRfYmxvY2sECQBuYW1lX2hhc2iYLshvjtXzFwMKAG5ldHdvcmtfaWTDJGBcCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:iron_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Omlyb25fYmxvY2sECQBuYW1lX2hhc2jYINmJQbvV/gMKAG5ldHdvcmtfaWRf7AbICgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:copper_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZIiUodwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:exposed_copper", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoQH3Fukmu3CEDCgBuZXR3b3JrX2lk72jFIwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:weathered_copper", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2hJCQXbvobv+gMKAG5ldHdvcmtfaWQwM0lJCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:oxidized_copper", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMDtJqR0G5Y7AwoAbmV0d29ya19pZGjN8bUKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:waxed_copper", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndheGVkX2NvcHBlcgQJAG5hbWVfaGFzaPF+FG6Eh5fsAwoAbmV0d29ya19pZIjtz/0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:waxed_exposed_copper", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoig8IOc+SCikDCgBuZXR3b3JrX2lklz8yWQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:waxed_weathered_copper", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2gjtPq8MOdvKgMKAG5ldHdvcmtfaWSQ9Ln9CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:waxed_oxidized_copper", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMaORhsO+LzjAwoAbmV0d29ya19pZJhGfLEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cut_copper", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmN1dF9jb3BwZXIECQBuYW1lX2hhc2hAfN3NGax3eAMKAG5ldHdvcmtfaWTnFBtYCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:exposed_cut_copper", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaA85G3yv/w6pAwoAbmV0d29ya19pZMQhr0QKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:weathered_cut_copper", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoVgRV0fBaz88DCgBuZXR3b3JrX2lk/0cYugoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:oxidized_cut_copper", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2iP8WmFWOkriwMKAG5ldHdvcmtfaWQPdce7CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:waxed_cut_copper", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2jumiwOZIqv2AMKAG5ldHdvcmtfaWQvuxx9CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:waxed_exposed_cut_copper", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaPE/OfK6IoVMAwoAbmV0d29ya19pZHy5HkcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:waxed_weathered_cut_copper", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoCA1xDp11bnwDCgBuZXR3b3JrX2lkDyEDVQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2i1pZAsZYHLDAMKAG5ldHdvcmtfaWQ/wSkCCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:emerald_block", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmVtZXJhbGRfYmxvY2sECQBuYW1lX2hhc2hK6QunqJznNAMKAG5ldHdvcmtfaWRk5+otCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:diamond_block", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmRpYW1vbmRfYmxvY2sECQBuYW1lX2hhc2iGKrxuvkytFQMKAG5ldHdvcmtfaWQQeQZXCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:lapis_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmxhcGlzX2Jsb2NrBAkAbmFtZV9oYXNoDZ44xdb2zVoDCgBuZXR3b3JrX2lktVy0BAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:raw_iron_block", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19pcm9uX2Jsb2NrBAkAbmFtZV9oYXNo9XyzNIQXxvwDCgBuZXR3b3JrX2lknms1QAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:raw_copper_block", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnJhd19jb3BwZXJfYmxvY2sECQBuYW1lX2hhc2hw1KG0TNUGgwMKAG5ldHdvcmtfaWS1vGo/CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:raw_gold_block", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19nb2xkX2Jsb2NrBAkAbmFtZV9oYXNo6YuwuLwfOBwDCgBuZXR3b3JrX2lkLiQ5gQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZEupC1AKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZM97+l0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZCbTfssKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQgAY2hpc2VsZWQICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZJss8V0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQYAc21vb3RoCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWRFIsoGCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWTDNWOvCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBABkYXJrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:slime", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNsaW1lBAkAbmFtZV9oYXNoHJiEEJx+JlkDCgBuZXR3b3JrX2lkfgfVzAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:honey_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmhvbmV5X2Jsb2NrBAkAbmFtZV9oYXNo9zLYSUlelywDCgBuZXR3b3JrX2lko+dyWgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:honeycomb_block", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmhvbmV5Y29tYl9ibG9jawQJAG5hbWVfaGFzaASIPuOCYd1oAwoAbmV0d29ya19pZKys4n4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:hay_block", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmhheV9ibG9jawQJAG5hbWVfaGFzaIB2VxKxX8EpAwoAbmV0d29ya19pZKuQSloKBgBzdGF0ZXMDCgBkZXByZWNhdGVkAAAAAAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bone_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmJvbmVfYmxvY2sECQBuYW1lX2hhc2i4ZX576W9AWgMKAG5ldHdvcmtfaWTWGacQCgYAc3RhdGVzAwoAZGVwcmVjYXRlZAAAAAAICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:nether_brick", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0Om5ldGhlcl9icmljawQJAG5hbWVfaGFzaMxcRiheU+nXAwoAbmV0d29ya19pZMkmzloKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_nether_brick", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2sECQBuYW1lX2hhc2j8pRO4LfoECAMKAG5ldHdvcmtfaWRpdF0YCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:netherite_block", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcml0ZV9ibG9jawQJAG5hbWVfaGFzaMghh6Zib/ZKAwoAbmV0d29ya19pZIz0mq0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:lodestone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmxvZGVzdG9uZQQJAG5hbWVfaGFzaJ2gmHOTlXv8AwoAbmV0d29ya19pZEfgB4wKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:white_wool", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWSO8paQCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:light_gray_wool", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfd29vbAQJAG5hbWVfaGFzaOpdQ1a2v4b3AwoAbmV0d29ya19pZIqZCYEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:gray_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmdyYXlfd29vbAQJAG5hbWVfaGFzaLsc1Lp1xdIOAwoAbmV0d29ya19pZFUs+HgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:black_wool", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrX3dvb2wECQBuYW1lX2hhc2hP2HC6o0X4HAMKAG5ldHdvcmtfaWRUbORcCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:brown_wool", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmJyb3duX3dvb2wECQBuYW1lX2hhc2ig5IW89PrREwMKAG5ldHdvcmtfaWRjT9j8CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_wool", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF93b29sBAkAbmFtZV9oYXNoY4TBDq+mFgUDCgBuZXR3b3JrX2lktn9lcAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:orange_wool", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om9yYW5nZV93b29sBAkAbmFtZV9oYXNoFstfrTZfSCgDCgBuZXR3b3JrX2lk+rqywwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:yellow_wool", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnllbGxvd193b29sBAkAbmFtZV9oYXNoTFyus2RHegcDCgBuZXR3b3JrX2lkkKBhXAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:lime_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmxpbWVfd29vbAQJAG5hbWVfaGFzaNVnnzKiMxmeAwoAbmV0d29ya19pZG9b32kKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:green_wool", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdyZWVuX3dvb2wECQBuYW1lX2hhc2i3mElRYHIcSQMKAG5ldHdvcmtfaWSssprwCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cyan_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmN5YW5fd29vbAQJAG5hbWVfaGFzaBNDfvHn8dqFAwoAbmV0d29ya19pZK0hAbgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:light_blue_wool", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfd29vbAQJAG5hbWVfaGFzaLWFAUfyxFPNAwoAbmV0d29ya19pZL2oEugKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:blue_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmJsdWVfd29vbAQJAG5hbWVfaGFzaLjHyxxbTWCLAwoAbmV0d29ya19pZPaLdFQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:purple_wool", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnBsZV93b29sBAkAbmFtZV9oYXNojvFtqzjAf/4DCgBuZXR3b3JrX2lklqASNQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:magenta_wool", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hZ2VudGFfd29vbAQJAG5hbWVfaGFzaGuOHvf+Pd4yAwoAbmV0d29ya19pZI4UoDQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:pink_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnBpbmtfd29vbAQJAG5hbWVfaGFzaPiVA2pFeoFLAwoAbmV0d29ya19pZOZRO6oKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:white_carpet", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZEahDFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:light_gray_carpet", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0BAkAbmFtZV9oYXNoHPw6ArBAsP0DCgBuZXR3b3JrX2lkQoAeUAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:gray_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FycGV0BAkAbmFtZV9oYXNoZVR0OI+1VRADCgBuZXR3b3JrX2lkETF4WwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:black_carpet", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhcnBldAQJAG5hbWVfaGFzaOk7LP9NptyhAwoAbmV0d29ya19pZFjmXtIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:brown_carpet", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhcnBldAQJAG5hbWVfaGFzaNaXFyOsAvIvAwoAbmV0d29ya19pZHPjFuoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_carpet", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYXJwZXQECQBuYW1lX2hhc2i9eSKBf6SO3wMKAG5ldHdvcmtfaWQuhI/KCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:orange_carpet", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQECQBuYW1lX2hhc2hIUkO4HlAdygMKAG5ldHdvcmtfaWSyKV9OCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:yellow_carpet", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYXJwZXQECQBuYW1lX2hhc2hSDKX3scCamwMKAG5ldHdvcmtfaWT8nq+ECgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:lime_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FycGV0BAkAbmFtZV9oYXNo+6KFOpzsib4DCgBuZXR3b3JrX2lkT+DS4woGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:green_carpet", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhcnBldAQJAG5hbWVfaGFzaCHPMP9ltqFJAwoAbmV0d29ya19pZBgwAvAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cyan_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FycGV0BAkAbmFtZV9oYXNobXf62dQBJj8DCgBuZXR3b3JrX2lkKVppLgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:light_blue_carpet", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0BAkAbmFtZV9oYXNo20l4oktdZ3sDCgBuZXR3b3JrX2lkjdeMiwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:blue_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FycGV0BAkAbmFtZV9oYXNo3p3lsW0eQwsDCgBuZXR3b3JrX2lkAovdPQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:purple_carpet", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQECQBuYW1lX2hhc2jwIA9pW/qp7QMKAG5ldHdvcmtfaWTqJqhjCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:magenta_carpet", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0BAkAbmFtZV9oYXNoFXT36YNNZhMDCgBuZXR3b3JrX2lk+tqsGAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:pink_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FycGV0BAkAbmFtZV9oYXNoHll72oqk+OoDCgBuZXR3b3JrX2lkrnBYDwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:white_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZJPZY8AKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:light_gray_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo7EUk30hmUtYDCgBuZXR3b3JrX2lkh8jVIwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:gray_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmdyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoW77af6WihdwDCgBuZXR3b3JrX2lkSsqC1woGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:black_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaAfWYp0xtgcfAwoAbmV0d29ya19pZMWTC8EKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:brown_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaB74EeiLO46XAwoAbmV0d29ya19pZEDHKqwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnJlZF9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gjFut6Z/VH1gMKAG5ldHdvcmtfaWSvcmwYCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:orange_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gADDj2IJiw+gMKAG5ldHdvcmtfaWTHph0FCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:yellow_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iy6qKNn3ob5wMKAG5ldHdvcmtfaWQZAI39CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:lime_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmxpbWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo4dYIPslbXPUDCgBuZXR3b3JrX2lk2O8X0AoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:green_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaM/c9x2aJh3HAwoAbmV0d29ya19pZA0VfBMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cyan_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmN5YW5fY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNok+xKAe7XXjoDCgBuZXR3b3JrX2lkmkn6uwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:light_blue_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNogScpIQceyAEDCgBuZXR3b3JrX2lkOmVSbgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:blue_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoFp7mmeL86r0DCgBuZXR3b3JrX2lkS3b3RQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:purple_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iYcVU04hoStwMKAG5ldHdvcmtfaWQXimEjCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:magenta_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoy/70q6VPsWgDCgBuZXR3b3JrX2lkf9mxQwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:pink_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnBpbmtfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoVikSAf8DwV0DCgBuZXR3b3JrX2lku2MivwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:white_concrete", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lk3MAYQAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:light_gray_concrete", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGUECQBuYW1lX2hhc2hEtet5wuDIKAMKAG5ldHdvcmtfaWQISs02CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:gray_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmdyYXlfY29uY3JldGUECQBuYW1lX2hhc2j92INnb0a83AMKAG5ldHdvcmtfaWQj8RHwCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:black_concrete", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlBAkAbmFtZV9oYXNo2X7NDIQmZ70DCgBuZXR3b3JrX2lk2uiVDQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:brown_concrete", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlBAkAbmFtZV9oYXNoeka02BwXf6oDCgBuZXR3b3JrX2lkYf+xDQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_concrete", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9jb25jcmV0ZQQJAG5hbWVfaGFzaPWmNowLGubqAwoAbmV0d29ya19pZKwyx58KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:orange_concrete", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZQQJAG5hbWVfaGFzaAgE8XmaAi6+AwoAbmV0d29ya19pZMDQNz8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:yellow_concrete", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZQQJAG5hbWVfaGFzaE6ONfJPBd0+AwoAbmV0d29ya19pZMarutwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:lime_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpbWVfY29uY3JldGUECQBuYW1lX2hhc2gnd8JW6wmJcAMKAG5ldHdvcmtfaWTd47aoCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:green_concrete", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlBAkAbmFtZV9oYXNokbFxRKchQZkDCgBuZXR3b3JrX2lkmhZWUgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cyan_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmN5YW5fY29uY3JldGUECQBuYW1lX2hhc2hFRrWJ33qj1wMKAG5ldHdvcmtfaWQbi5b8CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:light_blue_concrete", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGUECQBuYW1lX2hhc2gHAe0kl0SE4AMKAG5ldHdvcmtfaWRL/GbSCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:blue_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJsdWVfY29uY3JldGUECQBuYW1lX2hhc2hiay301nnj1wMKAG5ldHdvcmtfaWRMvFXNCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:purple_concrete", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZQQJAG5hbWVfaGFzaHBHflsPIwdXAwoAbmV0d29ya19pZCyKA5gKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:magenta_concrete", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGUECQBuYW1lX2hhc2gN7LuB/OvdZAMKAG5ldHdvcmtfaWTc6ZOdCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:pink_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnBpbmtfY29uY3JldGUECQBuYW1lX2hhc2ii2G5F0u3SOAMKAG5ldHdvcmtfaWSszGgrCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:clay", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OmNsYXkECQBuYW1lX2hhc2j/S6sKXRcpzwMKAG5ldHdvcmtfaWRmsb8nCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:hardened_clay", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRBCOrrCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:white_terracotta", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OndoaXRlX3RlcnJhY290dGEECQBuYW1lX2hhc2j3RSdgmnAIewMKAG5ldHdvcmtfaWSimKw+CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:light_gray_terracotta", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAz1Ri3wIxomAwoAbmV0d29ya19pZH5qgOcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:gray_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmdyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAXdSLAaNZ9vAwoAbmV0d29ya19pZM1QDV0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:black_terracotta", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJsYWNrX3RlcnJhY290dGEECQBuYW1lX2hhc2jxssdv5vlbpgMKAG5ldHdvcmtfaWRE3Ru/CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:brown_terracotta", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJyb3duX3RlcnJhY290dGEECQBuYW1lX2hhc2gG4kPenmOF9gMKAG5ldHdvcmtfaWQ/i0iNCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_terracotta", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo7fX56HXFejEDCgBuZXR3b3JrX2lk8tTF8QoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:orange_terracotta", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Om9yYW5nZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo0Hjmql3sruMDCgBuZXR3b3JrX2lklmqmkAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:yellow_terracotta", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnllbGxvd190ZXJyYWNvdHRhBAkAbmFtZV9oYXNoqkyKKrmA3VcDCgBuZXR3b3JrX2lkaM/orAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:lime_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmxpbWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaANjADFOF9v7AwoAbmV0d29ya19pZJt0XsgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:green_terracotta", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmdyZWVuX3RlcnJhY290dGEECQBuYW1lX2hhc2j5Ybq36yYwRQMKAG5ldHdvcmtfaWQ8kGdHCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cyan_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmN5YW5fdGVycmFjb3R0YQQJAG5hbWVfaGFzaN09COzMuHwAAwoAbmV0d29ya19pZIWPCzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:light_blue_terracotta", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaOMytez7cOZiAwoAbmV0d29ya19pZFHK1UsKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:blue_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaF6inyTK5RpAAwoAbmV0d29ya19pZF5mVZIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:purple_terracotta", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnB1cnBsZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoKF7YG61yTbEDCgBuZXR3b3JrX2lkhtRDlwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:magenta_terracotta", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hZ2VudGFfdGVycmFjb3R0YQQJAG5hbWVfaGFzaLWvtpAVtztyAwoAbmV0d29ya19pZN5SoakKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:pink_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnBpbmtfdGVycmFjb3R0YQQJAG5hbWVfaGFzaJ7mzvyzSQZTAwoAbmV0d29ya19pZDJWe4YKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:white_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkIlj9AAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:silver_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnNpbHZlcl9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAVsA0CnhzA4AwoAbmV0d29ya19pZPnxtJEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:gray_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmdyYXlfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2jvLZt9u/lF/AMKAG5ldHdvcmtfaWQVU8eFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:black_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmJsYWNrX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoe8I4xAXbO5UDCgBuZXR3b3JrX2lk2Icb9AoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:brown_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmJyb3duX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoSiNZOobbpjoDCgBuZXR3b3JrX2lkJy0jwgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaBdWFGLmCLFVAwoAbmV0d29ya19pZMYBJSEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:orange_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om9yYW5nZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaMyJMrnPr7szAwoAbmV0d29ya19pZN6+7TUKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:yellow_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnllbGxvd19nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaN6NaIhf6m0uAwoAbmV0d29ya19pZKRHXeoKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:lime_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmxpbWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2iF3E68/rB2EAMKAG5ldHdvcmtfaWSP7qQWCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:green_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmdyZWVuX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNow5mo8aQDFboDCgBuZXR3b3JrX2lkoF11kgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:cyan_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmN5YW5fZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gnNB+cCFRJhwMKAG5ldHdvcmtfaWT9buMtCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:light_blue_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSYAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gladnCDBKCigMKAG5ldHdvcmtfaWS5CszFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:blue_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmJsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2giOZK+2nB1igMKAG5ldHdvcmtfaWR+e22CCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:purple_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnB1cnBsZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaIQU03txeAfHAwoAbmV0d29ya19pZLKbSE4KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:magenta_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0Om1hZ2VudGFfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2i/SNqDJbfjMgMKAG5ldHdvcmtfaWQKf9UvCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:pink_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnBpbmtfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2hik8DVt4g+twMKAG5ldHdvcmtfaWTKzav2CgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:purpur_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZLD8ox4KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:purpur_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZPSAFFsKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:packed_mud", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9tdWQECQBuYW1lX2hhc2gHOMa121h4FgMKAG5ldHdvcmtfaWTUb6LyCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:mud_bricks", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om11ZF9icmlja3MECQBuYW1lX2hhc2iDL/SVl/PewQMKAG5ldHdvcmtfaWSkBjaDCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:nether_wart_block", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9XGS4GNnlV4DCgBuZXR3b3JrX2lkh3apIgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:warped_wart_block", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9IqDS9yUPJoDCgBuZXR3b3JrX2lkMpKAbAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:shroomlight", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnNocm9vbWxpZ2h0BAkAbmFtZV9oYXNoZHCHcHX/HYADCgBuZXR3b3JrX2lkLG2JiwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:crimson_nylium", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fbnlsaXVtBAkAbmFtZV9oYXNoOr6DJYW2bFYDCgBuZXR3b3JrX2lkuWpRDgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:warped_nylium", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9ueWxpdW0ECQBuYW1lX2hhc2g0Zf89cfr3rwMKAG5ldHdvcmtfaWSu/kekCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:netherrack", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om5ldGhlcnJhY2sECQBuYW1lX2hhc2i/r5ZyRsvPyQMKAG5ldHdvcmtfaWTAiTOACgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:basalt", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmJhc2FsdAQJAG5hbWVfaGFzaH+UQO2yWodiAwoAbmV0d29ya19pZBPNSV4KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_basalt", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnBvbGlzaGVkX2Jhc2FsdAQJAG5hbWVfaGFzaMS+L0gMnRcBAwoAbmV0d29ya19pZF+/mHwKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:smooth_basalt", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9iYXNhbHQECQBuYW1lX2hhc2jKPUdz89kuNAMKAG5ldHdvcmtfaWTkb/oVCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:soul_soil", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc29pbAQJAG5hbWVfaGFzaC1/87ccutuTAwoAbmV0d29ya19pZKc63SMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:dirt", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQmkQtoCgYAc3RhdGVzCAkAZGlydF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:dirt", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQId9pLCgYAc3RhdGVzCAkAZGlydF90eXBlBgBjb2Fyc2UAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:farmland", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmZhcm1sYW5kBAkAbmFtZV9oYXNoxyQ5ag7LolADCgBuZXR3b3JrX2lkX618FQoGAHN0YXRlcwMSAG1vaXN0dXJpemVkX2Ftb3VudAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:grass", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmdyYXNzBAkAbmFtZV9oYXNosppASPWFlsUDCgBuZXR3b3JrX2lkhLLQkQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:grass_path", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdyYXNzX3BhdGgECQBuYW1lX2hhc2i0/KZV8Qsy+gMKAG5ldHdvcmtfaWT7CcdzCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:podzol", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBvZHpvbAQJAG5hbWVfaGFzaBzqokRjH4Z1AwoAbmV0d29ya19pZPPS/GUKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:mycelium", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0Om15Y2VsaXVtBAkAbmFtZV9oYXNojTN09cKickIDCgBuZXR3b3JrX2lkLNPxXQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:mud", - "block_state_b64": "CgAACAQAbmFtZQ0AbWluZWNyYWZ0Om11ZAQJAG5hbWVfaGFzaPb/3P+uLy+9AwoAbmV0d29ya19pZPIUlUkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lky8FPmgoGAHN0YXRlcwgKAHN0b25lX3R5cGUFAHN0b25lAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:iron_ore", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lk3loneQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:gold_ore", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmdvbGRfb3JlBAkAbmFtZV9oYXNoC5Y+DUGXLC4DCgBuZXR3b3JrX2lkNhvMfwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:diamond_ore", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmRpYW1vbmRfb3JlBAkAbmFtZV9oYXNokUOJ2wZZrGQDCgBuZXR3b3JrX2lk/dChVAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:lapis_ore", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmxhcGlzX29yZQQJAG5hbWVfaGFzaMrmrUrSzb7qAwoAbmV0d29ya19pZMg+qK4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:redstone_ore", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZHN0b25lX29yZQQJAG5hbWVfaGFzaFHVnp8Wc4JbAwoAbmV0d29ya19pZKDYvQoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coal_ore", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmNvYWxfb3JlBAkAbmFtZV9oYXNo1OjA+Iuy51oDCgBuZXR3b3JrX2lk+R/aKAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:copper_ore", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcHBlcl9vcmUECQBuYW1lX2hhc2iSZduSntOzOwMKAG5ldHdvcmtfaWQtIuCnCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:emerald_ore", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmVtZXJhbGRfb3JlBAkAbmFtZV9oYXNoJTovr+VgINsDCgBuZXR3b3JrX2lknbkqCgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:quartz_ore", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnF1YXJ0el9vcmUECQBuYW1lX2hhc2g0yNHLMK9TaQMKAG5ldHdvcmtfaWSzN7nzCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:nether_gold_ore", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcl9nb2xkX29yZQQJAG5hbWVfaGFzaEJZ7segIBgBAwoAbmV0d29ya19pZNI9pDgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:ancient_debris", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmFuY2llbnRfZGVicmlzBAkAbmFtZV9oYXNoNrbxMc9AwKcDCgBuZXR3b3JrX2lkrSNjEAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:deepslate_iron_ore", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9pcm9uX29yZQQJAG5hbWVfaGFzaB/fDL9pgvXXAwoAbmV0d29ya19pZFA0bz4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:deepslate_gold_ore", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9nb2xkX29yZQQJAG5hbWVfaGFzaF9G7WYhKFinAwoAbmV0d29ya19pZHQTfBUKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:deepslate_diamond_ore", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9kaWFtb25kX29yZQQJAG5hbWVfaGFzaEUH5USh+iD3AwoAbmV0d29ya19pZHP6VzAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:deepslate_lapis_ore", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV9sYXBpc19vcmUECQBuYW1lX2hhc2j+yFxU/KZs1gMKAG5ldHdvcmtfaWRKINzICgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:deepslate_redstone_ore", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9yZWRzdG9uZV9vcmUECQBuYW1lX2hhc2iVgM3wWWD6ugMKAG5ldHdvcmtfaWReBdYRCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:deepslate_emerald_ore", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9lbWVyYWxkX29yZQQJAG5hbWVfaGFzaNlfo5HTwS6wAwoAbmV0d29ya19pZNeie6sKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:deepslate_coal_ore", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb2FsX29yZQQJAG5hbWVfaGFzaIjikmcbRrPPAwoAbmV0d29ya19pZD9TiygKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:deepslate_copper_ore", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb3BwZXJfb3JlBAkAbmFtZV9oYXNottjV4Ev5LAQDCgBuZXR3b3JrX2lkP23rgQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:gravel", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmdyYXZlbAQJAG5hbWVfaGFzaOFxz8XJd2r/AwoAbmV0d29ya19pZBpfI1sKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkbtgs0goGAHN0YXRlcwgKAHN0b25lX3R5cGUHAGdyYW5pdGUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lk3sDePAoGAHN0YXRlcwgKAHN0b25lX3R5cGUHAGRpb3JpdGUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkYG+0YwoGAHN0YXRlcwgKAHN0b25lX3R5cGUIAGFuZGVzaXRlAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:blackstone", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrc3RvbmUECQBuYW1lX2hhc2iMFYziD80D6QMKAG5ldHdvcmtfaWSrUryHCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:deepslate", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmRlZXBzbGF0ZQQJAG5hbWVfaGFzaKX5pAblxz8TAwoAbmV0d29ya19pZOJoQjsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkREbyhwoGAHN0YXRlcwgKAHN0b25lX3R5cGUOAGdyYW5pdGVfc21vb3RoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lk/EZ3UwoGAHN0YXRlcwgKAHN0b25lX3R5cGUOAGRpb3JpdGVfc21vb3RoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkmjeVIwoGAHN0YXRlcwgKAHN0b25lX3R5cGUPAGFuZGVzaXRlX3Ntb290aAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:polished_blackstone", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2jT9fHCl6vWQQMKAG5ldHdvcmtfaWR/Ho6oCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:polished_deepslate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaHC1edoaWF3uAwoAbmV0d29ya19pZCPeQsEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:sand", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWTekU/mCgYAc3RhdGVzCAkAc2FuZF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:sand", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWSTgcqmCgYAc3RhdGVzCAkAc2FuZF90eXBlAwByZWQAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cactus", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhY3R1cwQJAG5hbWVfaGFzaCG9zL0N4wvGAwoAbmV0d29ya19pZDeCERAKBgBzdGF0ZXMDAwBhZ2UAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:oak_log", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWQjfjoxCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stripped_oak_log", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0cmlwcGVkX29ha19sb2cECQBuYW1lX2hhc2h8dqh+OOHU4wMKAG5ldHdvcmtfaWSYKjdrCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:spruce_log", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNwcnVjZV9sb2cECQBuYW1lX2hhc2hZ03qaLoF3WgMKAG5ldHdvcmtfaWRlFD8eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stripped_spruce_log", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV9sb2cECQBuYW1lX2hhc2iNrhKjS5IyrgMKAG5ldHdvcmtfaWRQcEC3CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:birch_log", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmJpcmNoX2xvZwQJAG5hbWVfaGFzaBUzT3NxsZAnAwoAbmV0d29ya19pZBKN3VQKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stripped_birch_log", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX2xvZwQJAG5hbWVfaGFzaCFKS4AeuSidAwoAbmV0d29ya19pZN0IONIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:jungle_log", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Omp1bmdsZV9sb2cECQBuYW1lX2hhc2gkwW0KNulqDgMKAG5ldHdvcmtfaWQaziU/CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stripped_jungle_log", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV9sb2cECQBuYW1lX2hhc2hAwMsgOk02JAMKAG5ldHdvcmtfaWQvls0eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:acacia_log", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmFjYWNpYV9sb2cECQBuYW1lX2hhc2iV48VpYhjoYQMKAG5ldHdvcmtfaWRxEqe0CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stripped_acacia_log", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV9sb2cECQBuYW1lX2hhc2hJb0lQqnEqlgMKAG5ldHdvcmtfaWRg3IdRCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:dark_oak_log", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaIWfVRd0XUo3AwoAbmV0d29ya19pZPMM7LYKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stripped_dark_oak_log", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaPFTdxRdPwkOAwoAbmV0d29ya19pZDIzenIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:mangrove_log", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaHZe6DzPZBobAwoAbmV0d29ya19pZG6DuYkKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stripped_mangrove_log", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaLqIBo4hwA//AwoAbmV0d29ya19pZPtRn7UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cherry_log", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmNoZXJyeV9sb2cECQBuYW1lX2hhc2hwFlaioppB1wMKAG5ldHdvcmtfaWS2sdXECgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stripped_cherry_log", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV9sb2cECQBuYW1lX2hhc2i85H6G+WhXaAMKAG5ldHdvcmtfaWRjzoglCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:crimson_stem", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc3RlbQQJAG5hbWVfaGFzaM0FzfL0UTKZAwoAbmV0d29ya19pZKvzID0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stripped_crimson_stem", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25fc3RlbQQJAG5hbWVfaGFzaDlA6nood57EAwoAbmV0d29ya19pZHrIqjIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:warped_stem", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zdGVtBAkAbmFtZV9oYXNon7cKfPZxdrUDCgBuZXR3b3JrX2lkerWyMwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stripped_warped_stem", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9zdGVtBAkAbmFtZV9oYXNoEw+y0dDPSd8DCgBuZXR3b3JrX2lkIQ9vBAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSYGFlqCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlAwBvYWsAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSxnUzvCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlAwBvYWsAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWToyw4RCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBzcHJ1Y2UAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWTL0a3ZCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBzcHJ1Y2UAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQV99vJCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBQBiaXJjaAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQYDJk1CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBQBiaXJjaAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSfH48gCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBqdW5nbGUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQ44auiCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBqdW5nbGUAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSogpPYCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBhY2FjaWEAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSD7hT1CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBhY2FjaWEAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQagb3gCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlCABkYXJrX29hawADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQdnWU+CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlCABkYXJrX29hawADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:mangrove_wood", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2iXVxG0JG2fVAMKAG5ldHdvcmtfaWTok1JCCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stripped_mangrove_wood", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2h7CkbaBF7/WAMKAG5ldHdvcmtfaWQLAX88CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cherry_wood", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV93b29kBAkAbmFtZV9oYXNoAW8srlmpBM8DCgBuZXR3b3JrX2lkEALMfAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AQwAc3RyaXBwZWRfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stripped_cherry_wood", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV93b29kBAkAbmFtZV9oYXNo/e7KXv+CB38DCgBuZXR3b3JrX2lkg5aVtQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:crimson_hyphae", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNouRmKmfSqEWADCgBuZXR3b3JrX2lk+Tm5rQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stripped_crimson_hyphae", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNoFffwmABq4LUDCgBuZXR3b3JrX2lkZAlUbgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:warped_hyphae", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2hn8plQUr6pmQMKAG5ldHdvcmtfaWRU2AIBCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:stripped_warped_hyphae", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2irKq+HYPSgjQMKAG5ldHdvcmtfaWSbrOPDCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:bamboo_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19ibG9jawQJAG5hbWVfaGFzaAbDeur6stIBAwoAbmV0d29ya19pZCJAwn0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:stripped_bamboo_block", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2JhbWJvb19ibG9jawQJAG5hbWVfaGFzaJpwytpZOZM9AwoAbmV0d29ya19pZKuRbNEKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZOmqtzMKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlAwBvYWsBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZFMVNEQKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBgBzcHJ1Y2UBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZKCZEm8KBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBQBiaXJjaAEOAHBlcnNpc3RlbnRfYml0AAEKAHVwZGF0ZV9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZABprGgKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBgBqdW5nbGUBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:leaves2", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmxlYXZlczIECQBuYW1lX2hhc2gy/bgrncY1ZAMKAG5ldHdvcmtfaWSFh3olCgYAc3RhdGVzCA0AbmV3X2xlYWZfdHlwZQYAYWNhY2lhAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:leaves2", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmxlYXZlczIECQBuYW1lX2hhc2gy/bgrncY1ZAMKAG5ldHdvcmtfaWTvEAyeCgYAc3RhdGVzCA0AbmV3X2xlYWZfdHlwZQgAZGFya19vYWsBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:mangrove_leaves", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2xlYXZlcwQJAG5hbWVfaGFzaKyI/dWvhEG8AwoAbmV0d29ya19pZPQxCZ8KBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cherry_leaves", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9sZWF2ZXMECQBuYW1lX2hhc2giTs9ChhYBlQMKAG5ldHdvcmtfaWR8bPpwCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:azalea_leaves", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXMECQBuYW1lX2hhc2iXFhD57wFS7AMKAG5ldHdvcmtfaWTNB/9ECgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:azalea_leaves_flowered", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXNfZmxvd2VyZWQECQBuYW1lX2hhc2gs8jxlS/pMrwMKAG5ldHdvcmtfaWQ7W4PyCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQmoOEvCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUDAG9hawADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQO8pAmCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAHNwcnVjZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQDHhokCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUFAGJpcmNoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWTdQrcyCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAGp1bmdsZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRCDffNCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAGFjYWNpYQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWR0BRzPCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUIAGRhcmtfb2FrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:mangrove_propagule", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hbmdyb3ZlX3Byb3BhZ3VsZQQJAG5hbWVfaGFzaJGeox6hkfLFAwoAbmV0d29ya19pZAIpvpYKBgBzdGF0ZXMBBwBoYW5naW5nAAMPAHByb3BhZ3VsZV9zdGFnZQAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cherry_sapling", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNoZXJyeV9zYXBsaW5nBAkAbmFtZV9oYXNoGrPpNMf1LtcDCgBuZXR3b3JrX2lkypakXQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bee_nest", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmJlZV9uZXN0BAkAbmFtZV9oYXNo2R2WBxUHEZIDCgBuZXR3b3JrX2lkiXWLEAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAADCwBob25leV9sZXZlbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wheat_seeds" - }, - { - "id": "minecraft:pumpkin_seeds" - }, - { - "id": "minecraft:melon_seeds" - }, - { - "id": "minecraft:beetroot_seeds" - }, - { - "id": "minecraft:torchflower_seeds" - }, - { - "id": "minecraft:pitcher_pod" - }, - { - "id": "minecraft:wheat" - }, - { - "id": "minecraft:beetroot" - }, - { - "id": "minecraft:potato" - }, - { - "id": "minecraft:poisonous_potato" - }, - { - "id": "minecraft:carrot" - }, - { - "id": "minecraft:golden_carrot" - }, - { - "id": "minecraft:apple" - }, - { - "id": "minecraft:golden_apple" - }, - { - "id": "minecraft:enchanted_golden_apple" - }, - { - "id": "minecraft:melon_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1lbG9uX2Jsb2NrBAkAbmFtZV9oYXNoXxSm0iYpAx8DCgBuZXR3b3JrX2lkC9rqygoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:melon_slice" - }, - { - "id": "minecraft:glistering_melon_slice" - }, - { - "id": "minecraft:sweet_berries" - }, - { - "id": "minecraft:glow_berries" - }, - { - "id": "minecraft:pumpkin", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnB1bXBraW4ECQBuYW1lX2hhc2gc8A3jaSzWbgMKAG5ldHdvcmtfaWRFGA+xCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:carved_pumpkin", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNhcnZlZF9wdW1wa2luBAkAbmFtZV9oYXNoPu1T0MJuG90DCgBuZXR3b3JrX2lkXNNn5QoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:lit_pumpkin", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpdF9wdW1wa2luBAkAbmFtZV9oYXNo7gWtEm2uPL0DCgBuZXR3b3JrX2lki8sU4AoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:honeycomb" - }, - { - "id": "minecraft:tallgrass", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZOh33DMKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAGZlcm4AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZMx1sfgKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAZmVybgEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:tallgrass", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZErptfIKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAHRhbGwAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZAbadmIKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQUAZ3Jhc3MBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:nether_sprouts" - }, - { - "id": "minecraft:fire_coral", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWS9vF0UCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:brain_coral", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJyYWluX2NvcmFsBAkAbmFtZV9oYXNoRiWlLCwA2ycDCgBuZXR3b3JrX2lkrjAuhgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:bubble_coral", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbAQJAG5hbWVfaGFzaJz6rWnl+v2qAwoAbmV0d29ya19pZImIWy0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:tube_coral", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnR1YmVfY29yYWwECQBuYW1lX2hhc2iYa8oO/tgk7wMKAG5ldHdvcmtfaWRTfND5CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:horn_coral", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Omhvcm5fY29yYWwECQBuYW1lX2hhc2iZnRHjZbnLPgMKAG5ldHdvcmtfaWR+GGp8CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:dead_fire_coral", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbAQJAG5hbWVfaGFzaEPU6tFy/latAwoAbmV0d29ya19pZNMa7V4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:dead_brain_coral", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWwECQBuYW1lX2hhc2j5L6QJCISvzwMKAG5ldHdvcmtfaWQkKzeiCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:dead_bubble_coral", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsBAkAbmFtZV9oYXNoSTOZ/8wpeNYDCgBuZXR3b3JrX2lka6w9DAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:dead_tube_coral", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbAQJAG5hbWVfaGFzaJGjNWhlaIJeAwoAbmV0d29ya19pZO3Z0ygKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:dead_horn_coral", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbAQJAG5hbWVfaGFzaJBkz3qt+g2cAwoAbmV0d29ya19pZBAN+eYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZOg7iS4KBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgMAcmVkAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZIDj8HMKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgQAcGluawMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZLCJP0kKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgYAcHVycGxlAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZFz2ly4KBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgQAYmx1ZQMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZE4TgnYKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgYAeWVsbG93AxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkdhLQzwoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkSi6srQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkGiGSzAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkmvZKOgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lknLw+4QoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:crimson_roots", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fcm9vdHMECQBuYW1lX2hhc2j1fWgQLViv5QMKAG5ldHdvcmtfaWRLh5DXCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:warped_roots", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9yb290cwQJAG5hbWVfaGFzaBc3WvbJOLlkAwoAbmV0d29ya19pZNLgDnAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:yellow_flower", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19mbG93ZXIECQBuYW1lX2hhc2jWbU1pF0OUGAMKAG5ldHdvcmtfaWQgO3hpCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWSqsqQGCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUFAHBvcHB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTqDajjCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUGAG9yY2hpZAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWT5CjveCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUGAGFsbGl1bQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTORIBJCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUJAGhvdXN0b25pYQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTuNhmYCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUJAHR1bGlwX3JlZAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWT0O4nfCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUMAHR1bGlwX29yYW5nZQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTqkthyCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGULAHR1bGlwX3doaXRlAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRMbBA7CgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUKAHR1bGlwX3BpbmsAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRexMAuCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUFAG94ZXllAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWQgs7BECgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUKAGNvcm5mbG93ZXIAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRvDuNbCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUSAGxpbHlfb2ZfdGhlX3ZhbGxleQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZOemRt4KBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQkAc3VuZmxvd2VyAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZOFugoEKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAc3lyaW5nYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZN4O+/gKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAcm9zZQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZI3w4GMKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAcGFlb25pYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:pitcher_plant", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnBpdGNoZXJfcGxhbnQECQBuYW1lX2hhc2hRJHzsbDH+SQMKAG5ldHdvcmtfaWRnY76VCgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:pink_petals", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfcGV0YWxzBAkAbmFtZV9oYXNo6DQwN9SwV3QDCgBuZXR3b3JrX2lkNWneGgoGAHN0YXRlcwMGAGdyb3d0aAAAAAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:wither_rose", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OndpdGhlcl9yb3NlBAkAbmFtZV9oYXNoaSKxl3I516gDCgBuZXR3b3JrX2lkATXLPwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:torchflower", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnRvcmNoZmxvd2VyBAkAbmFtZV9oYXNoL+mHtElwbqQDCgBuZXR3b3JrX2lkI34O+AoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:white_dye" - }, - { - "id": "minecraft:light_gray_dye" - }, - { - "id": "minecraft:gray_dye" - }, - { - "id": "minecraft:black_dye" - }, - { - "id": "minecraft:brown_dye" - }, - { - "id": "minecraft:red_dye" - }, - { - "id": "minecraft:orange_dye" - }, - { - "id": "minecraft:yellow_dye" - }, - { - "id": "minecraft:lime_dye" - }, - { - "id": "minecraft:green_dye" - }, - { - "id": "minecraft:cyan_dye" - }, - { - "id": "minecraft:light_blue_dye" - }, - { - "id": "minecraft:blue_dye" - }, - { - "id": "minecraft:purple_dye" - }, - { - "id": "minecraft:magenta_dye" - }, - { - "id": "minecraft:pink_dye" - }, - { - "id": "minecraft:ink_sac" - }, - { - "id": "minecraft:glow_ink_sac" - }, - { - "id": "minecraft:cocoa_beans" - }, - { - "id": "minecraft:lapis_lazuli" - }, - { - "id": "minecraft:bone_meal" - }, - { - "id": "minecraft:vine", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnZpbmUECQBuYW1lX2hhc2j0Sj8/XeXOLAMKAG5ldHdvcmtfaWSUkDtbCgYAc3RhdGVzAxMAdmluZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:weeping_vines", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndlZXBpbmdfdmluZXMECQBuYW1lX2hhc2jrLgLHkQygiwMKAG5ldHdvcmtfaWQ8NHSJCgYAc3RhdGVzAxEAd2VlcGluZ192aW5lc19hZ2UAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:twisting_vines", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnR3aXN0aW5nX3ZpbmVzBAkAbmFtZV9oYXNoDYR5QgVUQJADCgBuZXR3b3JrX2lk5kYVIQoGAHN0YXRlcwMSAHR3aXN0aW5nX3ZpbmVzX2FnZQAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:waterlily", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OndhdGVybGlseQQJAG5hbWVfaGFzaEHgC4c1SXg0AwoAbmV0d29ya19pZOOerp8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:seagrass", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OnNlYWdyYXNzBAkAbmFtZV9oYXNoHSBFtoHdWxIDCgBuZXR3b3JrX2lkd3lhEAoGAHN0YXRlcwgOAHNlYV9ncmFzc190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:kelp" - }, - { - "id": "minecraft:deadbush", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmRlYWRidXNoBAkAbmFtZV9oYXNoPFODe4IScnYDCgBuZXR3b3JrX2lkVfnl+goGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:bamboo", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmJhbWJvbwQJAG5hbWVfaGFzaBgpGmyzhedCAwoAbmV0d29ya19pZIZv1nYKBgBzdGF0ZXMBBwBhZ2VfYml0AAgQAGJhbWJvb19sZWFmX3NpemUJAG5vX2xlYXZlcwgWAGJhbWJvb19zdGFsa190aGlja25lc3MEAHRoaW4AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:snow", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnNub3cECQBuYW1lX2hhc2gVHr5XXdETWAMKAG5ldHdvcmtfaWQ0zCeHCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:ice", - "block_state_b64": "CgAACAQAbmFtZQ0AbWluZWNyYWZ0OmljZQQJAG5hbWVfaGFzaNF26f+uUT29AwoAbmV0d29ya19pZOUMaQYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:packed_ice", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9pY2UECQBuYW1lX2hhc2hk4bu123ZrFgMKAG5ldHdvcmtfaWTr/ooaCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:blue_ice", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmJsdWVfaWNlBAkAbmFtZV9oYXNo+EKxYgFhKcgDCgBuZXR3b3JrX2lkxfsA8goGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:snow_layer", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNub3dfbGF5ZXIECQBuYW1lX2hhc2hXka6atMYUCQMKAG5ldHdvcmtfaWRCrIPcCgYAc3RhdGVzAQsAY292ZXJlZF9iaXQAAwYAaGVpZ2h0AAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:pointed_dripstone", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvaW50ZWRfZHJpcHN0b25lBAkAbmFtZV9oYXNoJMISzmHQgt8DCgBuZXR3b3JrX2lkbWrtYgoGAHN0YXRlcwgTAGRyaXBzdG9uZV90aGlja25lc3MDAHRpcAEHAGhhbmdpbmcBAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:dripstone_block", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRyaXBzdG9uZV9ibG9jawQJAG5hbWVfaGFzaIIXnEqY77YsAwoAbmV0d29ya19pZMZi2kwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:moss_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vc3NfY2FycGV0BAkAbmFtZV9oYXNo/NEDxRPTshYDCgBuZXR3b3JrX2lkaGG3QwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:moss_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om1vc3NfYmxvY2sECQBuYW1lX2hhc2iovcsPUYX2tgMKAG5ldHdvcmtfaWT3JSbfCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:dirt_with_roots", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRpcnRfd2l0aF9yb290cwQJAG5hbWVfaGFzaLCNDYPviDCIAwoAbmV0d29ya19pZNCkwzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:hanging_roots", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omhhbmdpbmdfcm9vdHMECQBuYW1lX2hhc2jaXn+Y5UZpDAMKAG5ldHdvcmtfaWRU4c2vCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:mangrove_roots", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNoa786PzQGZ6kDCgBuZXR3b3JrX2lklA0AHgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:muddy_mangrove_roots", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0Om11ZGR5X21hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNo9YApdHpo1RkDCgBuZXR3b3JrX2lkH0Oc4woGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:big_dripleaf", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpZ19kcmlwbGVhZgQJAG5hbWVfaGFzaGBEhXjo6qSdAwoAbmV0d29ya19pZMETsb8KBgBzdGF0ZXMBEQBiaWdfZHJpcGxlYWZfaGVhZAEIEQBiaWdfZHJpcGxlYWZfdGlsdAQAbm9uZQgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:small_dripleaf_block", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtYWxsX2RyaXBsZWFmX2Jsb2NrBAkAbmFtZV9oYXNojxRAgXP9uWADCgBuZXR3b3JrX2lkozbVPwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24EAGVhc3QBDwB1cHBlcl9ibG9ja19iaXQBAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:spore_blossom", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwb3JlX2Jsb3Nzb20ECQBuYW1lX2hhc2il3U72Gbco2gMKAG5ldHdvcmtfaWSbbbgcCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:azalea", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmF6YWxlYQQJAG5hbWVfaGFzaNyUl+BW9JrBAwoAbmV0d29ya19pZO/XZtQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:flowering_azalea", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmZsb3dlcmluZ19hemFsZWEECQBuYW1lX2hhc2ie9r33wz8kiwMKAG5ldHdvcmtfaWQ3ij0VCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:glow_lichen", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Omdsb3dfbGljaGVuBAkAbmFtZV9oYXNobyPUrIYlo44DCgBuZXR3b3JrX2lkCh8lSAoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHM/AAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:amethyst_block", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmFtZXRoeXN0X2Jsb2NrBAkAbmFtZV9oYXNob+JK1iiAthcDCgBuZXR3b3JrX2lk8HtpzgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:budding_amethyst", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1ZGRpbmdfYW1ldGh5c3QECQBuYW1lX2hhc2gJvAwfI14fxgMKAG5ldHdvcmtfaWTQYqfACgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:amethyst_cluster", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmFtZXRoeXN0X2NsdXN0ZXIECQBuYW1lX2hhc2jK82S88Jgm8wMKAG5ldHdvcmtfaWSCPMPGCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:large_amethyst_bud", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmxhcmdlX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaAHhdpWD+sd5AwoAbmV0d29ya19pZKkQxOcKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:medium_amethyst_bud", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om1lZGl1bV9hbWV0aHlzdF9idWQECQBuYW1lX2hhc2g5lBGtC0DzZQMKAG5ldHdvcmtfaWSYiP4gCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:small_amethyst_bud", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnNtYWxsX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaEnb4+q9PO4YAwoAbmV0d29ya19pZGWzxrQKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:tuff", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnR1ZmYECQBuYW1lX2hhc2h1Rwc1XYsBGwMKAG5ldHdvcmtfaWRwQGn0CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:calcite", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmNhbGNpdGUECQBuYW1lX2hhc2ixKLu8ZIdzDQMKAG5ldHdvcmtfaWQlSbJDCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:chicken" - }, - { - "id": "minecraft:porkchop" - }, - { - "id": "minecraft:beef" - }, - { - "id": "minecraft:mutton" - }, - { - "id": "minecraft:rabbit" - }, - { - "id": "minecraft:cod" - }, - { - "id": "minecraft:salmon" - }, - { - "id": "minecraft:tropical_fish" - }, - { - "id": "minecraft:pufferfish" - }, - { - "id": "minecraft:brown_mushroom", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkLh1OXAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_mushroom", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9tdXNocm9vbQQJAG5hbWVfaGFzaPpzJua7669xAwoAbmV0d29ya19pZCvWPYkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:crimson_fungus", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fZnVuZ3VzBAkAbmFtZV9oYXNolIcCUuFM2u0DCgBuZXR3b3JrX2lkD2NN0QoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:warped_fungus", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9mdW5ndXMECQBuYW1lX2hhc2gq8bSnRVTAFgMKAG5ldHdvcmtfaWTkwS+rCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkdOMhDAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw4AAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_mushroom_block", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9tdXNocm9vbV9ibG9jawQJAG5hbWVfaGFzaJTTyJbth9M9AwoAbmV0d29ya19pZM+AyboKBgBzdGF0ZXMDEgBodWdlX211c2hyb29tX2JpdHMOAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkbdt3CAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw8AAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkSrMl9goGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cwAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:egg" - }, - { - "id": "minecraft:sugar_cane" - }, - { - "id": "minecraft:sugar" - }, - { - "id": "minecraft:rotten_flesh" - }, - { - "id": "minecraft:bone" - }, - { - "id": "minecraft:web", - "block_state_b64": "CgAACAQAbmFtZQ0AbWluZWNyYWZ0OndlYgQJAG5hbWVfaGFzaA4GKQCvG4i9AwoAbmV0d29ya19pZApt+jgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:spider_eye" - }, - { - "id": "minecraft:mob_spawner", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vYl9zcGF3bmVyBAkAbmFtZV9oYXNoNwGrCV/Fkh8DCgBuZXR3b3JrX2lkM1wTmgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqXH7RgoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUFAHN0b25lAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkeIBb6QoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAGNvYmJsZXN0b25lAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkDZ2cFQoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAHN0b25lX2JyaWNrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkOR/cTAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGURAG1vc3N5X3N0b25lX2JyaWNrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqdwlHAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUTAGNyYWNrZWRfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFqqPggoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUUAGNoaXNlbGVkX3N0b25lX2JyaWNrAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:infested_deepslate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmluZmVzdGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaICF2VYccxF1AwoAbmV0d29ya19pZDa/624KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:dragon_egg", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmRyYWdvbl9lZ2cECQBuYW1lX2hhc2inMzXrV+/e1wMKAG5ldHdvcmtfaWTgO1yRCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:turtle_egg", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnR1cnRsZV9lZ2cECQBuYW1lX2hhc2iwSRcxOJIJ9gMKAG5ldHdvcmtfaWSIRNUhCgYAc3RhdGVzCA0AY3JhY2tlZF9zdGF0ZQkAbm9fY3JhY2tzCBAAdHVydGxlX2VnZ19jb3VudAcAb25lX2VnZwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sniffer_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnNuaWZmZXJfZWdnBAkAbmFtZV9oYXNoY1lozc8lPcYDCgBuZXR3b3JrX2lk7yb/2QoGAHN0YXRlcwgNAGNyYWNrZWRfc3RhdGUJAG5vX2NyYWNrcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:frog_spawn", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmZyb2dfc3Bhd24ECQBuYW1lX2hhc2iWmd7idp3ZZwMKAG5ldHdvcmtfaWRFzJudCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:pearlescent_froglight", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnBlYXJsZXNjZW50X2Zyb2dsaWdodAQJAG5hbWVfaGFzaKkcFRyycYGyAwoAbmV0d29ya19pZJqYakAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:verdant_froglight", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnZlcmRhbnRfZnJvZ2xpZ2h0BAkAbmFtZV9oYXNoA+eXuTBohrQDCgBuZXR3b3JrX2lkDIVnsQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:ochre_froglight", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om9jaHJlX2Zyb2dsaWdodAQJAG5hbWVfaGFzaMY59kjPe+c3AwoAbmV0d29ya19pZO2TD50KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:chicken_spawn_egg" - }, - { - "id": "minecraft:bee_spawn_egg" - }, - { - "id": "minecraft:cow_spawn_egg" - }, - { - "id": "minecraft:pig_spawn_egg" - }, - { - "id": "minecraft:sheep_spawn_egg" - }, - { - "id": "minecraft:wolf_spawn_egg" - }, - { - "id": "minecraft:polar_bear_spawn_egg" - }, - { - "id": "minecraft:ocelot_spawn_egg" - }, - { - "id": "minecraft:cat_spawn_egg" - }, - { - "id": "minecraft:mooshroom_spawn_egg" - }, - { - "id": "minecraft:bat_spawn_egg" - }, - { - "id": "minecraft:parrot_spawn_egg" - }, - { - "id": "minecraft:rabbit_spawn_egg" - }, - { - "id": "minecraft:llama_spawn_egg" - }, - { - "id": "minecraft:horse_spawn_egg" - }, - { - "id": "minecraft:donkey_spawn_egg" - }, - { - "id": "minecraft:mule_spawn_egg" - }, - { - "id": "minecraft:skeleton_horse_spawn_egg" - }, - { - "id": "minecraft:zombie_horse_spawn_egg" - }, - { - "id": "minecraft:tropical_fish_spawn_egg" - }, - { - "id": "minecraft:cod_spawn_egg" - }, - { - "id": "minecraft:pufferfish_spawn_egg" - }, - { - "id": "minecraft:salmon_spawn_egg" - }, - { - "id": "minecraft:dolphin_spawn_egg" - }, - { - "id": "minecraft:turtle_spawn_egg" - }, - { - "id": "minecraft:panda_spawn_egg" - }, - { - "id": "minecraft:fox_spawn_egg" - }, - { - "id": "minecraft:creeper_spawn_egg" - }, - { - "id": "minecraft:enderman_spawn_egg" - }, - { - "id": "minecraft:silverfish_spawn_egg" - }, - { - "id": "minecraft:skeleton_spawn_egg" - }, - { - "id": "minecraft:wither_skeleton_spawn_egg" - }, - { - "id": "minecraft:stray_spawn_egg" - }, - { - "id": "minecraft:slime_spawn_egg" - }, - { - "id": "minecraft:spider_spawn_egg" - }, - { - "id": "minecraft:zombie_spawn_egg" - }, - { - "id": "minecraft:zombie_pigman_spawn_egg" - }, - { - "id": "minecraft:husk_spawn_egg" - }, - { - "id": "minecraft:drowned_spawn_egg" - }, - { - "id": "minecraft:squid_spawn_egg" - }, - { - "id": "minecraft:glow_squid_spawn_egg" - }, - { - "id": "minecraft:cave_spider_spawn_egg" - }, - { - "id": "minecraft:witch_spawn_egg" - }, - { - "id": "minecraft:guardian_spawn_egg" - }, - { - "id": "minecraft:elder_guardian_spawn_egg" - }, - { - "id": "minecraft:endermite_spawn_egg" - }, - { - "id": "minecraft:magma_cube_spawn_egg" - }, - { - "id": "minecraft:strider_spawn_egg" - }, - { - "id": "minecraft:hoglin_spawn_egg" - }, - { - "id": "minecraft:piglin_spawn_egg" - }, - { - "id": "minecraft:zoglin_spawn_egg" - }, - { - "id": "minecraft:piglin_brute_spawn_egg" - }, - { - "id": "minecraft:goat_spawn_egg" - }, - { - "id": "minecraft:axolotl_spawn_egg" - }, - { - "id": "minecraft:warden_spawn_egg" - }, - { - "id": "minecraft:allay_spawn_egg" - }, - { - "id": "minecraft:frog_spawn_egg" - }, - { - "id": "minecraft:tadpole_spawn_egg" - }, - { - "id": "minecraft:trader_llama_spawn_egg" - }, - { - "id": "minecraft:camel_spawn_egg" - }, - { - "id": "minecraft:ghast_spawn_egg" - }, - { - "id": "minecraft:blaze_spawn_egg" - }, - { - "id": "minecraft:shulker_spawn_egg" - }, - { - "id": "minecraft:vindicator_spawn_egg" - }, - { - "id": "minecraft:evoker_spawn_egg" - }, - { - "id": "minecraft:vex_spawn_egg" - }, - { - "id": "minecraft:villager_spawn_egg" - }, - { - "id": "minecraft:wandering_trader_spawn_egg" - }, - { - "id": "minecraft:zombie_villager_spawn_egg" - }, - { - "id": "minecraft:phantom_spawn_egg" - }, - { - "id": "minecraft:pillager_spawn_egg" - }, - { - "id": "minecraft:ravager_spawn_egg" - }, - { - "id": "minecraft:iron_golem_spawn_egg" - }, - { - "id": "minecraft:snow_golem_spawn_egg" - }, - { - "id": "minecraft:sniffer_spawn_egg" - }, - { - "id": "minecraft:obsidian", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2lkaWFuBAkAbmFtZV9oYXNoiz4qrb8QjyEDCgBuZXR3b3JrX2lkuqnPpQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:crying_obsidian", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmNyeWluZ19vYnNpZGlhbgQJAG5hbWVfaGFzaKT0JlA7Z1K+AwoAbmV0d29ya19pZCjbPV4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:bedrock", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmJlZHJvY2sECQBuYW1lX2hhc2hWfFrh4LVtxwMKAG5ldHdvcmtfaWT7fKz1CgYAc3RhdGVzAQ4AaW5maW5pYnVybl9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:soul_sand", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc2FuZAQJAG5hbWVfaGFzaMaf+bccu+KTAwoAbmV0d29ya19pZBQSHrMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:magma", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0Om1hZ21hBAkAbmFtZV9oYXNoqyTjKaIsWfYDCgBuZXR3b3JrX2lkyfWAZgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:nether_wart" - }, - { - "id": "minecraft:end_stone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmVuZF9zdG9uZQQJAG5hbWVfaGFzaH1J9jA39GJNAwoAbmV0d29ya19pZFeFQ7UKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:chorus_flower", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNob3J1c19mbG93ZXIECQBuYW1lX2hhc2iMpSodli5uawMKAG5ldHdvcmtfaWRnd1ZWCgYAc3RhdGVzAwMAYWdlAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:chorus_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNob3J1c19wbGFudAQJAG5hbWVfaGFzaJhSrmNGKwaMAwoAbmV0d29ya19pZA3uVqMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:chorus_fruit" - }, - { - "id": "minecraft:popped_chorus_fruit" - }, - { - "id": "minecraft:sponge", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZF01rO0KBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAZHJ5AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:sponge", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZPiOc4QKBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAd2V0AAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkGnlaAwoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkSnHuagoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkmkHyegoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkdpUDxgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkYNWvYgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkZSxBQgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lklSTVqQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lk5fTYuQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkwUjqBAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkq4iWoQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:sculk", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lkyqUPPgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sculk_vein", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNjdWxrX3ZlaW4ECQBuYW1lX2hhc2gJUdhVooV4zwMKAG5ldHdvcmtfaWSUfn1XCgYAc3RhdGVzAxkAbXVsdGlfZmFjZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:sculk_catalyst", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX2NhdGFseXN0BAkAbmFtZV9oYXNo+gCpbrCHST4DCgBuZXR3b3JrX2lkMJ2n/woGAHN0YXRlcwEFAGJsb29tAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sculk_shrieker", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX3Nocmlla2VyBAkAbmFtZV9oYXNo5OXtyObniQ4DCgBuZXR3b3JrX2lkxapoNAoGAHN0YXRlcwEGAGFjdGl2ZQABCgBjYW5fc3VtbW9uAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sculk_sensor", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnNjdWxrX3NlbnNvcgQJAG5hbWVfaGFzaCkmHreeTgNnAwoAbmV0d29ya19pZLj2WPcKBgBzdGF0ZXMDEgBzY3Vsa19zZW5zb3JfcGhhc2UAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:calibrated_sculk_sensor", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmNhbGlicmF0ZWRfc2N1bGtfc2Vuc29yBAkAbmFtZV9oYXNoffAcXXN/iJUDCgBuZXR3b3JrX2lkwOx3QQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAxIAc2N1bGtfc2Vuc29yX3BoYXNlAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:reinforced_deepslate", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlaW5mb3JjZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoldDmj91EapQDCgBuZXR3b3JrX2lkHIt+aQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:leather_helmet" - }, - { - "id": "minecraft:chainmail_helmet" - }, - { - "id": "minecraft:iron_helmet" - }, - { - "id": "minecraft:golden_helmet" - }, - { - "id": "minecraft:diamond_helmet" - }, - { - "id": "minecraft:netherite_helmet" - }, - { - "id": "minecraft:leather_chestplate" - }, - { - "id": "minecraft:chainmail_chestplate" - }, - { - "id": "minecraft:iron_chestplate" - }, - { - "id": "minecraft:golden_chestplate" - }, - { - "id": "minecraft:diamond_chestplate" - }, - { - "id": "minecraft:netherite_chestplate" - }, - { - "id": "minecraft:leather_leggings" - }, - { - "id": "minecraft:chainmail_leggings" - }, - { - "id": "minecraft:iron_leggings" - }, - { - "id": "minecraft:golden_leggings" - }, - { - "id": "minecraft:diamond_leggings" - }, - { - "id": "minecraft:netherite_leggings" - }, - { - "id": "minecraft:leather_boots" - }, - { - "id": "minecraft:chainmail_boots" - }, - { - "id": "minecraft:iron_boots" - }, - { - "id": "minecraft:golden_boots" - }, - { - "id": "minecraft:diamond_boots" - }, - { - "id": "minecraft:netherite_boots" - }, - { - "id": "minecraft:wooden_sword" - }, - { - "id": "minecraft:stone_sword" - }, - { - "id": "minecraft:iron_sword" - }, - { - "id": "minecraft:golden_sword" - }, - { - "id": "minecraft:diamond_sword" - }, - { - "id": "minecraft:netherite_sword" - }, - { - "id": "minecraft:wooden_axe" - }, - { - "id": "minecraft:stone_axe" - }, - { - "id": "minecraft:iron_axe" - }, - { - "id": "minecraft:golden_axe" - }, - { - "id": "minecraft:diamond_axe" - }, - { - "id": "minecraft:netherite_axe" - }, - { - "id": "minecraft:wooden_pickaxe" - }, - { - "id": "minecraft:stone_pickaxe" - }, - { - "id": "minecraft:iron_pickaxe" - }, - { - "id": "minecraft:golden_pickaxe" - }, - { - "id": "minecraft:diamond_pickaxe" - }, - { - "id": "minecraft:netherite_pickaxe" - }, - { - "id": "minecraft:wooden_shovel" - }, - { - "id": "minecraft:stone_shovel" - }, - { - "id": "minecraft:iron_shovel" - }, - { - "id": "minecraft:golden_shovel" - }, - { - "id": "minecraft:diamond_shovel" - }, - { - "id": "minecraft:netherite_shovel" - }, - { - "id": "minecraft:wooden_hoe" - }, - { - "id": "minecraft:stone_hoe" - }, - { - "id": "minecraft:iron_hoe" - }, - { - "id": "minecraft:golden_hoe" - }, - { - "id": "minecraft:diamond_hoe" - }, - { - "id": "minecraft:netherite_hoe" - }, - { - "id": "minecraft:bow" - }, - { - "id": "minecraft:crossbow" - }, - { - "id": "minecraft:arrow" - }, - { - "id": "minecraft:arrow", - "damage": 6 - }, - { - "id": "minecraft:arrow", - "damage": 7 - }, - { - "id": "minecraft:arrow", - "damage": 8 - }, - { - "id": "minecraft:arrow", - "damage": 9 - }, - { - "id": "minecraft:arrow", - "damage": 10 - }, - { - "id": "minecraft:arrow", - "damage": 11 - }, - { - "id": "minecraft:arrow", - "damage": 12 - }, - { - "id": "minecraft:arrow", - "damage": 13 - }, - { - "id": "minecraft:arrow", - "damage": 14 - }, - { - "id": "minecraft:arrow", - "damage": 15 - }, - { - "id": "minecraft:arrow", - "damage": 16 - }, - { - "id": "minecraft:arrow", - "damage": 17 - }, - { - "id": "minecraft:arrow", - "damage": 18 - }, - { - "id": "minecraft:arrow", - "damage": 19 - }, - { - "id": "minecraft:arrow", - "damage": 20 - }, - { - "id": "minecraft:arrow", - "damage": 21 - }, - { - "id": "minecraft:arrow", - "damage": 22 - }, - { - "id": "minecraft:arrow", - "damage": 23 - }, - { - "id": "minecraft:arrow", - "damage": 24 - }, - { - "id": "minecraft:arrow", - "damage": 25 - }, - { - "id": "minecraft:arrow", - "damage": 26 - }, - { - "id": "minecraft:arrow", - "damage": 27 - }, - { - "id": "minecraft:arrow", - "damage": 28 - }, - { - "id": "minecraft:arrow", - "damage": 29 - }, - { - "id": "minecraft:arrow", - "damage": 30 - }, - { - "id": "minecraft:arrow", - "damage": 31 - }, - { - "id": "minecraft:arrow", - "damage": 32 - }, - { - "id": "minecraft:arrow", - "damage": 33 - }, - { - "id": "minecraft:arrow", - "damage": 34 - }, - { - "id": "minecraft:arrow", - "damage": 35 - }, - { - "id": "minecraft:arrow", - "damage": 36 - }, - { - "id": "minecraft:arrow", - "damage": 37 - }, - { - "id": "minecraft:arrow", - "damage": 38 - }, - { - "id": "minecraft:arrow", - "damage": 39 - }, - { - "id": "minecraft:arrow", - "damage": 40 - }, - { - "id": "minecraft:arrow", - "damage": 41 - }, - { - "id": "minecraft:arrow", - "damage": 42 - }, - { - "id": "minecraft:arrow", - "damage": 43 - }, - { - "id": "minecraft:shield" - }, - { - "id": "minecraft:cooked_chicken" - }, - { - "id": "minecraft:cooked_porkchop" - }, - { - "id": "minecraft:cooked_beef" - }, - { - "id": "minecraft:cooked_mutton" - }, - { - "id": "minecraft:cooked_rabbit" - }, - { - "id": "minecraft:cooked_cod" - }, - { - "id": "minecraft:cooked_salmon" - }, - { - "id": "minecraft:bread" - }, - { - "id": "minecraft:mushroom_stew" - }, - { - "id": "minecraft:beetroot_soup" - }, - { - "id": "minecraft:rabbit_stew" - }, - { - "id": "minecraft:baked_potato" - }, - { - "id": "minecraft:cookie" - }, - { - "id": "minecraft:pumpkin_pie" - }, - { - "id": "minecraft:cake" - }, - { - "id": "minecraft:dried_kelp" - }, - { - "id": "minecraft:fishing_rod" - }, - { - "id": "minecraft:carrot_on_a_stick" - }, - { - "id": "minecraft:warped_fungus_on_a_stick" - }, - { - "id": "minecraft:snowball" - }, - { - "id": "minecraft:shears" - }, - { - "id": "minecraft:flint_and_steel" - }, - { - "id": "minecraft:lead" - }, - { - "id": "minecraft:clock" - }, - { - "id": "minecraft:compass" - }, - { - "id": "minecraft:recovery_compass" - }, - { - "id": "minecraft:goat_horn" - }, - { - "id": "minecraft:goat_horn", - "damage": 1 - }, - { - "id": "minecraft:goat_horn", - "damage": 2 - }, - { - "id": "minecraft:goat_horn", - "damage": 3 - }, - { - "id": "minecraft:goat_horn", - "damage": 4 - }, - { - "id": "minecraft:goat_horn", - "damage": 5 - }, - { - "id": "minecraft:goat_horn", - "damage": 6 - }, - { - "id": "minecraft:goat_horn", - "damage": 7 - }, - { - "id": "minecraft:empty_map" - }, - { - "id": "minecraft:empty_map", - "damage": 2 - }, - { - "id": "minecraft:saddle" - }, - { - "id": "minecraft:leather_horse_armor" - }, - { - "id": "minecraft:iron_horse_armor" - }, - { - "id": "minecraft:golden_horse_armor" - }, - { - "id": "minecraft:diamond_horse_armor" - }, - { - "id": "minecraft:trident" - }, - { - "id": "minecraft:turtle_helmet" - }, - { - "id": "minecraft:elytra" - }, - { - "id": "minecraft:totem_of_undying" - }, - { - "id": "minecraft:glass_bottle" - }, - { - "id": "minecraft:experience_bottle" - }, - { - "id": "minecraft:potion" - }, - { - "id": "minecraft:potion", - "damage": 1 - }, - { - "id": "minecraft:potion", - "damage": 2 - }, - { - "id": "minecraft:potion", - "damage": 3 - }, - { - "id": "minecraft:potion", - "damage": 4 - }, - { - "id": "minecraft:potion", - "damage": 5 - }, - { - "id": "minecraft:potion", - "damage": 6 - }, - { - "id": "minecraft:potion", - "damage": 7 - }, - { - "id": "minecraft:potion", - "damage": 8 - }, - { - "id": "minecraft:potion", - "damage": 9 - }, - { - "id": "minecraft:potion", - "damage": 10 - }, - { - "id": "minecraft:potion", - "damage": 11 - }, - { - "id": "minecraft:potion", - "damage": 12 - }, - { - "id": "minecraft:potion", - "damage": 13 - }, - { - "id": "minecraft:potion", - "damage": 14 - }, - { - "id": "minecraft:potion", - "damage": 15 - }, - { - "id": "minecraft:potion", - "damage": 16 - }, - { - "id": "minecraft:potion", - "damage": 17 - }, - { - "id": "minecraft:potion", - "damage": 18 - }, - { - "id": "minecraft:potion", - "damage": 19 - }, - { - "id": "minecraft:potion", - "damage": 20 - }, - { - "id": "minecraft:potion", - "damage": 21 - }, - { - "id": "minecraft:potion", - "damage": 22 - }, - { - "id": "minecraft:potion", - "damage": 23 - }, - { - "id": "minecraft:potion", - "damage": 24 - }, - { - "id": "minecraft:potion", - "damage": 25 - }, - { - "id": "minecraft:potion", - "damage": 26 - }, - { - "id": "minecraft:potion", - "damage": 27 - }, - { - "id": "minecraft:potion", - "damage": 28 - }, - { - "id": "minecraft:potion", - "damage": 29 - }, - { - "id": "minecraft:potion", - "damage": 30 - }, - { - "id": "minecraft:potion", - "damage": 31 - }, - { - "id": "minecraft:potion", - "damage": 32 - }, - { - "id": "minecraft:potion", - "damage": 33 - }, - { - "id": "minecraft:potion", - "damage": 34 - }, - { - "id": "minecraft:potion", - "damage": 35 - }, - { - "id": "minecraft:potion", - "damage": 36 - }, - { - "id": "minecraft:potion", - "damage": 37 - }, - { - "id": "minecraft:potion", - "damage": 38 - }, - { - "id": "minecraft:potion", - "damage": 39 - }, - { - "id": "minecraft:potion", - "damage": 40 - }, - { - "id": "minecraft:potion", - "damage": 41 - }, - { - "id": "minecraft:potion", - "damage": 42 - }, - { - "id": "minecraft:splash_potion" - }, - { - "id": "minecraft:splash_potion", - "damage": 1 - }, - { - "id": "minecraft:splash_potion", - "damage": 2 - }, - { - "id": "minecraft:splash_potion", - "damage": 3 - }, - { - "id": "minecraft:splash_potion", - "damage": 4 - }, - { - "id": "minecraft:splash_potion", - "damage": 5 - }, - { - "id": "minecraft:splash_potion", - "damage": 6 - }, - { - "id": "minecraft:splash_potion", - "damage": 7 - }, - { - "id": "minecraft:splash_potion", - "damage": 8 - }, - { - "id": "minecraft:splash_potion", - "damage": 9 - }, - { - "id": "minecraft:splash_potion", - "damage": 10 - }, - { - "id": "minecraft:splash_potion", - "damage": 11 - }, - { - "id": "minecraft:splash_potion", - "damage": 12 - }, - { - "id": "minecraft:splash_potion", - "damage": 13 - }, - { - "id": "minecraft:splash_potion", - "damage": 14 - }, - { - "id": "minecraft:splash_potion", - "damage": 15 - }, - { - "id": "minecraft:splash_potion", - "damage": 16 - }, - { - "id": "minecraft:splash_potion", - "damage": 17 - }, - { - "id": "minecraft:splash_potion", - "damage": 18 - }, - { - "id": "minecraft:splash_potion", - "damage": 19 - }, - { - "id": "minecraft:splash_potion", - "damage": 20 - }, - { - "id": "minecraft:splash_potion", - "damage": 21 - }, - { - "id": "minecraft:splash_potion", - "damage": 22 - }, - { - "id": "minecraft:splash_potion", - "damage": 23 - }, - { - "id": "minecraft:splash_potion", - "damage": 24 - }, - { - "id": "minecraft:splash_potion", - "damage": 25 - }, - { - "id": "minecraft:splash_potion", - "damage": 26 - }, - { - "id": "minecraft:splash_potion", - "damage": 27 - }, - { - "id": "minecraft:splash_potion", - "damage": 28 - }, - { - "id": "minecraft:splash_potion", - "damage": 29 - }, - { - "id": "minecraft:splash_potion", - "damage": 30 - }, - { - "id": "minecraft:splash_potion", - "damage": 31 - }, - { - "id": "minecraft:splash_potion", - "damage": 32 - }, - { - "id": "minecraft:splash_potion", - "damage": 33 - }, - { - "id": "minecraft:splash_potion", - "damage": 34 - }, - { - "id": "minecraft:splash_potion", - "damage": 35 - }, - { - "id": "minecraft:splash_potion", - "damage": 36 - }, - { - "id": "minecraft:splash_potion", - "damage": 37 - }, - { - "id": "minecraft:splash_potion", - "damage": 38 - }, - { - "id": "minecraft:splash_potion", - "damage": 39 - }, - { - "id": "minecraft:splash_potion", - "damage": 40 - }, - { - "id": "minecraft:splash_potion", - "damage": 41 - }, - { - "id": "minecraft:splash_potion", - "damage": 42 - }, - { - "id": "minecraft:lingering_potion" - }, - { - "id": "minecraft:lingering_potion", - "damage": 1 - }, - { - "id": "minecraft:lingering_potion", - "damage": 2 - }, - { - "id": "minecraft:lingering_potion", - "damage": 3 - }, - { - "id": "minecraft:lingering_potion", - "damage": 4 - }, - { - "id": "minecraft:lingering_potion", - "damage": 5 - }, - { - "id": "minecraft:lingering_potion", - "damage": 6 - }, - { - "id": "minecraft:lingering_potion", - "damage": 7 - }, - { - "id": "minecraft:lingering_potion", - "damage": 8 - }, - { - "id": "minecraft:lingering_potion", - "damage": 9 - }, - { - "id": "minecraft:lingering_potion", - "damage": 10 - }, - { - "id": "minecraft:lingering_potion", - "damage": 11 - }, - { - "id": "minecraft:lingering_potion", - "damage": 12 - }, - { - "id": "minecraft:lingering_potion", - "damage": 13 - }, - { - "id": "minecraft:lingering_potion", - "damage": 14 - }, - { - "id": "minecraft:lingering_potion", - "damage": 15 - }, - { - "id": "minecraft:lingering_potion", - "damage": 16 - }, - { - "id": "minecraft:lingering_potion", - "damage": 17 - }, - { - "id": "minecraft:lingering_potion", - "damage": 18 - }, - { - "id": "minecraft:lingering_potion", - "damage": 19 - }, - { - "id": "minecraft:lingering_potion", - "damage": 20 - }, - { - "id": "minecraft:lingering_potion", - "damage": 21 - }, - { - "id": "minecraft:lingering_potion", - "damage": 22 - }, - { - "id": "minecraft:lingering_potion", - "damage": 23 - }, - { - "id": "minecraft:lingering_potion", - "damage": 24 - }, - { - "id": "minecraft:lingering_potion", - "damage": 25 - }, - { - "id": "minecraft:lingering_potion", - "damage": 26 - }, - { - "id": "minecraft:lingering_potion", - "damage": 27 - }, - { - "id": "minecraft:lingering_potion", - "damage": 28 - }, - { - "id": "minecraft:lingering_potion", - "damage": 29 - }, - { - "id": "minecraft:lingering_potion", - "damage": 30 - }, - { - "id": "minecraft:lingering_potion", - "damage": 31 - }, - { - "id": "minecraft:lingering_potion", - "damage": 32 - }, - { - "id": "minecraft:lingering_potion", - "damage": 33 - }, - { - "id": "minecraft:lingering_potion", - "damage": 34 - }, - { - "id": "minecraft:lingering_potion", - "damage": 35 - }, - { - "id": "minecraft:lingering_potion", - "damage": 36 - }, - { - "id": "minecraft:lingering_potion", - "damage": 37 - }, - { - "id": "minecraft:lingering_potion", - "damage": 38 - }, - { - "id": "minecraft:lingering_potion", - "damage": 39 - }, - { - "id": "minecraft:lingering_potion", - "damage": 40 - }, - { - "id": "minecraft:lingering_potion", - "damage": 41 - }, - { - "id": "minecraft:lingering_potion", - "damage": 42 - }, - { - "id": "minecraft:spyglass" - }, - { - "id": "minecraft:brush" - }, - { - "id": "minecraft:stick" - }, - { - "id": "minecraft:bed" - }, - { - "id": "minecraft:bed", - "damage": 8 - }, - { - "id": "minecraft:bed", - "damage": 7 - }, - { - "id": "minecraft:bed", - "damage": 15 - }, - { - "id": "minecraft:bed", - "damage": 12 - }, - { - "id": "minecraft:bed", - "damage": 14 - }, - { - "id": "minecraft:bed", - "damage": 1 - }, - { - "id": "minecraft:bed", - "damage": 4 - }, - { - "id": "minecraft:bed", - "damage": 5 - }, - { - "id": "minecraft:bed", - "damage": 13 - }, - { - "id": "minecraft:bed", - "damage": 9 - }, - { - "id": "minecraft:bed", - "damage": 3 - }, - { - "id": "minecraft:bed", - "damage": 11 - }, - { - "id": "minecraft:bed", - "damage": 10 - }, - { - "id": "minecraft:bed", - "damage": 2 - }, - { - "id": "minecraft:bed", - "damage": 6 - }, - { - "id": "minecraft:torch", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnRvcmNoBAkAbmFtZV9oYXNoagn7rmDBzisDCgBuZXR3b3JrX2lk+BwwuQoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:soul_torch", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNvdWxfdG9yY2gECQBuYW1lX2hhc2huixOT04BRdQMKAG5ldHdvcmtfaWShbFILCgYAc3RhdGVzCBYAdG9yY2hfZmFjaW5nX2RpcmVjdGlvbgcAdW5rbm93bgADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sea_pickle", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNlYV9waWNrbGUECQBuYW1lX2hhc2iONEfZJB+glgMKAG5ldHdvcmtfaWSINWQyCgYAc3RhdGVzAw0AY2x1c3Rlcl9jb3VudAAAAAABCABkZWFkX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:lantern", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmxhbnRlcm4ECQBuYW1lX2hhc2hMw44VI2HWygMKAG5ldHdvcmtfaWRkjQvzCgYAc3RhdGVzAQcAaGFuZ2luZwAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:soul_lantern", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnNvdWxfbGFudGVybgQJAG5hbWVfaGFzaGjIpjxk9z+RAwoAbmV0d29ya19pZGfoP8cKBgBzdGF0ZXMBBwBoYW5naW5nAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:candle", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZHsBMA0KBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:white_candle", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhbmRsZQQJAG5hbWVfaGFzaN1EG5Q1mHiEAwoAbmV0d29ya19pZKN1mmgKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:orange_candle", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYW5kbGUECQBuYW1lX2hhc2jySEVWHgUIHQMKAG5ldHdvcmtfaWSfVz82CgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:magenta_candle", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FuZGxlBAkAbmFtZV9oYXNoG0u6YIOoBSEDCgBuZXR3b3JrX2lk9xGNkQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:light_blue_candle", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FuZGxlBAkAbmFtZV9oYXNocXGeK0zgrG0DCgBuZXR3b3JrX2lk2m1y8goGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:yellow_candle", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYW5kbGUECQBuYW1lX2hhc2i00dtusU3CqQMKAG5ldHdvcmtfaWR9LTmpCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:lime_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FuZGxlBAkAbmFtZV9oYXNokcmrw5xvz7ADCgBuZXR3b3JrX2lkIAUu6QoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:pink_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FuZGxlBAkAbmFtZV9oYXNoQJdEY4sZ0dwDCgBuZXR3b3JrX2lk23Rn5AoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:gray_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FuZGxlBAkAbmFtZV9oYXNoS5poSo9wBDEDCgBuZXR3b3JrX2lk3trRCAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:light_gray_candle", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FuZGxlBAkAbmFtZV9oYXNo9ruTZLBNMasDCgBuZXR3b3JrX2lkb6DOegoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cyan_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FuZGxlBAkAbmFtZV9oYXNoc/M8PNVcjOwDCgBuZXR3b3JrX2lkZoIQOQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:purple_candle", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYW5kbGUECQBuYW1lX2hhc2jaI3xUW0/myQMKAG5ldHdvcmtfaWSnLI2BCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:blue_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FuZGxlBAkAbmFtZV9oYXNoAASSPW6TgQADCgBuZXR3b3JrX2lkrxrjQAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:brown_candle", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhbmRsZQQJAG5hbWVfaGFzaDia0l6s1+WYAwoAbmV0d29ya19pZKSkBXYKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:green_candle", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhbmRsZQQJAG5hbWVfaGFzaLeFPO1l+fIoAwoAbmV0d29ya19pZBkznDsKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:red_candle", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYW5kbGUECQBuYW1lX2hhc2jjAQpGf59ZdwMKAG5ldHdvcmtfaWRbb88GCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:black_candle", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhbmRsZQQJAG5hbWVfaGFzaB+wRDpOqREKAwoAbmV0d29ya19pZNnOnuEKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:crafting_table", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyYWZ0aW5nX3RhYmxlBAkAbmFtZV9oYXNoe76VAmjvbpYDCgBuZXR3b3JrX2lkwCxwaAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cartography_table", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmNhcnRvZ3JhcGh5X3RhYmxlBAkAbmFtZV9oYXNomaWiiD/znP8DCgBuZXR3b3JrX2lkI6FzMwoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:fletching_table", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmZsZXRjaGluZ190YWJsZQQJAG5hbWVfaGFzaPFibh8unKyUAwoAbmV0d29ya19pZJ2mW0oKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:smithing_table", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnNtaXRoaW5nX3RhYmxlBAkAbmFtZV9oYXNo4tFES2xOXEYDCgBuZXR3b3JrX2lkXWMBzQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:beehive", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmJlZWhpdmUECQBuYW1lX2hhc2hCcqn12UbNpwMKAG5ldHdvcmtfaWR/idcaCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAMLAGhvbmV5X2xldmVsAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:suspicious_sand", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnN1c3BpY2lvdXNfc2FuZAQJAG5hbWVfaGFzaL67QsuvLP00AwoAbmV0d29ya19pZKnkaIAKBgBzdGF0ZXMDEABicnVzaGVkX3Byb2dyZXNzAAAAAAEHAGhhbmdpbmcBAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:suspicious_gravel", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN1c3BpY2lvdXNfZ3JhdmVsBAkAbmFtZV9oYXNoJSVbGNk7C3oDCgBuZXR3b3JrX2lkvIEJAAoGAHN0YXRlcwMQAGJydXNoZWRfcHJvZ3Jlc3MAAAAAAQcAaGFuZ2luZwEAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:campfire" - }, - { - "id": "minecraft:soul_campfire" - }, - { - "id": "minecraft:furnace", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmZ1cm5hY2UECQBuYW1lX2hhc2ioOQrludYY8wMKAG5ldHdvcmtfaWRZxnDOCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:blast_furnace", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJsYXN0X2Z1cm5hY2UECQBuYW1lX2hhc2ivDbnjkpGm5QMKAG5ldHdvcmtfaWTcEbV/CgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:smoker", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnNtb2tlcgQJAG5hbWVfaGFzaJd1rDMkRWomAwoAbmV0d29ya19pZGWswMwKBgBzdGF0ZXMIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:respawn_anchor", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlc3Bhd25fYW5jaG9yBAkAbmFtZV9oYXNoZOdcjW05qigDCgBuZXR3b3JrX2lkmhMcaQoGAHN0YXRlcwMVAHJlc3Bhd25fYW5jaG9yX2NoYXJnZQAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:brewing_stand" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lk8Z3VowoGAHN0YXRlcwgGAGRhbWFnZQkAdW5kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkpiv8BAoGAHN0YXRlcwgGAGRhbWFnZRAAc2xpZ2h0bHlfZGFtYWdlZAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkFu+pdwoGAHN0YXRlcwgGAGRhbWFnZQwAdmVyeV9kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:grindstone", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdyaW5kc3RvbmUECQBuYW1lX2hhc2id56zc0nk99wMKAG5ldHdvcmtfaWS4Es07CgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:enchanting_table", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmVuY2hhbnRpbmdfdGFibGUECQBuYW1lX2hhc2jgIx24VLvMvwMKAG5ldHdvcmtfaWRliFFJCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bookshelf", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmJvb2tzaGVsZgQJAG5hbWVfaGFzaDU04DrgJCS9AwoAbmV0d29ya19pZBcWwIwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:chiseled_bookshelf", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2Jvb2tzaGVsZgQJAG5hbWVfaGFzaNXDBnsIsywYAwoAbmV0d29ya19pZIprt5IKBgBzdGF0ZXMDDABib29rc19zdG9yZWQAAAAAAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:lectern", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmxlY3Rlcm4ECQBuYW1lX2hhc2j5Z4Mmi/1QxAMKAG5ldHdvcmtfaWR4JfDHCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cauldron" - }, - { - "id": "minecraft:composter", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvbXBvc3RlcgQJAG5hbWVfaGFzaPAADHptzeWJAwoAbmV0d29ya19pZHIL6i4KBgBzdGF0ZXMDFABjb21wb3N0ZXJfZmlsbF9sZXZlbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:chest", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkDkOFvAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:trapped_chest", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnRyYXBwZWRfY2hlc3QECQBuYW1lX2hhc2g2qpF9stsEjgMKAG5ldHdvcmtfaWTjJWYxCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAbm9ydGgAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:ender_chest", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmVuZGVyX2NoZXN0BAkAbmFtZV9oYXNohEZzOFdg0WUDCgBuZXR3b3JrX2lkx4jiSQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:barrel", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmJhcnJlbAQJAG5hbWVfaGFzaHDkRPGymiRqAwoAbmV0d29ya19pZPnxzgsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:undyed_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZJ8rxp0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:white_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OndoaXRlX3NodWxrZXJfYm94BAkAbmFtZV9oYXNosK79m1rPUBwDCgBuZXR3b3JrX2lkjrET6goGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:light_gray_shulker_box", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iBe5zq7PxHmgMKAG5ldHdvcmtfaWSCVJv0CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:gray_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmdyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2ga2s8ctjHUhgMKAG5ldHdvcmtfaWS3WMsWCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:black_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoPm03OZphrp8DCgBuZXR3b3JrX2lkXHztNAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:brown_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmJyb3duX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoT3DD6qAL9cADCgBuZXR3b3JrX2lkaXxpYQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:red_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnJlZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaMIlKSCzqSZoAwoAbmV0d29ya19pZNrf+icKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:orange_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0Om9yYW5nZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaG2MAXU67wGrAwoAbmV0d29ya19pZGoO05gKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:yellow_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnllbGxvd19zaHVsa2VyX2JveAQJAG5hbWVfaGFzaIsLwQHYjcIEAwoAbmV0d29ya19pZBCBSiYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:lime_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmxpbWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hUwBkg+faUGAMKAG5ldHdvcmtfaWRJeKqqCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:green_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmdyZWVuX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoZgUeT3LupLUDCgBuZXR3b3JrX2lkzJiohQoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:cyan_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmN5YW5fc2h1bGtlcl9ib3gECQBuYW1lX2hhc2gSfbjteXg5yAMKAG5ldHdvcmtfaWTHeliECgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:light_blue_shulker_box", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2h0VFCX0qsRxQMKAG5ldHdvcmtfaWQXD8U0CgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:blue_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hn9gS0XIe6rAMKAG5ldHdvcmtfaWTO4PJaCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:purple_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnB1cnBsZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaEV/lkNPxRDdAwoAbmV0d29ya19pZFK25GAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:magenta_shulker_box", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hZ2VudGFfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iqWM7IJHxcFgMKAG5ldHdvcmtfaWTyyudTCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:pink_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnBpbmtfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2in1tkJ1GNcZgMKAG5ldHdvcmtfaWQOEGXjCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:armor_stand" - }, - { - "id": "minecraft:noteblock", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0Om5vdGVibG9jawQJAG5hbWVfaGFzaHPA8dBBH0UaAwoAbmV0d29ya19pZH1U5QkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:jukebox", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0Omp1a2Vib3gECQBuYW1lX2hhc2ieAIPExf/ZfgMKAG5ldHdvcmtfaWSmR7JfCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:music_disc_13" - }, - { - "id": "minecraft:music_disc_cat" - }, - { - "id": "minecraft:music_disc_blocks" - }, - { - "id": "minecraft:music_disc_chirp" - }, - { - "id": "minecraft:music_disc_far" - }, - { - "id": "minecraft:music_disc_mall" - }, - { - "id": "minecraft:music_disc_mellohi" - }, - { - "id": "minecraft:music_disc_stal" - }, - { - "id": "minecraft:music_disc_strad" - }, - { - "id": "minecraft:music_disc_ward" - }, - { - "id": "minecraft:music_disc_11" - }, - { - "id": "minecraft:music_disc_wait" - }, - { - "id": "minecraft:music_disc_otherside" - }, - { - "id": "minecraft:music_disc_5" - }, - { - "id": "minecraft:music_disc_pigstep" - }, - { - "id": "minecraft:music_disc_relic" - }, - { - "id": "minecraft:disc_fragment_5" - }, - { - "id": "minecraft:glowstone_dust" - }, - { - "id": "minecraft:glowstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0Omdsb3dzdG9uZQQJAG5hbWVfaGFzaFYqXNkefIlPAwoAbmV0d29ya19pZGT7WYYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:redstone_lamp", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZHN0b25lX2xhbXAECQBuYW1lX2hhc2hJ9V80caPvEgMKAG5ldHdvcmtfaWRvNPwnCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:sea_lantern", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnNlYV9sYW50ZXJuBAkAbmFtZV9oYXNoLPsv1TX9M+QDCgBuZXR3b3JrX2lk1PPVyAoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:oak_sign" - }, - { - "id": "minecraft:spruce_sign" - }, - { - "id": "minecraft:birch_sign" - }, - { - "id": "minecraft:jungle_sign" - }, - { - "id": "minecraft:acacia_sign" - }, - { - "id": "minecraft:dark_oak_sign" - }, - { - "id": "minecraft:mangrove_sign" - }, - { - "id": "minecraft:cherry_sign" - }, - { - "id": "minecraft:bamboo_sign" - }, - { - "id": "minecraft:crimson_sign" - }, - { - "id": "minecraft:warped_sign" - }, - { - "id": "minecraft:oak_hanging_sign" - }, - { - "id": "minecraft:spruce_hanging_sign" - }, - { - "id": "minecraft:birch_hanging_sign" - }, - { - "id": "minecraft:jungle_hanging_sign" - }, - { - "id": "minecraft:acacia_hanging_sign" - }, - { - "id": "minecraft:dark_oak_hanging_sign" - }, - { - "id": "minecraft:mangrove_hanging_sign" - }, - { - "id": "minecraft:cherry_hanging_sign" - }, - { - "id": "minecraft:bamboo_hanging_sign" - }, - { - "id": "minecraft:crimson_hanging_sign" - }, - { - "id": "minecraft:warped_hanging_sign" - }, - { - "id": "minecraft:painting" - }, - { - "id": "minecraft:frame" - }, - { - "id": "minecraft:glow_frame" - }, - { - "id": "minecraft:honey_bottle" - }, - { - "id": "minecraft:flower_pot" - }, - { - "id": "minecraft:bowl" - }, - { - "id": "minecraft:bucket" - }, - { - "id": "minecraft:milk_bucket" - }, - { - "id": "minecraft:water_bucket" - }, - { - "id": "minecraft:lava_bucket" - }, - { - "id": "minecraft:cod_bucket" - }, - { - "id": "minecraft:salmon_bucket" - }, - { - "id": "minecraft:tropical_fish_bucket" - }, - { - "id": "minecraft:pufferfish_bucket" - }, - { - "id": "minecraft:powder_snow_bucket" - }, - { - "id": "minecraft:axolotl_bucket" - }, - { - "id": "minecraft:tadpole_bucket" - }, - { - "id": "minecraft:skull", - "damage": 3 - }, - { - "id": "minecraft:skull", - "damage": 2 - }, - { - "id": "minecraft:skull", - "damage": 4 - }, - { - "id": "minecraft:skull", - "damage": 5 - }, - { - "id": "minecraft:skull" - }, - { - "id": "minecraft:skull", - "damage": 1 - }, - { - "id": "minecraft:skull", - "damage": 6 - }, - { - "id": "minecraft:beacon", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmJlYWNvbgQJAG5hbWVfaGFzaACwhhfSkdkHAwoAbmV0d29ya19pZF8jfiEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:bell", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OmJlbGwECQBuYW1lX2hhc2iPqsgDXRcsxAMKAG5ldHdvcmtfaWT7zhOoCgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAQoAdG9nZ2xlX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:conduit", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmNvbmR1aXQECQBuYW1lX2hhc2jqxKAxq2EaWQMKAG5ldHdvcmtfaWTWcBVnCgYAc3RhdGVzAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stonecutter_block", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lY3V0dGVyX2Jsb2NrBAkAbmFtZV9oYXNoQAXTbAM3MeYDCgBuZXR3b3JrX2lkWS4RjAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:end_portal_frame", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9wb3J0YWxfZnJhbWUECQBuYW1lX2hhc2gqofyUIjGOpQMKAG5ldHdvcmtfaWRbGHf8CgYAc3RhdGVzARIAZW5kX3BvcnRhbF9leWVfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:coal" - }, - { - "id": "minecraft:charcoal" - }, - { - "id": "minecraft:diamond" - }, - { - "id": "minecraft:iron_nugget" - }, - { - "id": "minecraft:raw_iron" - }, - { - "id": "minecraft:raw_gold" - }, - { - "id": "minecraft:raw_copper" - }, - { - "id": "minecraft:copper_ingot" - }, - { - "id": "minecraft:iron_ingot" - }, - { - "id": "minecraft:netherite_scrap" - }, - { - "id": "minecraft:netherite_ingot" - }, - { - "id": "minecraft:gold_nugget" - }, - { - "id": "minecraft:gold_ingot" - }, - { - "id": "minecraft:emerald" - }, - { - "id": "minecraft:quartz" - }, - { - "id": "minecraft:clay_ball" - }, - { - "id": "minecraft:brick" - }, - { - "id": "minecraft:netherbrick" - }, - { - "id": "minecraft:prismarine_shard" - }, - { - "id": "minecraft:amethyst_shard" - }, - { - "id": "minecraft:prismarine_crystals" - }, - { - "id": "minecraft:nautilus_shell" - }, - { - "id": "minecraft:heart_of_the_sea" - }, - { - "id": "minecraft:scute" - }, - { - "id": "minecraft:phantom_membrane" - }, - { - "id": "minecraft:string" - }, - { - "id": "minecraft:feather" - }, - { - "id": "minecraft:flint" - }, - { - "id": "minecraft:gunpowder" - }, - { - "id": "minecraft:leather" - }, - { - "id": "minecraft:rabbit_hide" - }, - { - "id": "minecraft:rabbit_foot" - }, - { - "id": "minecraft:fire_charge" - }, - { - "id": "minecraft:blaze_rod" - }, - { - "id": "minecraft:blaze_powder" - }, - { - "id": "minecraft:magma_cream" - }, - { - "id": "minecraft:fermented_spider_eye" - }, - { - "id": "minecraft:echo_shard" - }, - { - "id": "minecraft:dragon_breath" - }, - { - "id": "minecraft:shulker_shell" - }, - { - "id": "minecraft:ghast_tear" - }, - { - "id": "minecraft:slime_ball" - }, - { - "id": "minecraft:ender_pearl" - }, - { - "id": "minecraft:ender_eye" - }, - { - "id": "minecraft:nether_star" - }, - { - "id": "minecraft:end_rod", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmVuZF9yb2QECQBuYW1lX2hhc2jx/q5cEA0hmQMKAG5ldHdvcmtfaWQ2eM8kCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:lightning_rod", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpZ2h0bmluZ19yb2QECQBuYW1lX2hhc2ioXQF1xvfHNQMKAG5ldHdvcmtfaWRLuHyACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:end_crystal" - }, - { - "id": "minecraft:paper" - }, - { - "id": "minecraft:book" - }, - { - "id": "minecraft:writable_book" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:oak_boat" - }, - { - "id": "minecraft:spruce_boat" - }, - { - "id": "minecraft:birch_boat" - }, - { - "id": "minecraft:jungle_boat" - }, - { - "id": "minecraft:acacia_boat" - }, - { - "id": "minecraft:dark_oak_boat" - }, - { - "id": "minecraft:mangrove_boat" - }, - { - "id": "minecraft:cherry_boat" - }, - { - "id": "minecraft:bamboo_raft" - }, - { - "id": "minecraft:oak_chest_boat" - }, - { - "id": "minecraft:spruce_chest_boat" - }, - { - "id": "minecraft:birch_chest_boat" - }, - { - "id": "minecraft:jungle_chest_boat" - }, - { - "id": "minecraft:acacia_chest_boat" - }, - { - "id": "minecraft:dark_oak_chest_boat" - }, - { - "id": "minecraft:mangrove_chest_boat" - }, - { - "id": "minecraft:cherry_chest_boat" - }, - { - "id": "minecraft:bamboo_chest_raft" - }, - { - "id": "minecraft:rail", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWR+Sp6YCgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:golden_rail", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmdvbGRlbl9yYWlsBAkAbmFtZV9oYXNoOoV5MaKipoUDCgBuZXR3b3JrX2lkfAcxLwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:detector_rail", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmRldGVjdG9yX3JhaWwECQBuYW1lX2hhc2gVUk31qOysUQMKAG5ldHdvcmtfaWRVW/aICgYAc3RhdGVzAQ0AcmFpbF9kYXRhX2JpdAADDgByYWlsX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:activator_rail", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmFjdGl2YXRvcl9yYWlsBAkAbmFtZV9oYXNosIL91qriCRkDCgBuZXR3b3JrX2lkZfckmwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:minecart" - }, - { - "id": "minecraft:chest_minecart" - }, - { - "id": "minecraft:hopper_minecart" - }, - { - "id": "minecraft:tnt_minecart" - }, - { - "id": "minecraft:redstone" - }, - { - "id": "minecraft:redstone_block", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX2Jsb2NrBAkAbmFtZV9oYXNoRhULL0r8o0sDCgBuZXR3b3JrX2lklayOHgoGAHN0YXRlcwADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:redstone_torch", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX3RvcmNoBAkAbmFtZV9oYXNoizFRjpYMIDgDCgBuZXR3b3JrX2lkuHz7yAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:lever", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmxldmVyBAkAbmFtZV9oYXNoGMJeLJsUMLYDCgBuZXR3b3JrX2lkEF/GuAoGAHN0YXRlcwgPAGxldmVyX2RpcmVjdGlvbg4AZG93bl9lYXN0X3dlc3QBCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wooden_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWSU07kYCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:spruce_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9idXR0b24ECQBuYW1lX2hhc2jBW9Z8aYE7YQMKAG5ldHdvcmtfaWTkUIGuCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:birch_button", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2J1dHRvbgQJAG5hbWVfaGFzaJXYgGuSHbTwAwoAbmV0d29ya19pZGWp3yoKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:jungle_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9idXR0b24ECQBuYW1lX2hhc2iCgNANcJs+BQMKAG5ldHdvcmtfaWT9fImWCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:acacia_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9idXR0b24ECQBuYW1lX2hhc2gVvmcT7LTO0wMKAG5ldHdvcmtfaWRQnxIJCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:dark_oak_button", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaIV10ZGGrCIEAwoAbmV0d29ya19pZN5vAmIKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:mangrove_button", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2J1dHRvbgQJAG5hbWVfaGFzaNzeYYKLgOzJAwoAbmV0d29ya19pZAFEGQ0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cherry_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9idXR0b24ECQBuYW1lX2hhc2j2/IHjeAbUcwMKAG5ldHdvcmtfaWRJ1irQCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bamboo_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19idXR0b24ECQBuYW1lX2hhc2j7AddMi+6nsgMKAG5ldHdvcmtfaWSa9w4/CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_button", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2J1dHRvbgQJAG5hbWVfaGFzaM4ejMctmvohAwoAbmV0d29ya19pZMw+aC0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:crimson_button", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fYnV0dG9uBAkAbmFtZV9oYXNofnjYHaYIeWgDCgBuZXR3b3JrX2lk+n1vyQoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:warped_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9idXR0b24ECQBuYW1lX2hhc2jwkV2EU6Cn1QMKAG5ldHdvcmtfaWTnHnk1CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:polished_blackstone_button", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnV0dG9uBAkAbmFtZV9oYXNojmxzQKS0S/EDCgBuZXR3b3JrX2lkDtQ95woGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:tripwire_hook", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaXB3aXJlX2hvb2sECQBuYW1lX2hhc2gQdp+oGZLNnAMKAG5ldHdvcmtfaWSy+1KJCgYAc3RhdGVzAQwAYXR0YWNoZWRfYml0AAMJAGRpcmVjdGlvbgAAAAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:wooden_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZDRzPNwKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:spruce_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnNwcnVjZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNmwuq549fJKAwoAbmV0d29ya19pZLQMCw0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:birch_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJpcmNoX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNorQkT9kDdlTwDCgBuZXR3b3JrX2lkH0G97AoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:jungle_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0Omp1bmdsZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaJ7DcteCkb8/AwoAbmV0d29ya19pZLdPBSAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:acacia_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmFjYWNpYV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaC2frZtfoYqCAwoAbmV0d29ya19pZIDdI18KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:dark_oak_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmRhcmtfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoHUCJsTy52pwDCgBuZXR3b3JrX2lkKpi8rAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:mangrove_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hbmdyb3ZlX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoiDsTfJaX100DCgBuZXR3b3JrX2lkuwWDyQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:cherry_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmNoZXJyeV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaALMqYEZDUQHAwoAbmV0d29ya19pZPNT+r0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:bamboo_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmJhbWJvb19wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNvxJ7NIAaqlAwoAbmV0d29ya19pZIZ8XnYKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:crimson_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmNyaW1zb25fcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2hqBDVDAd31/gMKAG5ldHdvcmtfaWRmV18LCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:warped_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndhcnBlZF9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaBxFoQksWtYUAwoAbmV0d29ya19pZJVRoIcKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:stone_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnN0b25lX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNounJuTBUTrU8DCgBuZXR3b3JrX2lkjDydwQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:light_weighted_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoOyOJkNxLtkEDCgBuZXR3b3JrX2lkrr2AjgoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:heavy_weighted_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OmhlYXZ5X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoltgDmDvTajUDCgBuZXR3b3JrX2lkFxVKuQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:polished_blackstone_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZSwAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2h65Ci6/CeGqwMKAG5ldHdvcmtfaWTaSW5xCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:observer", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2VydmVyBAkAbmFtZV9oYXNoYhlh1lpmHTgDCgBuZXR3b3JrX2lkQEh55goGAHN0YXRlcwgaAG1pbmVjcmFmdDpmYWNpbmdfZGlyZWN0aW9uBABkb3duAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:daylight_detector", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmRheWxpZ2h0X2RldGVjdG9yBAkAbmFtZV9oYXNoV0F0s7B7PVgDCgBuZXR3b3JrX2lkri5afQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:repeater" - }, - { - "id": "minecraft:comparator" - }, - { - "id": "minecraft:hopper" - }, - { - "id": "minecraft:dropper", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmRyb3BwZXIECQBuYW1lX2hhc2joXP7XqU0l3QMKAG5ldHdvcmtfaWQfQN6zCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgMAAAABDQB0cmlnZ2VyZWRfYml0AAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:dispenser", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmRpc3BlbnNlcgQJAG5hbWVfaGFzaP1RR+zAbYP2AwoAbmV0d29ya19pZGAayD0KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAwAAAAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24DKBQBAA==" - }, - { - "id": "minecraft:piston", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBpc3RvbgQJAG5hbWVfaGFzaDs3AFh1fL0uAwoAbmV0d29ya19pZLD/5XQKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAQAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:sticky_piston", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnN0aWNreV9waXN0b24ECQBuYW1lX2hhc2hPFJFJSiJ0ZQMKAG5ldHdvcmtfaWT/MzCJCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgEAAAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:tnt", - "block_state_b64": "CgAACAQAbmFtZQ0AbWluZWNyYWZ0OnRudAQJAG5hbWVfaGFzaEYOHwCvJH29AwoAbmV0d29ya19pZCGfjU4KBgBzdGF0ZXMBFABhbGxvd191bmRlcndhdGVyX2JpdAABCwBleHBsb2RlX2JpdAAAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:name_tag" - }, - { - "id": "minecraft:loom", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Omxvb20ECQBuYW1lX2hhc2i7DKjAXNq8TAMKAG5ldHdvcmtfaWR/49HXCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:banner" - }, - { - "id": "minecraft:banner", - "damage": 8 - }, - { - "id": "minecraft:banner", - "damage": 7 - }, - { - "id": "minecraft:banner", - "damage": 15 - }, - { - "id": "minecraft:banner", - "damage": 12 - }, - { - "id": "minecraft:banner", - "damage": 14 - }, - { - "id": "minecraft:banner", - "damage": 1 - }, - { - "id": "minecraft:banner", - "damage": 4 - }, - { - "id": "minecraft:banner", - "damage": 5 - }, - { - "id": "minecraft:banner", - "damage": 13 - }, - { - "id": "minecraft:banner", - "damage": 9 - }, - { - "id": "minecraft:banner", - "damage": 3 - }, - { - "id": "minecraft:banner", - "damage": 11 - }, - { - "id": "minecraft:banner", - "damage": 10 - }, - { - "id": "minecraft:banner", - "damage": 2 - }, - { - "id": "minecraft:banner", - "damage": 6 - }, - { - "id": "minecraft:banner", - "damage": 15, - "nbt_b64": "CgAAAwQAVHlwZQEAAAAA" - }, - { - "id": "minecraft:creeper_banner_pattern" - }, - { - "id": "minecraft:skull_banner_pattern" - }, - { - "id": "minecraft:flower_banner_pattern" - }, - { - "id": "minecraft:mojang_banner_pattern" - }, - { - "id": "minecraft:field_masoned_banner_pattern" - }, - { - "id": "minecraft:bordure_indented_banner_pattern" - }, - { - "id": "minecraft:piglin_banner_pattern" - }, - { - "id": "minecraft:globe_banner_pattern" - }, - { - "id": "minecraft:angler_pottery_sherd" - }, - { - "id": "minecraft:archer_pottery_sherd" - }, - { - "id": "minecraft:arms_up_pottery_sherd" - }, - { - "id": "minecraft:blade_pottery_sherd" - }, - { - "id": "minecraft:brewer_pottery_sherd" - }, - { - "id": "minecraft:burn_pottery_sherd" - }, - { - "id": "minecraft:danger_pottery_sherd" - }, - { - "id": "minecraft:explorer_pottery_sherd" - }, - { - "id": "minecraft:friend_pottery_sherd" - }, - { - "id": "minecraft:heart_pottery_sherd" - }, - { - "id": "minecraft:heartbreak_pottery_sherd" - }, - { - "id": "minecraft:howl_pottery_sherd" - }, - { - "id": "minecraft:miner_pottery_sherd" - }, - { - "id": "minecraft:mourner_pottery_sherd" - }, - { - "id": "minecraft:plenty_pottery_sherd" - }, - { - "id": "minecraft:prize_pottery_sherd" - }, - { - "id": "minecraft:sheaf_pottery_sherd" - }, - { - "id": "minecraft:shelter_pottery_sherd" - }, - { - "id": "minecraft:skull_pottery_sherd" - }, - { - "id": "minecraft:snort_pottery_sherd" - }, - { - "id": "minecraft:netherite_upgrade_smithing_template" - }, - { - "id": "minecraft:sentry_armor_trim_smithing_template" - }, - { - "id": "minecraft:vex_armor_trim_smithing_template" - }, - { - "id": "minecraft:wild_armor_trim_smithing_template" - }, - { - "id": "minecraft:coast_armor_trim_smithing_template" - }, - { - "id": "minecraft:dune_armor_trim_smithing_template" - }, - { - "id": "minecraft:wayfinder_armor_trim_smithing_template" - }, - { - "id": "minecraft:shaper_armor_trim_smithing_template" - }, - { - "id": "minecraft:raiser_armor_trim_smithing_template" - }, - { - "id": "minecraft:host_armor_trim_smithing_template" - }, - { - "id": "minecraft:ward_armor_trim_smithing_template" - }, - { - "id": "minecraft:silence_armor_trim_smithing_template" - }, - { - "id": "minecraft:tide_armor_trim_smithing_template" - }, - { - "id": "minecraft:snout_armor_trim_smithing_template" - }, - { - "id": "minecraft:rib_armor_trim_smithing_template" - }, - { - "id": "minecraft:eye_armor_trim_smithing_template" - }, - { - "id": "minecraft:spire_armor_trim_smithing_template" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_star", - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 8, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 7, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 15, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 12, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 14, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 1, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 4, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 5, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 13, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 9, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 3, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 11, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 10, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 2, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 6, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" - }, - { - "id": "minecraft:chain" - }, - { - "id": "minecraft:target", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnRhcmdldAQJAG5hbWVfaGFzaJc66SVbYlaxAwoAbmV0d29ya19pZPBozs0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMoFAEA" - }, - { - "id": "minecraft:decorated_pot", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmRlY29yYXRlZF9wb3QECQBuYW1lX2hhc2jjQgckn8VTvwMKAG5ldHdvcmtfaWRwvkUUCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAygUAQA=" - }, - { - "id": "minecraft:lodestone_compass" - }, - { - "id": "minecraft:wither_spawn_egg" - }, - { - "id": "minecraft:ender_dragon_spawn_egg" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/creative_items.1_20_50.json b/core/src/main/resources/bedrock/creative_items.1_20_50.json deleted file mode 100644 index d93aa4c00..000000000 --- a/core/src/main/resources/bedrock/creative_items.1_20_50.json +++ /dev/null @@ -1,5995 +0,0 @@ -{ - "items": [ - { - "id": "minecraft:oak_planks", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19wbGFua3MECQBuYW1lX2hhc2ilMDLR92rQ4wMKAG5ldHdvcmtfaWS2GotyCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:spruce_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9wbGFua3MECQBuYW1lX2hhc2iumBkmFGFE8gMKAG5ldHdvcmtfaWSo8TFgCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:birch_planks", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3BsYW5rcwQJAG5hbWVfaGFzaLrrAKJqV2WFAwoAbmV0d29ya19pZL+e3ZAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:jungle_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9wbGFua3MECQBuYW1lX2hhc2iBM3k4T3FAugMKAG5ldHdvcmtfaWSXUmBCCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:acacia_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9wbGFua3MECQBuYW1lX2hhc2g60edJxO5/aAMKAG5ldHdvcmtfaWTUXozECgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dark_oak_planks", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3BsYW5rcwQJAG5hbWVfaGFzaAr64wkQ9cA7AwoAbmV0d29ya19pZFbMeR0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:mangrove_planks", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3BsYW5rcwQJAG5hbWVfaGFzaPvLtcEA0F8xAwoAbmV0d29ya19pZEvnlCYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cherry_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9wbGFua3MECQBuYW1lX2hhc2hNIvVh/lVW7gMKAG5ldHdvcmtfaWQTXpRoCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bamboo_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19wbGFua3MECQBuYW1lX2hhc2gYnjNz7SCCjgMKAG5ldHdvcmtfaWTi8ySSCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bamboo_mosaic", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWMECQBuYW1lX2hhc2izSEgiMKOp/AMKAG5ldHdvcmtfaWQZ/p8xCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:crimson_planks", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fcGxhbmtzBAkAbmFtZV9oYXNoJc5IKqNXJnwDCgBuZXR3b3JrX2lkwtJDdQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:warped_planks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9wbGFua3MECQBuYW1lX2hhc2g3yGXEWhe6LgMKAG5ldHdvcmtfaWStTABvCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSE4JosCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBjb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWTUvV6XCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9jb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWT4opb2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBncmFuaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQAMQTVCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBkaW9yaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQIbDOcCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCABhbmRlc2l0ZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSZKhusCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBzYW5kc3RvbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSp4zgCCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDQByZWRfc2FuZHN0b25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRbqVHTCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBzdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRr0ZT/CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9zdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRnLis3CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBQBicmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQNLzfSCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDABuZXRoZXJfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQ5h0xwCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEAByZWRfbmV0aGVyX2JyaWNrCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWS9J0B2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBlbmRfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRPbkJeCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCgBwcmlzbWFyaW5lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:blackstone_wall", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaMP8XppUSU1RAwoAbmV0d29ya19pZMbeBBsKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_blackstone_wall", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaP6SwV08YwzAAwoAbmV0d29ya19pZAJLsz8KBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_blackstone_brick_wall", - "block_state_b64": "CgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBBIDZbHxiEzAwoAbmV0d29ya19pZEbLV8cKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate_wall", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3dhbGwECQBuYW1lX2hhc2iECY5oKxeT+gMKAG5ldHdvcmtfaWRCnPrFCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:deepslate_tile_wall", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3dhbGwECQBuYW1lX2hhc2jz7N+PeuEXgQMKAG5ldHdvcmtfaWTqw4s4CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:polished_deepslate_wall", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV93YWxsBAkAbmFtZV9oYXNoHxjTdj9pevMDCgBuZXR3b3JrX2lkIvBYYwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:deepslate_brick_wall", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja193YWxsBAkAbmFtZV9oYXNoEs3EQrjroyEDCgBuZXR3b3JrX2lkwlrCGwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:mud_brick_wall", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja193YWxsBAkAbmFtZV9oYXNov9b98ATpUSwDCgBuZXR3b3JrX2lkH/1WZQoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:oak_fence", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZDvPEXcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:spruce_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZQQJAG5hbWVfaGFzaPQCm+aX1ZQeAwoAbmV0d29ya19pZD1QUEoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:birch_fence", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlBAkAbmFtZV9oYXNo6CJ2ATpANfgDCgBuZXR3b3JrX2lkmCUV2QoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:jungle_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZQQJAG5hbWVfaGFzaOX4cD9uAmsdAwoAbmV0d29ya19pZHz1VxkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:acacia_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZQQJAG5hbWVfaGFzaGjn+RlKVDH6AwoAbmV0d29ya19pZNVGubwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:dark_oak_fence", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlBAkAbmFtZV9oYXNoGPj0gCgM0c0DCgBuZXR3b3JrX2lk2w+gEwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:mangrove_fence", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlBAkAbmFtZV9oYXNowwAd7tPu9bsDCgBuZXR3b3JrX2lkKEcd0goGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cherry_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZQQJAG5hbWVfaGFzaFmtUfHfTxcxAwoAbmV0d29ya19pZPCBxAIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:bamboo_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19mZW5jZQQJAG5hbWVfaGFzaCKRbxfXsfkiAwoAbmV0d29ya19pZJNXKFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:nether_brick_fence", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0Om5ldGhlcl9icmlja19mZW5jZQQJAG5hbWVfaGFzaA6030ngawxcAwoAbmV0d29ya19pZLnjLF4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:crimson_fence", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2UECQBuYW1lX2hhc2jhUhKv1HGj9AMKAG5ldHdvcmtfaWR3OH3OCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:warped_fence", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9mZW5jZQQJAG5hbWVfaGFzaJfb3/YuKmOWAwoAbmV0d29ya19pZCpaGC8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:fence_gate", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWR+T9kTCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:spruce_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoanTVB84HRbkDCgBuZXR3b3JrX2lkEnw5egoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:birch_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2jmfPklI8azSwMKAG5ldHdvcmtfaWQL77/BCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:jungle_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNobYVQkfBomIcDCgBuZXR3b3JrX2lkA1zgtgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:acacia_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoZnrLUx/XSekDCgBuZXR3b3JrX2lkHg/kTgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:dark_oak_fence_gate", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2j2PTvdJJHcVQMKAG5ldHdvcmtfaWTwjOCeCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:mangrove_fence_gate", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2i/kOhBKiI/dAMKAG5ldHdvcmtfaWSfweCSCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cherry_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoKWLgCk0z+PsDCgBuZXR3b3JrX2lk/9bTZQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:bamboo_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmJhbWJvb19mZW5jZV9nYXRlBAkAbmFtZV9oYXNopH1JrUgwdIADCgBuZXR3b3JrX2lkzIpPywoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:crimson_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2VfZ2F0ZQQJAG5hbWVfaGFzaHE3Gfd0Z2d2AwoAbmV0d29ya19pZDQzVbEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQsAaW5fd2FsbF9iaXQAAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:warped_fence_gate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoy0oIBjDIG4kDCgBuZXR3b3JrX2lkkf+/3QoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:normal_stone_stairs", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hAEktZZOkGIwMKAG5ldHdvcmtfaWQeH1ALCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_stairs", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZDcCv+MKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:mossy_cobblestone_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3N0YWlycwQJAG5hbWVfaGFzaMVSTq5z9n1RAwoAbmV0d29ya19pZFIfrhkKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:oak_stairs", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19zdGFpcnMECQBuYW1lX2hhc2jk/HFzdXy0FQMKAG5ldHdvcmtfaWQJjyzBCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:spruce_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9zdGFpcnMECQBuYW1lX2hhc2iznygw7uBPBQMKAG5ldHdvcmtfaWTv+is3CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:birch_stairs", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3N0YWlycwQJAG5hbWVfaGFzaPfhbL619a3GAwoAbmV0d29ya19pZFyPlHAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:jungle_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9zdGFpcnMECQBuYW1lX2hhc2jodJsHUbOVxQMKAG5ldHdvcmtfaWR0z5d4CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:acacia_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9zdGFpcnMECQBuYW1lX2hhc2h3x1NmD43IqQMKAG5ldHdvcmtfaWS7Jwz6CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dark_oak_stairs", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3N0YWlycwQJAG5hbWVfaGFzaMfwkbYPbNmAAwoAbmV0d29ya19pZCmBYKAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:mangrove_stairs", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3N0YWlycwQJAG5hbWVfaGFzaNpUDY+uGMpyAwoAbmV0d29ya19pZChzUAsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cherry_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9zdGFpcnMECQBuYW1lX2hhc2jMtr0v9JY4zwMKAG5ldHdvcmtfaWRQwq31CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bamboo_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19zdGFpcnMECQBuYW1lX2hhc2jFOzWL8PalKwMKAG5ldHdvcmtfaWTVPh42CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bamboo_mosaic_stairs", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc3RhaXJzBAkAbmFtZV9oYXNoNLPiveSHPaoDCgBuZXR3b3JrX2lk44PHjgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaN6tQViRo5cwAwoAbmV0d29ya19pZDMyMgIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:mossy_stone_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaIB/Zv5YBPuYAwoAbmV0d29ya19pZANTOsMKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:sandstone_stairs", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnNhbmRzdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hOyA0BoYUOPQMKAG5ldHdvcmtfaWSV/834CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:smooth_sandstone_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoB+CuCd8Ruz8DCgBuZXR3b3JrX2lksR+m8QoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_sandstone_stairs", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoPs0LpHPL24YDCgBuZXR3b3JrX2lkLYVt3woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:smooth_red_sandstone_stairs", - "block_state_b64": "CgAACAQAbmFtZSUAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3N0YWlycwQJAG5hbWVfaGFzaBvjtQv5pf+MAwoAbmV0d29ya19pZMHNND8KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:granite_stairs", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmdyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNoGzpvtoqKQjgDCgBuZXR3b3JrX2lkPkcB1goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_granite_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNo3PvbSfEQklIDCgBuZXR3b3JrX2lkMmEm3AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:diorite_stairs", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmRpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoi73T8VQuZmcDCgBuZXR3b3JrX2lk6i6nBQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_diorite_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoFKRJd5Wk5L0DCgBuZXR3b3JrX2lkbt2ioAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:andesite_stairs", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmFuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaO5w2FKBw76EAwoAbmV0d29ya19pZKhXEgUKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:polished_andesite_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaNcZZ/zmLInIAwoAbmV0d29ya19pZJTHrlEKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyaWNrX3N0YWlycwQJAG5hbWVfaGFzaMyt+cRDk5O2AwoAbmV0d29ya19pZNeMh58KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:nether_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om5ldGhlcl9icmlja19zdGFpcnMECQBuYW1lX2hhc2jRqIoOXgifBAMKAG5ldHdvcmtfaWQDiw5yCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_nether_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNogQvosSbcj7kDCgBuZXR3b3JrX2lkx2IMtAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:end_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2hmlAk+QhsUsQMKAG5ldHdvcmtfaWTN7KFaCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:quartz_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9zdGFpcnMECQBuYW1lX2hhc2hmvpvOqGi6egMKAG5ldHdvcmtfaWRmUTh7CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:smooth_quartz_stairs", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc3RhaXJzBAkAbmFtZV9oYXNoNZZ9rX0qZOsDCgBuZXR3b3JrX2lkzsgQyQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:purpur_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9zdGFpcnMECQBuYW1lX2hhc2ifwDxeezXD7gMKAG5ldHdvcmtfaWTT+rxiCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:prismarine_stairs", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfc3RhaXJzBAkAbmFtZV9oYXNooTHSZ+IrYtcDCgBuZXR3b3JrX2lkxTJfeAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:dark_prismarine_stairs", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zdGFpcnMECQBuYW1lX2hhc2hIciLmam4o4AMKAG5ldHdvcmtfaWTVu7TCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:prismarine_bricks_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzX3N0YWlycwQJAG5hbWVfaGFzaNIjq1oBlZMMAwoAbmV0d29ya19pZGEFwLYKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:crimson_stairs", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fc3RhaXJzBAkAbmFtZV9oYXNoZJqIzCBpCq4DCgBuZXR3b3JrX2lktXE00AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:warped_stairs", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9zdGFpcnMECQBuYW1lX2hhc2hOkY27jLD4RQMKAG5ldHdvcmtfaWQ+E5VrCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:blackstone_stairs", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNokdoUb76p9McDCgBuZXR3b3JrX2lk5fWI5goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_blackstone_stairs", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNolCFtFIE8MmADCgBuZXR3b3JrX2lkGTf7sgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_blackstone_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZSoAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNonks6UlfpOmkDCgBuZXR3b3JrX2lkgYeOdAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoHfoAXYq5G3MDCgBuZXR3b3JrX2lkeetf7woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:exposed_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2howneQGtZ9cgMKAG5ldHdvcmtfaWSg73zdCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:weathered_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSUAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaP+R5loXxrVgAwoAbmV0d29ya19pZOnbRf4KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:oxidized_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNo6Jeoq5rsPxsDCgBuZXR3b3JrX2lkmRjDnQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoh07CQj0/SR8DCgBuZXR3b3JrX2lkmYqoqAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_exposed_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2guVct1ilmxTwMKAG5ldHdvcmtfaWQgCPROCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_weathered_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSsAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaPXC8Sz/phCpAwoAbmV0d29ya19pZHlwHVsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper_stairs", - "block_state_b64": "CgAACAQAbmFtZSoAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoaqGdkuhxVZUDCgBuZXR3b3JrX2lkYQXzzgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate_stairs", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3N0YWlycwQJAG5hbWVfaGFzaPIfa+TpyJcIAwoAbmV0d29ya19pZJUvOYIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:deepslate_tile_stairs", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3N0YWlycwQJAG5hbWVfaGFzaGFRFzB72mN2AwoAbmV0d29ya19pZJEOgIsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:polished_deepslate_stairs", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zdGFpcnMECQBuYW1lX2hhc2iNCYxVik9sGAMKAG5ldHdvcmtfaWSRVPnYCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:deepslate_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zdGFpcnMECQBuYW1lX2hhc2hIasOahEf83wMKAG5ldHdvcmtfaWQ1qEDCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:mud_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0Om11ZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2gt3qxK1NWajAMKAG5ldHdvcmtfaWSm9N3MCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:wooden_door" - }, - { - "id": "minecraft:spruce_door" - }, - { - "id": "minecraft:birch_door" - }, - { - "id": "minecraft:jungle_door" - }, - { - "id": "minecraft:acacia_door" - }, - { - "id": "minecraft:dark_oak_door" - }, - { - "id": "minecraft:mangrove_door" - }, - { - "id": "minecraft:cherry_door" - }, - { - "id": "minecraft:bamboo_door" - }, - { - "id": "minecraft:iron_door" - }, - { - "id": "minecraft:crimson_door" - }, - { - "id": "minecraft:warped_door" - }, - { - "id": "minecraft:trapdoor", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkyTAWkAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:spruce_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnNwcnVjZV90cmFwZG9vcgQJAG5hbWVfaGFzaOwlfbgBkUW4AwoAbmV0d29ya19pZPHy1K0KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:birch_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmJpcmNoX3RyYXBkb29yBAkAbmFtZV9oYXNoSLtLweOLJ7wDCgBuZXR3b3JrX2lkeJWDfgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:jungle_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Omp1bmdsZV90cmFwZG9vcgQJAG5hbWVfaGFzaDP/TnM9wyCIAwoAbmV0d29ya19pZEy2fJoKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:acacia_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmFjYWNpYV90cmFwZG9vcgQJAG5hbWVfaGFzaMj8xi3vmEKOAwoAbmV0d29ya19pZOHj8E8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:dark_oak_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmRhcmtfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNomB2GGJQ2aOMDCgBuZXR3b3JrX2lko5ZHTwoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:mangrove_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Om1hbmdyb3ZlX3RyYXBkb29yBAkAbmFtZV9oYXNooV3kQsQUUmkDCgBuZXR3b3JrX2lkkF/mxAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cherry_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmNoZXJyeV90cmFwZG9vcgQJAG5hbWVfaGFzaH/PefpfdHgtAwoAbmV0d29ya19pZOA7eNgKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:bamboo_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmJhbWJvb190cmFwZG9vcgQJAG5hbWVfaGFzaJrEOpsTwtKCAwoAbmV0d29ya19pZLvbPz8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:iron_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omlyb25fdHJhcGRvb3IECQBuYW1lX2hhc2gwA+IumsEiGQMKAG5ldHdvcmtfaWTvSVl/CgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:crimson_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmNyaW1zb25fdHJhcGRvb3IECQBuYW1lX2hhc2jHXufTnwUkYgMKAG5ldHdvcmtfaWQLjMYVCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:warped_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OndhcnBlZF90cmFwZG9vcgQJAG5hbWVfaGFzaA20wG/+vkd6AwoAbmV0d29ya19pZHKR/hYKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:iron_bars", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0Omlyb25fYmFycwQJAG5hbWVfaGFzaPuefWSNAe56AwoAbmV0d29ya19pZN2LB5IKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:glass", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lk0hdLNwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:white_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iHubqoMbu9fAMKAG5ldHdvcmtfaWRndBrUCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:light_gray_stained_glass", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaKKa+LrRsHQhAwoAbmV0d29ya19pZEv2giYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:gray_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaIETy7Y/HZREAwoAbmV0d29ya19pZDomVrUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:black_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iV6BCwpfDMmwMKAG5ldHdvcmtfaWSV7doJCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:brown_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2igsEiq5np8JgMKAG5ldHdvcmtfaWRMzE/lCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoCa2J12/lQoIDCgBuZXR3b3JrX2lk283lWAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:orange_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNozgjAuvzhxGsDCgBuZXR3b3JrX2lkW5CkhQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:yellow_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNo7EbHMd5WVugDCgBuZXR3b3JrX2lkkdDyXQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:lime_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBtZA1nZtwcFAwoAbmV0d29ya19pZDxX85UKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:green_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2h91ptDgbehWwMKAG5ldHdvcmtfaWTlDhnECgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cyan_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBkIYQ8nQLqbAwoAbmV0d29ya19pZOL1lHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:light_blue_stained_glass", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaLt05n1G0fiSAwoAbmV0d29ya19pZNbwulIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:blue_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaPhLocSfzduRAwoAbmV0d29ya19pZENsjFwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:purple_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoJk0DhRO0szUDCgBuZXR3b3JrX2lkD98ZxgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:magenta_stained_glass", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaFEDeFiJj3zSAwoAbmV0d29ya19pZG+iFRoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:pink_stained_glass", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaDijTX87ywxhAwoAbmV0d29ya19pZKdEricKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:tinted_glass", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnRpbnRlZF9nbGFzcwQJAG5hbWVfaGFzaAFZWSamk6KdAwoAbmV0d29ya19pZGSvWX8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:glass_pane", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWRGwixuCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:white_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaHgxQmgJVtRrAwoAbmV0d29ya19pZBEr/DYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:light_gray_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNon0aQw9lNkSEDCgBuZXR3b3JrX2lk9dp5VgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:gray_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNors74IIw+2MMDCgBuZXR3b3JrX2lkmrGO5woGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:black_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaOK/5ZRRd+M1AwoAbmV0d29ya19pZDv++oQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:brown_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaLHeGJyRFTIWAwoAbmV0d29ya19pZMz9L0wKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2gGr4x6JheAywMKAG5ldHdvcmtfaWQBjCTmCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:orange_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hbHxPD2gEbEAMKAG5ldHdvcmtfaWSt/7a5CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:yellow_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2g9tl4aOCyZBwMKAG5ldHdvcmtfaWTXRAS7CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:lime_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3CtUyLwoGegDCgBuZXR3b3JrX2lkYJDnggoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:green_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaJo6YP7IMy9SAwoAbmV0d29ya19pZHOnixoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cyan_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoti97c6QrbLQDCgBuZXR3b3JrX2lkUqFUeQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:light_blue_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNovDg/gQle104DCgBuZXR3b3JrX2lkFuy4MQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:blue_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoGc57tiexbQMDCgBuZXR3b3JrX2lk1eBLUAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:purple_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hDJHYdd0FdfQMKAG5ldHdvcmtfaWSNsdK5CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:magenta_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3pcOw5bs5XoDCgBuZXR3b3JrX2lkVbOR7AoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:pink_stained_glass_pane", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoWRhSACMWgswDCgBuZXR3b3JrX2lkIR92xwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:ladder", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxhZGRlcgQJAG5hbWVfaGFzaKBhqheJVOz+AwoAbmV0d29ya19pZCgvzlsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:scaffolding", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnNjYWZmb2xkaW5nBAkAbmFtZV9oYXNoYrkevrqcljwDCgBuZXR3b3JrX2lkD13mlAoGAHN0YXRlcwMJAHN0YWJpbGl0eQAAAAABDwBzdGFiaWxpdHlfY2hlY2sAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWTkNl0JCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAc21vb3RoX3N0b25lAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkQJoxlgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNAUAc3RvbmUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWRHh04KCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAY29iYmxlc3RvbmUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkVRZB+woGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhEAbW9zc3lfY29iYmxlc3RvbmUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkBaobgAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUDAG9hawADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkhz9TeQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAHNwcnVjZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lk3HkwowoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUFAGJpcmNoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkDIBqVQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAGp1bmdsZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkL5hFYAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAGFjYWNpYQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkKRUHSQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUIAGRhcmtfb2FrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:mangrove_slab", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3NsYWIECQBuYW1lX2hhc2jYCcmhJPeNMwMKAG5ldHdvcmtfaWQx6U1yCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cherry_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV9zbGFiBAkAbmFtZV9oYXNoTt0MmVn/mqoDCgBuZXR3b3JrX2lk2VVsZQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:bamboo_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJhbWJvb19zbGFiBAkAbmFtZV9oYXNoo1xuFqINeLYDCgBuZXR3b3JrX2lkVC+0twoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:bamboo_mosaic_slab", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc2xhYgQJAG5hbWVfaGFzaNbVRBZ/ChI3AwoAbmV0d29ya19pZOLZHFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWQSiInOCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkoF89tgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAbW9zc3lfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSkoAE4CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQkAc2FuZHN0b25lAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkWfF7pgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0AY3V0X3NhbmRzdG9uZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkbKRChAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAc21vb3RoX3NhbmRzdG9uZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkBlrvqAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg0AcmVkX3NhbmRzdG9uZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkRWFXuwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAY3V0X3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkom8neQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxQAc21vb3RoX3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkd1ZaWgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZ3Jhbml0ZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkISH4iwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZ3Jhbml0ZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkqxEDMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZGlvcml0ZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkSYs86QoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZGlvcml0ZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkq6BU6goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwgAYW5kZXNpdGUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkTSXY8AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxEAcG9saXNoZWRfYW5kZXNpdGUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWQiYHKTCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQUAYnJpY2sAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWTk/0LfCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAbmV0aGVyX2JyaWNrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk/hXQ7AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcmVkX25ldGhlcl9icmljawADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkYJNxrwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMw8AZW5kX3N0b25lX2JyaWNrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWRlj0/sCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQYAcXVhcnR6AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkMae+2goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0Ac21vb3RoX3F1YXJ0egADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk+kMHGAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMgYAcHVycHVyAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkKOSOMAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9yb3VnaAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk8igLCQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg8AcHJpc21hcmluZV9kYXJrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkSFbyEwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9icmljawADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:crimson_slab", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc2xhYgQJAG5hbWVfaGFzaKZ+EfP0ZYOZAwoAbmV0d29ya19pZAxRUWAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:warped_slab", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zbGFiBAkAbmFtZV9oYXNo/AT0e/Z9W7UDCgBuZXR3b3JrX2lk1yq11AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:blackstone_slab", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaF/DD4ZUlNgtAwoAbmV0d29ya19pZGy1DjwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_blackstone_slab", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaDYnuUs86EWfAwoAbmV0d29ya19pZJj2bXIKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_blackstone_brick_slab", - "block_state_b64": "CgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaKySLqvHc4xXAwoAbmV0d29ya19pZOyWX94KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaDsNpb2qs4iBAwoAbmV0d29ya19pZOTm2nsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:exposed_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNoahQ5OwIQb7kDCgBuZXR3b3JrX2lkrUlZLwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:weathered_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2hBIuGIOVVXogMKAG5ldHdvcmtfaWQgnaDiCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:oxidized_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaOptj9ycfpaDAwoAbmV0d29ya19pZMzFSRgKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaAlx6DZOCTHzAwoAbmV0d29ya19pZFRBvDAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_exposed_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNo3KqS5OnhtRIDCgBuZXR3b3JrX2lkHTGcTgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_weathered_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2gzZ1oX0HCFtwMKAG5ldHdvcmtfaWSgJR+XCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper_slab", - "block_state_b64": "CgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaMjjTnLu1KcqAwoAbmV0d29ya19pZIxsnFYKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cobbled_deepslate_slab", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3NsYWIECQBuYW1lX2hhc2gwJIVWK1TM2QMKAG5ldHdvcmtfaWTYAoX5CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_deepslate_slab", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zbGFiBAkAbmFtZV9oYXNoC/Adiz8k6RYDCgBuZXR3b3JrX2lkuFYMAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:deepslate_tile_slab", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3NsYWIECQBuYW1lX2hhc2hPydV6emzIXAMKAG5ldHdvcmtfaWQwlbFCCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:deepslate_brick_slab", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zbGFiBAkAbmFtZV9oYXNoSv62V7iw10UDCgBuZXR3b3JrX2lkWMoragoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:mud_brick_slab", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja19zbGFiBAkAbmFtZV9oYXNoq/tGBQWkv08DCgBuZXR3b3JrX2lkl4nnMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:brick_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJyaWNrX2Jsb2NrBAkAbmFtZV9oYXNo5Qc2E005S3oDCgBuZXR3b3JrX2lkqeGWRgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:chiseled_nether_bricks", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX25ldGhlcl9icmlja3MECQBuYW1lX2hhc2g31SBPTcUK1QMKAG5ldHdvcmtfaWS8TJ+TCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cracked_nether_bricks", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmNyYWNrZWRfbmV0aGVyX2JyaWNrcwQJAG5hbWVfaGFzaAdC6eKzXT5tAwoAbmV0d29ya19pZIUSejwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:quartz_bricks", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9icmlja3MECQBuYW1lX2hhc2jSZO590dd8sAMKAG5ldHdvcmtfaWSc5xCLCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQ5kni1CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAZGVmYXVsdAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTDw813CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQUAbW9zc3kAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWSTvQGECgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAY3JhY2tlZAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQIM0OwCgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQgAY2hpc2VsZWQAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:end_bricks", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmVuZF9icmlja3MECQBuYW1lX2hhc2hIUFfxNLZaFgMKAG5ldHdvcmtfaWQ/vDihCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWSH021WCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBgBicmlja3MAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:polished_blackstone_bricks", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoIHgsgIdzKXcDCgBuZXR3b3JrX2lkUw9b3woGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cracked_polished_blackstone_bricks", - "block_state_b64": "CgAACAQAbmFtZSwAbWluZWNyYWZ0OmNyYWNrZWRfcG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3MECQBuYW1lX2hhc2jQIO1GQDk80AMKAG5ldHdvcmtfaWQ3UlRYCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:gilded_blackstone", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmdpbGRlZF9ibGFja3N0b25lBAkAbmFtZV9oYXNoNoWt1ocG0HEDCgBuZXR3b3JrX2lktL8gUwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:chiseled_polished_blackstone", - "block_state_b64": "CgAACAQAbmFtZSYAbWluZWNyYWZ0OmNoaXNlbGVkX3BvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2gzFa+kEjCJgAMKAG5ldHdvcmtfaWR2NJX2CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:deepslate_tiles", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlcwQJAG5hbWVfaGFzaGcLLx3NXAFvAwoAbmV0d29ya19pZI/G/xYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cracked_deepslate_tiles", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX3RpbGVzBAkAbmFtZV9oYXNo9zWgkFuMM1QDCgBuZXR3b3JrX2lkGwY6OgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:deepslate_bricks", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja3MECQBuYW1lX2hhc2gucvFmPdZxigMKAG5ldHdvcmtfaWSH4HDPCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cracked_deepslate_bricks", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX2JyaWNrcwQJAG5hbWVfaGFzaN40aqhh9WqHAwoAbmV0d29ya19pZO9GPBQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:chiseled_deepslate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaEU7/uRG8HSBAwoAbmV0d29ya19pZEqmI0EKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cobblestone", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYmJsZXN0b25lBAkAbmFtZV9oYXNoPoK7mGlSUz4DCgBuZXR3b3JrX2lkLm7RZwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:mossy_cobblestone", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoGJ67FCbkChMDCgBuZXR3b3JrX2lk/pYs1AoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoLUz9Y/ywmLwDCgBuZXR3b3JrX2lkNwzZ+AoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:smooth_stone", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnNtb290aF9zdG9uZQQJAG5hbWVfaGFzaMwf87/JaTNvAwoAbmV0d29ya19pZLkZICEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB2wApMKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUHAGRlZmF1bHQAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB7E+eQKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGULAGhlaXJvZ2x5cGhzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZFQnDaEKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUDAGN1dAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZPO4A3IKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUGAHNtb290aAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWRhNYiFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTqXJr1CgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlCwBoZWlyb2dseXBocwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTQRGkFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlAwBjdXQAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTvAHWDCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBgBzbW9vdGgAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coal_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvYWxfYmxvY2sECQBuYW1lX2hhc2jH8QQP3t5PiAMKAG5ldHdvcmtfaWRo+sR+CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dried_kelp_block", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmRyaWVkX2tlbHBfYmxvY2sECQBuYW1lX2hhc2iRoucexkrl8wMKAG5ldHdvcmtfaWQQCCrvCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:gold_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdvbGRfYmxvY2sECQBuYW1lX2hhc2iYLshvjtXzFwMKAG5ldHdvcmtfaWTDJGBcCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:iron_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Omlyb25fYmxvY2sECQBuYW1lX2hhc2jYINmJQbvV/gMKAG5ldHdvcmtfaWRf7AbICgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:copper_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZIiUodwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:copper_door" - }, - { - "id": "minecraft:copper_trapdoor", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmNvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaO9fXio+svKVAwoAbmV0d29ya19pZMCoRjEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:copper_grate", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaC/JEFOWnmEcAwoAbmV0d29ya19pZC6YiiMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:exposed_copper", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoQH3Fukmu3CEDCgBuZXR3b3JrX2lk72jFIwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:exposed_copper_door" - }, - { - "id": "minecraft:exposed_copper_trapdoor", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX3RyYXBkb29yBAkAbmFtZV9oYXNoYhDFUysN7qUDCgBuZXR3b3JrX2lkMzwGJgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:exposed_copper_grate", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX2dyYXRlBAkAbmFtZV9oYXNolFIBYLYU0IcDCgBuZXR3b3JrX2lk4UqptAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:weathered_copper", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2hJCQXbvobv+gMKAG5ldHdvcmtfaWQwM0lJCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:weathered_copper_door" - }, - { - "id": "minecraft:weathered_copper_trapdoor", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfdHJhcGRvb3IECQBuYW1lX2hhc2hFnEC282a1tgMKAG5ldHdvcmtfaWTk70oiCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:weathered_copper_grate", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfZ3JhdGUECQBuYW1lX2hhc2jB3o8enlv1RgMKAG5ldHdvcmtfaWRih2pOCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:oxidized_copper", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMDtJqR0G5Y7AwoAbmV0d29ya19pZGjN8bUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:oxidized_copper_door" - }, - { - "id": "minecraft:oxidized_copper_trapdoor", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaOJpG/XFexVwAwoAbmV0d29ya19pZPhi0J4KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:oxidized_copper_grate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaBRfNhyndve7AwoAbmV0d29ya19pZKY2cnEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_copper", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndheGVkX2NvcHBlcgQJAG5hbWVfaGFzaPF+FG6Eh5fsAwoAbmV0d29ya19pZIjtz/0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_copper_door" - }, - { - "id": "minecraft:waxed_copper_trapdoor", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaO0JUKUHqNU6AwoAbmV0d29ya19pZJC3ZuMKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_copper_grate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OndheGVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaDmC92M2RO+HAwoAbmV0d29ya19pZH4og2AKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_exposed_copper", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoig8IOc+SCikDCgBuZXR3b3JrX2lklz8yWQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_exposed_copper_door" - }, - { - "id": "minecraft:waxed_exposed_copper_trapdoor", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX3RyYXBkb29yBAkAbmFtZV9oYXNoBHHxCpkUzpgDCgBuZXR3b3JrX2lkw2XBGQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_exposed_copper_grate", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX2dyYXRlBAkAbmFtZV9oYXNoWmd6B+hWwiEDCgBuZXR3b3JrX2lk8d4ZQwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_weathered_copper", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2gjtPq8MOdvKgMKAG5ldHdvcmtfaWSQ9Ln9CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_weathered_copper_door" - }, - { - "id": "minecraft:waxed_weathered_copper_trapdoor", - "block_state_b64": "CgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfdHJhcGRvb3IECQBuYW1lX2hhc2gH9Fi3JCF4egMKAG5ldHdvcmtfaWRkGU6TCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_weathered_copper_grate", - "block_state_b64": "CgAACAQAbmFtZSYAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfZ3JhdGUECQBuYW1lX2hhc2hXfilVFDAiYQMKAG5ldHdvcmtfaWQqTGC1CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_oxidized_copper", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMaORhsO+LzjAwoAbmV0d29ya19pZJhGfLEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_oxidized_copper_door" - }, - { - "id": "minecraft:waxed_oxidized_copper_trapdoor", - "block_state_b64": "CgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaNA/q9qAy6Z9AwoAbmV0d29ya19pZDgExS8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_oxidized_copper_grate", - "block_state_b64": "CgAACAQAbmFtZSUAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaEbeMT605GP4AwoAbmV0d29ya19pZOZjpkkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cut_copper", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmN1dF9jb3BwZXIECQBuYW1lX2hhc2hAfN3NGax3eAMKAG5ldHdvcmtfaWTnFBtYCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:exposed_cut_copper", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaA85G3yv/w6pAwoAbmV0d29ya19pZMQhr0QKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:weathered_cut_copper", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoVgRV0fBaz88DCgBuZXR3b3JrX2lk/0cYugoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:oxidized_cut_copper", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2iP8WmFWOkriwMKAG5ldHdvcmtfaWQPdce7CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_cut_copper", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2jumiwOZIqv2AMKAG5ldHdvcmtfaWQvuxx9CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_exposed_cut_copper", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaPE/OfK6IoVMAwoAbmV0d29ya19pZHy5HkcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_weathered_cut_copper", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoCA1xDp11bnwDCgBuZXR3b3JrX2lkDyEDVQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2i1pZAsZYHLDAMKAG5ldHdvcmtfaWQ/wSkCCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:chiseled_copper", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmNoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaIsW5pmpJEuQAwoAbmV0d29ya19pZHetwrkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:exposed_chiseled_copper", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY2hpc2VsZWRfY29wcGVyBAkAbmFtZV9oYXNoOvrLJ0UowbgDCgBuZXR3b3JrX2lkZj7cPwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:weathered_chiseled_copper", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jaGlzZWxlZF9jb3BwZXIECQBuYW1lX2hhc2hh+42XlsWvGAMKAG5ldHdvcmtfaWS7Cy59CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:oxidized_chiseled_copper", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaLpTIsnfluiCAwoAbmV0d29ya19pZB9/jS8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_chiseled_copper", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaFnXvXY5OinzAwoAbmV0d29ya19pZAcKtHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_exposed_chiseled_copper", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY2hpc2VsZWRfY29wcGVyBAkAbmFtZV9oYXNoHJdq+Pph6hMDCgBuZXR3b3JrX2lkdge7IAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_oxidized_chiseled_copper", - "block_state_b64": "CgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaMj49OvlTpgCAwoAbmV0d29ya19pZN/r+roKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_weathered_chiseled_copper", - "block_state_b64": "CgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jaGlzZWxlZF9jb3BwZXIECQBuYW1lX2hhc2hzuO+Sg9LYQwMKAG5ldHdvcmtfaWQ7AN7iCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:copper_bulb", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcHBlcl9idWxiBAkAbmFtZV9oYXNo41TimHOsMWcDCgBuZXR3b3JrX2lkJnZvAgoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:exposed_copper_bulb", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX2J1bGIECQBuYW1lX2hhc2g++f1wYLLCrAMKAG5ldHdvcmtfaWRLdMmGCgYAc3RhdGVzAQMAbGl0AAELAHBvd2VyZWRfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:weathered_copper_bulb", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfYnVsYgQJAG5hbWVfaGFzaMEtsYfwRTXlAwoAbmV0d29ya19pZAp51LQKBgBzdGF0ZXMBAwBsaXQAAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:oxidized_copper_bulb", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNovnrBQZs8nDIDCgBuZXR3b3JrX2lkPsj0AAoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_copper_bulb", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OndheGVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNoGTg6TYllMiIDCgBuZXR3b3JrX2lk9m0WhgoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waxed_exposed_copper_bulb", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX2J1bGIECQBuYW1lX2hhc2gI6xkPcvBDVwMKAG5ldHdvcmtfaWR7BRcACgYAc3RhdGVzAQMAbGl0AAELAHBvd2VyZWRfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:waxed_weathered_copper_bulb", - "block_state_b64": "CgAACAQAbmFtZSUAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfYnVsYgQJAG5hbWVfaGFzaMsUnmp3/VqVAwoAbmV0d29ya19pZEoworoKBgBzdGF0ZXMBAwBsaXQAAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:waxed_oxidized_copper_bulb", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNoBFKxY3fjVq4DCgBuZXR3b3JrX2lkzrJ6aAoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:emerald_block", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmVtZXJhbGRfYmxvY2sECQBuYW1lX2hhc2hK6QunqJznNAMKAG5ldHdvcmtfaWRk5+otCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:diamond_block", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmRpYW1vbmRfYmxvY2sECQBuYW1lX2hhc2iGKrxuvkytFQMKAG5ldHdvcmtfaWQQeQZXCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:lapis_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmxhcGlzX2Jsb2NrBAkAbmFtZV9oYXNoDZ44xdb2zVoDCgBuZXR3b3JrX2lktVy0BAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:raw_iron_block", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19pcm9uX2Jsb2NrBAkAbmFtZV9oYXNo9XyzNIQXxvwDCgBuZXR3b3JrX2lknms1QAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:raw_copper_block", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnJhd19jb3BwZXJfYmxvY2sECQBuYW1lX2hhc2hw1KG0TNUGgwMKAG5ldHdvcmtfaWS1vGo/CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:raw_gold_block", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19nb2xkX2Jsb2NrBAkAbmFtZV9oYXNo6YuwuLwfOBwDCgBuZXR3b3JrX2lkLiQ5gQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZEupC1AKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZM97+l0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZCbTfssKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQgAY2hpc2VsZWQICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZJss8V0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQYAc21vb3RoCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWRFIsoGCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWTDNWOvCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBABkYXJrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:slime", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNsaW1lBAkAbmFtZV9oYXNoHJiEEJx+JlkDCgBuZXR3b3JrX2lkfgfVzAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:honey_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmhvbmV5X2Jsb2NrBAkAbmFtZV9oYXNo9zLYSUlelywDCgBuZXR3b3JrX2lko+dyWgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:honeycomb_block", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmhvbmV5Y29tYl9ibG9jawQJAG5hbWVfaGFzaASIPuOCYd1oAwoAbmV0d29ya19pZKys4n4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:hay_block", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmhheV9ibG9jawQJAG5hbWVfaGFzaIB2VxKxX8EpAwoAbmV0d29ya19pZKuQSloKBgBzdGF0ZXMDCgBkZXByZWNhdGVkAAAAAAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bone_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmJvbmVfYmxvY2sECQBuYW1lX2hhc2i4ZX576W9AWgMKAG5ldHdvcmtfaWTWGacQCgYAc3RhdGVzAwoAZGVwcmVjYXRlZAAAAAAICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:nether_brick", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0Om5ldGhlcl9icmljawQJAG5hbWVfaGFzaMxcRiheU+nXAwoAbmV0d29ya19pZMkmzloKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_nether_brick", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2sECQBuYW1lX2hhc2j8pRO4LfoECAMKAG5ldHdvcmtfaWRpdF0YCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:netherite_block", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcml0ZV9ibG9jawQJAG5hbWVfaGFzaMghh6Zib/ZKAwoAbmV0d29ya19pZIz0mq0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:lodestone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmxvZGVzdG9uZQQJAG5hbWVfaGFzaJ2gmHOTlXv8AwoAbmV0d29ya19pZEfgB4wKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:white_wool", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWSO8paQCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:light_gray_wool", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfd29vbAQJAG5hbWVfaGFzaOpdQ1a2v4b3AwoAbmV0d29ya19pZIqZCYEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:gray_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmdyYXlfd29vbAQJAG5hbWVfaGFzaLsc1Lp1xdIOAwoAbmV0d29ya19pZFUs+HgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:black_wool", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrX3dvb2wECQBuYW1lX2hhc2hP2HC6o0X4HAMKAG5ldHdvcmtfaWRUbORcCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:brown_wool", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmJyb3duX3dvb2wECQBuYW1lX2hhc2ig5IW89PrREwMKAG5ldHdvcmtfaWRjT9j8CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_wool", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF93b29sBAkAbmFtZV9oYXNoY4TBDq+mFgUDCgBuZXR3b3JrX2lktn9lcAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:orange_wool", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om9yYW5nZV93b29sBAkAbmFtZV9oYXNoFstfrTZfSCgDCgBuZXR3b3JrX2lk+rqywwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:yellow_wool", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnllbGxvd193b29sBAkAbmFtZV9oYXNoTFyus2RHegcDCgBuZXR3b3JrX2lkkKBhXAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:lime_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmxpbWVfd29vbAQJAG5hbWVfaGFzaNVnnzKiMxmeAwoAbmV0d29ya19pZG9b32kKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:green_wool", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdyZWVuX3dvb2wECQBuYW1lX2hhc2i3mElRYHIcSQMKAG5ldHdvcmtfaWSssprwCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cyan_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmN5YW5fd29vbAQJAG5hbWVfaGFzaBNDfvHn8dqFAwoAbmV0d29ya19pZK0hAbgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:light_blue_wool", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfd29vbAQJAG5hbWVfaGFzaLWFAUfyxFPNAwoAbmV0d29ya19pZL2oEugKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:blue_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmJsdWVfd29vbAQJAG5hbWVfaGFzaLjHyxxbTWCLAwoAbmV0d29ya19pZPaLdFQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:purple_wool", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnBsZV93b29sBAkAbmFtZV9oYXNojvFtqzjAf/4DCgBuZXR3b3JrX2lklqASNQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:magenta_wool", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hZ2VudGFfd29vbAQJAG5hbWVfaGFzaGuOHvf+Pd4yAwoAbmV0d29ya19pZI4UoDQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:pink_wool", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnBpbmtfd29vbAQJAG5hbWVfaGFzaPiVA2pFeoFLAwoAbmV0d29ya19pZOZRO6oKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:white_carpet", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZEahDFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:light_gray_carpet", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0BAkAbmFtZV9oYXNoHPw6ArBAsP0DCgBuZXR3b3JrX2lkQoAeUAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:gray_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FycGV0BAkAbmFtZV9oYXNoZVR0OI+1VRADCgBuZXR3b3JrX2lkETF4WwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:black_carpet", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhcnBldAQJAG5hbWVfaGFzaOk7LP9NptyhAwoAbmV0d29ya19pZFjmXtIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:brown_carpet", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhcnBldAQJAG5hbWVfaGFzaNaXFyOsAvIvAwoAbmV0d29ya19pZHPjFuoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_carpet", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYXJwZXQECQBuYW1lX2hhc2i9eSKBf6SO3wMKAG5ldHdvcmtfaWQuhI/KCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:orange_carpet", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQECQBuYW1lX2hhc2hIUkO4HlAdygMKAG5ldHdvcmtfaWSyKV9OCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:yellow_carpet", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYXJwZXQECQBuYW1lX2hhc2hSDKX3scCamwMKAG5ldHdvcmtfaWT8nq+ECgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:lime_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FycGV0BAkAbmFtZV9oYXNo+6KFOpzsib4DCgBuZXR3b3JrX2lkT+DS4woGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:green_carpet", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhcnBldAQJAG5hbWVfaGFzaCHPMP9ltqFJAwoAbmV0d29ya19pZBgwAvAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cyan_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FycGV0BAkAbmFtZV9oYXNobXf62dQBJj8DCgBuZXR3b3JrX2lkKVppLgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:light_blue_carpet", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0BAkAbmFtZV9oYXNo20l4oktdZ3sDCgBuZXR3b3JrX2lkjdeMiwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:blue_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FycGV0BAkAbmFtZV9oYXNo3p3lsW0eQwsDCgBuZXR3b3JrX2lkAovdPQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:purple_carpet", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQECQBuYW1lX2hhc2jwIA9pW/qp7QMKAG5ldHdvcmtfaWTqJqhjCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:magenta_carpet", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0BAkAbmFtZV9oYXNoFXT36YNNZhMDCgBuZXR3b3JrX2lk+tqsGAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:pink_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FycGV0BAkAbmFtZV9oYXNoHll72oqk+OoDCgBuZXR3b3JrX2lkrnBYDwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:white_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZJPZY8AKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:light_gray_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo7EUk30hmUtYDCgBuZXR3b3JrX2lkh8jVIwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:gray_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmdyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoW77af6WihdwDCgBuZXR3b3JrX2lkSsqC1woGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:black_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaAfWYp0xtgcfAwoAbmV0d29ya19pZMWTC8EKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:brown_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaB74EeiLO46XAwoAbmV0d29ya19pZEDHKqwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnJlZF9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gjFut6Z/VH1gMKAG5ldHdvcmtfaWSvcmwYCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:orange_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gADDj2IJiw+gMKAG5ldHdvcmtfaWTHph0FCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:yellow_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iy6qKNn3ob5wMKAG5ldHdvcmtfaWQZAI39CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:lime_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmxpbWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo4dYIPslbXPUDCgBuZXR3b3JrX2lk2O8X0AoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:green_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaM/c9x2aJh3HAwoAbmV0d29ya19pZA0VfBMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cyan_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmN5YW5fY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNok+xKAe7XXjoDCgBuZXR3b3JrX2lkmkn6uwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:light_blue_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNogScpIQceyAEDCgBuZXR3b3JrX2lkOmVSbgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:blue_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoFp7mmeL86r0DCgBuZXR3b3JrX2lkS3b3RQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:purple_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iYcVU04hoStwMKAG5ldHdvcmtfaWQXimEjCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:magenta_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoy/70q6VPsWgDCgBuZXR3b3JrX2lkf9mxQwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:pink_concrete_powder", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnBpbmtfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoVikSAf8DwV0DCgBuZXR3b3JrX2lku2MivwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:white_concrete", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lk3MAYQAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:light_gray_concrete", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGUECQBuYW1lX2hhc2hEtet5wuDIKAMKAG5ldHdvcmtfaWQISs02CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:gray_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmdyYXlfY29uY3JldGUECQBuYW1lX2hhc2j92INnb0a83AMKAG5ldHdvcmtfaWQj8RHwCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:black_concrete", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlBAkAbmFtZV9oYXNo2X7NDIQmZ70DCgBuZXR3b3JrX2lk2uiVDQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:brown_concrete", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlBAkAbmFtZV9oYXNoeka02BwXf6oDCgBuZXR3b3JrX2lkYf+xDQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_concrete", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9jb25jcmV0ZQQJAG5hbWVfaGFzaPWmNowLGubqAwoAbmV0d29ya19pZKwyx58KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:orange_concrete", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZQQJAG5hbWVfaGFzaAgE8XmaAi6+AwoAbmV0d29ya19pZMDQNz8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:yellow_concrete", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZQQJAG5hbWVfaGFzaE6ONfJPBd0+AwoAbmV0d29ya19pZMarutwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:lime_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpbWVfY29uY3JldGUECQBuYW1lX2hhc2gnd8JW6wmJcAMKAG5ldHdvcmtfaWTd47aoCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:green_concrete", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlBAkAbmFtZV9oYXNokbFxRKchQZkDCgBuZXR3b3JrX2lkmhZWUgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cyan_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmN5YW5fY29uY3JldGUECQBuYW1lX2hhc2hFRrWJ33qj1wMKAG5ldHdvcmtfaWQbi5b8CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:light_blue_concrete", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGUECQBuYW1lX2hhc2gHAe0kl0SE4AMKAG5ldHdvcmtfaWRL/GbSCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:blue_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJsdWVfY29uY3JldGUECQBuYW1lX2hhc2hiay301nnj1wMKAG5ldHdvcmtfaWRMvFXNCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:purple_concrete", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZQQJAG5hbWVfaGFzaHBHflsPIwdXAwoAbmV0d29ya19pZCyKA5gKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:magenta_concrete", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGUECQBuYW1lX2hhc2gN7LuB/OvdZAMKAG5ldHdvcmtfaWTc6ZOdCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:pink_concrete", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnBpbmtfY29uY3JldGUECQBuYW1lX2hhc2ii2G5F0u3SOAMKAG5ldHdvcmtfaWSszGgrCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:clay", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OmNsYXkECQBuYW1lX2hhc2j/S6sKXRcpzwMKAG5ldHdvcmtfaWRmsb8nCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:hardened_clay", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRBCOrrCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:white_terracotta", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OndoaXRlX3RlcnJhY290dGEECQBuYW1lX2hhc2j3RSdgmnAIewMKAG5ldHdvcmtfaWSimKw+CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:light_gray_terracotta", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAz1Ri3wIxomAwoAbmV0d29ya19pZH5qgOcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:gray_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmdyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAXdSLAaNZ9vAwoAbmV0d29ya19pZM1QDV0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:black_terracotta", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJsYWNrX3RlcnJhY290dGEECQBuYW1lX2hhc2jxssdv5vlbpgMKAG5ldHdvcmtfaWRE3Ru/CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:brown_terracotta", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJyb3duX3RlcnJhY290dGEECQBuYW1lX2hhc2gG4kPenmOF9gMKAG5ldHdvcmtfaWQ/i0iNCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_terracotta", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo7fX56HXFejEDCgBuZXR3b3JrX2lk8tTF8QoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:orange_terracotta", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Om9yYW5nZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo0Hjmql3sruMDCgBuZXR3b3JrX2lklmqmkAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:yellow_terracotta", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnllbGxvd190ZXJyYWNvdHRhBAkAbmFtZV9oYXNoqkyKKrmA3VcDCgBuZXR3b3JrX2lkaM/orAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:lime_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmxpbWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaANjADFOF9v7AwoAbmV0d29ya19pZJt0XsgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:green_terracotta", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmdyZWVuX3RlcnJhY290dGEECQBuYW1lX2hhc2j5Ybq36yYwRQMKAG5ldHdvcmtfaWQ8kGdHCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cyan_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmN5YW5fdGVycmFjb3R0YQQJAG5hbWVfaGFzaN09COzMuHwAAwoAbmV0d29ya19pZIWPCzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:light_blue_terracotta", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaOMytez7cOZiAwoAbmV0d29ya19pZFHK1UsKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:blue_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaF6inyTK5RpAAwoAbmV0d29ya19pZF5mVZIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:purple_terracotta", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnB1cnBsZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoKF7YG61yTbEDCgBuZXR3b3JrX2lkhtRDlwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:magenta_terracotta", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hZ2VudGFfdGVycmFjb3R0YQQJAG5hbWVfaGFzaLWvtpAVtztyAwoAbmV0d29ya19pZN5SoakKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:pink_terracotta", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnBpbmtfdGVycmFjb3R0YQQJAG5hbWVfaGFzaJ7mzvyzSQZTAwoAbmV0d29ya19pZDJWe4YKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:white_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkIlj9AAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:silver_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnNpbHZlcl9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAVsA0CnhzA4AwoAbmV0d29ya19pZPnxtJEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:gray_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmdyYXlfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2jvLZt9u/lF/AMKAG5ldHdvcmtfaWQVU8eFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:black_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmJsYWNrX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoe8I4xAXbO5UDCgBuZXR3b3JrX2lk2Icb9AoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:brown_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmJyb3duX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoSiNZOobbpjoDCgBuZXR3b3JrX2lkJy0jwgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaBdWFGLmCLFVAwoAbmV0d29ya19pZMYBJSEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:orange_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0Om9yYW5nZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaMyJMrnPr7szAwoAbmV0d29ya19pZN6+7TUKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:yellow_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnllbGxvd19nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaN6NaIhf6m0uAwoAbmV0d29ya19pZKRHXeoKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:lime_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmxpbWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2iF3E68/rB2EAMKAG5ldHdvcmtfaWSP7qQWCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:green_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmdyZWVuX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNow5mo8aQDFboDCgBuZXR3b3JrX2lkoF11kgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:cyan_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmN5YW5fZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gnNB+cCFRJhwMKAG5ldHdvcmtfaWT9buMtCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:light_blue_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSYAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gladnCDBKCigMKAG5ldHdvcmtfaWS5CszFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:blue_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmJsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2giOZK+2nB1igMKAG5ldHdvcmtfaWR+e22CCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:purple_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSIAbWluZWNyYWZ0OnB1cnBsZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaIQU03txeAfHAwoAbmV0d29ya19pZLKbSE4KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:magenta_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSMAbWluZWNyYWZ0Om1hZ2VudGFfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2i/SNqDJbfjMgMKAG5ldHdvcmtfaWQKf9UvCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:pink_glazed_terracotta", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnBpbmtfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2hik8DVt4g+twMKAG5ldHdvcmtfaWTKzav2CgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:purpur_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZLD8ox4KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:purpur_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZPSAFFsKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:packed_mud", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9tdWQECQBuYW1lX2hhc2gHOMa121h4FgMKAG5ldHdvcmtfaWTUb6LyCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:mud_bricks", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om11ZF9icmlja3MECQBuYW1lX2hhc2iDL/SVl/PewQMKAG5ldHdvcmtfaWSkBjaDCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:nether_wart_block", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9XGS4GNnlV4DCgBuZXR3b3JrX2lkh3apIgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:warped_wart_block", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9IqDS9yUPJoDCgBuZXR3b3JrX2lkMpKAbAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:shroomlight", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnNocm9vbWxpZ2h0BAkAbmFtZV9oYXNoZHCHcHX/HYADCgBuZXR3b3JrX2lkLG2JiwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:crimson_nylium", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fbnlsaXVtBAkAbmFtZV9oYXNoOr6DJYW2bFYDCgBuZXR3b3JrX2lkuWpRDgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:warped_nylium", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9ueWxpdW0ECQBuYW1lX2hhc2g0Zf89cfr3rwMKAG5ldHdvcmtfaWSu/kekCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:netherrack", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om5ldGhlcnJhY2sECQBuYW1lX2hhc2i/r5ZyRsvPyQMKAG5ldHdvcmtfaWTAiTOACgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:basalt", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmJhc2FsdAQJAG5hbWVfaGFzaH+UQO2yWodiAwoAbmV0d29ya19pZBPNSV4KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_basalt", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnBvbGlzaGVkX2Jhc2FsdAQJAG5hbWVfaGFzaMS+L0gMnRcBAwoAbmV0d29ya19pZF+/mHwKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:smooth_basalt", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9iYXNhbHQECQBuYW1lX2hhc2jKPUdz89kuNAMKAG5ldHdvcmtfaWTkb/oVCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:soul_soil", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc29pbAQJAG5hbWVfaGFzaC1/87ccutuTAwoAbmV0d29ya19pZKc63SMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:dirt", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQmkQtoCgYAc3RhdGVzCAkAZGlydF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:dirt", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQId9pLCgYAc3RhdGVzCAkAZGlydF90eXBlBgBjb2Fyc2UAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:farmland", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmZhcm1sYW5kBAkAbmFtZV9oYXNoxyQ5ag7LolADCgBuZXR3b3JrX2lkX618FQoGAHN0YXRlcwMSAG1vaXN0dXJpemVkX2Ftb3VudAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:grass", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmdyYXNzBAkAbmFtZV9oYXNosppASPWFlsUDCgBuZXR3b3JrX2lkhLLQkQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:grass_path", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdyYXNzX3BhdGgECQBuYW1lX2hhc2i0/KZV8Qsy+gMKAG5ldHdvcmtfaWT7CcdzCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:podzol", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBvZHpvbAQJAG5hbWVfaGFzaBzqokRjH4Z1AwoAbmV0d29ya19pZPPS/GUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:mycelium", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0Om15Y2VsaXVtBAkAbmFtZV9oYXNojTN09cKickIDCgBuZXR3b3JrX2lkLNPxXQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:mud", - "block_state_b64": "CgAACAQAbmFtZQ0AbWluZWNyYWZ0Om11ZAQJAG5hbWVfaGFzaPb/3P+uLy+9AwoAbmV0d29ya19pZPIUlUkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkIQ4xgAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:iron_ore", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lk3loneQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:gold_ore", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmdvbGRfb3JlBAkAbmFtZV9oYXNoC5Y+DUGXLC4DCgBuZXR3b3JrX2lkNhvMfwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:diamond_ore", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmRpYW1vbmRfb3JlBAkAbmFtZV9oYXNokUOJ2wZZrGQDCgBuZXR3b3JrX2lk/dChVAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:lapis_ore", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmxhcGlzX29yZQQJAG5hbWVfaGFzaMrmrUrSzb7qAwoAbmV0d29ya19pZMg+qK4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:redstone_ore", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZHN0b25lX29yZQQJAG5hbWVfaGFzaFHVnp8Wc4JbAwoAbmV0d29ya19pZKDYvQoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coal_ore", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmNvYWxfb3JlBAkAbmFtZV9oYXNo1OjA+Iuy51oDCgBuZXR3b3JrX2lk+R/aKAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:copper_ore", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcHBlcl9vcmUECQBuYW1lX2hhc2iSZduSntOzOwMKAG5ldHdvcmtfaWQtIuCnCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:emerald_ore", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmVtZXJhbGRfb3JlBAkAbmFtZV9oYXNoJTovr+VgINsDCgBuZXR3b3JrX2lknbkqCgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:quartz_ore", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnF1YXJ0el9vcmUECQBuYW1lX2hhc2g0yNHLMK9TaQMKAG5ldHdvcmtfaWSzN7nzCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:nether_gold_ore", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcl9nb2xkX29yZQQJAG5hbWVfaGFzaEJZ7segIBgBAwoAbmV0d29ya19pZNI9pDgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:ancient_debris", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmFuY2llbnRfZGVicmlzBAkAbmFtZV9oYXNoNrbxMc9AwKcDCgBuZXR3b3JrX2lkrSNjEAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:deepslate_iron_ore", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9pcm9uX29yZQQJAG5hbWVfaGFzaB/fDL9pgvXXAwoAbmV0d29ya19pZFA0bz4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:deepslate_gold_ore", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9nb2xkX29yZQQJAG5hbWVfaGFzaF9G7WYhKFinAwoAbmV0d29ya19pZHQTfBUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:deepslate_diamond_ore", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9kaWFtb25kX29yZQQJAG5hbWVfaGFzaEUH5USh+iD3AwoAbmV0d29ya19pZHP6VzAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:deepslate_lapis_ore", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV9sYXBpc19vcmUECQBuYW1lX2hhc2j+yFxU/KZs1gMKAG5ldHdvcmtfaWRKINzICgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:deepslate_redstone_ore", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9yZWRzdG9uZV9vcmUECQBuYW1lX2hhc2iVgM3wWWD6ugMKAG5ldHdvcmtfaWReBdYRCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:deepslate_emerald_ore", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9lbWVyYWxkX29yZQQJAG5hbWVfaGFzaNlfo5HTwS6wAwoAbmV0d29ya19pZNeie6sKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:deepslate_coal_ore", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb2FsX29yZQQJAG5hbWVfaGFzaIjikmcbRrPPAwoAbmV0d29ya19pZD9TiygKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:deepslate_copper_ore", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb3BwZXJfb3JlBAkAbmFtZV9oYXNottjV4Ev5LAQDCgBuZXR3b3JrX2lkP23rgQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:gravel", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmdyYXZlbAQJAG5hbWVfaGFzaOFxz8XJd2r/AwoAbmV0d29ya19pZBpfI1sKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:granite", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmdyYW5pdGUECQBuYW1lX2hhc2iq+Dur2pw4AwMKAG5ldHdvcmtfaWT2NMfJCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:diorite", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmRpb3JpdGUECQBuYW1lX2hhc2iaFsq2iinZBQMKAG5ldHdvcmtfaWQqGE6XCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:andesite", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmFuZGVzaXRlBAkAbmFtZV9oYXNosaLIEnQQoSYDCgBuZXR3b3JrX2lkEApRZAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:blackstone", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrc3RvbmUECQBuYW1lX2hhc2iMFYziD80D6QMKAG5ldHdvcmtfaWSrUryHCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:deepslate", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmRlZXBzbGF0ZQQJAG5hbWVfaGFzaKX5pAblxz8TAwoAbmV0d29ya19pZOJoQjsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_granite", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGUECQBuYW1lX2hhc2iLiEfys8pFIAMKAG5ldHdvcmtfaWTCxxcHCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_diorite", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGUECQBuYW1lX2hhc2hTxY4fKmNmlAMKAG5ldHdvcmtfaWTmtjdRCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_andesite", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlBAkAbmFtZV9oYXNovl28uFk4HuQDCgBuZXR3b3JrX2lklFjuCwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_blackstone", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2jT9fHCl6vWQQMKAG5ldHdvcmtfaWR/Ho6oCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_deepslate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaHC1edoaWF3uAwoAbmV0d29ya19pZCPeQsEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:sand", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWTekU/mCgYAc3RhdGVzCAkAc2FuZF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:sand", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWSTgcqmCgYAc3RhdGVzCAkAc2FuZF90eXBlAwByZWQAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cactus", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhY3R1cwQJAG5hbWVfaGFzaCG9zL0N4wvGAwoAbmV0d29ya19pZDeCERAKBgBzdGF0ZXMDAwBhZ2UAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:oak_log", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWQjfjoxCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stripped_oak_log", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnN0cmlwcGVkX29ha19sb2cECQBuYW1lX2hhc2h8dqh+OOHU4wMKAG5ldHdvcmtfaWSYKjdrCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:spruce_log", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNwcnVjZV9sb2cECQBuYW1lX2hhc2hZ03qaLoF3WgMKAG5ldHdvcmtfaWRlFD8eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stripped_spruce_log", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV9sb2cECQBuYW1lX2hhc2iNrhKjS5IyrgMKAG5ldHdvcmtfaWRQcEC3CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:birch_log", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmJpcmNoX2xvZwQJAG5hbWVfaGFzaBUzT3NxsZAnAwoAbmV0d29ya19pZBKN3VQKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stripped_birch_log", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX2xvZwQJAG5hbWVfaGFzaCFKS4AeuSidAwoAbmV0d29ya19pZN0IONIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:jungle_log", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Omp1bmdsZV9sb2cECQBuYW1lX2hhc2gkwW0KNulqDgMKAG5ldHdvcmtfaWQaziU/CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stripped_jungle_log", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV9sb2cECQBuYW1lX2hhc2hAwMsgOk02JAMKAG5ldHdvcmtfaWQvls0eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:acacia_log", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmFjYWNpYV9sb2cECQBuYW1lX2hhc2iV48VpYhjoYQMKAG5ldHdvcmtfaWRxEqe0CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stripped_acacia_log", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV9sb2cECQBuYW1lX2hhc2hJb0lQqnEqlgMKAG5ldHdvcmtfaWRg3IdRCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:dark_oak_log", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaIWfVRd0XUo3AwoAbmV0d29ya19pZPMM7LYKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stripped_dark_oak_log", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaPFTdxRdPwkOAwoAbmV0d29ya19pZDIzenIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:mangrove_log", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaHZe6DzPZBobAwoAbmV0d29ya19pZG6DuYkKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stripped_mangrove_log", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaLqIBo4hwA//AwoAbmV0d29ya19pZPtRn7UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cherry_log", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmNoZXJyeV9sb2cECQBuYW1lX2hhc2hwFlaioppB1wMKAG5ldHdvcmtfaWS2sdXECgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stripped_cherry_log", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV9sb2cECQBuYW1lX2hhc2i85H6G+WhXaAMKAG5ldHdvcmtfaWRjzoglCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:crimson_stem", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc3RlbQQJAG5hbWVfaGFzaM0FzfL0UTKZAwoAbmV0d29ya19pZKvzID0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stripped_crimson_stem", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25fc3RlbQQJAG5hbWVfaGFzaDlA6nood57EAwoAbmV0d29ya19pZHrIqjIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:warped_stem", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zdGVtBAkAbmFtZV9oYXNon7cKfPZxdrUDCgBuZXR3b3JrX2lkerWyMwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stripped_warped_stem", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9zdGVtBAkAbmFtZV9oYXNoEw+y0dDPSd8DCgBuZXR3b3JrX2lkIQ9vBAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSYGFlqCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlAwBvYWsAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSxnUzvCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlAwBvYWsAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWToyw4RCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBzcHJ1Y2UAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWTL0a3ZCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBzcHJ1Y2UAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQV99vJCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBQBiaXJjaAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQYDJk1CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBQBiaXJjaAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSfH48gCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBqdW5nbGUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQ44auiCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBqdW5nbGUAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSogpPYCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBhY2FjaWEAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWSD7hT1CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBhY2FjaWEAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQagb3gCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlCABkYXJrX29hawADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQdnWU+CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlCABkYXJrX29hawADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:mangrove_wood", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2iXVxG0JG2fVAMKAG5ldHdvcmtfaWTok1JCCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stripped_mangrove_wood", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2h7CkbaBF7/WAMKAG5ldHdvcmtfaWQLAX88CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cherry_wood", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV93b29kBAkAbmFtZV9oYXNoAW8srlmpBM8DCgBuZXR3b3JrX2lkEALMfAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AQwAc3RyaXBwZWRfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stripped_cherry_wood", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV93b29kBAkAbmFtZV9oYXNo/e7KXv+CB38DCgBuZXR3b3JrX2lkg5aVtQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:crimson_hyphae", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNouRmKmfSqEWADCgBuZXR3b3JrX2lk+Tm5rQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stripped_crimson_hyphae", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNoFffwmABq4LUDCgBuZXR3b3JrX2lkZAlUbgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:warped_hyphae", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2hn8plQUr6pmQMKAG5ldHdvcmtfaWRU2AIBCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:stripped_warped_hyphae", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2irKq+HYPSgjQMKAG5ldHdvcmtfaWSbrOPDCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:bamboo_block", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19ibG9jawQJAG5hbWVfaGFzaAbDeur6stIBAwoAbmV0d29ya19pZCJAwn0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:stripped_bamboo_block", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2JhbWJvb19ibG9jawQJAG5hbWVfaGFzaJpwytpZOZM9AwoAbmV0d29ya19pZKuRbNEKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZOmqtzMKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlAwBvYWsBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZFMVNEQKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBgBzcHJ1Y2UBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZKCZEm8KBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBQBiaXJjaAEOAHBlcnNpc3RlbnRfYml0AAEKAHVwZGF0ZV9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZABprGgKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBgBqdW5nbGUBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:leaves2", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmxlYXZlczIECQBuYW1lX2hhc2gy/bgrncY1ZAMKAG5ldHdvcmtfaWSFh3olCgYAc3RhdGVzCA0AbmV3X2xlYWZfdHlwZQYAYWNhY2lhAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:leaves2", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmxlYXZlczIECQBuYW1lX2hhc2gy/bgrncY1ZAMKAG5ldHdvcmtfaWTvEAyeCgYAc3RhdGVzCA0AbmV3X2xlYWZfdHlwZQgAZGFya19vYWsBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:mangrove_leaves", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2xlYXZlcwQJAG5hbWVfaGFzaKyI/dWvhEG8AwoAbmV0d29ya19pZPQxCZ8KBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cherry_leaves", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9sZWF2ZXMECQBuYW1lX2hhc2giTs9ChhYBlQMKAG5ldHdvcmtfaWR8bPpwCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:azalea_leaves", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXMECQBuYW1lX2hhc2iXFhD57wFS7AMKAG5ldHdvcmtfaWTNB/9ECgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:azalea_leaves_flowered", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXNfZmxvd2VyZWQECQBuYW1lX2hhc2gs8jxlS/pMrwMKAG5ldHdvcmtfaWQ7W4PyCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQmoOEvCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUDAG9hawADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQO8pAmCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAHNwcnVjZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQDHhokCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUFAGJpcmNoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWTdQrcyCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAGp1bmdsZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRCDffNCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAGFjYWNpYQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWR0BRzPCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUIAGRhcmtfb2FrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:mangrove_propagule", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hbmdyb3ZlX3Byb3BhZ3VsZQQJAG5hbWVfaGFzaJGeox6hkfLFAwoAbmV0d29ya19pZAIpvpYKBgBzdGF0ZXMBBwBoYW5naW5nAAMPAHByb3BhZ3VsZV9zdGFnZQAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cherry_sapling", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNoZXJyeV9zYXBsaW5nBAkAbmFtZV9oYXNoGrPpNMf1LtcDCgBuZXR3b3JrX2lkypakXQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bee_nest", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmJlZV9uZXN0BAkAbmFtZV9oYXNo2R2WBxUHEZIDCgBuZXR3b3JrX2lkiXWLEAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAADCwBob25leV9sZXZlbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wheat_seeds" - }, - { - "id": "minecraft:pumpkin_seeds" - }, - { - "id": "minecraft:melon_seeds" - }, - { - "id": "minecraft:beetroot_seeds" - }, - { - "id": "minecraft:torchflower_seeds" - }, - { - "id": "minecraft:pitcher_pod" - }, - { - "id": "minecraft:wheat" - }, - { - "id": "minecraft:beetroot" - }, - { - "id": "minecraft:potato" - }, - { - "id": "minecraft:poisonous_potato" - }, - { - "id": "minecraft:carrot" - }, - { - "id": "minecraft:golden_carrot" - }, - { - "id": "minecraft:apple" - }, - { - "id": "minecraft:golden_apple" - }, - { - "id": "minecraft:enchanted_golden_apple" - }, - { - "id": "minecraft:melon_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1lbG9uX2Jsb2NrBAkAbmFtZV9oYXNoXxSm0iYpAx8DCgBuZXR3b3JrX2lkC9rqygoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:melon_slice" - }, - { - "id": "minecraft:glistering_melon_slice" - }, - { - "id": "minecraft:sweet_berries" - }, - { - "id": "minecraft:glow_berries" - }, - { - "id": "minecraft:pumpkin", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OnB1bXBraW4ECQBuYW1lX2hhc2gc8A3jaSzWbgMKAG5ldHdvcmtfaWRFGA+xCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:carved_pumpkin", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNhcnZlZF9wdW1wa2luBAkAbmFtZV9oYXNoPu1T0MJuG90DCgBuZXR3b3JrX2lkXNNn5QoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:lit_pumpkin", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpdF9wdW1wa2luBAkAbmFtZV9oYXNo7gWtEm2uPL0DCgBuZXR3b3JrX2lki8sU4AoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:honeycomb" - }, - { - "id": "minecraft:tallgrass", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZOh33DMKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAGZlcm4AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZMx1sfgKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAZmVybgEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:tallgrass", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZErptfIKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAHRhbGwAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZAbadmIKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQUAZ3Jhc3MBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:nether_sprouts" - }, - { - "id": "minecraft:fire_coral", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWS9vF0UCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:brain_coral", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJyYWluX2NvcmFsBAkAbmFtZV9oYXNoRiWlLCwA2ycDCgBuZXR3b3JrX2lkrjAuhgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:bubble_coral", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbAQJAG5hbWVfaGFzaJz6rWnl+v2qAwoAbmV0d29ya19pZImIWy0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:tube_coral", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnR1YmVfY29yYWwECQBuYW1lX2hhc2iYa8oO/tgk7wMKAG5ldHdvcmtfaWRTfND5CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:horn_coral", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Omhvcm5fY29yYWwECQBuYW1lX2hhc2iZnRHjZbnLPgMKAG5ldHdvcmtfaWR+GGp8CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dead_fire_coral", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbAQJAG5hbWVfaGFzaEPU6tFy/latAwoAbmV0d29ya19pZNMa7V4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:dead_brain_coral", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWwECQBuYW1lX2hhc2j5L6QJCISvzwMKAG5ldHdvcmtfaWQkKzeiCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dead_bubble_coral", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsBAkAbmFtZV9oYXNoSTOZ/8wpeNYDCgBuZXR3b3JrX2lka6w9DAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:dead_tube_coral", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbAQJAG5hbWVfaGFzaJGjNWhlaIJeAwoAbmV0d29ya19pZO3Z0ygKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:dead_horn_coral", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbAQJAG5hbWVfaGFzaJBkz3qt+g2cAwoAbmV0d29ya19pZBAN+eYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZOg7iS4KBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgMAcmVkAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZIDj8HMKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgQAcGluawMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZLCJP0kKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgYAcHVycGxlAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZFz2ly4KBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgQAYmx1ZQMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZE4TgnYKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgYAeWVsbG93AxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkdhLQzwoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkSi6srQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkGiGSzAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkmvZKOgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lknLw+4QoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:crimson_roots", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fcm9vdHMECQBuYW1lX2hhc2j1fWgQLViv5QMKAG5ldHdvcmtfaWRLh5DXCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:warped_roots", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9yb290cwQJAG5hbWVfaGFzaBc3WvbJOLlkAwoAbmV0d29ya19pZNLgDnAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:yellow_flower", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19mbG93ZXIECQBuYW1lX2hhc2jWbU1pF0OUGAMKAG5ldHdvcmtfaWQgO3hpCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWSqsqQGCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUFAHBvcHB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTqDajjCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUGAG9yY2hpZAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWT5CjveCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUGAGFsbGl1bQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTORIBJCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUJAGhvdXN0b25pYQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTuNhmYCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUJAHR1bGlwX3JlZAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWT0O4nfCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUMAHR1bGlwX29yYW5nZQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTqkthyCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGULAHR1bGlwX3doaXRlAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRMbBA7CgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUKAHR1bGlwX3BpbmsAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRexMAuCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUFAG94ZXllAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWQgs7BECgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUKAGNvcm5mbG93ZXIAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRvDuNbCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUSAGxpbHlfb2ZfdGhlX3ZhbGxleQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZOemRt4KBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQkAc3VuZmxvd2VyAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZOFugoEKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAc3lyaW5nYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZN4O+/gKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAcm9zZQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZI3w4GMKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAcGFlb25pYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:pitcher_plant", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnBpdGNoZXJfcGxhbnQECQBuYW1lX2hhc2hRJHzsbDH+SQMKAG5ldHdvcmtfaWRnY76VCgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:pink_petals", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfcGV0YWxzBAkAbmFtZV9oYXNo6DQwN9SwV3QDCgBuZXR3b3JrX2lkNWneGgoGAHN0YXRlcwMGAGdyb3d0aAAAAAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:wither_rose", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OndpdGhlcl9yb3NlBAkAbmFtZV9oYXNoaSKxl3I516gDCgBuZXR3b3JrX2lkATXLPwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:torchflower", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnRvcmNoZmxvd2VyBAkAbmFtZV9oYXNoL+mHtElwbqQDCgBuZXR3b3JrX2lkI34O+AoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:white_dye" - }, - { - "id": "minecraft:light_gray_dye" - }, - { - "id": "minecraft:gray_dye" - }, - { - "id": "minecraft:black_dye" - }, - { - "id": "minecraft:brown_dye" - }, - { - "id": "minecraft:red_dye" - }, - { - "id": "minecraft:orange_dye" - }, - { - "id": "minecraft:yellow_dye" - }, - { - "id": "minecraft:lime_dye" - }, - { - "id": "minecraft:green_dye" - }, - { - "id": "minecraft:cyan_dye" - }, - { - "id": "minecraft:light_blue_dye" - }, - { - "id": "minecraft:blue_dye" - }, - { - "id": "minecraft:purple_dye" - }, - { - "id": "minecraft:magenta_dye" - }, - { - "id": "minecraft:pink_dye" - }, - { - "id": "minecraft:ink_sac" - }, - { - "id": "minecraft:glow_ink_sac" - }, - { - "id": "minecraft:cocoa_beans" - }, - { - "id": "minecraft:lapis_lazuli" - }, - { - "id": "minecraft:bone_meal" - }, - { - "id": "minecraft:vine", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnZpbmUECQBuYW1lX2hhc2j0Sj8/XeXOLAMKAG5ldHdvcmtfaWSUkDtbCgYAc3RhdGVzAxMAdmluZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:weeping_vines", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndlZXBpbmdfdmluZXMECQBuYW1lX2hhc2jrLgLHkQygiwMKAG5ldHdvcmtfaWQ8NHSJCgYAc3RhdGVzAxEAd2VlcGluZ192aW5lc19hZ2UAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:twisting_vines", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnR3aXN0aW5nX3ZpbmVzBAkAbmFtZV9oYXNoDYR5QgVUQJADCgBuZXR3b3JrX2lk5kYVIQoGAHN0YXRlcwMSAHR3aXN0aW5nX3ZpbmVzX2FnZQAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:waterlily", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OndhdGVybGlseQQJAG5hbWVfaGFzaEHgC4c1SXg0AwoAbmV0d29ya19pZOOerp8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:seagrass", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OnNlYWdyYXNzBAkAbmFtZV9oYXNoHSBFtoHdWxIDCgBuZXR3b3JrX2lkd3lhEAoGAHN0YXRlcwgOAHNlYV9ncmFzc190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:kelp" - }, - { - "id": "minecraft:deadbush", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmRlYWRidXNoBAkAbmFtZV9oYXNoPFODe4IScnYDCgBuZXR3b3JrX2lkVfnl+goGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:bamboo", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmJhbWJvbwQJAG5hbWVfaGFzaBgpGmyzhedCAwoAbmV0d29ya19pZIZv1nYKBgBzdGF0ZXMBBwBhZ2VfYml0AAgQAGJhbWJvb19sZWFmX3NpemUJAG5vX2xlYXZlcwgWAGJhbWJvb19zdGFsa190aGlja25lc3MEAHRoaW4AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:snow", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnNub3cECQBuYW1lX2hhc2gVHr5XXdETWAMKAG5ldHdvcmtfaWQ0zCeHCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:ice", - "block_state_b64": "CgAACAQAbmFtZQ0AbWluZWNyYWZ0OmljZQQJAG5hbWVfaGFzaNF26f+uUT29AwoAbmV0d29ya19pZOUMaQYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:packed_ice", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9pY2UECQBuYW1lX2hhc2hk4bu123ZrFgMKAG5ldHdvcmtfaWTr/ooaCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:blue_ice", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0OmJsdWVfaWNlBAkAbmFtZV9oYXNo+EKxYgFhKcgDCgBuZXR3b3JrX2lkxfsA8goGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:snow_layer", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNub3dfbGF5ZXIECQBuYW1lX2hhc2hXka6atMYUCQMKAG5ldHdvcmtfaWRCrIPcCgYAc3RhdGVzAQsAY292ZXJlZF9iaXQAAwYAaGVpZ2h0AAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:pointed_dripstone", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvaW50ZWRfZHJpcHN0b25lBAkAbmFtZV9oYXNoJMISzmHQgt8DCgBuZXR3b3JrX2lkbWrtYgoGAHN0YXRlcwgTAGRyaXBzdG9uZV90aGlja25lc3MDAHRpcAEHAGhhbmdpbmcBAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dripstone_block", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRyaXBzdG9uZV9ibG9jawQJAG5hbWVfaGFzaIIXnEqY77YsAwoAbmV0d29ya19pZMZi2kwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:moss_carpet", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vc3NfY2FycGV0BAkAbmFtZV9oYXNo/NEDxRPTshYDCgBuZXR3b3JrX2lkaGG3QwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:moss_block", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0Om1vc3NfYmxvY2sECQBuYW1lX2hhc2iovcsPUYX2tgMKAG5ldHdvcmtfaWT3JSbfCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dirt_with_roots", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRpcnRfd2l0aF9yb290cwQJAG5hbWVfaGFzaLCNDYPviDCIAwoAbmV0d29ya19pZNCkwzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:hanging_roots", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omhhbmdpbmdfcm9vdHMECQBuYW1lX2hhc2jaXn+Y5UZpDAMKAG5ldHdvcmtfaWRU4c2vCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:mangrove_roots", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNoa786PzQGZ6kDCgBuZXR3b3JrX2lklA0AHgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:muddy_mangrove_roots", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0Om11ZGR5X21hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNo9YApdHpo1RkDCgBuZXR3b3JrX2lkH0Oc4woGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:big_dripleaf", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpZ19kcmlwbGVhZgQJAG5hbWVfaGFzaGBEhXjo6qSdAwoAbmV0d29ya19pZMETsb8KBgBzdGF0ZXMBEQBiaWdfZHJpcGxlYWZfaGVhZAEIEQBiaWdfZHJpcGxlYWZfdGlsdAQAbm9uZQgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:small_dripleaf_block", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtYWxsX2RyaXBsZWFmX2Jsb2NrBAkAbmFtZV9oYXNojxRAgXP9uWADCgBuZXR3b3JrX2lkozbVPwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24EAGVhc3QBDwB1cHBlcl9ibG9ja19iaXQBAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:spore_blossom", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwb3JlX2Jsb3Nzb20ECQBuYW1lX2hhc2il3U72Gbco2gMKAG5ldHdvcmtfaWSbbbgcCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:azalea", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmF6YWxlYQQJAG5hbWVfaGFzaNyUl+BW9JrBAwoAbmV0d29ya19pZO/XZtQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:flowering_azalea", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmZsb3dlcmluZ19hemFsZWEECQBuYW1lX2hhc2ie9r33wz8kiwMKAG5ldHdvcmtfaWQ3ij0VCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:glow_lichen", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Omdsb3dfbGljaGVuBAkAbmFtZV9oYXNobyPUrIYlo44DCgBuZXR3b3JrX2lkCh8lSAoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHM/AAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:amethyst_block", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmFtZXRoeXN0X2Jsb2NrBAkAbmFtZV9oYXNob+JK1iiAthcDCgBuZXR3b3JrX2lk8HtpzgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:budding_amethyst", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1ZGRpbmdfYW1ldGh5c3QECQBuYW1lX2hhc2gJvAwfI14fxgMKAG5ldHdvcmtfaWTQYqfACgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:amethyst_cluster", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmFtZXRoeXN0X2NsdXN0ZXIECQBuYW1lX2hhc2jK82S88Jgm8wMKAG5ldHdvcmtfaWSCPMPGCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:large_amethyst_bud", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmxhcmdlX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaAHhdpWD+sd5AwoAbmV0d29ya19pZKkQxOcKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:medium_amethyst_bud", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om1lZGl1bV9hbWV0aHlzdF9idWQECQBuYW1lX2hhc2g5lBGtC0DzZQMKAG5ldHdvcmtfaWSYiP4gCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:small_amethyst_bud", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnNtYWxsX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaEnb4+q9PO4YAwoAbmV0d29ya19pZGWzxrQKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:tuff", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnR1ZmYECQBuYW1lX2hhc2h1Rwc1XYsBGwMKAG5ldHdvcmtfaWRwQGn0CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:tuff_stairs", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnR1ZmZfc3RhaXJzBAkAbmFtZV9oYXNoKjyNUBjcfZsDCgBuZXR3b3JrX2lk+LsycgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:tuff_slab", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnR1ZmZfc2xhYgQJAG5hbWVfaGFzaIhCGdlIsnMUAwoAbmV0d29ya19pZN1dUL4KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:tuff_wall", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnR1ZmZfd2FsbAQJAG5hbWVfaGFzaMyeeu1IRf03AwoAbmV0d29ya19pZDkIrosKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:chiseled_tuff", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoaXNlbGVkX3R1ZmYECQBuYW1lX2hhc2iVliOT8OTQ9AMKAG5ldHdvcmtfaWTLNKOiCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_tuff", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmYECQBuYW1lX2hhc2hyaLe/KEVZ0gMKAG5ldHdvcmtfaWTcX3NrCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_tuff_stairs", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfc3RhaXJzBAkAbmFtZV9oYXNo8yuah8QI1dcDCgBuZXR3b3JrX2lkjLoU4AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:polished_tuff_slab", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfc2xhYgQJAG5hbWVfaGFzaLXdb48YvAsHAwoAbmV0d29ya19pZAnJ7W0KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_tuff_wall", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfd2FsbAQJAG5hbWVfaGFzaJVZj6QYWXUrAwoAbmV0d29ya19pZLU7dooKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:tuff_bricks", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnR1ZmZfYnJpY2tzBAkAbmFtZV9oYXNo/hbQ+mXSK7wDCgBuZXR3b3JrX2lk6gmIwQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:tuff_brick_stairs", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNoWJpkAurUfKwDCgBuZXR3b3JrX2lkUMcjiwoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:tuff_brick_slab", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaLqPMjVCv5dIAwoAbmV0d29ya19pZOmeRhcKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:tuff_brick_wall", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaIL0IyNCOsonAwoAbmV0d29ya19pZJW4T5UKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:chiseled_tuff_bricks", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmNoaXNlbGVkX3R1ZmZfYnJpY2tzBAkAbmFtZV9oYXNo3oQw6gmxYuADCgBuZXR3b3JrX2lkm3D8AgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:calcite", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmNhbGNpdGUECQBuYW1lX2hhc2ixKLu8ZIdzDQMKAG5ldHdvcmtfaWQlSbJDCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:chicken" - }, - { - "id": "minecraft:porkchop" - }, - { - "id": "minecraft:beef" - }, - { - "id": "minecraft:mutton" - }, - { - "id": "minecraft:rabbit" - }, - { - "id": "minecraft:cod" - }, - { - "id": "minecraft:salmon" - }, - { - "id": "minecraft:tropical_fish" - }, - { - "id": "minecraft:pufferfish" - }, - { - "id": "minecraft:brown_mushroom", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkLh1OXAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_mushroom", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9tdXNocm9vbQQJAG5hbWVfaGFzaPpzJua7669xAwoAbmV0d29ya19pZCvWPYkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:crimson_fungus", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fZnVuZ3VzBAkAbmFtZV9oYXNolIcCUuFM2u0DCgBuZXR3b3JrX2lkD2NN0QoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:warped_fungus", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9mdW5ndXMECQBuYW1lX2hhc2gq8bSnRVTAFgMKAG5ldHdvcmtfaWTkwS+rCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkdOMhDAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw4AAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_mushroom_block", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9tdXNocm9vbV9ibG9jawQJAG5hbWVfaGFzaJTTyJbth9M9AwoAbmV0d29ya19pZM+AyboKBgBzdGF0ZXMDEgBodWdlX211c2hyb29tX2JpdHMOAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkbdt3CAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw8AAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkSrMl9goGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cwAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:egg" - }, - { - "id": "minecraft:sugar_cane" - }, - { - "id": "minecraft:sugar" - }, - { - "id": "minecraft:rotten_flesh" - }, - { - "id": "minecraft:bone" - }, - { - "id": "minecraft:web", - "block_state_b64": "CgAACAQAbmFtZQ0AbWluZWNyYWZ0OndlYgQJAG5hbWVfaGFzaA4GKQCvG4i9AwoAbmV0d29ya19pZApt+jgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:spider_eye" - }, - { - "id": "minecraft:mob_spawner", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vYl9zcGF3bmVyBAkAbmFtZV9oYXNoNwGrCV/Fkh8DCgBuZXR3b3JrX2lkM1wTmgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqXH7RgoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUFAHN0b25lAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkeIBb6QoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAGNvYmJsZXN0b25lAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkDZ2cFQoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAHN0b25lX2JyaWNrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkOR/cTAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGURAG1vc3N5X3N0b25lX2JyaWNrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqdwlHAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUTAGNyYWNrZWRfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFqqPggoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUUAGNoaXNlbGVkX3N0b25lX2JyaWNrAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:infested_deepslate", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmluZmVzdGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaICF2VYccxF1AwoAbmV0d29ya19pZDa/624KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:dragon_egg", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmRyYWdvbl9lZ2cECQBuYW1lX2hhc2inMzXrV+/e1wMKAG5ldHdvcmtfaWTgO1yRCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:turtle_egg", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnR1cnRsZV9lZ2cECQBuYW1lX2hhc2iwSRcxOJIJ9gMKAG5ldHdvcmtfaWSIRNUhCgYAc3RhdGVzCA0AY3JhY2tlZF9zdGF0ZQkAbm9fY3JhY2tzCBAAdHVydGxlX2VnZ19jb3VudAcAb25lX2VnZwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sniffer_egg", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnNuaWZmZXJfZWdnBAkAbmFtZV9oYXNoY1lozc8lPcYDCgBuZXR3b3JrX2lk7yb/2QoGAHN0YXRlcwgNAGNyYWNrZWRfc3RhdGUJAG5vX2NyYWNrcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:frog_spawn", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmZyb2dfc3Bhd24ECQBuYW1lX2hhc2iWmd7idp3ZZwMKAG5ldHdvcmtfaWRFzJudCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:pearlescent_froglight", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnBlYXJsZXNjZW50X2Zyb2dsaWdodAQJAG5hbWVfaGFzaKkcFRyycYGyAwoAbmV0d29ya19pZJqYakAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:verdant_froglight", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnZlcmRhbnRfZnJvZ2xpZ2h0BAkAbmFtZV9oYXNoA+eXuTBohrQDCgBuZXR3b3JrX2lkDIVnsQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:ochre_froglight", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om9jaHJlX2Zyb2dsaWdodAQJAG5hbWVfaGFzaMY59kjPe+c3AwoAbmV0d29ya19pZO2TD50KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:chicken_spawn_egg" - }, - { - "id": "minecraft:bee_spawn_egg" - }, - { - "id": "minecraft:cow_spawn_egg" - }, - { - "id": "minecraft:pig_spawn_egg" - }, - { - "id": "minecraft:sheep_spawn_egg" - }, - { - "id": "minecraft:wolf_spawn_egg" - }, - { - "id": "minecraft:polar_bear_spawn_egg" - }, - { - "id": "minecraft:ocelot_spawn_egg" - }, - { - "id": "minecraft:cat_spawn_egg" - }, - { - "id": "minecraft:mooshroom_spawn_egg" - }, - { - "id": "minecraft:bat_spawn_egg" - }, - { - "id": "minecraft:parrot_spawn_egg" - }, - { - "id": "minecraft:rabbit_spawn_egg" - }, - { - "id": "minecraft:llama_spawn_egg" - }, - { - "id": "minecraft:horse_spawn_egg" - }, - { - "id": "minecraft:donkey_spawn_egg" - }, - { - "id": "minecraft:mule_spawn_egg" - }, - { - "id": "minecraft:skeleton_horse_spawn_egg" - }, - { - "id": "minecraft:zombie_horse_spawn_egg" - }, - { - "id": "minecraft:tropical_fish_spawn_egg" - }, - { - "id": "minecraft:cod_spawn_egg" - }, - { - "id": "minecraft:pufferfish_spawn_egg" - }, - { - "id": "minecraft:salmon_spawn_egg" - }, - { - "id": "minecraft:dolphin_spawn_egg" - }, - { - "id": "minecraft:turtle_spawn_egg" - }, - { - "id": "minecraft:panda_spawn_egg" - }, - { - "id": "minecraft:fox_spawn_egg" - }, - { - "id": "minecraft:creeper_spawn_egg" - }, - { - "id": "minecraft:enderman_spawn_egg" - }, - { - "id": "minecraft:silverfish_spawn_egg" - }, - { - "id": "minecraft:skeleton_spawn_egg" - }, - { - "id": "minecraft:wither_skeleton_spawn_egg" - }, - { - "id": "minecraft:stray_spawn_egg" - }, - { - "id": "minecraft:slime_spawn_egg" - }, - { - "id": "minecraft:spider_spawn_egg" - }, - { - "id": "minecraft:zombie_spawn_egg" - }, - { - "id": "minecraft:zombie_pigman_spawn_egg" - }, - { - "id": "minecraft:husk_spawn_egg" - }, - { - "id": "minecraft:drowned_spawn_egg" - }, - { - "id": "minecraft:squid_spawn_egg" - }, - { - "id": "minecraft:glow_squid_spawn_egg" - }, - { - "id": "minecraft:cave_spider_spawn_egg" - }, - { - "id": "minecraft:witch_spawn_egg" - }, - { - "id": "minecraft:guardian_spawn_egg" - }, - { - "id": "minecraft:elder_guardian_spawn_egg" - }, - { - "id": "minecraft:endermite_spawn_egg" - }, - { - "id": "minecraft:magma_cube_spawn_egg" - }, - { - "id": "minecraft:strider_spawn_egg" - }, - { - "id": "minecraft:hoglin_spawn_egg" - }, - { - "id": "minecraft:piglin_spawn_egg" - }, - { - "id": "minecraft:zoglin_spawn_egg" - }, - { - "id": "minecraft:piglin_brute_spawn_egg" - }, - { - "id": "minecraft:goat_spawn_egg" - }, - { - "id": "minecraft:axolotl_spawn_egg" - }, - { - "id": "minecraft:warden_spawn_egg" - }, - { - "id": "minecraft:allay_spawn_egg" - }, - { - "id": "minecraft:frog_spawn_egg" - }, - { - "id": "minecraft:tadpole_spawn_egg" - }, - { - "id": "minecraft:trader_llama_spawn_egg" - }, - { - "id": "minecraft:camel_spawn_egg" - }, - { - "id": "minecraft:ghast_spawn_egg" - }, - { - "id": "minecraft:blaze_spawn_egg" - }, - { - "id": "minecraft:shulker_spawn_egg" - }, - { - "id": "minecraft:vindicator_spawn_egg" - }, - { - "id": "minecraft:evoker_spawn_egg" - }, - { - "id": "minecraft:vex_spawn_egg" - }, - { - "id": "minecraft:villager_spawn_egg" - }, - { - "id": "minecraft:wandering_trader_spawn_egg" - }, - { - "id": "minecraft:zombie_villager_spawn_egg" - }, - { - "id": "minecraft:phantom_spawn_egg" - }, - { - "id": "minecraft:pillager_spawn_egg" - }, - { - "id": "minecraft:ravager_spawn_egg" - }, - { - "id": "minecraft:iron_golem_spawn_egg" - }, - { - "id": "minecraft:snow_golem_spawn_egg" - }, - { - "id": "minecraft:sniffer_spawn_egg" - }, - { - "id": "minecraft:obsidian", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2lkaWFuBAkAbmFtZV9oYXNoiz4qrb8QjyEDCgBuZXR3b3JrX2lkuqnPpQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:crying_obsidian", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmNyeWluZ19vYnNpZGlhbgQJAG5hbWVfaGFzaKT0JlA7Z1K+AwoAbmV0d29ya19pZCjbPV4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:bedrock", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmJlZHJvY2sECQBuYW1lX2hhc2hWfFrh4LVtxwMKAG5ldHdvcmtfaWT7fKz1CgYAc3RhdGVzAQ4AaW5maW5pYnVybl9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:soul_sand", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc2FuZAQJAG5hbWVfaGFzaMaf+bccu+KTAwoAbmV0d29ya19pZBQSHrMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:magma", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0Om1hZ21hBAkAbmFtZV9oYXNoqyTjKaIsWfYDCgBuZXR3b3JrX2lkyfWAZgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:nether_wart" - }, - { - "id": "minecraft:end_stone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmVuZF9zdG9uZQQJAG5hbWVfaGFzaH1J9jA39GJNAwoAbmV0d29ya19pZFeFQ7UKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:chorus_flower", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNob3J1c19mbG93ZXIECQBuYW1lX2hhc2iMpSodli5uawMKAG5ldHdvcmtfaWRnd1ZWCgYAc3RhdGVzAwMAYWdlAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:chorus_plant", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmNob3J1c19wbGFudAQJAG5hbWVfaGFzaJhSrmNGKwaMAwoAbmV0d29ya19pZA3uVqMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:chorus_fruit" - }, - { - "id": "minecraft:popped_chorus_fruit" - }, - { - "id": "minecraft:sponge", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZF01rO0KBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAZHJ5AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:sponge", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZPiOc4QKBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAd2V0AAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkGnlaAwoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkSnHuagoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkmkHyegoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkdpUDxgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkYNWvYgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkZSxBQgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lklSTVqQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lk5fTYuQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkwUjqBAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkq4iWoQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:sculk", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lkyqUPPgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sculk_vein", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNjdWxrX3ZlaW4ECQBuYW1lX2hhc2gJUdhVooV4zwMKAG5ldHdvcmtfaWSUfn1XCgYAc3RhdGVzAxkAbXVsdGlfZmFjZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:sculk_catalyst", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX2NhdGFseXN0BAkAbmFtZV9oYXNo+gCpbrCHST4DCgBuZXR3b3JrX2lkMJ2n/woGAHN0YXRlcwEFAGJsb29tAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sculk_shrieker", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX3Nocmlla2VyBAkAbmFtZV9oYXNo5OXtyObniQ4DCgBuZXR3b3JrX2lkxapoNAoGAHN0YXRlcwEGAGFjdGl2ZQABCgBjYW5fc3VtbW9uAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sculk_sensor", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnNjdWxrX3NlbnNvcgQJAG5hbWVfaGFzaCkmHreeTgNnAwoAbmV0d29ya19pZLj2WPcKBgBzdGF0ZXMDEgBzY3Vsa19zZW5zb3JfcGhhc2UAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:calibrated_sculk_sensor", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmNhbGlicmF0ZWRfc2N1bGtfc2Vuc29yBAkAbmFtZV9oYXNoffAcXXN/iJUDCgBuZXR3b3JrX2lkwOx3QQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAxIAc2N1bGtfc2Vuc29yX3BoYXNlAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:reinforced_deepslate", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlaW5mb3JjZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoldDmj91EapQDCgBuZXR3b3JrX2lkHIt+aQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:leather_helmet" - }, - { - "id": "minecraft:chainmail_helmet" - }, - { - "id": "minecraft:iron_helmet" - }, - { - "id": "minecraft:golden_helmet" - }, - { - "id": "minecraft:diamond_helmet" - }, - { - "id": "minecraft:netherite_helmet" - }, - { - "id": "minecraft:leather_chestplate" - }, - { - "id": "minecraft:chainmail_chestplate" - }, - { - "id": "minecraft:iron_chestplate" - }, - { - "id": "minecraft:golden_chestplate" - }, - { - "id": "minecraft:diamond_chestplate" - }, - { - "id": "minecraft:netherite_chestplate" - }, - { - "id": "minecraft:leather_leggings" - }, - { - "id": "minecraft:chainmail_leggings" - }, - { - "id": "minecraft:iron_leggings" - }, - { - "id": "minecraft:golden_leggings" - }, - { - "id": "minecraft:diamond_leggings" - }, - { - "id": "minecraft:netherite_leggings" - }, - { - "id": "minecraft:leather_boots" - }, - { - "id": "minecraft:chainmail_boots" - }, - { - "id": "minecraft:iron_boots" - }, - { - "id": "minecraft:golden_boots" - }, - { - "id": "minecraft:diamond_boots" - }, - { - "id": "minecraft:netherite_boots" - }, - { - "id": "minecraft:wooden_sword" - }, - { - "id": "minecraft:stone_sword" - }, - { - "id": "minecraft:iron_sword" - }, - { - "id": "minecraft:golden_sword" - }, - { - "id": "minecraft:diamond_sword" - }, - { - "id": "minecraft:netherite_sword" - }, - { - "id": "minecraft:wooden_axe" - }, - { - "id": "minecraft:stone_axe" - }, - { - "id": "minecraft:iron_axe" - }, - { - "id": "minecraft:golden_axe" - }, - { - "id": "minecraft:diamond_axe" - }, - { - "id": "minecraft:netherite_axe" - }, - { - "id": "minecraft:wooden_pickaxe" - }, - { - "id": "minecraft:stone_pickaxe" - }, - { - "id": "minecraft:iron_pickaxe" - }, - { - "id": "minecraft:golden_pickaxe" - }, - { - "id": "minecraft:diamond_pickaxe" - }, - { - "id": "minecraft:netherite_pickaxe" - }, - { - "id": "minecraft:wooden_shovel" - }, - { - "id": "minecraft:stone_shovel" - }, - { - "id": "minecraft:iron_shovel" - }, - { - "id": "minecraft:golden_shovel" - }, - { - "id": "minecraft:diamond_shovel" - }, - { - "id": "minecraft:netherite_shovel" - }, - { - "id": "minecraft:wooden_hoe" - }, - { - "id": "minecraft:stone_hoe" - }, - { - "id": "minecraft:iron_hoe" - }, - { - "id": "minecraft:golden_hoe" - }, - { - "id": "minecraft:diamond_hoe" - }, - { - "id": "minecraft:netherite_hoe" - }, - { - "id": "minecraft:bow" - }, - { - "id": "minecraft:crossbow" - }, - { - "id": "minecraft:arrow" - }, - { - "id": "minecraft:arrow", - "damage": 6 - }, - { - "id": "minecraft:arrow", - "damage": 7 - }, - { - "id": "minecraft:arrow", - "damage": 8 - }, - { - "id": "minecraft:arrow", - "damage": 9 - }, - { - "id": "minecraft:arrow", - "damage": 10 - }, - { - "id": "minecraft:arrow", - "damage": 11 - }, - { - "id": "minecraft:arrow", - "damage": 12 - }, - { - "id": "minecraft:arrow", - "damage": 13 - }, - { - "id": "minecraft:arrow", - "damage": 14 - }, - { - "id": "minecraft:arrow", - "damage": 15 - }, - { - "id": "minecraft:arrow", - "damage": 16 - }, - { - "id": "minecraft:arrow", - "damage": 17 - }, - { - "id": "minecraft:arrow", - "damage": 18 - }, - { - "id": "minecraft:arrow", - "damage": 19 - }, - { - "id": "minecraft:arrow", - "damage": 20 - }, - { - "id": "minecraft:arrow", - "damage": 21 - }, - { - "id": "minecraft:arrow", - "damage": 22 - }, - { - "id": "minecraft:arrow", - "damage": 23 - }, - { - "id": "minecraft:arrow", - "damage": 24 - }, - { - "id": "minecraft:arrow", - "damage": 25 - }, - { - "id": "minecraft:arrow", - "damage": 26 - }, - { - "id": "minecraft:arrow", - "damage": 27 - }, - { - "id": "minecraft:arrow", - "damage": 28 - }, - { - "id": "minecraft:arrow", - "damage": 29 - }, - { - "id": "minecraft:arrow", - "damage": 30 - }, - { - "id": "minecraft:arrow", - "damage": 31 - }, - { - "id": "minecraft:arrow", - "damage": 32 - }, - { - "id": "minecraft:arrow", - "damage": 33 - }, - { - "id": "minecraft:arrow", - "damage": 34 - }, - { - "id": "minecraft:arrow", - "damage": 35 - }, - { - "id": "minecraft:arrow", - "damage": 36 - }, - { - "id": "minecraft:arrow", - "damage": 37 - }, - { - "id": "minecraft:arrow", - "damage": 38 - }, - { - "id": "minecraft:arrow", - "damage": 39 - }, - { - "id": "minecraft:arrow", - "damage": 40 - }, - { - "id": "minecraft:arrow", - "damage": 41 - }, - { - "id": "minecraft:arrow", - "damage": 42 - }, - { - "id": "minecraft:arrow", - "damage": 43 - }, - { - "id": "minecraft:shield" - }, - { - "id": "minecraft:cooked_chicken" - }, - { - "id": "minecraft:cooked_porkchop" - }, - { - "id": "minecraft:cooked_beef" - }, - { - "id": "minecraft:cooked_mutton" - }, - { - "id": "minecraft:cooked_rabbit" - }, - { - "id": "minecraft:cooked_cod" - }, - { - "id": "minecraft:cooked_salmon" - }, - { - "id": "minecraft:bread" - }, - { - "id": "minecraft:mushroom_stew" - }, - { - "id": "minecraft:beetroot_soup" - }, - { - "id": "minecraft:rabbit_stew" - }, - { - "id": "minecraft:baked_potato" - }, - { - "id": "minecraft:cookie" - }, - { - "id": "minecraft:pumpkin_pie" - }, - { - "id": "minecraft:cake" - }, - { - "id": "minecraft:dried_kelp" - }, - { - "id": "minecraft:fishing_rod" - }, - { - "id": "minecraft:carrot_on_a_stick" - }, - { - "id": "minecraft:warped_fungus_on_a_stick" - }, - { - "id": "minecraft:snowball" - }, - { - "id": "minecraft:shears" - }, - { - "id": "minecraft:flint_and_steel" - }, - { - "id": "minecraft:lead" - }, - { - "id": "minecraft:clock" - }, - { - "id": "minecraft:compass" - }, - { - "id": "minecraft:recovery_compass" - }, - { - "id": "minecraft:goat_horn" - }, - { - "id": "minecraft:goat_horn", - "damage": 1 - }, - { - "id": "minecraft:goat_horn", - "damage": 2 - }, - { - "id": "minecraft:goat_horn", - "damage": 3 - }, - { - "id": "minecraft:goat_horn", - "damage": 4 - }, - { - "id": "minecraft:goat_horn", - "damage": 5 - }, - { - "id": "minecraft:goat_horn", - "damage": 6 - }, - { - "id": "minecraft:goat_horn", - "damage": 7 - }, - { - "id": "minecraft:empty_map" - }, - { - "id": "minecraft:empty_map", - "damage": 2 - }, - { - "id": "minecraft:saddle" - }, - { - "id": "minecraft:leather_horse_armor" - }, - { - "id": "minecraft:iron_horse_armor" - }, - { - "id": "minecraft:golden_horse_armor" - }, - { - "id": "minecraft:diamond_horse_armor" - }, - { - "id": "minecraft:trident" - }, - { - "id": "minecraft:turtle_helmet" - }, - { - "id": "minecraft:elytra" - }, - { - "id": "minecraft:totem_of_undying" - }, - { - "id": "minecraft:glass_bottle" - }, - { - "id": "minecraft:experience_bottle" - }, - { - "id": "minecraft:potion" - }, - { - "id": "minecraft:potion", - "damage": 1 - }, - { - "id": "minecraft:potion", - "damage": 2 - }, - { - "id": "minecraft:potion", - "damage": 3 - }, - { - "id": "minecraft:potion", - "damage": 4 - }, - { - "id": "minecraft:potion", - "damage": 5 - }, - { - "id": "minecraft:potion", - "damage": 6 - }, - { - "id": "minecraft:potion", - "damage": 7 - }, - { - "id": "minecraft:potion", - "damage": 8 - }, - { - "id": "minecraft:potion", - "damage": 9 - }, - { - "id": "minecraft:potion", - "damage": 10 - }, - { - "id": "minecraft:potion", - "damage": 11 - }, - { - "id": "minecraft:potion", - "damage": 12 - }, - { - "id": "minecraft:potion", - "damage": 13 - }, - { - "id": "minecraft:potion", - "damage": 14 - }, - { - "id": "minecraft:potion", - "damage": 15 - }, - { - "id": "minecraft:potion", - "damage": 16 - }, - { - "id": "minecraft:potion", - "damage": 17 - }, - { - "id": "minecraft:potion", - "damage": 18 - }, - { - "id": "minecraft:potion", - "damage": 19 - }, - { - "id": "minecraft:potion", - "damage": 20 - }, - { - "id": "minecraft:potion", - "damage": 21 - }, - { - "id": "minecraft:potion", - "damage": 22 - }, - { - "id": "minecraft:potion", - "damage": 23 - }, - { - "id": "minecraft:potion", - "damage": 24 - }, - { - "id": "minecraft:potion", - "damage": 25 - }, - { - "id": "minecraft:potion", - "damage": 26 - }, - { - "id": "minecraft:potion", - "damage": 27 - }, - { - "id": "minecraft:potion", - "damage": 28 - }, - { - "id": "minecraft:potion", - "damage": 29 - }, - { - "id": "minecraft:potion", - "damage": 30 - }, - { - "id": "minecraft:potion", - "damage": 31 - }, - { - "id": "minecraft:potion", - "damage": 32 - }, - { - "id": "minecraft:potion", - "damage": 33 - }, - { - "id": "minecraft:potion", - "damage": 34 - }, - { - "id": "minecraft:potion", - "damage": 35 - }, - { - "id": "minecraft:potion", - "damage": 36 - }, - { - "id": "minecraft:potion", - "damage": 37 - }, - { - "id": "minecraft:potion", - "damage": 38 - }, - { - "id": "minecraft:potion", - "damage": 39 - }, - { - "id": "minecraft:potion", - "damage": 40 - }, - { - "id": "minecraft:potion", - "damage": 41 - }, - { - "id": "minecraft:potion", - "damage": 42 - }, - { - "id": "minecraft:splash_potion" - }, - { - "id": "minecraft:splash_potion", - "damage": 1 - }, - { - "id": "minecraft:splash_potion", - "damage": 2 - }, - { - "id": "minecraft:splash_potion", - "damage": 3 - }, - { - "id": "minecraft:splash_potion", - "damage": 4 - }, - { - "id": "minecraft:splash_potion", - "damage": 5 - }, - { - "id": "minecraft:splash_potion", - "damage": 6 - }, - { - "id": "minecraft:splash_potion", - "damage": 7 - }, - { - "id": "minecraft:splash_potion", - "damage": 8 - }, - { - "id": "minecraft:splash_potion", - "damage": 9 - }, - { - "id": "minecraft:splash_potion", - "damage": 10 - }, - { - "id": "minecraft:splash_potion", - "damage": 11 - }, - { - "id": "minecraft:splash_potion", - "damage": 12 - }, - { - "id": "minecraft:splash_potion", - "damage": 13 - }, - { - "id": "minecraft:splash_potion", - "damage": 14 - }, - { - "id": "minecraft:splash_potion", - "damage": 15 - }, - { - "id": "minecraft:splash_potion", - "damage": 16 - }, - { - "id": "minecraft:splash_potion", - "damage": 17 - }, - { - "id": "minecraft:splash_potion", - "damage": 18 - }, - { - "id": "minecraft:splash_potion", - "damage": 19 - }, - { - "id": "minecraft:splash_potion", - "damage": 20 - }, - { - "id": "minecraft:splash_potion", - "damage": 21 - }, - { - "id": "minecraft:splash_potion", - "damage": 22 - }, - { - "id": "minecraft:splash_potion", - "damage": 23 - }, - { - "id": "minecraft:splash_potion", - "damage": 24 - }, - { - "id": "minecraft:splash_potion", - "damage": 25 - }, - { - "id": "minecraft:splash_potion", - "damage": 26 - }, - { - "id": "minecraft:splash_potion", - "damage": 27 - }, - { - "id": "minecraft:splash_potion", - "damage": 28 - }, - { - "id": "minecraft:splash_potion", - "damage": 29 - }, - { - "id": "minecraft:splash_potion", - "damage": 30 - }, - { - "id": "minecraft:splash_potion", - "damage": 31 - }, - { - "id": "minecraft:splash_potion", - "damage": 32 - }, - { - "id": "minecraft:splash_potion", - "damage": 33 - }, - { - "id": "minecraft:splash_potion", - "damage": 34 - }, - { - "id": "minecraft:splash_potion", - "damage": 35 - }, - { - "id": "minecraft:splash_potion", - "damage": 36 - }, - { - "id": "minecraft:splash_potion", - "damage": 37 - }, - { - "id": "minecraft:splash_potion", - "damage": 38 - }, - { - "id": "minecraft:splash_potion", - "damage": 39 - }, - { - "id": "minecraft:splash_potion", - "damage": 40 - }, - { - "id": "minecraft:splash_potion", - "damage": 41 - }, - { - "id": "minecraft:splash_potion", - "damage": 42 - }, - { - "id": "minecraft:lingering_potion" - }, - { - "id": "minecraft:lingering_potion", - "damage": 1 - }, - { - "id": "minecraft:lingering_potion", - "damage": 2 - }, - { - "id": "minecraft:lingering_potion", - "damage": 3 - }, - { - "id": "minecraft:lingering_potion", - "damage": 4 - }, - { - "id": "minecraft:lingering_potion", - "damage": 5 - }, - { - "id": "minecraft:lingering_potion", - "damage": 6 - }, - { - "id": "minecraft:lingering_potion", - "damage": 7 - }, - { - "id": "minecraft:lingering_potion", - "damage": 8 - }, - { - "id": "minecraft:lingering_potion", - "damage": 9 - }, - { - "id": "minecraft:lingering_potion", - "damage": 10 - }, - { - "id": "minecraft:lingering_potion", - "damage": 11 - }, - { - "id": "minecraft:lingering_potion", - "damage": 12 - }, - { - "id": "minecraft:lingering_potion", - "damage": 13 - }, - { - "id": "minecraft:lingering_potion", - "damage": 14 - }, - { - "id": "minecraft:lingering_potion", - "damage": 15 - }, - { - "id": "minecraft:lingering_potion", - "damage": 16 - }, - { - "id": "minecraft:lingering_potion", - "damage": 17 - }, - { - "id": "minecraft:lingering_potion", - "damage": 18 - }, - { - "id": "minecraft:lingering_potion", - "damage": 19 - }, - { - "id": "minecraft:lingering_potion", - "damage": 20 - }, - { - "id": "minecraft:lingering_potion", - "damage": 21 - }, - { - "id": "minecraft:lingering_potion", - "damage": 22 - }, - { - "id": "minecraft:lingering_potion", - "damage": 23 - }, - { - "id": "minecraft:lingering_potion", - "damage": 24 - }, - { - "id": "minecraft:lingering_potion", - "damage": 25 - }, - { - "id": "minecraft:lingering_potion", - "damage": 26 - }, - { - "id": "minecraft:lingering_potion", - "damage": 27 - }, - { - "id": "minecraft:lingering_potion", - "damage": 28 - }, - { - "id": "minecraft:lingering_potion", - "damage": 29 - }, - { - "id": "minecraft:lingering_potion", - "damage": 30 - }, - { - "id": "minecraft:lingering_potion", - "damage": 31 - }, - { - "id": "minecraft:lingering_potion", - "damage": 32 - }, - { - "id": "minecraft:lingering_potion", - "damage": 33 - }, - { - "id": "minecraft:lingering_potion", - "damage": 34 - }, - { - "id": "minecraft:lingering_potion", - "damage": 35 - }, - { - "id": "minecraft:lingering_potion", - "damage": 36 - }, - { - "id": "minecraft:lingering_potion", - "damage": 37 - }, - { - "id": "minecraft:lingering_potion", - "damage": 38 - }, - { - "id": "minecraft:lingering_potion", - "damage": 39 - }, - { - "id": "minecraft:lingering_potion", - "damage": 40 - }, - { - "id": "minecraft:lingering_potion", - "damage": 41 - }, - { - "id": "minecraft:lingering_potion", - "damage": 42 - }, - { - "id": "minecraft:spyglass" - }, - { - "id": "minecraft:brush" - }, - { - "id": "minecraft:stick" - }, - { - "id": "minecraft:bed" - }, - { - "id": "minecraft:bed", - "damage": 8 - }, - { - "id": "minecraft:bed", - "damage": 7 - }, - { - "id": "minecraft:bed", - "damage": 15 - }, - { - "id": "minecraft:bed", - "damage": 12 - }, - { - "id": "minecraft:bed", - "damage": 14 - }, - { - "id": "minecraft:bed", - "damage": 1 - }, - { - "id": "minecraft:bed", - "damage": 4 - }, - { - "id": "minecraft:bed", - "damage": 5 - }, - { - "id": "minecraft:bed", - "damage": 13 - }, - { - "id": "minecraft:bed", - "damage": 9 - }, - { - "id": "minecraft:bed", - "damage": 3 - }, - { - "id": "minecraft:bed", - "damage": 11 - }, - { - "id": "minecraft:bed", - "damage": 10 - }, - { - "id": "minecraft:bed", - "damage": 2 - }, - { - "id": "minecraft:bed", - "damage": 6 - }, - { - "id": "minecraft:torch", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OnRvcmNoBAkAbmFtZV9oYXNoagn7rmDBzisDCgBuZXR3b3JrX2lk+BwwuQoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:soul_torch", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNvdWxfdG9yY2gECQBuYW1lX2hhc2huixOT04BRdQMKAG5ldHdvcmtfaWShbFILCgYAc3RhdGVzCBYAdG9yY2hfZmFjaW5nX2RpcmVjdGlvbgcAdW5rbm93bgADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sea_pickle", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnNlYV9waWNrbGUECQBuYW1lX2hhc2iONEfZJB+glgMKAG5ldHdvcmtfaWSINWQyCgYAc3RhdGVzAw0AY2x1c3Rlcl9jb3VudAAAAAABCABkZWFkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:lantern", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmxhbnRlcm4ECQBuYW1lX2hhc2hMw44VI2HWygMKAG5ldHdvcmtfaWRkjQvzCgYAc3RhdGVzAQcAaGFuZ2luZwAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:soul_lantern", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnNvdWxfbGFudGVybgQJAG5hbWVfaGFzaGjIpjxk9z+RAwoAbmV0d29ya19pZGfoP8cKBgBzdGF0ZXMBBwBoYW5naW5nAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:candle", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZHsBMA0KBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:white_candle", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhbmRsZQQJAG5hbWVfaGFzaN1EG5Q1mHiEAwoAbmV0d29ya19pZKN1mmgKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:orange_candle", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYW5kbGUECQBuYW1lX2hhc2jySEVWHgUIHQMKAG5ldHdvcmtfaWSfVz82CgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:magenta_candle", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FuZGxlBAkAbmFtZV9oYXNoG0u6YIOoBSEDCgBuZXR3b3JrX2lk9xGNkQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:light_blue_candle", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FuZGxlBAkAbmFtZV9oYXNocXGeK0zgrG0DCgBuZXR3b3JrX2lk2m1y8goGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:yellow_candle", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYW5kbGUECQBuYW1lX2hhc2i00dtusU3CqQMKAG5ldHdvcmtfaWR9LTmpCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:lime_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FuZGxlBAkAbmFtZV9oYXNokcmrw5xvz7ADCgBuZXR3b3JrX2lkIAUu6QoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:pink_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FuZGxlBAkAbmFtZV9oYXNoQJdEY4sZ0dwDCgBuZXR3b3JrX2lk23Rn5AoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:gray_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FuZGxlBAkAbmFtZV9oYXNoS5poSo9wBDEDCgBuZXR3b3JrX2lk3trRCAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:light_gray_candle", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FuZGxlBAkAbmFtZV9oYXNo9ruTZLBNMasDCgBuZXR3b3JrX2lkb6DOegoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cyan_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FuZGxlBAkAbmFtZV9oYXNoc/M8PNVcjOwDCgBuZXR3b3JrX2lkZoIQOQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:purple_candle", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYW5kbGUECQBuYW1lX2hhc2jaI3xUW0/myQMKAG5ldHdvcmtfaWSnLI2BCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:blue_candle", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FuZGxlBAkAbmFtZV9oYXNoAASSPW6TgQADCgBuZXR3b3JrX2lkrxrjQAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:brown_candle", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhbmRsZQQJAG5hbWVfaGFzaDia0l6s1+WYAwoAbmV0d29ya19pZKSkBXYKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:green_candle", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhbmRsZQQJAG5hbWVfaGFzaLeFPO1l+fIoAwoAbmV0d29ya19pZBkznDsKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:red_candle", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYW5kbGUECQBuYW1lX2hhc2jjAQpGf59ZdwMKAG5ldHdvcmtfaWRbb88GCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:black_candle", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhbmRsZQQJAG5hbWVfaGFzaB+wRDpOqREKAwoAbmV0d29ya19pZNnOnuEKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:crafting_table", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyYWZ0aW5nX3RhYmxlBAkAbmFtZV9oYXNoe76VAmjvbpYDCgBuZXR3b3JrX2lkwCxwaAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cartography_table", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmNhcnRvZ3JhcGh5X3RhYmxlBAkAbmFtZV9oYXNomaWiiD/znP8DCgBuZXR3b3JrX2lkI6FzMwoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:fletching_table", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmZsZXRjaGluZ190YWJsZQQJAG5hbWVfaGFzaPFibh8unKyUAwoAbmV0d29ya19pZJ2mW0oKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:smithing_table", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnNtaXRoaW5nX3RhYmxlBAkAbmFtZV9oYXNo4tFES2xOXEYDCgBuZXR3b3JrX2lkXWMBzQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:beehive", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmJlZWhpdmUECQBuYW1lX2hhc2hCcqn12UbNpwMKAG5ldHdvcmtfaWR/idcaCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAMLAGhvbmV5X2xldmVsAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:suspicious_sand", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnN1c3BpY2lvdXNfc2FuZAQJAG5hbWVfaGFzaL67QsuvLP00AwoAbmV0d29ya19pZKnkaIAKBgBzdGF0ZXMDEABicnVzaGVkX3Byb2dyZXNzAAAAAAEHAGhhbmdpbmcBAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:suspicious_gravel", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN1c3BpY2lvdXNfZ3JhdmVsBAkAbmFtZV9oYXNoJSVbGNk7C3oDCgBuZXR3b3JrX2lkvIEJAAoGAHN0YXRlcwMQAGJydXNoZWRfcHJvZ3Jlc3MAAAAAAQcAaGFuZ2luZwEAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:campfire" - }, - { - "id": "minecraft:soul_campfire" - }, - { - "id": "minecraft:furnace", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmZ1cm5hY2UECQBuYW1lX2hhc2ioOQrludYY8wMKAG5ldHdvcmtfaWRZxnDOCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:blast_furnace", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJsYXN0X2Z1cm5hY2UECQBuYW1lX2hhc2ivDbnjkpGm5QMKAG5ldHdvcmtfaWTcEbV/CgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:smoker", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnNtb2tlcgQJAG5hbWVfaGFzaJd1rDMkRWomAwoAbmV0d29ya19pZGWswMwKBgBzdGF0ZXMIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:respawn_anchor", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlc3Bhd25fYW5jaG9yBAkAbmFtZV9oYXNoZOdcjW05qigDCgBuZXR3b3JrX2lkmhMcaQoGAHN0YXRlcwMVAHJlc3Bhd25fYW5jaG9yX2NoYXJnZQAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:brewing_stand" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lk8Z3VowoGAHN0YXRlcwgGAGRhbWFnZQkAdW5kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkpiv8BAoGAHN0YXRlcwgGAGRhbWFnZRAAc2xpZ2h0bHlfZGFtYWdlZAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkFu+pdwoGAHN0YXRlcwgGAGRhbWFnZQwAdmVyeV9kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:grindstone", - "block_state_b64": "CgAACAQAbmFtZRQAbWluZWNyYWZ0OmdyaW5kc3RvbmUECQBuYW1lX2hhc2id56zc0nk99wMKAG5ldHdvcmtfaWS4Es07CgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:enchanting_table", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmVuY2hhbnRpbmdfdGFibGUECQBuYW1lX2hhc2jgIx24VLvMvwMKAG5ldHdvcmtfaWRliFFJCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bookshelf", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmJvb2tzaGVsZgQJAG5hbWVfaGFzaDU04DrgJCS9AwoAbmV0d29ya19pZBcWwIwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:chiseled_bookshelf", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2Jvb2tzaGVsZgQJAG5hbWVfaGFzaNXDBnsIsywYAwoAbmV0d29ya19pZIprt5IKBgBzdGF0ZXMDDABib29rc19zdG9yZWQAAAAAAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:lectern", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmxlY3Rlcm4ECQBuYW1lX2hhc2j5Z4Mmi/1QxAMKAG5ldHdvcmtfaWR4JfDHCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cauldron" - }, - { - "id": "minecraft:composter", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmNvbXBvc3RlcgQJAG5hbWVfaGFzaPAADHptzeWJAwoAbmV0d29ya19pZHIL6i4KBgBzdGF0ZXMDFABjb21wb3N0ZXJfZmlsbF9sZXZlbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:chest", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkDkOFvAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:trapped_chest", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnRyYXBwZWRfY2hlc3QECQBuYW1lX2hhc2g2qpF9stsEjgMKAG5ldHdvcmtfaWTjJWYxCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAbm9ydGgAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:ender_chest", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmVuZGVyX2NoZXN0BAkAbmFtZV9oYXNohEZzOFdg0WUDCgBuZXR3b3JrX2lkx4jiSQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:barrel", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmJhcnJlbAQJAG5hbWVfaGFzaHDkRPGymiRqAwoAbmV0d29ya19pZPnxzgsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:undyed_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZJ8rxp0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:white_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OndoaXRlX3NodWxrZXJfYm94BAkAbmFtZV9oYXNosK79m1rPUBwDCgBuZXR3b3JrX2lkjrET6goGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:light_gray_shulker_box", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iBe5zq7PxHmgMKAG5ldHdvcmtfaWSCVJv0CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:gray_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmdyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2ga2s8ctjHUhgMKAG5ldHdvcmtfaWS3WMsWCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:black_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoPm03OZphrp8DCgBuZXR3b3JrX2lkXHztNAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:brown_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmJyb3duX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoT3DD6qAL9cADCgBuZXR3b3JrX2lkaXxpYQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:red_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OnJlZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaMIlKSCzqSZoAwoAbmV0d29ya19pZNrf+icKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:orange_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0Om9yYW5nZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaG2MAXU67wGrAwoAbmV0d29ya19pZGoO05gKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:yellow_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnllbGxvd19zaHVsa2VyX2JveAQJAG5hbWVfaGFzaIsLwQHYjcIEAwoAbmV0d29ya19pZBCBSiYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:lime_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmxpbWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hUwBkg+faUGAMKAG5ldHdvcmtfaWRJeKqqCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:green_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmdyZWVuX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoZgUeT3LupLUDCgBuZXR3b3JrX2lkzJiohQoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:cyan_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmN5YW5fc2h1bGtlcl9ib3gECQBuYW1lX2hhc2gSfbjteXg5yAMKAG5ldHdvcmtfaWTHeliECgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:light_blue_shulker_box", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2h0VFCX0qsRxQMKAG5ldHdvcmtfaWQXD8U0CgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:blue_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmJsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hn9gS0XIe6rAMKAG5ldHdvcmtfaWTO4PJaCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:purple_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRwAbWluZWNyYWZ0OnB1cnBsZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaEV/lkNPxRDdAwoAbmV0d29ya19pZFK25GAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:magenta_shulker_box", - "block_state_b64": "CgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hZ2VudGFfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iqWM7IJHxcFgMKAG5ldHdvcmtfaWTyyudTCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:pink_shulker_box", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OnBpbmtfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2in1tkJ1GNcZgMKAG5ldHdvcmtfaWQOEGXjCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:armor_stand" - }, - { - "id": "minecraft:noteblock", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0Om5vdGVibG9jawQJAG5hbWVfaGFzaHPA8dBBH0UaAwoAbmV0d29ya19pZH1U5QkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:jukebox", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0Omp1a2Vib3gECQBuYW1lX2hhc2ieAIPExf/ZfgMKAG5ldHdvcmtfaWSmR7JfCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:music_disc_13" - }, - { - "id": "minecraft:music_disc_cat" - }, - { - "id": "minecraft:music_disc_blocks" - }, - { - "id": "minecraft:music_disc_chirp" - }, - { - "id": "minecraft:music_disc_far" - }, - { - "id": "minecraft:music_disc_mall" - }, - { - "id": "minecraft:music_disc_mellohi" - }, - { - "id": "minecraft:music_disc_stal" - }, - { - "id": "minecraft:music_disc_strad" - }, - { - "id": "minecraft:music_disc_ward" - }, - { - "id": "minecraft:music_disc_11" - }, - { - "id": "minecraft:music_disc_wait" - }, - { - "id": "minecraft:music_disc_otherside" - }, - { - "id": "minecraft:music_disc_5" - }, - { - "id": "minecraft:music_disc_pigstep" - }, - { - "id": "minecraft:music_disc_relic" - }, - { - "id": "minecraft:disc_fragment_5" - }, - { - "id": "minecraft:glowstone_dust" - }, - { - "id": "minecraft:glowstone", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0Omdsb3dzdG9uZQQJAG5hbWVfaGFzaFYqXNkefIlPAwoAbmV0d29ya19pZGT7WYYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:redstone_lamp", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZHN0b25lX2xhbXAECQBuYW1lX2hhc2hJ9V80caPvEgMKAG5ldHdvcmtfaWRvNPwnCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:sea_lantern", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OnNlYV9sYW50ZXJuBAkAbmFtZV9oYXNoLPsv1TX9M+QDCgBuZXR3b3JrX2lk1PPVyAoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:oak_sign" - }, - { - "id": "minecraft:spruce_sign" - }, - { - "id": "minecraft:birch_sign" - }, - { - "id": "minecraft:jungle_sign" - }, - { - "id": "minecraft:acacia_sign" - }, - { - "id": "minecraft:dark_oak_sign" - }, - { - "id": "minecraft:mangrove_sign" - }, - { - "id": "minecraft:cherry_sign" - }, - { - "id": "minecraft:bamboo_sign" - }, - { - "id": "minecraft:crimson_sign" - }, - { - "id": "minecraft:warped_sign" - }, - { - "id": "minecraft:oak_hanging_sign" - }, - { - "id": "minecraft:spruce_hanging_sign" - }, - { - "id": "minecraft:birch_hanging_sign" - }, - { - "id": "minecraft:jungle_hanging_sign" - }, - { - "id": "minecraft:acacia_hanging_sign" - }, - { - "id": "minecraft:dark_oak_hanging_sign" - }, - { - "id": "minecraft:mangrove_hanging_sign" - }, - { - "id": "minecraft:cherry_hanging_sign" - }, - { - "id": "minecraft:bamboo_hanging_sign" - }, - { - "id": "minecraft:crimson_hanging_sign" - }, - { - "id": "minecraft:warped_hanging_sign" - }, - { - "id": "minecraft:painting" - }, - { - "id": "minecraft:frame" - }, - { - "id": "minecraft:glow_frame" - }, - { - "id": "minecraft:honey_bottle" - }, - { - "id": "minecraft:flower_pot" - }, - { - "id": "minecraft:bowl" - }, - { - "id": "minecraft:bucket" - }, - { - "id": "minecraft:milk_bucket" - }, - { - "id": "minecraft:water_bucket" - }, - { - "id": "minecraft:lava_bucket" - }, - { - "id": "minecraft:cod_bucket" - }, - { - "id": "minecraft:salmon_bucket" - }, - { - "id": "minecraft:tropical_fish_bucket" - }, - { - "id": "minecraft:pufferfish_bucket" - }, - { - "id": "minecraft:powder_snow_bucket" - }, - { - "id": "minecraft:axolotl_bucket" - }, - { - "id": "minecraft:tadpole_bucket" - }, - { - "id": "minecraft:skull", - "damage": 3 - }, - { - "id": "minecraft:skull", - "damage": 2 - }, - { - "id": "minecraft:skull", - "damage": 4 - }, - { - "id": "minecraft:skull", - "damage": 5 - }, - { - "id": "minecraft:skull" - }, - { - "id": "minecraft:skull", - "damage": 1 - }, - { - "id": "minecraft:skull", - "damage": 6 - }, - { - "id": "minecraft:beacon", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OmJlYWNvbgQJAG5hbWVfaGFzaACwhhfSkdkHAwoAbmV0d29ya19pZF8jfiEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:bell", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OmJlbGwECQBuYW1lX2hhc2iPqsgDXRcsxAMKAG5ldHdvcmtfaWT7zhOoCgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAQoAdG9nZ2xlX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:conduit", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmNvbmR1aXQECQBuYW1lX2hhc2jqxKAxq2EaWQMKAG5ldHdvcmtfaWTWcBVnCgYAc3RhdGVzAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stonecutter_block", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lY3V0dGVyX2Jsb2NrBAkAbmFtZV9oYXNoQAXTbAM3MeYDCgBuZXR3b3JrX2lkWS4RjAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:end_portal_frame", - "block_state_b64": "CgAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9wb3J0YWxfZnJhbWUECQBuYW1lX2hhc2gqofyUIjGOpQMKAG5ldHdvcmtfaWRbGHf8CgYAc3RhdGVzARIAZW5kX3BvcnRhbF9leWVfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:coal" - }, - { - "id": "minecraft:charcoal" - }, - { - "id": "minecraft:diamond" - }, - { - "id": "minecraft:iron_nugget" - }, - { - "id": "minecraft:raw_iron" - }, - { - "id": "minecraft:raw_gold" - }, - { - "id": "minecraft:raw_copper" - }, - { - "id": "minecraft:copper_ingot" - }, - { - "id": "minecraft:iron_ingot" - }, - { - "id": "minecraft:netherite_scrap" - }, - { - "id": "minecraft:netherite_ingot" - }, - { - "id": "minecraft:gold_nugget" - }, - { - "id": "minecraft:gold_ingot" - }, - { - "id": "minecraft:emerald" - }, - { - "id": "minecraft:quartz" - }, - { - "id": "minecraft:clay_ball" - }, - { - "id": "minecraft:brick" - }, - { - "id": "minecraft:netherbrick" - }, - { - "id": "minecraft:prismarine_shard" - }, - { - "id": "minecraft:amethyst_shard" - }, - { - "id": "minecraft:prismarine_crystals" - }, - { - "id": "minecraft:nautilus_shell" - }, - { - "id": "minecraft:heart_of_the_sea" - }, - { - "id": "minecraft:scute" - }, - { - "id": "minecraft:phantom_membrane" - }, - { - "id": "minecraft:string" - }, - { - "id": "minecraft:feather" - }, - { - "id": "minecraft:flint" - }, - { - "id": "minecraft:gunpowder" - }, - { - "id": "minecraft:leather" - }, - { - "id": "minecraft:rabbit_hide" - }, - { - "id": "minecraft:rabbit_foot" - }, - { - "id": "minecraft:fire_charge" - }, - { - "id": "minecraft:blaze_rod" - }, - { - "id": "minecraft:blaze_powder" - }, - { - "id": "minecraft:magma_cream" - }, - { - "id": "minecraft:fermented_spider_eye" - }, - { - "id": "minecraft:echo_shard" - }, - { - "id": "minecraft:dragon_breath" - }, - { - "id": "minecraft:shulker_shell" - }, - { - "id": "minecraft:ghast_tear" - }, - { - "id": "minecraft:slime_ball" - }, - { - "id": "minecraft:ender_pearl" - }, - { - "id": "minecraft:ender_eye" - }, - { - "id": "minecraft:nether_star" - }, - { - "id": "minecraft:end_rod", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmVuZF9yb2QECQBuYW1lX2hhc2jx/q5cEA0hmQMKAG5ldHdvcmtfaWQ2eM8kCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:lightning_rod", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpZ2h0bmluZ19yb2QECQBuYW1lX2hhc2ioXQF1xvfHNQMKAG5ldHdvcmtfaWRLuHyACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:end_crystal" - }, - { - "id": "minecraft:paper" - }, - { - "id": "minecraft:book" - }, - { - "id": "minecraft:writable_book" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:oak_boat" - }, - { - "id": "minecraft:spruce_boat" - }, - { - "id": "minecraft:birch_boat" - }, - { - "id": "minecraft:jungle_boat" - }, - { - "id": "minecraft:acacia_boat" - }, - { - "id": "minecraft:dark_oak_boat" - }, - { - "id": "minecraft:mangrove_boat" - }, - { - "id": "minecraft:cherry_boat" - }, - { - "id": "minecraft:bamboo_raft" - }, - { - "id": "minecraft:oak_chest_boat" - }, - { - "id": "minecraft:spruce_chest_boat" - }, - { - "id": "minecraft:birch_chest_boat" - }, - { - "id": "minecraft:jungle_chest_boat" - }, - { - "id": "minecraft:acacia_chest_boat" - }, - { - "id": "minecraft:dark_oak_chest_boat" - }, - { - "id": "minecraft:mangrove_chest_boat" - }, - { - "id": "minecraft:cherry_chest_boat" - }, - { - "id": "minecraft:bamboo_chest_raft" - }, - { - "id": "minecraft:rail", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWR+Sp6YCgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:golden_rail", - "block_state_b64": "CgAACAQAbmFtZRUAbWluZWNyYWZ0OmdvbGRlbl9yYWlsBAkAbmFtZV9oYXNoOoV5MaKipoUDCgBuZXR3b3JrX2lkfAcxLwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:detector_rail", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmRldGVjdG9yX3JhaWwECQBuYW1lX2hhc2gVUk31qOysUQMKAG5ldHdvcmtfaWRVW/aICgYAc3RhdGVzAQ0AcmFpbF9kYXRhX2JpdAADDgByYWlsX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:activator_rail", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmFjdGl2YXRvcl9yYWlsBAkAbmFtZV9oYXNosIL91qriCRkDCgBuZXR3b3JrX2lkZfckmwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:minecart" - }, - { - "id": "minecraft:chest_minecart" - }, - { - "id": "minecraft:hopper_minecart" - }, - { - "id": "minecraft:tnt_minecart" - }, - { - "id": "minecraft:redstone" - }, - { - "id": "minecraft:redstone_block", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX2Jsb2NrBAkAbmFtZV9oYXNoRhULL0r8o0sDCgBuZXR3b3JrX2lklayOHgoGAHN0YXRlcwADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:redstone_torch", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX3RvcmNoBAkAbmFtZV9oYXNoizFRjpYMIDgDCgBuZXR3b3JrX2lkuHz7yAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:lever", - "block_state_b64": "CgAACAQAbmFtZQ8AbWluZWNyYWZ0OmxldmVyBAkAbmFtZV9oYXNoGMJeLJsUMLYDCgBuZXR3b3JrX2lkEF/GuAoGAHN0YXRlcwgPAGxldmVyX2RpcmVjdGlvbg4AZG93bl9lYXN0X3dlc3QBCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wooden_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWSU07kYCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:spruce_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9idXR0b24ECQBuYW1lX2hhc2jBW9Z8aYE7YQMKAG5ldHdvcmtfaWTkUIGuCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:birch_button", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2J1dHRvbgQJAG5hbWVfaGFzaJXYgGuSHbTwAwoAbmV0d29ya19pZGWp3yoKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:jungle_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9idXR0b24ECQBuYW1lX2hhc2iCgNANcJs+BQMKAG5ldHdvcmtfaWT9fImWCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:acacia_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9idXR0b24ECQBuYW1lX2hhc2gVvmcT7LTO0wMKAG5ldHdvcmtfaWRQnxIJCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dark_oak_button", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaIV10ZGGrCIEAwoAbmV0d29ya19pZN5vAmIKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:mangrove_button", - "block_state_b64": "CgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2J1dHRvbgQJAG5hbWVfaGFzaNzeYYKLgOzJAwoAbmV0d29ya19pZAFEGQ0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cherry_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9idXR0b24ECQBuYW1lX2hhc2j2/IHjeAbUcwMKAG5ldHdvcmtfaWRJ1irQCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bamboo_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19idXR0b24ECQBuYW1lX2hhc2j7AddMi+6nsgMKAG5ldHdvcmtfaWSa9w4/CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_button", - "block_state_b64": "CgAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2J1dHRvbgQJAG5hbWVfaGFzaM4ejMctmvohAwoAbmV0d29ya19pZMw+aC0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:crimson_button", - "block_state_b64": "CgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fYnV0dG9uBAkAbmFtZV9oYXNofnjYHaYIeWgDCgBuZXR3b3JrX2lk+n1vyQoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:warped_button", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9idXR0b24ECQBuYW1lX2hhc2jwkV2EU6Cn1QMKAG5ldHdvcmtfaWTnHnk1CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:polished_blackstone_button", - "block_state_b64": "CgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnV0dG9uBAkAbmFtZV9oYXNojmxzQKS0S/EDCgBuZXR3b3JrX2lkDtQ95woGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:tripwire_hook", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaXB3aXJlX2hvb2sECQBuYW1lX2hhc2gQdp+oGZLNnAMKAG5ldHdvcmtfaWSy+1KJCgYAc3RhdGVzAQwAYXR0YWNoZWRfYml0AAMJAGRpcmVjdGlvbgAAAAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:wooden_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZDRzPNwKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:spruce_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OnNwcnVjZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNmwuq549fJKAwoAbmV0d29ya19pZLQMCw0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:birch_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OmJpcmNoX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNorQkT9kDdlTwDCgBuZXR3b3JrX2lkH0G97AoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:jungle_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0Omp1bmdsZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaJ7DcteCkb8/AwoAbmV0d29ya19pZLdPBSAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:acacia_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmFjYWNpYV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaC2frZtfoYqCAwoAbmV0d29ya19pZIDdI18KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:dark_oak_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0OmRhcmtfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoHUCJsTy52pwDCgBuZXR3b3JrX2lkKpi8rAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:mangrove_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hbmdyb3ZlX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoiDsTfJaX100DCgBuZXR3b3JrX2lkuwWDyQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:cherry_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmNoZXJyeV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaALMqYEZDUQHAwoAbmV0d29ya19pZPNT+r0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:bamboo_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OmJhbWJvb19wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNvxJ7NIAaqlAwoAbmV0d29ya19pZIZ8XnYKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:crimson_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZSAAbWluZWNyYWZ0OmNyaW1zb25fcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2hqBDVDAd31/gMKAG5ldHdvcmtfaWRmV18LCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:warped_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR8AbWluZWNyYWZ0OndhcnBlZF9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaBxFoQksWtYUAwoAbmV0d29ya19pZJVRoIcKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:stone_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZR4AbWluZWNyYWZ0OnN0b25lX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNounJuTBUTrU8DCgBuZXR3b3JrX2lkjDydwQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:light_weighted_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoOyOJkNxLtkEDCgBuZXR3b3JrX2lkrr2AjgoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:heavy_weighted_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZScAbWluZWNyYWZ0OmhlYXZ5X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoltgDmDvTajUDCgBuZXR3b3JrX2lkFxVKuQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:polished_blackstone_pressure_plate", - "block_state_b64": "CgAACAQAbmFtZSwAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2h65Ci6/CeGqwMKAG5ldHdvcmtfaWTaSW5xCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:observer", - "block_state_b64": "CgAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2VydmVyBAkAbmFtZV9oYXNoYhlh1lpmHTgDCgBuZXR3b3JrX2lkQEh55goGAHN0YXRlcwgaAG1pbmVjcmFmdDpmYWNpbmdfZGlyZWN0aW9uBABkb3duAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:daylight_detector", - "block_state_b64": "CgAACAQAbmFtZRsAbWluZWNyYWZ0OmRheWxpZ2h0X2RldGVjdG9yBAkAbmFtZV9oYXNoV0F0s7B7PVgDCgBuZXR3b3JrX2lkri5afQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:repeater" - }, - { - "id": "minecraft:comparator" - }, - { - "id": "minecraft:hopper" - }, - { - "id": "minecraft:dropper", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmRyb3BwZXIECQBuYW1lX2hhc2joXP7XqU0l3QMKAG5ldHdvcmtfaWQfQN6zCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgMAAAABDQB0cmlnZ2VyZWRfYml0AAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:dispenser", - "block_state_b64": "CgAACAQAbmFtZRMAbWluZWNyYWZ0OmRpc3BlbnNlcgQJAG5hbWVfaGFzaP1RR+zAbYP2AwoAbmV0d29ya19pZGAayD0KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAwAAAAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:crafter", - "block_state_b64": "CgAACAQAbmFtZREAbWluZWNyYWZ0OmNyYWZ0ZXIECQBuYW1lX2hhc2iLCT/rJmRN8QMKAG5ldHdvcmtfaWTPTbvrCgYAc3RhdGVzAQgAY3JhZnRpbmcACAsAb3JpZW50YXRpb24JAGRvd25fZWFzdAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24BMhQBAA==" - }, - { - "id": "minecraft:piston", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnBpc3RvbgQJAG5hbWVfaGFzaDs3AFh1fL0uAwoAbmV0d29ya19pZLD/5XQKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAQAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:sticky_piston", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OnN0aWNreV9waXN0b24ECQBuYW1lX2hhc2hPFJFJSiJ0ZQMKAG5ldHdvcmtfaWT/MzCJCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgEAAAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:tnt", - "block_state_b64": "CgAACAQAbmFtZQ0AbWluZWNyYWZ0OnRudAQJAG5hbWVfaGFzaEYOHwCvJH29AwoAbmV0d29ya19pZCGfjU4KBgBzdGF0ZXMBFABhbGxvd191bmRlcndhdGVyX2JpdAABCwBleHBsb2RlX2JpdAAAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:name_tag" - }, - { - "id": "minecraft:loom", - "block_state_b64": "CgAACAQAbmFtZQ4AbWluZWNyYWZ0Omxvb20ECQBuYW1lX2hhc2i7DKjAXNq8TAMKAG5ldHdvcmtfaWR/49HXCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:banner" - }, - { - "id": "minecraft:banner", - "damage": 8 - }, - { - "id": "minecraft:banner", - "damage": 7 - }, - { - "id": "minecraft:banner", - "damage": 15 - }, - { - "id": "minecraft:banner", - "damage": 12 - }, - { - "id": "minecraft:banner", - "damage": 14 - }, - { - "id": "minecraft:banner", - "damage": 1 - }, - { - "id": "minecraft:banner", - "damage": 4 - }, - { - "id": "minecraft:banner", - "damage": 5 - }, - { - "id": "minecraft:banner", - "damage": 13 - }, - { - "id": "minecraft:banner", - "damage": 9 - }, - { - "id": "minecraft:banner", - "damage": 3 - }, - { - "id": "minecraft:banner", - "damage": 11 - }, - { - "id": "minecraft:banner", - "damage": 10 - }, - { - "id": "minecraft:banner", - "damage": 2 - }, - { - "id": "minecraft:banner", - "damage": 6 - }, - { - "id": "minecraft:banner", - "damage": 15, - "nbt_b64": "CgAAAwQAVHlwZQEAAAAA" - }, - { - "id": "minecraft:creeper_banner_pattern" - }, - { - "id": "minecraft:skull_banner_pattern" - }, - { - "id": "minecraft:flower_banner_pattern" - }, - { - "id": "minecraft:mojang_banner_pattern" - }, - { - "id": "minecraft:field_masoned_banner_pattern" - }, - { - "id": "minecraft:bordure_indented_banner_pattern" - }, - { - "id": "minecraft:piglin_banner_pattern" - }, - { - "id": "minecraft:globe_banner_pattern" - }, - { - "id": "minecraft:angler_pottery_sherd" - }, - { - "id": "minecraft:archer_pottery_sherd" - }, - { - "id": "minecraft:arms_up_pottery_sherd" - }, - { - "id": "minecraft:blade_pottery_sherd" - }, - { - "id": "minecraft:brewer_pottery_sherd" - }, - { - "id": "minecraft:burn_pottery_sherd" - }, - { - "id": "minecraft:danger_pottery_sherd" - }, - { - "id": "minecraft:explorer_pottery_sherd" - }, - { - "id": "minecraft:friend_pottery_sherd" - }, - { - "id": "minecraft:heart_pottery_sherd" - }, - { - "id": "minecraft:heartbreak_pottery_sherd" - }, - { - "id": "minecraft:howl_pottery_sherd" - }, - { - "id": "minecraft:miner_pottery_sherd" - }, - { - "id": "minecraft:mourner_pottery_sherd" - }, - { - "id": "minecraft:plenty_pottery_sherd" - }, - { - "id": "minecraft:prize_pottery_sherd" - }, - { - "id": "minecraft:sheaf_pottery_sherd" - }, - { - "id": "minecraft:shelter_pottery_sherd" - }, - { - "id": "minecraft:skull_pottery_sherd" - }, - { - "id": "minecraft:snort_pottery_sherd" - }, - { - "id": "minecraft:netherite_upgrade_smithing_template" - }, - { - "id": "minecraft:sentry_armor_trim_smithing_template" - }, - { - "id": "minecraft:vex_armor_trim_smithing_template" - }, - { - "id": "minecraft:wild_armor_trim_smithing_template" - }, - { - "id": "minecraft:coast_armor_trim_smithing_template" - }, - { - "id": "minecraft:dune_armor_trim_smithing_template" - }, - { - "id": "minecraft:wayfinder_armor_trim_smithing_template" - }, - { - "id": "minecraft:shaper_armor_trim_smithing_template" - }, - { - "id": "minecraft:raiser_armor_trim_smithing_template" - }, - { - "id": "minecraft:host_armor_trim_smithing_template" - }, - { - "id": "minecraft:ward_armor_trim_smithing_template" - }, - { - "id": "minecraft:silence_armor_trim_smithing_template" - }, - { - "id": "minecraft:tide_armor_trim_smithing_template" - }, - { - "id": "minecraft:snout_armor_trim_smithing_template" - }, - { - "id": "minecraft:rib_armor_trim_smithing_template" - }, - { - "id": "minecraft:eye_armor_trim_smithing_template" - }, - { - "id": "minecraft:spire_armor_trim_smithing_template" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_star", - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 8, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 7, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 15, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 12, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 14, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 1, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 4, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 5, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 13, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 9, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 3, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 11, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 10, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 2, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 6, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" - }, - { - "id": "minecraft:chain" - }, - { - "id": "minecraft:target", - "block_state_b64": "CgAACAQAbmFtZRAAbWluZWNyYWZ0OnRhcmdldAQJAG5hbWVfaGFzaJc66SVbYlaxAwoAbmV0d29ya19pZPBozs0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEyFAEA" - }, - { - "id": "minecraft:decorated_pot", - "block_state_b64": "CgAACAQAbmFtZRcAbWluZWNyYWZ0OmRlY29yYXRlZF9wb3QECQBuYW1lX2hhc2jjQgckn8VTvwMKAG5ldHdvcmtfaWRwvkUUCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATIUAQA=" - }, - { - "id": "minecraft:lodestone_compass" - }, - { - "id": "minecraft:wither_spawn_egg" - }, - { - "id": "minecraft:ender_dragon_spawn_egg" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/creative_items.1_20_60.json b/core/src/main/resources/bedrock/creative_items.1_20_60.json deleted file mode 100644 index d4063030e..000000000 --- a/core/src/main/resources/bedrock/creative_items.1_20_60.json +++ /dev/null @@ -1,5787 +0,0 @@ -{ - "items": [ - { - "id": "minecraft:oak_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19wbGFua3MECQBuYW1lX2hhc2ilMDLR92rQ4wMKAG5ldHdvcmtfaWS2MwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:spruce_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAwAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9wbGFua3MECQBuYW1lX2hhc2iumBkmFGFE8gMKAG5ldHdvcmtfaWQZNQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:birch_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3BsYW5rcwQJAG5hbWVfaGFzaLrrAKJqV2WFAwoAbmV0d29ya19pZJQjAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:jungle_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAwAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9wbGFua3MECQBuYW1lX2hhc2iBM3k4T3FAugMKAG5ldHdvcmtfaWQwLgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:acacia_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAwAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9wbGFua3MECQBuYW1lX2hhc2g60edJxO5/aAMKAG5ldHdvcmtfaWSDHAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dark_oak_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3BsYW5rcwQJAG5hbWVfaGFzaAr64wkQ9cA7AwoAbmV0d29ya19pZDMXAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:mangrove_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3BsYW5rcwQJAG5hbWVfaGFzaPvLtcEA0F8xAwoAbmV0d29ya19pZGgJAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cherry_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9wbGFua3MECQBuYW1lX2hhc2hNIvVh/lVW7gMKAG5ldHdvcmtfaWSVNAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bamboo_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19wbGFua3MECQBuYW1lX2hhc2gYnjNz7SCCjgMKAG5ldHdvcmtfaWTbJAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bamboo_mosaic", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWMECQBuYW1lX2hhc2izSEgiMKOp/AMKAG5ldHdvcmtfaWT0NgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:crimson_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fcGxhbmtzBAkAbmFtZV9oYXNoJc5IKqNXJnwDCgBuZXR3b3JrX2lkmyEAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:warped_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9wbGFua3MECQBuYW1lX2hhc2g3yGXEWhe6LgMKAG5ldHdvcmtfaWRLCQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRFCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBjb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRGCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9jb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRHCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBncmFuaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRICgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBkaW9yaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRJCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCABhbmRlc2l0ZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRKCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBzYW5kc3RvbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRRCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDQByZWRfc2FuZHN0b25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRMCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBzdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRNCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9zdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRLCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBQBicmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWROCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDABuZXRoZXJfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRSCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEAByZWRfbmV0aGVyX2JyaWNrCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRPCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBlbmRfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRQCgAACgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCgBwcmlzbWFyaW5lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:blackstone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaMP8XppUSU1RAwoAbmV0d29ya19pZDsaAAAKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_blackstone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaP6SwV08YwzAAwoAbmV0d29ya19pZJsuAAAKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_blackstone_brick_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBBIDZbHxiEzAwoAbmV0d29ya19pZHYJAAAKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3dhbGwECQBuYW1lX2hhc2iECY5oKxeT+gMKAG5ldHdvcmtfaWQwNgAACgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:deepslate_tile_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3dhbGwECQBuYW1lX2hhc2jz7N+PeuEXgQMKAG5ldHdvcmtfaWSNIgAACgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:polished_deepslate_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV93YWxsBAkAbmFtZV9oYXNoHxjTdj9pevMDCgBuZXR3b3JrX2lkKDUAAAoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:deepslate_brick_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja193YWxsBAkAbmFtZV9oYXNoEs3EQrjroyEDCgBuZXR3b3JrX2lkoQQAAAoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:mud_brick_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja193YWxsBAkAbmFtZV9oYXNov9b98ATpUSwDCgBuZXR3b3JrX2lkfQgAAAoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:oak_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAAAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZF0lAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:spruce_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAwAACAQAbmFtZRYAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZQQJAG5hbWVfaGFzaPQCm+aX1ZQeAwoAbmV0d29ya19pZHcEAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:birch_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AwAACAQAbmFtZRUAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlBAkAbmFtZV9oYXNo6CJ2ATpANfgDCgBuZXR3b3JrX2lkIzYAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:jungle_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAwAACAQAbmFtZRYAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZQQJAG5hbWVfaGFzaOX4cD9uAmsdAwoAbmV0d29ya19pZHAEAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:acacia_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AwAACAQAbmFtZRYAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZQQJAG5hbWVfaGFzaGjn+RlKVDH6AwoAbmV0d29ya19pZC42AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:dark_oak_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAwAACAQAbmFtZRgAbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlBAkAbmFtZV9oYXNoGPj0gCgM0c0DCgBuZXR3b3JrX2lkNTAAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:mangrove_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlBAkAbmFtZV9oYXNowwAd7tPu9bsDCgBuZXR3b3JrX2lkQi4AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cherry_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAwAACAQAbmFtZRYAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZQQJAG5hbWVfaGFzaFmtUfHfTxcxAwoAbmV0d29ya19pZGcJAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:bamboo_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19mZW5jZQQJAG5hbWVfaGFzaCKRbxfXsfkiAwoAbmV0d29ya19pZF0FAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:nether_brick_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAAAACAQAbmFtZRwAbWluZWNyYWZ0Om5ldGhlcl9icmlja19mZW5jZQQJAG5hbWVfaGFzaA6030ngawxcAwoAbmV0d29ya19pZLUbAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:crimson_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2UECQBuYW1lX2hhc2jhUhKv1HGj9AMKAG5ldHdvcmtfaWTcNQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:warped_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9mZW5jZQQJAG5hbWVfaGFzaJfb3/YuKmOWAwoAbmV0d29ya19pZG0nAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAAAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWRVAAAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:spruce_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AAAACAQAbmFtZRsAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoanTVB84HRbkDCgBuZXR3b3JrX2lkEC4AAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:birch_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2jmfPklI8azSwMKAG5ldHdvcmtfaWQkGAAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:jungle_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS5AAAACAQAbmFtZRsAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNobYVQkfBomIcDCgBuZXR3b3JrX2lkuCMAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:acacia_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS7AAAACAQAbmFtZRsAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoZnrLUx/XSekDCgBuZXR3b3JrX2lk5jMAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:dark_oak_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS6AAAACAQAbmFtZR0AbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2j2PTvdJJHcVQMKAG5ldHdvcmtfaWQxGwAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:mangrove_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2i/kOhBKiI/dAMKAG5ldHdvcmtfaWReHQAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cherry_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAwAACAQAbmFtZRsAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoKWLgCk0z+PsDCgBuZXR3b3JrX2lk3TYAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:bamboo_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJhbWJvb19mZW5jZV9nYXRlBAkAbmFtZV9oYXNopH1JrUgwdIADCgBuZXR3b3JrX2lkdCIAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:crimson_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2VfZ2F0ZQQJAG5hbWVfaGFzaHE3Gfd0Z2d2AwoAbmV0d29ya19pZCIfAAAKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQsAaW5fd2FsbF9iaXQAAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:warped_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoy0oIBjDIG4kDCgBuZXR3b3JrX2lk3iMAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:normal_stone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAQAACAQAbmFtZR0AbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hAEktZZOkGIwMKAG5ldHdvcmtfaWReBQAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZNQXAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:mossy_cobblestone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSyAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3N0YWlycwQJAG5hbWVfaGFzaMVSTq5z9n1RAwoAbmV0d29ya19pZN0aAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:oak_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19zdGFpcnMECQBuYW1lX2hhc2jk/HFzdXy0FQMKAG5ldHdvcmtfaWTSAgAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:spruce_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9zdGFpcnMECQBuYW1lX2hhc2iznygw7uBPBQMKAG5ldHdvcmtfaWSMAAAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:birch_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3N0YWlycwQJAG5hbWVfaGFzaPfhbL619a3GAwoAbmV0d29ya19pZL8vAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:jungle_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9zdGFpcnMECQBuYW1lX2hhc2jodJsHUbOVxQMKAG5ldHdvcmtfaWSYLwAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:acacia_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9zdGFpcnMECQBuYW1lX2hhc2h3x1NmD43IqQMKAG5ldHdvcmtfaWRULAAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dark_oak_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3N0YWlycwQJAG5hbWVfaGFzaMfwkbYPbNmAAwoAbmV0d29ya19pZIUiAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:mangrove_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3N0YWlycwQJAG5hbWVfaGFzaNpUDY+uGMpyAwoAbmV0d29ya19pZDQdAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cherry_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9zdGFpcnMECQBuYW1lX2hhc2jMtr0v9JY4zwMKAG5ldHdvcmtfaWRkMAAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bamboo_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19zdGFpcnMECQBuYW1lX2hhc2jFOzWL8PalKwMKAG5ldHdvcmtfaWRvCAAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bamboo_mosaic_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc3RhaXJzBAkAbmFtZV9oYXNoNLPiveSHPaoDCgBuZXR3b3JrX2lkXCwAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAAAACAQAbmFtZRwAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaN6tQViRo5cwAwoAbmV0d29ya19pZFcJAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:mossy_stone_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaIB/Zv5YBPuYAwoAbmV0d29ya19pZCwpAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:sandstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAAAACAQAbmFtZRoAbWluZWNyYWZ0OnNhbmRzdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hOyA0BoYUOPQMKAG5ldHdvcmtfaWRUFwAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:smooth_sandstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSwAQAACAQAbmFtZSEAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoB+CuCd8Ruz8DCgBuZXR3b3JrX2lkghcAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_sandstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS0AAAACAQAbmFtZR4AbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoPs0LpHPL24YDCgBuZXR3b3JrX2lkqSMAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:smooth_red_sandstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAQAACAQAbmFtZSUAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3N0YWlycwQJAG5hbWVfaGFzaBvjtQv5pf+MAwoAbmV0d29ya19pZJIkAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:granite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAQAACAQAbmFtZRgAbWluZWNyYWZ0OmdyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNoGzpvtoqKQjgDCgBuZXR3b3JrX2lkjxUAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_granite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNo3PvbSfEQklIDCgBuZXR3b3JrX2lkGRsAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:diorite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAQAACAQAbmFtZRgAbWluZWNyYWZ0OmRpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoi73T8VQuZmcDCgBuZXR3b3JrX2lkShwAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_diorite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoFKRJd5Wk5L0DCgBuZXR3b3JrX2lkii4AAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:andesite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaO5w2FKBw76EAwoAbmV0d29ya19pZIwjAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:polished_andesite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWStAQAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaNcZZ/zmLInIAwoAbmV0d29ya19pZNsvAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJyaWNrX3N0YWlycwQJAG5hbWVfaGFzaMyt+cRDk5O2AwoAbmV0d29ya19pZMgtAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:nether_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAAAACAQAbmFtZR0AbWluZWNyYWZ0Om5ldGhlcl9icmlja19zdGFpcnMECQBuYW1lX2hhc2jRqIoOXgifBAMKAG5ldHdvcmtfaWRzAAAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_nether_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AQAACAQAbmFtZSEAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNogQvosSbcj7kDCgBuZXR3b3JrX2lkIi4AAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:end_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSxAQAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2hmlAk+QhsUsQMKAG5ldHdvcmtfaWQKLQAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:quartz_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWScAAAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9zdGFpcnMECQBuYW1lX2hhc2hmvpvOqGi6egMKAG5ldHdvcmtfaWTEHwAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:smooth_quartz_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AQAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc3RhaXJzBAkAbmFtZV9oYXNoNZZ9rX0qZOsDCgBuZXR3b3JrX2lkWDQAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:purpur_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAAAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9zdGFpcnMECQBuYW1lX2hhc2ifwDxeezXD7gMKAG5ldHdvcmtfaWSZNAAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:prismarine_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAQAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfc3RhaXJzBAkAbmFtZV9oYXNooTHSZ+IrYtcDCgBuZXR3b3JrX2lkkTIAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:dark_prismarine_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAQAACAQAbmFtZSAAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zdGFpcnMECQBuYW1lX2hhc2hIciLmam4o4AMKAG5ldHdvcmtfaWRBMwAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:prismarine_bricks_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAQAACAQAbmFtZSIAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzX3N0YWlycwQJAG5hbWVfaGFzaNIjq1oBlZMMAwoAbmV0d29ya19pZHECAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:crimson_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fc3RhaXJzBAkAbmFtZV9oYXNoZJqIzCBpCq4DCgBuZXR3b3JrX2lknywAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:warped_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9zdGFpcnMECQBuYW1lX2hhc2hOkY27jLD4RQMKAG5ldHdvcmtfaWThFwAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:blackstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNokdoUb76p9McDCgBuZXR3b3JrX2lk0C8AAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_blackstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNolCFtFIE8MmADCgBuZXR3b3JrX2lk3hsAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_blackstone_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAgAACAQAbmFtZSoAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNonks6UlfpOmkDCgBuZXR3b3JrX2lkphwAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAgAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoHfoAXYq5G3MDCgBuZXR3b3JrX2lkPR0AAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:exposed_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAgAACAQAbmFtZSMAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2howneQGtZ9cgMKAG5ldHdvcmtfaWQsHQAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:weathered_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAgAACAQAbmFtZSUAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaP+R5loXxrVgAwoAbmV0d29ya19pZOYbAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:oxidized_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAgAACAQAbmFtZSQAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNo6Jeoq5rsPxsDCgBuZXR3b3JrX2lkSgQAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:waxed_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAgAACAQAbmFtZSEAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoh07CQj0/SR8DCgBuZXR3b3JrX2lkegQAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:waxed_exposed_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2guVct1ilmxTwMKAG5ldHdvcmtfaWQeGgAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:waxed_weathered_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAgAACAQAbmFtZSsAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaPXC8Sz/phCpAwoAbmV0d29ya19pZEMsAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS/AgAACAQAbmFtZSoAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoaqGdkuhxVZUDCgBuZXR3b3JrX2lkQCcAAAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AgAACAQAbmFtZSIAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3N0YWlycwQJAG5hbWVfaGFzaPIfa+TpyJcIAwoAbmV0d29ya19pZDUCAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:deepslate_tile_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3N0YWlycwQJAG5hbWVfaGFzaGFRFzB72mN2AwoAbmV0d29ya19pZBofAAAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:polished_deepslate_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAgAACAQAbmFtZSMAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zdGFpcnMECQBuYW1lX2hhc2iNCYxVik9sGAMKAG5ldHdvcmtfaWQNBAAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:deepslate_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zdGFpcnMECQBuYW1lX2hhc2hIasOahEf83wMKAG5ldHdvcmtfaWQ5MwAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:mud_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAgAACAQAbmFtZRoAbWluZWNyYWZ0Om11ZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2gt3qxK1NWajAMKAG5ldHdvcmtfaWR6JAAACgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:wooden_door" - }, - { - "id": "minecraft:spruce_door" - }, - { - "id": "minecraft:birch_door" - }, - { - "id": "minecraft:jungle_door" - }, - { - "id": "minecraft:acacia_door" - }, - { - "id": "minecraft:dark_oak_door" - }, - { - "id": "minecraft:mangrove_door" - }, - { - "id": "minecraft:cherry_door" - }, - { - "id": "minecraft:bamboo_door" - }, - { - "id": "minecraft:iron_door" - }, - { - "id": "minecraft:crimson_door" - }, - { - "id": "minecraft:warped_door" - }, - { - "id": "minecraft:trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAAAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkkQIAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:spruce_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAQAACAQAbmFtZRkAbWluZWNyYWZ0OnNwcnVjZV90cmFwZG9vcgQJAG5hbWVfaGFzaOwlfbgBkUW4AwoAbmV0d29ya19pZO8tAAAKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:birch_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAQAACAQAbmFtZRgAbWluZWNyYWZ0OmJpcmNoX3RyYXBkb29yBAkAbmFtZV9oYXNoSLtLweOLJ7wDCgBuZXR3b3JrX2lkVC4AAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:jungle_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAQAACAQAbmFtZRkAbWluZWNyYWZ0Omp1bmdsZV90cmFwZG9vcgQJAG5hbWVfaGFzaDP/TnM9wyCIAwoAbmV0d29ya19pZMsjAAAKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:acacia_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFjYWNpYV90cmFwZG9vcgQJAG5hbWVfaGFzaMj8xi3vmEKOAwoAbmV0d29ya19pZLskAAAKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:dark_oak_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAQAACAQAbmFtZRsAbWluZWNyYWZ0OmRhcmtfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNomB2GGJQ2aOMDCgBuZXR3b3JrX2lkizMAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:mangrove_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAgAACAQAbmFtZRsAbWluZWNyYWZ0Om1hbmdyb3ZlX3RyYXBkb29yBAkAbmFtZV9oYXNooV3kQsQUUmkDCgBuZXR3b3JrX2lkrhwAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cherry_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoZXJyeV90cmFwZG9vcgQJAG5hbWVfaGFzaH/PefpfdHgtAwoAbmV0d29ya19pZDEJAAAKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:bamboo_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJhbWJvb190cmFwZG9vcgQJAG5hbWVfaGFzaJrEOpsTwtKCAwoAbmV0d29ya19pZE4jAAAKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:iron_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAAAACAQAbmFtZRcAbWluZWNyYWZ0Omlyb25fdHJhcGRvb3IECQBuYW1lX2hhc2gwA+IumsEiGQMKAG5ldHdvcmtfaWQqBAAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:crimson_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AQAACAQAbmFtZRoAbWluZWNyYWZ0OmNyaW1zb25fdHJhcGRvb3IECQBuYW1lX2hhc2jHXufTnwUkYgMKAG5ldHdvcmtfaWQHHAAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:warped_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AQAACAQAbmFtZRkAbWluZWNyYWZ0OndhcnBlZF90cmFwZG9vcgQJAG5hbWVfaGFzaA20wG/+vkd6AwoAbmV0d29ya19pZJIfAAAKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:iron_bars", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAAAACAQAbmFtZRMAbWluZWNyYWZ0Omlyb25fYmFycwQJAG5hbWVfaGFzaPuefWSNAe56AwoAbmV0d29ya19pZOcfAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lkQCwAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:white_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAAAACAQAbmFtZR0AbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iHubqoMbu9fAMKAG5ldHdvcmtfaWSdIQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:light_gray_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaKKa+LrRsHQhAwoAbmV0d29ya19pZJ4EAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:gray_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAwAACAQAbmFtZRwAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaIETy7Y/HZREAwoAbmV0d29ya19pZN0XAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:black_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iV6BCwpfDMmwMKAG5ldHdvcmtfaWRZKQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:brown_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2igsEiq5np8JgMKAG5ldHdvcmtfaWTxBgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWStAwAACAQAbmFtZRsAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoCa2J12/lQoIDCgBuZXR3b3JrX2lkPSMAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:orange_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAwAACAQAbmFtZR4AbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNozgjAuvzhxGsDCgBuZXR3b3JrX2lk8RwAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:yellow_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAwAACAQAbmFtZR4AbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNo7EbHMd5WVugDCgBuZXR3b3JrX2lk5DMAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:lime_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAwAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBtZA1nZtwcFAwoAbmV0d29ya19pZH4AAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:green_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAwAACAQAbmFtZR0AbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2h91ptDgbehWwMKAG5ldHdvcmtfaWS0GwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cyan_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAwAACAQAbmFtZRwAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBkIYQ8nQLqbAwoAbmV0d29ya19pZFgpAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:light_blue_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaLt05n1G0fiSAwoAbmV0d29ya19pZIYlAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:blue_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaPhLocSfzduRAwoAbmV0d29ya19pZGIlAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:purple_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAwAACAQAbmFtZR4AbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoJk0DhRO0szUDCgBuZXR3b3JrX2lkPQoAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:magenta_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAwAACAQAbmFtZR8AbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaFEDeFiJj3zSAwoAbmV0d29ya19pZGgyAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:pink_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaDijTX87ywxhAwoAbmV0d29ya19pZPYbAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:tinted_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAgAACAQAbmFtZRYAbWluZWNyYWZ0OnRpbnRlZF9nbGFzcwQJAG5hbWVfaGFzaAFZWSamk6KdAwoAbmV0d29ya19pZNkpAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWQvIwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:white_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAAAACAQAbmFtZSIAbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaHgxQmgJVtRrAwoAbmV0d29ya19pZPIcAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:light_gray_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNon0aQw9lNkSEDCgBuZXR3b3JrX2lkoAQAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:gray_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAwAACAQAbmFtZSEAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNors74IIw+2MMDCgBuZXR3b3JrX2lkTi8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:black_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaOK/5ZRRd+M1AwoAbmV0d29ya19pZEQKAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:brown_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaLHeGJyRFTIWAwoAbmV0d29ya19pZN4CAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAwAACAQAbmFtZSAAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2gGr4x6JheAywMKAG5ldHdvcmtfaWQtMAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:orange_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAwAACAQAbmFtZSMAbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hbHxPD2gEbEAMKAG5ldHdvcmtfaWSIAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:yellow_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAwAACAQAbmFtZSMAbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2g9tl4aOCyZBwMKAG5ldHdvcmtfaWQxAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:lime_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAwAACAQAbmFtZSEAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3CtUyLwoGegDCgBuZXR3b3JrX2lk4jMAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:green_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAwAACAQAbmFtZSIAbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaJo6YP7IMy9SAwoAbmV0d29ya19pZBgbAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cyan_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAwAACAQAbmFtZSEAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoti97c6QrbLQDCgBuZXR3b3JrX2lkmy0AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:light_blue_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNovDg/gQle104DCgBuZXR3b3JrX2lkDBoAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:blue_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAwAACAQAbmFtZSEAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoGc57tiexbQMDCgBuZXR3b3JrX2lkVAAAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:purple_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAwAACAQAbmFtZSMAbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hDJHYdd0FdfQMKAG5ldHdvcmtfaWSeIQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:magenta_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAwAACAQAbmFtZSQAbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3pcOw5bs5XoDCgBuZXR3b3JrX2lk5h8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:pink_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAwAACAQAbmFtZSEAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoWRhSACMWgswDCgBuZXR3b3JrX2lkMjAAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:ladder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxhZGRlcgQJAG5hbWVfaGFzaKBhqheJVOz+AwoAbmV0d29ya19pZPo2AAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:scaffolding", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNjYWZmb2xkaW5nBAkAbmFtZV9oYXNoYrkevrqcljwDCgBuZXR3b3JrX2lkRBcAAAoGAHN0YXRlcwMJAHN0YWJpbGl0eQAAAAABDwBzdGFiaWxpdHlfY2hlY2sAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSeGwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAc21vb3RoX3N0b25lAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkqSUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNAUAc3RvbmUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWShGwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAY29iYmxlc3RvbmUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkjCUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhEAbW9zc3lfY29iYmxlc3RvbmUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkZiMAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUDAG9hawADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkZyMAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAHNwcnVjZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkaCMAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUFAGJpcmNoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkaSMAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAGp1bmdsZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkaiMAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUGAGFjYWNpYQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:wooden_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRUAbWluZWNyYWZ0Ondvb2Rlbl9zbGFiBAkAbmFtZV9oYXNoBVBkRBCCh4MDCgBuZXR3b3JrX2lkayMAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20ICQB3b29kX3R5cGUIAGRhcmtfb2FrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:mangrove_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWToAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3NsYWIECQBuYW1lX2hhc2jYCcmhJPeNMwMKAG5ldHdvcmtfaWQYCgAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cherry_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV9zbGFiBAkAbmFtZV9oYXNoTt0MmVn/mqoDCgBuZXR3b3JrX2lkZSwAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:bamboo_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJhbWJvb19zbGFiBAkAbmFtZV9oYXNoo1xuFqINeLYDCgBuZXR3b3JrX2lkxS0AAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:bamboo_mosaic_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc2xhYgQJAG5hbWVfaGFzaNbVRBZ/ChI3AwoAbmV0d29ya19pZCkTAAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSjGwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkpyUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAbW9zc3lfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSfGwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQkAc2FuZHN0b25lAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkqiUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0AY3V0X3NhbmRzdG9uZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkjSUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAc21vb3RoX3NhbmRzdG9uZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkhyUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg0AcmVkX3NhbmRzdG9uZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkqyUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAY3V0X3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkmCUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxQAc21vb3RoX3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lknSUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZ3Jhbml0ZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkniUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZ3Jhbml0ZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkmyUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZGlvcml0ZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lknCUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZGlvcml0ZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkmiUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwgAYW5kZXNpdGUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkmSUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxEAcG9saXNoZWRfYW5kZXNpdGUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSiGwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQUAYnJpY2sAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSlGwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAbmV0aGVyX2JyaWNrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkjiUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcmVkX25ldGhlcl9icmljawADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lklyUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMw8AZW5kX3N0b25lX2JyaWNrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSkGwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQYAcXVhcnR6AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkqCUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0Ac21vb3RoX3F1YXJ0egADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkiCUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMgYAcHVycHVyAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkiSUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9yb3VnaAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkiiUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg8AcHJpc21hcmluZV9kYXJrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkiyUAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9icmljawADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:crimson_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc2xhYgQJAG5hbWVfaGFzaKZ+EfP0ZYOZAwoAbmV0d29ya19pZEApAAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:warped_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zbGFiBAkAbmFtZV9oYXNo/AT0e/Z9W7UDCgBuZXR3b3JrX2lkoC0AAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:blackstone_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaF/DD4ZUlNgtAwoAbmV0d29ya19pZEEJAAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:polished_blackstone_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaDYnuUs86EWfAwoAbmV0d29ya19pZIUrAAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:polished_blackstone_brick_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaKySLqvHc4xXAwoAbmV0d29ya19pZEsbAAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAgAACAQAbmFtZRkAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaDsNpb2qs4iBAwoAbmV0d29ya19pZDEjAAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:exposed_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNoahQ5OwIQb7kDCgBuZXR3b3JrX2lkIC4AAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:weathered_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2hBIuGIOVVXogMKAG5ldHdvcmtfaWS0KwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:oxidized_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaOptj9ycfpaDAwoAbmV0d29ya19pZHIjAAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:waxed_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaAlx6DZOCTHzAwoAbmV0d29ya19pZCY1AAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:waxed_exposed_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNo3KqS5OnhtRIDCgBuZXR3b3JrX2lkpQIAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:waxed_weathered_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2gzZ1oX0HCFtwMKAG5ldHdvcmtfaWToLQAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTAAgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaMjjTnLu1KcqAwoAbmV0d29ya19pZL0HAAAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cobbled_deepslate_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3NsYWIECQBuYW1lX2hhc2gwJIVWK1TM2QMKAG5ldHdvcmtfaWTLMgAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_deepslate_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zbGFiBAkAbmFtZV9oYXNoC/Adiz8k6RYDCgBuZXR3b3JrX2lk5wIAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:deepslate_tile_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3NsYWIECQBuYW1lX2hhc2hPydV6emzIXAMKAG5ldHdvcmtfaWS2GwAACgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:deepslate_brick_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zbGFiBAkAbmFtZV9oYXNoSv62V7iw10UDCgBuZXR3b3JrX2lk3xcAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:mud_brick_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja19zbGFiBAkAbmFtZV9oYXNoq/tGBQWkv08DCgBuZXR3b3JrX2lkJxoAAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:brick_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAAAACAQAbmFtZRUAbWluZWNyYWZ0OmJyaWNrX2Jsb2NrBAkAbmFtZV9oYXNo5Qc2E005S3oDCgBuZXR3b3JrX2lksh8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:chiseled_nether_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX25ldGhlcl9icmlja3MECQBuYW1lX2hhc2g31SBPTcUK1QMKAG5ldHdvcmtfaWR7MgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cracked_nether_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAgAACAQAbmFtZR8AbWluZWNyYWZ0OmNyYWNrZWRfbmV0aGVyX2JyaWNrcwQJAG5hbWVfaGFzaAdC6eKzXT5tAwoAbmV0d29ya19pZPMcAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:quartz_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9icmlja3MECQBuYW1lX2hhc2jSZO590dd8sAMKAG5ldHdvcmtfaWTrLAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTqLQAACgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAZGVmYXVsdAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTrLQAACgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQUAbW9zc3kAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTsLQAACgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAY3JhY2tlZAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stonebrick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTtLQAACgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQgAY2hpc2VsZWQAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:end_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAAAACAQAbmFtZRQAbWluZWNyYWZ0OmVuZF9icmlja3MECQBuYW1lX2hhc2hIUFfxNLZaFgMKAG5ldHdvcmtfaWTfAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWThKwAACgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBgBicmlja3MAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:polished_blackstone_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoIHgsgIdzKXcDCgBuZXR3b3JrX2lkNR8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cracked_polished_blackstone_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAgAACAQAbmFtZSwAbWluZWNyYWZ0OmNyYWNrZWRfcG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3MECQBuYW1lX2hhc2jQIO1GQDk80AMKAG5ldHdvcmtfaWRGMgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:gilded_blackstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAgAACAQAbmFtZRsAbWluZWNyYWZ0OmdpbGRlZF9ibGFja3N0b25lBAkAbmFtZV9oYXNoNoWt1ocG0HEDCgBuZXR3b3JrX2lkKR0AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:chiseled_polished_blackstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAgAACAQAbmFtZSYAbWluZWNyYWZ0OmNoaXNlbGVkX3BvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2gzFa+kEjCJgAMKAG5ldHdvcmtfaWSEIgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:deepslate_tiles", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlcwQJAG5hbWVfaGFzaGcLLx3NXAFvAwoAbmV0d29ya19pZBEdAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cracked_deepslate_tiles", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAgAACAQAbmFtZSEAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX3RpbGVzBAkAbmFtZV9oYXNo9zWgkFuMM1QDCgBuZXR3b3JrX2lkJBsAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:deepslate_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja3MECQBuYW1lX2hhc2gucvFmPdZxigMKAG5ldHdvcmtfaWQ/JAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cracked_deepslate_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAgAACAQAbmFtZSIAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX2JyaWNrcwQJAG5hbWVfaGFzaN40aqhh9WqHAwoAbmV0d29ya19pZLcjAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:chiseled_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaEU7/uRG8HSBAwoAbmV0d29ya19pZDAjAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cobblestone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYmJsZXN0b25lBAkAbmFtZV9oYXNoPoK7mGlSUz4DCgBuZXR3b3JrX2lkcxcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:mossy_cobblestone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAAAACAQAbmFtZRsAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoGJ67FCbkChMDCgBuZXR3b3JrX2lkqAIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cobbled_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AgAACAQAbmFtZRsAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoLUz9Y/ywmLwDCgBuZXR3b3JrX2lkaS4AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:smooth_stone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AQAACAQAbmFtZRYAbWluZWNyYWZ0OnNtb290aF9zdG9uZQQJAG5hbWVfaGFzaMwf87/JaTNvAwoAbmV0d29ya19pZBIdAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZJ0XAAAKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUHAGRlZmF1bHQAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZJ4XAAAKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGULAGhlaXJvZ2x5cGhzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZJ8XAAAKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUDAGN1dAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZKAXAAAKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUGAHNtb290aAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWQLLgAACgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWQMLgAACgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlCwBoZWlyb2dseXBocwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWQNLgAACgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlAwBjdXQAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWQOLgAACgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBgBzbW9vdGgAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coal_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWStAAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvYWxfYmxvY2sECQBuYW1lX2hhc2jH8QQP3t5PiAMKAG5ldHdvcmtfaWTcIwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dried_kelp_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAQAACAQAbmFtZRoAbWluZWNyYWZ0OmRyaWVkX2tlbHBfYmxvY2sECQBuYW1lX2hhc2iRoucexkrl8wMKAG5ldHdvcmtfaWTKNQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:gold_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdvbGRfYmxvY2sECQBuYW1lX2hhc2iYLshvjtXzFwMKAG5ldHdvcmtfaWQKAwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:iron_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAAAACAQAbmFtZRQAbWluZWNyYWZ0Omlyb25fYmxvY2sECQBuYW1lX2hhc2jYINmJQbvV/gMKAG5ldHdvcmtfaWT5NgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:copper_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZBgfAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:exposed_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAgAACAQAbmFtZRgAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoQH3Fukmu3CEDCgBuZXR3b3JrX2lkRgUAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:weathered_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAgAACAQAbmFtZRoAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2hJCQXbvobv+gMKAG5ldHdvcmtfaWTVNgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:oxidized_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMDtJqR0G5Y7AwoAbmV0d29ya19pZDEXAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:waxed_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAgAACAQAbmFtZRYAbWluZWNyYWZ0OndheGVkX2NvcHBlcgQJAG5hbWVfaGFzaPF+FG6Eh5fsAwoAbmV0d29ya19pZIA0AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:waxed_exposed_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAgAACAQAbmFtZR4AbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoig8IOc+SCikDCgBuZXR3b3JrX2lkrwcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:waxed_weathered_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAgAACAQAbmFtZSAAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2gjtPq8MOdvKgMKAG5ldHdvcmtfaWS8BwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:waxed_oxidized_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS9AgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMaORhsO+LzjAwoAbmV0d29ya19pZLUzAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAgAACAQAbmFtZRQAbWluZWNyYWZ0OmN1dF9jb3BwZXIECQBuYW1lX2hhc2hAfN3NGax3eAMKAG5ldHdvcmtfaWQ+HwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:exposed_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAgAACAQAbmFtZRwAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaA85G3yv/w6pAwoAbmV0d29ya19pZEIsAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:weathered_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAgAACAQAbmFtZR4AbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoVgRV0fBaz88DCgBuZXR3b3JrX2lkNTIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:oxidized_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAgAACAQAbmFtZR0AbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2iP8WmFWOkriwMKAG5ldHdvcmtfaWRNJAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:waxed_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWReAgAACAQAbmFtZRoAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2jumiwOZIqv2AMKAG5ldHdvcmtfaWS6MgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:waxed_exposed_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAgAACAQAbmFtZSIAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaPE/OfK6IoVMAwoAbmV0d29ya19pZEQYAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:waxed_weathered_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoCA1xDp11bnwDCgBuZXR3b3JrX2lknCEAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:waxed_oxidized_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS+AgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2i1pZAsZYHLDAMKAG5ldHdvcmtfaWR5AgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:emerald_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAAAACAQAbmFtZRcAbWluZWNyYWZ0OmVtZXJhbGRfYmxvY2sECQBuYW1lX2hhc2hK6QunqJznNAMKAG5ldHdvcmtfaWQkCgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:diamond_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AAAACAQAbmFtZRcAbWluZWNyYWZ0OmRpYW1vbmRfYmxvY2sECQBuYW1lX2hhc2iGKrxuvkytFQMKAG5ldHdvcmtfaWTRAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:lapis_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxhcGlzX2Jsb2NrBAkAbmFtZV9oYXNoDZ44xdb2zVoDCgBuZXR3b3JrX2lkrhsAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:raw_iron_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19pcm9uX2Jsb2NrBAkAbmFtZV9oYXNo9XyzNIQXxvwDCgBuZXR3b3JrX2lk9jYAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:raw_copper_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAgAACAQAbmFtZRoAbWluZWNyYWZ0OnJhd19jb3BwZXJfYmxvY2sECQBuYW1lX2hhc2hw1KG0TNUGgwMKAG5ldHdvcmtfaWRlIwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:raw_gold_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19nb2xkX2Jsb2NrBAkAbmFtZV9oYXNo6YuwuLwfOBwDCgBuZXR3b3JrX2lkVAQAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZMgXAAAKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZMoXAAAKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZMkXAAAKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQgAY2hpc2VsZWQICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:quartz_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZMsXAAAKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQYAc21vb3RoCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWTfKwAACgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:prismarine", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWTgKwAACgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBABkYXJrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:slime", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnNsaW1lBAkAbmFtZV9oYXNoHJiEEJx+JlkDCgBuZXR3b3JrX2lkdhsAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:honey_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAQAACAQAbmFtZRUAbWluZWNyYWZ0OmhvbmV5X2Jsb2NrBAkAbmFtZV9oYXNo9zLYSUlelywDCgBuZXR3b3JrX2lkHwkAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:honeycomb_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAQAACAQAbmFtZRkAbWluZWNyYWZ0OmhvbmV5Y29tYl9ibG9jawQJAG5hbWVfaGFzaASIPuOCYd1oAwoAbmV0d29ya19pZKUcAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:hay_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAAAACAQAbmFtZRMAbWluZWNyYWZ0OmhheV9ibG9jawQJAG5hbWVfaGFzaIB2VxKxX8EpAwoAbmV0d29ya19pZLAHAAAKBgBzdGF0ZXMDCgBkZXByZWNhdGVkAAAAAAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bone_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAAAACAQAbmFtZRQAbWluZWNyYWZ0OmJvbmVfYmxvY2sECQBuYW1lX2hhc2i4ZX576W9AWgMKAG5ldHdvcmtfaWR3GwAACgYAc3RhdGVzAwoAZGVwcmVjYXRlZAAAAAAICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:nether_brick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAAAACAQAbmFtZRYAbWluZWNyYWZ0Om5ldGhlcl9icmljawQJAG5hbWVfaGFzaMxcRiheU+nXAwoAbmV0d29ya19pZKUyAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_nether_brick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAAAACAQAbmFtZRoAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2sECQBuYW1lX2hhc2j8pRO4LfoECAMKAG5ldHdvcmtfaWQ0AgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:netherite_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcml0ZV9ibG9jawQJAG5hbWVfaGFzaMghh6Zib/ZKAwoAbmV0d29ya19pZCEYAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:lodestone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAQAACAQAbmFtZRMAbWluZWNyYWZ0OmxvZGVzdG9uZQQJAG5hbWVfaGFzaJ2gmHOTlXv8AwoAbmV0d29ya19pZPM2AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:white_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAAAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWTdIwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:light_gray_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfd29vbAQJAG5hbWVfaGFzaOpdQ1a2v4b3AwoAbmV0d29ya19pZAo2AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:gray_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAwAACAQAbmFtZRMAbWluZWNyYWZ0OmdyYXlfd29vbAQJAG5hbWVfaGFzaLsc1Lp1xdIOAwoAbmV0d29ya19pZIcCAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:black_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrX3dvb2wECQBuYW1lX2hhc2hP2HC6o0X4HAMKAG5ldHdvcmtfaWRXBAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:brown_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJyb3duX3dvb2wECQBuYW1lX2hhc2ig5IW89PrREwMKAG5ldHdvcmtfaWS9AgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAwAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF93b29sBAkAbmFtZV9oYXNoY4TBDq+mFgUDCgBuZXR3b3JrX2lkfwAAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:orange_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAwAACAQAbmFtZRUAbWluZWNyYWZ0Om9yYW5nZV93b29sBAkAbmFtZV9oYXNoFstfrTZfSCgDCgBuZXR3b3JrX2lknAcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:yellow_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAwAACAQAbmFtZRUAbWluZWNyYWZ0OnllbGxvd193b29sBAkAbmFtZV9oYXNoTFyus2RHegcDCgBuZXR3b3JrX2lkKgIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:lime_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAwAACAQAbmFtZRMAbWluZWNyYWZ0OmxpbWVfd29vbAQJAG5hbWVfaGFzaNVnnzKiMxmeAwoAbmV0d29ya19pZHorAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:green_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAwAACAQAbmFtZRQAbWluZWNyYWZ0OmdyZWVuX3dvb2wECQBuYW1lX2hhc2i3mElRYHIcSQMKAG5ldHdvcmtfaWTtFwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cyan_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAwAACAQAbmFtZRMAbWluZWNyYWZ0OmN5YW5fd29vbAQJAG5hbWVfaGFzaBNDfvHn8dqFAwoAbmV0d29ya19pZKEjAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:light_blue_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfd29vbAQJAG5hbWVfaGFzaLWFAUfyxFPNAwoAbmV0d29ya19pZDMwAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:blue_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAwAACAQAbmFtZRMAbWluZWNyYWZ0OmJsdWVfd29vbAQJAG5hbWVfaGFzaLjHyxxbTWCLAwoAbmV0d29ya19pZE4kAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:purple_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAwAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnBsZV93b29sBAkAbmFtZV9oYXNojvFtqzjAf/4DCgBuZXR3b3JrX2lk+DYAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:magenta_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AwAACAQAbmFtZRYAbWluZWNyYWZ0Om1hZ2VudGFfd29vbAQJAG5hbWVfaGFzaGuOHvf+Pd4yAwoAbmV0d29ya19pZG8JAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:pink_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AwAACAQAbmFtZRMAbWluZWNyYWZ0OnBpbmtfd29vbAQJAG5hbWVfaGFzaPiVA2pFeoFLAwoAbmV0d29ya19pZCIYAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:white_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAAAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZJkyAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:light_gray_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0BAkAbmFtZV9oYXNoHPw6ArBAsP0DCgBuZXR3b3JrX2lk9zYAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:gray_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FycGV0BAkAbmFtZV9oYXNoZVR0OI+1VRADCgBuZXR3b3JrX2lkigIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:black_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhcnBldAQJAG5hbWVfaGFzaOk7LP9NptyhAwoAbmV0d29ya19pZKErAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:brown_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhcnBldAQJAG5hbWVfaGFzaNaXFyOsAvIvAwoAbmV0d29ya19pZFIJAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAwAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYXJwZXQECQBuYW1lX2hhc2i9eSKBf6SO3wMKAG5ldHdvcmtfaWQ3MwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:orange_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAwAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQECQBuYW1lX2hhc2hIUkO4HlAdygMKAG5ldHdvcmtfaWQKMAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:yellow_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAwAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYXJwZXQECQBuYW1lX2hhc2hSDKX3scCamwMKAG5ldHdvcmtfaWRXKQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:lime_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAwAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FycGV0BAkAbmFtZV9oYXNo+6KFOpzsib4DCgBuZXR3b3JrX2lklS4AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:green_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAwAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhcnBldAQJAG5hbWVfaGFzaCHPMP9ltqFJAwoAbmV0d29ya19pZO4XAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cyan_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAwAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FycGV0BAkAbmFtZV9oYXNobXf62dQBJj8DCgBuZXR3b3JrX2lkdhcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:light_blue_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0BAkAbmFtZV9oYXNo20l4oktdZ3sDCgBuZXR3b3JrX2lk6R8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:blue_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWReAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FycGV0BAkAbmFtZV9oYXNo3p3lsW0eQwsDCgBuZXR3b3JrX2lkVQIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:purple_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAwAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQECQBuYW1lX2hhc2jwIA9pW/qp7QMKAG5ldHdvcmtfaWSRNAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:magenta_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAwAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0BAkAbmFtZV9oYXNoFXT36YNNZhMDCgBuZXR3b3JrX2lkrAIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:pink_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FycGV0BAkAbmFtZV9oYXNoHll72oqk+OoDCgBuZXR3b3JrX2lkVzQAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:white_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTtAAAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZGohAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:light_gray_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo7EUk30hmUtYDCgBuZXR3b3JrX2lkiTIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:gray_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmdyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoW77af6WihdwDCgBuZXR3b3JrX2lkATMAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:black_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTSAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaAfWYp0xtgcfAwoAbmV0d29ya19pZHkEAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:brown_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaB74EeiLO46XAwoAbmV0d29ya19pZJMnAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAwAACAQAbmFtZR0AbWluZWNyYWZ0OnJlZF9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gjFut6Z/VH1gMKAG5ldHdvcmtfaWSIMgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:orange_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAwAACAQAbmFtZSAAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gADDj2IJiw+gMKAG5ldHdvcmtfaWTSNgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:yellow_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAwAACAQAbmFtZSAAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iy6qKNn3ob5wMKAG5ldHdvcmtfaWTdMwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:lime_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAwAACAQAbmFtZR4AbWluZWNyYWZ0OmxpbWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo4dYIPslbXPUDCgBuZXR3b3JrX2lk3jUAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:green_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAwAACAQAbmFtZR8AbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaM/c9x2aJh3HAwoAbmV0d29ya19pZM0vAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cyan_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAwAACAQAbmFtZR4AbWluZWNyYWZ0OmN5YW5fY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNok+xKAe7XXjoDCgBuZXR3b3JrX2lkGhcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:light_blue_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNogScpIQceyAEDCgBuZXR3b3JrX2lkPgAAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:blue_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoFp7mmeL86r0DCgBuZXR3b3JrX2lkki4AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:purple_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAwAACAQAbmFtZSAAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iYcVU04hoStwMKAG5ldHdvcmtfaWThLQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:magenta_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAwAACAQAbmFtZSEAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoy/70q6VPsWgDCgBuZXR3b3JrX2lkhBwAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:pink_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBpbmtfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoVikSAf8DwV0DCgBuZXR3b3JrX2lkuBsAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:white_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAAAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lkJzYAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:light_gray_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGUECQBuYW1lX2hhc2hEtet5wuDIKAMKAG5ldHdvcmtfaWSmBwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:gray_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AwAACAQAbmFtZRcAbWluZWNyYWZ0OmdyYXlfY29uY3JldGUECQBuYW1lX2hhc2j92INnb0a83AMKAG5ldHdvcmtfaWQCMwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:black_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAwAACAQAbmFtZRgAbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlBAkAbmFtZV9oYXNo2X7NDIQmZ70DCgBuZXR3b3JrX2lkgi4AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:brown_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AwAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlBAkAbmFtZV9oYXNoeka02BwXf6oDCgBuZXR3b3JrX2lkZCwAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAwAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9jb25jcmV0ZQQJAG5hbWVfaGFzaPWmNowLGubqAwoAbmV0d29ya19pZFY0AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:orange_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRzAwAACAQAbmFtZRkAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZQQJAG5hbWVfaGFzaAgE8XmaAi6+AwoAbmV0d29ya19pZJMuAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:yellow_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR2AwAACAQAbmFtZRkAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZQQJAG5hbWVfaGFzaE6ONfJPBd0+AwoAbmV0d29ya19pZHUXAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:lime_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR3AwAACAQAbmFtZRcAbWluZWNyYWZ0OmxpbWVfY29uY3JldGUECQBuYW1lX2hhc2gnd8JW6wmJcAMKAG5ldHdvcmtfaWQlHQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:green_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AwAACAQAbmFtZRgAbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlBAkAbmFtZV9oYXNokbFxRKchQZkDCgBuZXR3b3JrX2lkPSkAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cyan_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AwAACAQAbmFtZRcAbWluZWNyYWZ0OmN5YW5fY29uY3JldGUECQBuYW1lX2hhc2hFRrWJ33qj1wMKAG5ldHdvcmtfaWSaMgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:light_blue_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR1AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGUECQBuYW1lX2hhc2gHAe0kl0SE4AMKAG5ldHdvcmtfaWRKMwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:blue_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AwAACAQAbmFtZRcAbWluZWNyYWZ0OmJsdWVfY29uY3JldGUECQBuYW1lX2hhc2hiay301nnj1wMKAG5ldHdvcmtfaWSkMgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:purple_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AwAACAQAbmFtZRkAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZQQJAG5hbWVfaGFzaHBHflsPIwdXAwoAbmV0d29ya19pZEYbAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:magenta_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AwAACAQAbmFtZRoAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGUECQBuYW1lX2hhc2gN7LuB/OvdZAMKAG5ldHdvcmtfaWQpHAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:pink_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpbmtfY29uY3JldGUECQBuYW1lX2hhc2ii2G5F0u3SOAMKAG5ldHdvcmtfaWSXFQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:clay", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmNsYXkECQBuYW1lX2hhc2j/S6sKXRcpzwMKAG5ldHdvcmtfaWRjMAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:hardened_clay", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAAAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRmBQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:white_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAAAACAQAbmFtZRoAbWluZWNyYWZ0OndoaXRlX3RlcnJhY290dGEECQBuYW1lX2hhc2j3RSdgmnAIewMKAG5ldHdvcmtfaWToHwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:light_gray_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAz1Ri3wIxomAwoAbmV0d29ya19pZOwGAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:gray_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAwAACAQAbmFtZRkAbWluZWNyYWZ0OmdyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAXdSLAaNZ9vAwoAbmV0d29ya19pZBQdAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:black_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWThAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsYWNrX3RlcnJhY290dGEECQBuYW1lX2hhc2jxssdv5vlbpgMKAG5ldHdvcmtfaWT0KwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:brown_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJyb3duX3RlcnJhY290dGEECQBuYW1lX2hhc2gG4kPenmOF9gMKAG5ldHdvcmtfaWT4NQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAwAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo7fX56HXFejEDCgBuZXR3b3JrX2lkagkAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:orange_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAwAACAQAbmFtZRsAbWluZWNyYWZ0Om9yYW5nZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo0Hjmql3sruMDCgBuZXR3b3JrX2lktDMAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:yellow_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAwAACAQAbmFtZRsAbWluZWNyYWZ0OnllbGxvd190ZXJyYWNvdHRhBAkAbmFtZV9oYXNoqkyKKrmA3VcDCgBuZXR3b3JrX2lkThsAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:lime_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpbWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaANjADFOF9v7AwoAbmV0d29ya19pZNw2AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:green_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyZWVuX3RlcnJhY290dGEECQBuYW1lX2hhc2j5Ybq36yYwRQMKAG5ldHdvcmtfaWTeFwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cyan_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAwAACAQAbmFtZRkAbWluZWNyYWZ0OmN5YW5fdGVycmFjb3R0YQQJAG5hbWVfaGFzaN09COzMuHwAAwoAbmV0d29ya19pZAAAAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:light_blue_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaOMytez7cOZiAwoAbmV0d29ya19pZBscAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:blue_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaF6inyTK5RpAAwoAbmV0d29ya19pZJwXAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:purple_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAwAACAQAbmFtZRsAbWluZWNyYWZ0OnB1cnBsZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoKF7YG61yTbEDCgBuZXR3b3JrX2lkEi0AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:magenta_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAwAACAQAbmFtZRwAbWluZWNyYWZ0Om1hZ2VudGFfdGVycmFjb3R0YQQJAG5hbWVfaGFzaLWvtpAVtztyAwoAbmV0d29ya19pZCsdAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:pink_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAwAACAQAbmFtZRkAbWluZWNyYWZ0OnBpbmtfdGVycmFjb3R0YQQJAG5hbWVfaGFzaJ7mzvyzSQZTAwoAbmV0d29ya19pZCEbAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:white_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAAAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkrSQAAAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:silver_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAAAACAQAbmFtZSIAbWluZWNyYWZ0OnNpbHZlcl9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAVsA0CnhzA4AwoAbmV0d29ya19pZIkVAAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:gray_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAAAACAQAbmFtZSAAbWluZWNyYWZ0OmdyYXlfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2jvLZt9u/lF/AMKAG5ldHdvcmtfaWTtNgAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:black_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJsYWNrX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoe8I4xAXbO5UDCgBuZXR3b3JrX2lkOicAAAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:brown_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWToAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJyb3duX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoSiNZOobbpjoDCgBuZXR3b3JrX2lkGxcAAAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaBdWFGLmCLFVAwoAbmV0d29ya19pZCsbAAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:orange_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAAAACAQAbmFtZSIAbWluZWNyYWZ0Om9yYW5nZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaMyJMrnPr7szAwoAbmV0d29ya19pZBoKAAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:yellow_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAAAACAQAbmFtZSIAbWluZWNyYWZ0OnllbGxvd19nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaN6NaIhf6m0uAwoAbmV0d29ya19pZEQJAAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:lime_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWThAAAACAQAbmFtZSAAbWluZWNyYWZ0OmxpbWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2iF3E68/rB2EAMKAG5ldHdvcmtfaWSLAgAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:green_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAAAACAQAbmFtZSEAbWluZWNyYWZ0OmdyZWVuX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNow5mo8aQDFboDCgBuZXR3b3JrX2lkKi4AAAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:cyan_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAAAACAQAbmFtZSAAbWluZWNyYWZ0OmN5YW5fZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gnNB+cCFRJhwMKAG5ldHdvcmtfaWSxIwAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:light_blue_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAAAACAQAbmFtZSYAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gladnCDBKCigMKAG5ldHdvcmtfaWRGJAAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:blue_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAAAACAQAbmFtZSAAbWluZWNyYWZ0OmJsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2giOZK+2nB1igMKAG5ldHdvcmtfaWRAJAAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:purple_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAAAACAQAbmFtZSIAbWluZWNyYWZ0OnB1cnBsZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaIQU03txeAfHAwoAbmV0d29ya19pZMcvAAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:magenta_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAAAACAQAbmFtZSMAbWluZWNyYWZ0Om1hZ2VudGFfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2i/SNqDJbfjMgMKAG5ldHdvcmtfaWRwCQAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:pink_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAAAACAQAbmFtZSAAbWluZWNyYWZ0OnBpbmtfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2hik8DVt4g+twMKAG5ldHdvcmtfaWTiLQAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:purpur_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZGY0AAAKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:purpur_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZGg0AAAKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:packed_mud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9tdWQECQBuYW1lX2hhc2gHOMa121h4FgMKAG5ldHdvcmtfaWTiAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:mud_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAgAACAQAbmFtZRQAbWluZWNyYWZ0Om11ZF9icmlja3MECQBuYW1lX2hhc2iDL/SVl/PewQMKAG5ldHdvcmtfaWRBLwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:nether_wart_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9XGS4GNnlV4DCgBuZXR3b3JrX2lkuhsAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:warped_wart_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAQAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9IqDS9yUPJoDCgBuZXR3b3JrX2lkRSkAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:shroomlight", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNocm9vbWxpZ2h0BAkAbmFtZV9oYXNoZHCHcHX/HYADCgBuZXR3b3JrX2lkcyIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:crimson_nylium", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fbnlsaXVtBAkAbmFtZV9oYXNoOr6DJYW2bFYDCgBuZXR3b3JrX2lkQxsAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:warped_nylium", - "block_state_b64": "CgAAAwgAYmxvY2tfaWToAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9ueWxpdW0ECQBuYW1lX2hhc2g0Zf89cfr3rwMKAG5ldHdvcmtfaWTpLAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:netherrack", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAAAACAQAbmFtZRQAbWluZWNyYWZ0Om5ldGhlcnJhY2sECQBuYW1lX2hhc2i/r5ZyRsvPyQMKAG5ldHdvcmtfaWTlLwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:basalt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhc2FsdAQJAG5hbWVfaGFzaH+UQO2yWodiAwoAbmV0d29ya19pZBccAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_basalt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAQAACAQAbmFtZRkAbWluZWNyYWZ0OnBvbGlzaGVkX2Jhc2FsdAQJAG5hbWVfaGFzaMS+L0gMnRcBAwoAbmV0d29ya19pZBoAAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:smooth_basalt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AgAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9iYXNhbHQECQBuYW1lX2hhc2jKPUdz89kuNAMKAG5ldHdvcmtfaWQhCgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:soul_soil", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAQAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc29pbAQJAG5hbWVfaGFzaC1/87ccutuTAwoAbmV0d29ya19pZLElAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:dirt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWRgJQAACgYAc3RhdGVzCAkAZGlydF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:dirt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWRhJQAACgYAc3RhdGVzCAkAZGlydF90eXBlBgBjb2Fyc2UAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:farmland", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AAAACAQAbmFtZRIAbWluZWNyYWZ0OmZhcm1sYW5kBAkAbmFtZV9oYXNoxyQ5ag7LolADCgBuZXR3b3JrX2lkKRoAAAoGAHN0YXRlcwMSAG1vaXN0dXJpemVkX2Ftb3VudAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:grass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmdyYXNzBAkAbmFtZV9oYXNosppASPWFlsUDCgBuZXR3b3JrX2lkoC8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:grass_path", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdyYXNzX3BhdGgECQBuYW1lX2hhc2i0/KZV8Qsy+gMKAG5ldHdvcmtfaWQvNgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:podzol", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTzAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBvZHpvbAQJAG5hbWVfaGFzaBzqokRjH4Z1AwoAbmV0d29ya19pZBcfAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:mycelium", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAAAACAQAbmFtZRIAbWluZWNyYWZ0Om15Y2VsaXVtBAkAbmFtZV9oYXNojTN09cKickIDCgBuZXR3b3JrX2lkuxcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:mud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAgAACAQAbmFtZQ0AbWluZWNyYWZ0Om11ZAQJAG5hbWVfaGFzaPb/3P+uLy+9AwoAbmV0d29ya19pZGsuAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lk9AYAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:iron_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAAAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lkPx8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:gold_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAAAACAQAbmFtZRIAbWluZWNyYWZ0OmdvbGRfb3JlBAkAbmFtZV9oYXNoC5Y+DUGXLC4DCgBuZXR3b3JrX2lkQwkAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:diamond_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AAAACAQAbmFtZRUAbWluZWNyYWZ0OmRpYW1vbmRfb3JlBAkAbmFtZV9oYXNokUOJ2wZZrGQDCgBuZXR3b3JrX2lkJxwAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:lapis_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAAAACAQAbmFtZRMAbWluZWNyYWZ0OmxhcGlzX29yZQQJAG5hbWVfaGFzaMrmrUrSzb7qAwoAbmV0d29ya19pZFU0AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:redstone_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZHN0b25lX29yZQQJAG5hbWVfaGFzaFHVnp8Wc4JbAwoAbmV0d29ya19pZLEbAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coal_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAAAACAQAbmFtZRIAbWluZWNyYWZ0OmNvYWxfb3JlBAkAbmFtZV9oYXNo1OjA+Iuy51oDCgBuZXR3b3JrX2lkrxsAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:copper_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcHBlcl9vcmUECQBuYW1lX2hhc2iSZduSntOzOwMKAG5ldHdvcmtfaWQyFwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:emerald_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVtZXJhbGRfb3JlBAkAbmFtZV9oYXNoJTovr+VgINsDCgBuZXR3b3JrX2lk8DIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:quartz_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAAAACAQAbmFtZRQAbWluZWNyYWZ0OnF1YXJ0el9vcmUECQBuYW1lX2hhc2g0yNHLMK9TaQMKAG5ldHdvcmtfaWS+HAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:nether_gold_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcl9nb2xkX29yZQQJAG5hbWVfaGFzaEJZ7segIBgBAwoAbmV0d29ya19pZB0AAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:ancient_debris", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFuY2llbnRfZGVicmlzBAkAbmFtZV9oYXNoNrbxMc9AwKcDCgBuZXR3b3JrX2lkBiwAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:deepslate_iron_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9pcm9uX29yZQQJAG5hbWVfaGFzaB/fDL9pgvXXAwoAbmV0d29ya19pZKYyAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:deepslate_gold_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9nb2xkX29yZQQJAG5hbWVfaGFzaF9G7WYhKFinAwoAbmV0d29ya19pZAUsAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:deepslate_diamond_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9kaWFtb25kX29yZQQJAG5hbWVfaGFzaEUH5USh+iD3AwoAbmV0d29ya19pZPk1AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:deepslate_lapis_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV9sYXBpc19vcmUECQBuYW1lX2hhc2j+yFxU/KZs1gMKAG5ldHdvcmtfaWSKMgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:deepslate_redstone_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9yZWRzdG9uZV9vcmUECQBuYW1lX2hhc2iVgM3wWWD6ugMKAG5ldHdvcmtfaWQxLgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:deepslate_emerald_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9lbWVyYWxkX29yZQQJAG5hbWVfaGFzaNlfo5HTwS6wAwoAbmV0d29ya19pZOosAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:deepslate_coal_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb2FsX29yZQQJAG5hbWVfaGFzaIjikmcbRrPPAwoAbmV0d29ya19pZDQyAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:deepslate_copper_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb3BwZXJfb3JlBAkAbmFtZV9oYXNottjV4Ev5LAQDCgBuZXR3b3JrX2lkcgAAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:gravel", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAAAACAQAbmFtZRAAbWluZWNyYWZ0OmdyYXZlbAQJAG5hbWVfaGFzaOFxz8XJd2r/AwoAbmV0d29ya19pZBM3AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:granite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAwAACAQAbmFtZREAbWluZWNyYWZ0OmdyYW5pdGUECQBuYW1lX2hhc2iq+Dur2pw4AwMKAG5ldHdvcmtfaWRTAAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:diorite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAwAACAQAbmFtZREAbWluZWNyYWZ0OmRpb3JpdGUECQBuYW1lX2hhc2iaFsq2iinZBQMKAG5ldHdvcmtfaWSVAAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:andesite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAwAACAQAbmFtZRIAbWluZWNyYWZ0OmFuZGVzaXRlBAkAbmFtZV9oYXNosaLIEnQQoSYDCgBuZXR3b3JrX2lk8gYAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:blackstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrc3RvbmUECQBuYW1lX2hhc2iMFYziD80D6QMKAG5ldHdvcmtfaWTlMwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AgAACAQAbmFtZRMAbWluZWNyYWZ0OmRlZXBzbGF0ZQQJAG5hbWVfaGFzaKX5pAblxz8TAwoAbmV0d29ya19pZKkCAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_granite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWROAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGUECQBuYW1lX2hhc2iLiEfys8pFIAMKAG5ldHdvcmtfaWSDBAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:polished_diorite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGUECQBuYW1lX2hhc2hTxY4fKmNmlAMKAG5ldHdvcmtfaWQzJwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:polished_andesite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAwAACAQAbmFtZRsAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlBAkAbmFtZV9oYXNovl28uFk4HuQDCgBuZXR3b3JrX2lkujMAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:polished_blackstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAgAACAQAbmFtZR0AbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2jT9fHCl6vWQQMKAG5ldHdvcmtfaWS6FwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:polished_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaHC1edoaWF3uAwoAbmV0d29ya19pZJY0AAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:sand", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWRQGwAACgYAc3RhdGVzCAkAc2FuZF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:sand", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWRRGwAACgYAc3RhdGVzCAkAc2FuZF90eXBlAwByZWQAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cactus", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAAAACAQAbmFtZRAAbWluZWNyYWZ0OmNhY3R1cwQJAG5hbWVfaGFzaCG9zL0N4wvGAwoAbmV0d29ya19pZKsvAAAKBgBzdGF0ZXMDAwBhZ2UAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:oak_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAAAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWTbAgAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stripped_oak_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQJAQAACAQAbmFtZRoAbWluZWNyYWZ0OnN0cmlwcGVkX29ha19sb2cECQBuYW1lX2hhc2h8dqh+OOHU4wMKAG5ldHdvcmtfaWS3MwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:spruce_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AwAACAQAbmFtZRQAbWluZWNyYWZ0OnNwcnVjZV9sb2cECQBuYW1lX2hhc2hZ03qaLoF3WgMKAG5ldHdvcmtfaWSbGwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stripped_spruce_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV9sb2cECQBuYW1lX2hhc2iNrhKjS5IyrgMKAG5ldHdvcmtfaWSnLAAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:birch_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AwAACAQAbmFtZRMAbWluZWNyYWZ0OmJpcmNoX2xvZwQJAG5hbWVfaGFzaBUzT3NxsZAnAwoAbmV0d29ya19pZPUGAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stripped_birch_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAQAACAQAbmFtZRwAbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX2xvZwQJAG5hbWVfaGFzaCFKS4AeuSidAwoAbmV0d29ya19pZNYpAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:jungle_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AwAACAQAbmFtZRQAbWluZWNyYWZ0Omp1bmdsZV9sb2cECQBuYW1lX2hhc2gkwW0KNulqDgMKAG5ldHdvcmtfaWR/AgAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stripped_jungle_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV9sb2cECQBuYW1lX2hhc2hAwMsgOk02JAMKAG5ldHdvcmtfaWTnBgAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:acacia_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAAAACAQAbmFtZRQAbWluZWNyYWZ0OmFjYWNpYV9sb2cECQBuYW1lX2hhc2iV48VpYhjoYQMKAG5ldHdvcmtfaWQEHAAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stripped_acacia_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV9sb2cECQBuYW1lX2hhc2hJb0lQqnEqlgMKAG5ldHdvcmtfaWRoJwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:dark_oak_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AwAACAQAbmFtZRYAbWluZWNyYWZ0OmRhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaIWfVRd0XUo3AwoAbmV0d29ya19pZCsTAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stripped_dark_oak_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaPFTdxRdPwkOAwoAbmV0d29ya19pZHsCAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:mangrove_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaHZe6DzPZBobAwoAbmV0d29ya19pZEcEAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stripped_mangrove_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaLqIBo4hwA//AwoAbmV0d29ya19pZBA3AAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cherry_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAwAACAQAbmFtZRQAbWluZWNyYWZ0OmNoZXJyeV9sb2cECQBuYW1lX2hhc2hwFlaioppB1wMKAG5ldHdvcmtfaWSOMgAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stripped_cherry_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAwAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV9sb2cECQBuYW1lX2hhc2i85H6G+WhXaAMKAG5ldHdvcmtfaWR0HAAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:crimson_stem", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAQAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc3RlbQQJAG5hbWVfaGFzaM0FzfL0UTKZAwoAbmV0d29ya19pZDopAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stripped_crimson_stem", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25fc3RlbQQJAG5hbWVfaGFzaDlA6nood57EAwoAbmV0d29ya19pZIQvAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:warped_stem", - "block_state_b64": "CgAAAwgAYmxvY2tfaWThAQAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zdGVtBAkAbmFtZV9oYXNon7cKfPZxdrUDCgBuZXR3b3JrX2lkoi0AAAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stripped_warped_stem", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAQAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9zdGVtBAkAbmFtZV9oYXNoEw+y0dDPSd8DCgBuZXR3b3JrX2lkIjMAAAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQuEwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlAwBvYWsAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQ0EwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlAwBvYWsAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQvEwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBzcHJ1Y2UAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQ1EwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBzcHJ1Y2UAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQwEwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBQBiaXJjaAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQ2EwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBQBiaXJjaAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQxEwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBqdW5nbGUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQ3EwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBqdW5nbGUAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQyEwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlBgBhY2FjaWEAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQ4EwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlBgBhY2FjaWEAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQzEwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQACAkAd29vZF90eXBlCABkYXJrX29hawADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZQ4AbWluZWNyYWZ0Ondvb2QECQBuYW1lX2hhc2gbHdJFXQ1vNwMKAG5ldHdvcmtfaWQ5EwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQBCAkAd29vZF90eXBlCABkYXJrX29hawADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:mangrove_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2iXVxG0JG2fVAMKAG5ldHdvcmtfaWQlGwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stripped_mangrove_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2h7CkbaBF7/WAMKAG5ldHdvcmtfaWRyGwAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cherry_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV93b29kBAkAbmFtZV9oYXNoAW8srlmpBM8DCgBuZXR3b3JrX2lkWjAAAAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AQwAc3RyaXBwZWRfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stripped_cherry_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAwAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV93b29kBAkAbmFtZV9oYXNo/e7KXv+CB38DCgBuZXR3b3JrX2lktiEAAAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:crimson_hyphae", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNouRmKmfSqEWADCgBuZXR3b3JrX2lk2xsAAAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stripped_crimson_hyphae", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAgAACAQAbmFtZSEAbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNoFffwmABq4LUDCgBuZXR3b3JrX2lkpi0AAAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:warped_hyphae", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2hn8plQUr6pmQMKAG5ldHdvcmtfaWRCKQAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:stripped_warped_hyphae", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2irKq+HYPSgjQMKAG5ldHdvcmtfaWSzJAAACgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:bamboo_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19ibG9jawQJAG5hbWVfaGFzaAbDeur6stIBAwoAbmV0d29ya19pZD8AAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:stripped_bamboo_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAwAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2JhbWJvb19ibG9jawQJAG5hbWVfaGFzaJpwytpZOZM9AwoAbmV0d29ya19pZF4XAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZPUrAAAKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlAwBvYWsBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZPYrAAAKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBgBzcHJ1Y2UBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZPcrAAAKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBQBiaXJjaAEOAHBlcnNpc3RlbnRfYml0AAEKAHVwZGF0ZV9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxlYXZlcwQJAG5hbWVfaGFzaACPIsusW0mnAwoAbmV0d29ya19pZPgrAAAKBgBzdGF0ZXMIDQBvbGRfbGVhZl90eXBlBgBqdW5nbGUBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:leaves2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAAAACAQAbmFtZREAbWluZWNyYWZ0OmxlYXZlczIECQBuYW1lX2hhc2gy/bgrncY1ZAMKAG5ldHdvcmtfaWQdHAAACgYAc3RhdGVzCA0AbmV3X2xlYWZfdHlwZQYAYWNhY2lhAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:leaves2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAAAACAQAbmFtZREAbWluZWNyYWZ0OmxlYXZlczIECQBuYW1lX2hhc2gy/bgrncY1ZAMKAG5ldHdvcmtfaWQeHAAACgYAc3RhdGVzCA0AbmV3X2xlYWZfdHlwZQgAZGFya19vYWsBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:mangrove_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2xlYXZlcwQJAG5hbWVfaGFzaKyI/dWvhEG8AwoAbmV0d29ya19pZGUuAAAKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cherry_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9sZWF2ZXMECQBuYW1lX2hhc2giTs9ChhYBlQMKAG5ldHdvcmtfaWQ2JwAACgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:azalea_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAgAACAQAbmFtZRcAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXMECQBuYW1lX2hhc2iXFhD57wFS7AMKAG5ldHdvcmtfaWRiNAAACgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:azalea_leaves_flowered", - "block_state_b64": "CgAAAwgAYmxvY2tfaWREAgAACAQAbmFtZSAAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXNfZmxvd2VyZWQECQBuYW1lX2hhc2gs8jxlS/pMrwMKAG5ldHdvcmtfaWTeLAAACgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRjCAAACgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUDAG9hawADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRkCAAACgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAHNwcnVjZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRlCAAACgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUFAGJpcmNoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRmCAAACgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAGp1bmdsZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRnCAAACgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAGFjYWNpYQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRoCAAACgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUIAGRhcmtfb2FrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:mangrove_propagule", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hbmdyb3ZlX3Byb3BhZ3VsZQQJAG5hbWVfaGFzaJGeox6hkfLFAwoAbmV0d29ya19pZKEvAAAKBgBzdGF0ZXMBBwBoYW5naW5nAAMPAHByb3BhZ3VsZV9zdGFnZQAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cherry_sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAwAACAQAbmFtZRgAbWluZWNyYWZ0OmNoZXJyeV9zYXBsaW5nBAkAbmFtZV9oYXNoGrPpNMf1LtcDCgBuZXR3b3JrX2lkjDIAAAoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bee_nest", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJlZV9uZXN0BAkAbmFtZV9oYXNo2R2WBxUHEZIDCgBuZXR3b3JrX2lkZCUAAAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAADCwBob25leV9sZXZlbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wheat_seeds" - }, - { - "id": "minecraft:pumpkin_seeds" - }, - { - "id": "minecraft:melon_seeds" - }, - { - "id": "minecraft:beetroot_seeds" - }, - { - "id": "minecraft:torchflower_seeds" - }, - { - "id": "minecraft:pitcher_pod" - }, - { - "id": "minecraft:wheat" - }, - { - "id": "minecraft:beetroot" - }, - { - "id": "minecraft:potato" - }, - { - "id": "minecraft:poisonous_potato" - }, - { - "id": "minecraft:carrot" - }, - { - "id": "minecraft:golden_carrot" - }, - { - "id": "minecraft:apple" - }, - { - "id": "minecraft:golden_apple" - }, - { - "id": "minecraft:enchanted_golden_apple" - }, - { - "id": "minecraft:melon_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1lbG9uX2Jsb2NrBAkAbmFtZV9oYXNoXxSm0iYpAx8DCgBuZXR3b3JrX2lkeAQAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:melon_slice" - }, - { - "id": "minecraft:glistering_melon_slice" - }, - { - "id": "minecraft:sweet_berries" - }, - { - "id": "minecraft:glow_berries" - }, - { - "id": "minecraft:pumpkin", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAAAACAQAbmFtZREAbWluZWNyYWZ0OnB1bXBraW4ECQBuYW1lX2hhc2gc8A3jaSzWbgMKAG5ldHdvcmtfaWQNHQAACgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:carved_pumpkin", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNhcnZlZF9wdW1wa2luBAkAbmFtZV9oYXNoPu1T0MJuG90DCgBuZXR3b3JrX2lkDDMAAAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:lit_pumpkin", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxpdF9wdW1wa2luBAkAbmFtZV9oYXNo7gWtEm2uPL0DCgBuZXR3b3JrX2lkbC4AAAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:honeycomb" - }, - { - "id": "minecraft:tallgrass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZFUJAAAKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAGZlcm4AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZBYkAAAKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAZmVybgEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:tallgrass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZFQJAAAKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAHRhbGwAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZBUkAAAKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQUAZ3Jhc3MBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:nether_sprouts" - }, - { - "id": "minecraft:fire_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAwAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWTzBgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:brain_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWREAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJyYWluX2NvcmFsBAkAbmFtZV9oYXNoRiWlLCwA2ycDCgBuZXR3b3JrX2lkmwcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:bubble_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbAQJAG5hbWVfaGFzaJz6rWnl+v2qAwoAbmV0d29ya19pZGcsAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:tube_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1YmVfY29yYWwECQBuYW1lX2hhc2iYa8oO/tgk7wMKAG5ldHdvcmtfaWShNAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:horn_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAwAACAQAbmFtZRQAbWluZWNyYWZ0Omhvcm5fY29yYWwECQBuYW1lX2hhc2iZnRHjZbnLPgMKAG5ldHdvcmtfaWR0FwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dead_fire_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbAQJAG5hbWVfaGFzaEPU6tFy/latAwoAbmV0d29ya19pZJ4sAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:dead_brain_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAwAACAQAbmFtZRoAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWwECQBuYW1lX2hhc2j5L6QJCISvzwMKAG5ldHdvcmtfaWQzMgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dead_bubble_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAwAACAQAbmFtZRsAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsBAkAbmFtZV9oYXNoSTOZ/8wpeNYDCgBuZXR3b3JrX2lkizIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:dead_tube_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbAQJAG5hbWVfaGFzaJGjNWhlaIJeAwoAbmV0d29ya19pZLkbAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:dead_horn_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbAQJAG5hbWVfaGFzaJBkz3qt+g2cAwoAbmV0d29ya19pZHopAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZEkdAAAKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgMAcmVkAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZEcdAAAKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgQAcGluawMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZEgdAAAKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgYAcHVycGxlAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZEYdAAAKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgQAYmx1ZQMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZEodAAAKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgYAeWVsbG93AxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkTAAAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkSgAAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkSwAAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkSQAAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkTQAAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:crimson_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fcm9vdHMECQBuYW1lX2hhc2j1fWgQLViv5QMKAG5ldHdvcmtfaWTYMwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:warped_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAQAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9yb290cwQJAG5hbWVfaGFzaBc3WvbJOLlkAwoAbmV0d29ya19pZCgcAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:yellow_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQlAAAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19mbG93ZXIECQBuYW1lX2hhc2jWbU1pF0OUGAMKAG5ldHdvcmtfaWQVBAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR3FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUFAHBvcHB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR4FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUGAG9yY2hpZAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR5FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUGAGFsbGl1bQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR6FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUJAGhvdXN0b25pYQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR7FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUJAHR1bGlwX3JlZAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR8FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUMAHR1bGlwX29yYW5nZQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR9FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGULAHR1bGlwX3doaXRlAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR+FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUKAHR1bGlwX3BpbmsAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWR/FwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUFAG94ZXllAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWSAFwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUKAGNvcm5mbG93ZXIAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWSBFwAACgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUSAGxpbHlfb2ZfdGhlX3ZhbGxleQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZBMkAAAKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQkAc3VuZmxvd2VyAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZBQkAAAKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAc3lyaW5nYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZBckAAAKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAcm9zZQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZBgkAAAKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAcGFlb25pYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:pitcher_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpdGNoZXJfcGxhbnQECQBuYW1lX2hhc2hRJHzsbDH+SQMKAG5ldHdvcmtfaWQPGAAACgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:pink_petals", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfcGV0YWxzBAkAbmFtZV9oYXNo6DQwN9SwV3QDCgBuZXR3b3JrX2lkbh0AAAoGAHN0YXRlcwMGAGdyb3d0aAAAAAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:wither_rose", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAQAACAQAbmFtZRUAbWluZWNyYWZ0OndpdGhlcl9yb3NlBAkAbmFtZV9oYXNoaSKxl3I516gDCgBuZXR3b3JrX2lkQSwAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:torchflower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AwAACAQAbmFtZRUAbWluZWNyYWZ0OnRvcmNoZmxvd2VyBAkAbmFtZV9oYXNoL+mHtElwbqQDCgBuZXR3b3JrX2lkxisAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:white_dye" - }, - { - "id": "minecraft:light_gray_dye" - }, - { - "id": "minecraft:gray_dye" - }, - { - "id": "minecraft:black_dye" - }, - { - "id": "minecraft:brown_dye" - }, - { - "id": "minecraft:red_dye" - }, - { - "id": "minecraft:orange_dye" - }, - { - "id": "minecraft:yellow_dye" - }, - { - "id": "minecraft:lime_dye" - }, - { - "id": "minecraft:green_dye" - }, - { - "id": "minecraft:cyan_dye" - }, - { - "id": "minecraft:light_blue_dye" - }, - { - "id": "minecraft:blue_dye" - }, - { - "id": "minecraft:purple_dye" - }, - { - "id": "minecraft:magenta_dye" - }, - { - "id": "minecraft:pink_dye" - }, - { - "id": "minecraft:ink_sac" - }, - { - "id": "minecraft:glow_ink_sac" - }, - { - "id": "minecraft:cocoa_beans" - }, - { - "id": "minecraft:lapis_lazuli" - }, - { - "id": "minecraft:bone_meal" - }, - { - "id": "minecraft:vine", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnZpbmUECQBuYW1lX2hhc2j0Sj8/XeXOLAMKAG5ldHdvcmtfaWQhCQAACgYAc3RhdGVzAxMAdmluZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:weeping_vines", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAQAACAQAbmFtZRcAbWluZWNyYWZ0OndlZXBpbmdfdmluZXMECQBuYW1lX2hhc2jrLgLHkQygiwMKAG5ldHdvcmtfaWRPJAAACgYAc3RhdGVzAxEAd2VlcGluZ192aW5lc19hZ2UAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:twisting_vines", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAgAACAQAbmFtZRgAbWluZWNyYWZ0OnR3aXN0aW5nX3ZpbmVzBAkAbmFtZV9oYXNoDYR5QgVUQJADCgBuZXR3b3JrX2lkIiUAAAoGAHN0YXRlcwMSAHR3aXN0aW5nX3ZpbmVzX2FnZQAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:waterlily", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAAAACAQAbmFtZRMAbWluZWNyYWZ0OndhdGVybGlseQQJAG5hbWVfaGFzaEHgC4c1SXg0AwoAbmV0d29ya19pZCIKAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:seagrass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAQAACAQAbmFtZRIAbWluZWNyYWZ0OnNlYWdyYXNzBAkAbmFtZV9oYXNoHSBFtoHdWxIDCgBuZXR3b3JrX2lkogIAAAoGAHN0YXRlcwgOAHNlYV9ncmFzc190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:kelp" - }, - { - "id": "minecraft:deadbush", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAAAACAQAbmFtZRIAbWluZWNyYWZ0OmRlYWRidXNoBAkAbmFtZV9oYXNoPFODe4IScnYDCgBuZXR3b3JrX2lkMh8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:bamboo", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhbWJvbwQJAG5hbWVfaGFzaBgpGmyzhedCAwoAbmV0d29ya19pZLwXAAAKBgBzdGF0ZXMBBwBhZ2VfYml0AAgQAGJhbWJvb19sZWFmX3NpemUJAG5vX2xlYXZlcwgWAGJhbWJvb19zdGFsa190aGlja25lc3MEAHRoaW4AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:snow", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNub3cECQBuYW1lX2hhc2gVHr5XXdETWAMKAG5ldHdvcmtfaWRPGwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:ice", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAAAACAQAbmFtZQ0AbWluZWNyYWZ0OmljZQQJAG5hbWVfaGFzaNF26f+uUT29AwoAbmV0d29ya19pZHAuAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:packed_ice", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAAAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9pY2UECQBuYW1lX2hhc2hk4bu123ZrFgMKAG5ldHdvcmtfaWThAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:blue_ice", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJsdWVfaWNlBAkAbmFtZV9oYXNo+EKxYgFhKcgDCgBuZXR3b3JrX2lk2C8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:snow_layer", - "block_state_b64": "CgAAAwgAYmxvY2tfaWROAAAACAQAbmFtZRQAbWluZWNyYWZ0OnNub3dfbGF5ZXIECQBuYW1lX2hhc2hXka6atMYUCQMKAG5ldHdvcmtfaWQ9AgAACgYAc3RhdGVzAQsAY292ZXJlZF9iaXQAAwYAaGVpZ2h0AAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:pointed_dripstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvaW50ZWRfZHJpcHN0b25lBAkAbmFtZV9oYXNoJMISzmHQgt8DCgBuZXR3b3JrX2lkMjMAAAoGAHN0YXRlcwgTAGRyaXBzdG9uZV90aGlja25lc3MDAHRpcAEHAGhhbmdpbmcBAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dripstone_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRyaXBzdG9uZV9ibG9jawQJAG5hbWVfaGFzaIIXnEqY77YsAwoAbmV0d29ya19pZCAJAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:moss_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWROAgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vc3NfY2FycGV0BAkAbmFtZV9oYXNo/NEDxRPTshYDCgBuZXR3b3JrX2lk5QIAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:moss_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AgAACAQAbmFtZRQAbWluZWNyYWZ0Om1vc3NfYmxvY2sECQBuYW1lX2hhc2iovcsPUYX2tgMKAG5ldHdvcmtfaWTgLQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dirt_with_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRpcnRfd2l0aF9yb290cwQJAG5hbWVfaGFzaLCNDYPviDCIAwoAbmV0d29ya19pZNsjAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:hanging_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AgAACAQAbmFtZRcAbWluZWNyYWZ0Omhhbmdpbmdfcm9vdHMECQBuYW1lX2hhc2jaXn+Y5UZpDAMKAG5ldHdvcmtfaWRwAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:mangrove_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWThAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNoa786PzQGZ6kDCgBuZXR3b3JrX2lkSywAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:muddy_mangrove_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAgAACAQAbmFtZR4AbWluZWNyYWZ0Om11ZGR5X21hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNo9YApdHpo1RkDCgBuZXR3b3JrX2lkQgQAAAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:big_dripleaf", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpZ19kcmlwbGVhZgQJAG5hbWVfaGFzaGBEhXjo6qSdAwoAbmV0d29ya19pZN4pAAAKBgBzdGF0ZXMBEQBiaWdfZHJpcGxlYWZfaGVhZAEIEQBiaWdfZHJpcGxlYWZfdGlsdAQAbm9uZQgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:small_dripleaf_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtYWxsX2RyaXBsZWFmX2Jsb2NrBAkAbmFtZV9oYXNojxRAgXP9uWADCgBuZXR3b3JrX2lk9RsAAAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24EAGVhc3QBDwB1cHBlcl9ibG9ja19iaXQBAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:spore_blossom", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwb3JlX2Jsb3Nzb20ECQBuYW1lX2hhc2il3U72Gbco2gMKAG5ldHdvcmtfaWTNMgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:azalea", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAgAACAQAbmFtZRAAbWluZWNyYWZ0OmF6YWxlYQQJAG5hbWVfaGFzaNyUl+BW9JrBAwoAbmV0d29ya19pZEAvAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:flowering_azalea", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAgAACAQAbmFtZRoAbWluZWNyYWZ0OmZsb3dlcmluZ19hemFsZWEECQBuYW1lX2hhc2ie9r33wz8kiwMKAG5ldHdvcmtfaWRMJAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:glow_lichen", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAgAACAQAbmFtZRUAbWluZWNyYWZ0Omdsb3dfbGljaGVuBAkAbmFtZV9oYXNobyPUrIYlo44DCgBuZXR3b3JrX2lkGyUAAAoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHM/AAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:amethyst_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFtZXRoeXN0X2Jsb2NrBAkAbmFtZV9oYXNob+JK1iiAthcDCgBuZXR3b3JrX2lkCQMAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:budding_amethyst", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAgAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1ZGRpbmdfYW1ldGh5c3QECQBuYW1lX2hhc2gJvAwfI14fxgMKAG5ldHdvcmtfaWS7LwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:amethyst_cluster", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAgAACAQAbmFtZRoAbWluZWNyYWZ0OmFtZXRoeXN0X2NsdXN0ZXIECQBuYW1lX2hhc2jK82S88Jgm8wMKAG5ldHdvcmtfaWQgNQAACgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:large_amethyst_bud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAgAACAQAbmFtZRwAbWluZWNyYWZ0OmxhcmdlX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaAHhdpWD+sd5AwoAbmV0d29ya19pZGUfAAAKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:medium_amethyst_bud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1lZGl1bV9hbWV0aHlzdF9idWQECQBuYW1lX2hhc2g5lBGtC0DzZQMKAG5ldHdvcmtfaWQ1HAAACgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:small_amethyst_bud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAgAACAQAbmFtZRwAbWluZWNyYWZ0OnNtYWxsX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaEnb4+q9PO4YAwoAbmV0d29ya19pZBkEAAAKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:tuff", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAgAACAQAbmFtZQ4AbWluZWNyYWZ0OnR1ZmYECQBuYW1lX2hhc2h1Rwc1XYsBGwMKAG5ldHdvcmtfaWRGBAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:calcite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAgAACAQAbmFtZREAbWluZWNyYWZ0OmNhbGNpdGUECQBuYW1lX2hhc2ixKLu8ZIdzDQMKAG5ldHdvcmtfaWR6AgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:chicken" - }, - { - "id": "minecraft:porkchop" - }, - { - "id": "minecraft:beef" - }, - { - "id": "minecraft:mutton" - }, - { - "id": "minecraft:rabbit" - }, - { - "id": "minecraft:cod" - }, - { - "id": "minecraft:salmon" - }, - { - "id": "minecraft:tropical_fish" - }, - { - "id": "minecraft:pufferfish" - }, - { - "id": "minecraft:brown_mushroom", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAAAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkGRcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_mushroom", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9tdXNocm9vbQQJAG5hbWVfaGFzaPpzJua7669xAwoAbmV0d29ya19pZCgdAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:crimson_fungus", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fZnVuZ3VzBAkAbmFtZV9oYXNolIcCUuFM2u0DCgBuZXR3b3JrX2lklDQAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:warped_fungus", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9mdW5ndXMECQBuYW1lX2hhc2gq8bSnRVTAFgMKAG5ldHdvcmtfaWTmAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lk/zIAAAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw4AAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_mushroom_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9tdXNocm9vbV9ibG9jawQJAG5hbWVfaGFzaJTTyJbth9M9AwoAbmV0d29ya19pZG8XAAAKBgBzdGF0ZXMDEgBodWdlX211c2hyb29tX2JpdHMOAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkADMAAAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw8AAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lk8TIAAAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cwAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:egg" - }, - { - "id": "minecraft:sugar_cane" - }, - { - "id": "minecraft:sugar" - }, - { - "id": "minecraft:rotten_flesh" - }, - { - "id": "minecraft:bone" - }, - { - "id": "minecraft:web", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAAAACAQAbmFtZQ0AbWluZWNyYWZ0OndlYgQJAG5hbWVfaGFzaA4GKQCvG4i9AwoAbmV0d29ya19pZIkuAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:spider_eye" - }, - { - "id": "minecraft:mob_spawner", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vYl9zcGF3bmVyBAkAbmFtZV9oYXNoNwGrCV/Fkh8DCgBuZXR3b3JrX2lkggQAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkEhsAAAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUFAHN0b25lAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkExsAAAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAGNvYmJsZXN0b25lAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFBsAAAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAHN0b25lX2JyaWNrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFRsAAAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGURAG1vc3N5X3N0b25lX2JyaWNrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFhsAAAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUTAGNyYWNrZWRfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFxsAAAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUUAGNoaXNlbGVkX3N0b25lX2JyaWNrAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:infested_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAgAACAQAbmFtZRwAbWluZWNyYWZ0OmluZmVzdGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaICF2VYccxF1AwoAbmV0d29ya19pZA4fAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:dragon_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AAAACAQAbmFtZRQAbWluZWNyYWZ0OmRyYWdvbl9lZ2cECQBuYW1lX2hhc2inMzXrV+/e1wMKAG5ldHdvcmtfaWSjMgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:turtle_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1cnRsZV9lZ2cECQBuYW1lX2hhc2iwSRcxOJIJ9gMKAG5ldHdvcmtfaWTfNQAACgYAc3RhdGVzCA0AY3JhY2tlZF9zdGF0ZQkAbm9fY3JhY2tzCBAAdHVydGxlX2VnZ19jb3VudAcAb25lX2VnZwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sniffer_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAwAACAQAbmFtZRUAbWluZWNyYWZ0OnNuaWZmZXJfZWdnBAkAbmFtZV9oYXNoY1lozc8lPcYDCgBuZXR3b3JrX2lkvC8AAAoGAHN0YXRlcwgNAGNyYWNrZWRfc3RhdGUJAG5vX2NyYWNrcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:frog_spawn", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAgAACAQAbmFtZRQAbWluZWNyYWZ0OmZyb2dfc3Bhd24ECQBuYW1lX2hhc2iWmd7idp3ZZwMKAG5ldHdvcmtfaWRSHAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:pearlescent_froglight", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAgAACAQAbmFtZR8AbWluZWNyYWZ0OnBlYXJsZXNjZW50X2Zyb2dsaWdodAQJAG5hbWVfaGFzaKkcFRyycYGyAwoAbmV0d29ya19pZGEtAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:verdant_froglight", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAgAACAQAbmFtZRsAbWluZWNyYWZ0OnZlcmRhbnRfZnJvZ2xpZ2h0BAkAbmFtZV9oYXNoA+eXuTBohrQDCgBuZXR3b3JrX2lknC0AAAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:ochre_froglight", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om9jaHJlX2Zyb2dsaWdodAQJAG5hbWVfaGFzaMY59kjPe+c3AwoAbmV0d29ya19pZNIUAAAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:chicken_spawn_egg" - }, - { - "id": "minecraft:bee_spawn_egg" - }, - { - "id": "minecraft:cow_spawn_egg" - }, - { - "id": "minecraft:pig_spawn_egg" - }, - { - "id": "minecraft:sheep_spawn_egg" - }, - { - "id": "minecraft:wolf_spawn_egg" - }, - { - "id": "minecraft:polar_bear_spawn_egg" - }, - { - "id": "minecraft:ocelot_spawn_egg" - }, - { - "id": "minecraft:cat_spawn_egg" - }, - { - "id": "minecraft:mooshroom_spawn_egg" - }, - { - "id": "minecraft:bat_spawn_egg" - }, - { - "id": "minecraft:parrot_spawn_egg" - }, - { - "id": "minecraft:rabbit_spawn_egg" - }, - { - "id": "minecraft:llama_spawn_egg" - }, - { - "id": "minecraft:horse_spawn_egg" - }, - { - "id": "minecraft:donkey_spawn_egg" - }, - { - "id": "minecraft:mule_spawn_egg" - }, - { - "id": "minecraft:skeleton_horse_spawn_egg" - }, - { - "id": "minecraft:zombie_horse_spawn_egg" - }, - { - "id": "minecraft:tropical_fish_spawn_egg" - }, - { - "id": "minecraft:cod_spawn_egg" - }, - { - "id": "minecraft:pufferfish_spawn_egg" - }, - { - "id": "minecraft:salmon_spawn_egg" - }, - { - "id": "minecraft:dolphin_spawn_egg" - }, - { - "id": "minecraft:turtle_spawn_egg" - }, - { - "id": "minecraft:panda_spawn_egg" - }, - { - "id": "minecraft:fox_spawn_egg" - }, - { - "id": "minecraft:creeper_spawn_egg" - }, - { - "id": "minecraft:enderman_spawn_egg" - }, - { - "id": "minecraft:silverfish_spawn_egg" - }, - { - "id": "minecraft:skeleton_spawn_egg" - }, - { - "id": "minecraft:wither_skeleton_spawn_egg" - }, - { - "id": "minecraft:stray_spawn_egg" - }, - { - "id": "minecraft:slime_spawn_egg" - }, - { - "id": "minecraft:spider_spawn_egg" - }, - { - "id": "minecraft:zombie_spawn_egg" - }, - { - "id": "minecraft:zombie_pigman_spawn_egg" - }, - { - "id": "minecraft:husk_spawn_egg" - }, - { - "id": "minecraft:drowned_spawn_egg" - }, - { - "id": "minecraft:squid_spawn_egg" - }, - { - "id": "minecraft:glow_squid_spawn_egg" - }, - { - "id": "minecraft:cave_spider_spawn_egg" - }, - { - "id": "minecraft:witch_spawn_egg" - }, - { - "id": "minecraft:guardian_spawn_egg" - }, - { - "id": "minecraft:elder_guardian_spawn_egg" - }, - { - "id": "minecraft:endermite_spawn_egg" - }, - { - "id": "minecraft:magma_cube_spawn_egg" - }, - { - "id": "minecraft:strider_spawn_egg" - }, - { - "id": "minecraft:hoglin_spawn_egg" - }, - { - "id": "minecraft:piglin_spawn_egg" - }, - { - "id": "minecraft:zoglin_spawn_egg" - }, - { - "id": "minecraft:piglin_brute_spawn_egg" - }, - { - "id": "minecraft:goat_spawn_egg" - }, - { - "id": "minecraft:axolotl_spawn_egg" - }, - { - "id": "minecraft:warden_spawn_egg" - }, - { - "id": "minecraft:allay_spawn_egg" - }, - { - "id": "minecraft:frog_spawn_egg" - }, - { - "id": "minecraft:tadpole_spawn_egg" - }, - { - "id": "minecraft:trader_llama_spawn_egg" - }, - { - "id": "minecraft:camel_spawn_egg" - }, - { - "id": "minecraft:ghast_spawn_egg" - }, - { - "id": "minecraft:blaze_spawn_egg" - }, - { - "id": "minecraft:shulker_spawn_egg" - }, - { - "id": "minecraft:vindicator_spawn_egg" - }, - { - "id": "minecraft:evoker_spawn_egg" - }, - { - "id": "minecraft:vex_spawn_egg" - }, - { - "id": "minecraft:villager_spawn_egg" - }, - { - "id": "minecraft:wandering_trader_spawn_egg" - }, - { - "id": "minecraft:zombie_villager_spawn_egg" - }, - { - "id": "minecraft:phantom_spawn_egg" - }, - { - "id": "minecraft:pillager_spawn_egg" - }, - { - "id": "minecraft:ravager_spawn_egg" - }, - { - "id": "minecraft:iron_golem_spawn_egg" - }, - { - "id": "minecraft:snow_golem_spawn_egg" - }, - { - "id": "minecraft:sniffer_spawn_egg" - }, - { - "id": "minecraft:obsidian", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2lkaWFuBAkAbmFtZV9oYXNoiz4qrb8QjyEDCgBuZXR3b3JrX2lknwQAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:crying_obsidian", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAgAACAQAbmFtZRkAbWluZWNyYWZ0OmNyeWluZ19vYnNpZGlhbgQJAG5hbWVfaGFzaKT0JlA7Z1K+AwoAbmV0d29ya19pZJQuAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:bedrock", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAAAACAQAbmFtZREAbWluZWNyYWZ0OmJlZHJvY2sECQBuYW1lX2hhc2hWfFrh4LVtxwMKAG5ldHdvcmtfaWTOLwAACgYAc3RhdGVzAQ4AaW5maW5pYnVybl9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:soul_sand", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc2FuZAQJAG5hbWVfaGFzaMaf+bccu+KTAwoAbmV0d29ya19pZLIlAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:magma", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAAAACAQAbmFtZQ8AbWluZWNyYWZ0Om1hZ21hBAkAbmFtZV9oYXNoqyTjKaIsWfYDCgBuZXR3b3JrX2lk6zUAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:nether_wart" - }, - { - "id": "minecraft:end_stone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AAAACAQAbmFtZRMAbWluZWNyYWZ0OmVuZF9zdG9uZQQJAG5hbWVfaGFzaH1J9jA39GJNAwoAbmV0d29ya19pZNkZAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:chorus_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAAAACAQAbmFtZRcAbWluZWNyYWZ0OmNob3J1c19mbG93ZXIECQBuYW1lX2hhc2iMpSodli5uawMKAG5ldHdvcmtfaWTbHAAACgYAc3RhdGVzAwMAYWdlAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:chorus_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAAAACAQAbmFtZRYAbWluZWNyYWZ0OmNob3J1c19wbGFudAQJAG5hbWVfaGFzaJhSrmNGKwaMAwoAbmV0d29ya19pZGkkAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:chorus_fruit" - }, - { - "id": "minecraft:popped_chorus_fruit" - }, - { - "id": "minecraft:sponge", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZFkFAAAKBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAZHJ5AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:sponge", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZFoFAAAKBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAd2V0AAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkMyMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkNCMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkNSMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkNiMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkNyMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkOCMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkOSMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkOiMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkOyMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkPCMAAAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:sculk", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lk4y8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sculk_vein", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNjdWxrX3ZlaW4ECQBuYW1lX2hhc2gJUdhVooV4zwMKAG5ldHdvcmtfaWTzMQAACgYAc3RhdGVzAxkAbXVsdGlfZmFjZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:sculk_catalyst", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX2NhdGFseXN0BAkAbmFtZV9oYXNo+gCpbrCHST4DCgBuZXR3b3JrX2lkcRcAAAoGAHN0YXRlcwEFAGJsb29tAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sculk_shrieker", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX3Nocmlla2VyBAkAbmFtZV9oYXNo5OXtyObniQ4DCgBuZXR3b3JrX2lkgwIAAAoGAHN0YXRlcwEGAGFjdGl2ZQABCgBjYW5fc3VtbW9uAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sculk_sensor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNjdWxrX3NlbnNvcgQJAG5hbWVfaGFzaCkmHreeTgNnAwoAbmV0d29ya19pZEMcAAAKBgBzdGF0ZXMDEgBzY3Vsa19zZW5zb3JfcGhhc2UAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:calibrated_sculk_sensor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAwAACAQAbmFtZSEAbWluZWNyYWZ0OmNhbGlicmF0ZWRfc2N1bGtfc2Vuc29yBAkAbmFtZV9oYXNoffAcXXN/iJUDCgBuZXR3b3JrX2lkTCcAAAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAxIAc2N1bGtfc2Vuc29yX3BoYXNlAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:reinforced_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlaW5mb3JjZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoldDmj91EapQDCgBuZXR3b3JrX2lkNCcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:leather_helmet" - }, - { - "id": "minecraft:chainmail_helmet" - }, - { - "id": "minecraft:iron_helmet" - }, - { - "id": "minecraft:golden_helmet" - }, - { - "id": "minecraft:diamond_helmet" - }, - { - "id": "minecraft:netherite_helmet" - }, - { - "id": "minecraft:leather_chestplate" - }, - { - "id": "minecraft:chainmail_chestplate" - }, - { - "id": "minecraft:iron_chestplate" - }, - { - "id": "minecraft:golden_chestplate" - }, - { - "id": "minecraft:diamond_chestplate" - }, - { - "id": "minecraft:netherite_chestplate" - }, - { - "id": "minecraft:leather_leggings" - }, - { - "id": "minecraft:chainmail_leggings" - }, - { - "id": "minecraft:iron_leggings" - }, - { - "id": "minecraft:golden_leggings" - }, - { - "id": "minecraft:diamond_leggings" - }, - { - "id": "minecraft:netherite_leggings" - }, - { - "id": "minecraft:leather_boots" - }, - { - "id": "minecraft:chainmail_boots" - }, - { - "id": "minecraft:iron_boots" - }, - { - "id": "minecraft:golden_boots" - }, - { - "id": "minecraft:diamond_boots" - }, - { - "id": "minecraft:netherite_boots" - }, - { - "id": "minecraft:wooden_sword" - }, - { - "id": "minecraft:stone_sword" - }, - { - "id": "minecraft:iron_sword" - }, - { - "id": "minecraft:golden_sword" - }, - { - "id": "minecraft:diamond_sword" - }, - { - "id": "minecraft:netherite_sword" - }, - { - "id": "minecraft:wooden_axe" - }, - { - "id": "minecraft:stone_axe" - }, - { - "id": "minecraft:iron_axe" - }, - { - "id": "minecraft:golden_axe" - }, - { - "id": "minecraft:diamond_axe" - }, - { - "id": "minecraft:netherite_axe" - }, - { - "id": "minecraft:wooden_pickaxe" - }, - { - "id": "minecraft:stone_pickaxe" - }, - { - "id": "minecraft:iron_pickaxe" - }, - { - "id": "minecraft:golden_pickaxe" - }, - { - "id": "minecraft:diamond_pickaxe" - }, - { - "id": "minecraft:netherite_pickaxe" - }, - { - "id": "minecraft:wooden_shovel" - }, - { - "id": "minecraft:stone_shovel" - }, - { - "id": "minecraft:iron_shovel" - }, - { - "id": "minecraft:golden_shovel" - }, - { - "id": "minecraft:diamond_shovel" - }, - { - "id": "minecraft:netherite_shovel" - }, - { - "id": "minecraft:wooden_hoe" - }, - { - "id": "minecraft:stone_hoe" - }, - { - "id": "minecraft:iron_hoe" - }, - { - "id": "minecraft:golden_hoe" - }, - { - "id": "minecraft:diamond_hoe" - }, - { - "id": "minecraft:netherite_hoe" - }, - { - "id": "minecraft:bow" - }, - { - "id": "minecraft:crossbow" - }, - { - "id": "minecraft:arrow" - }, - { - "id": "minecraft:arrow", - "damage": 6 - }, - { - "id": "minecraft:arrow", - "damage": 7 - }, - { - "id": "minecraft:arrow", - "damage": 8 - }, - { - "id": "minecraft:arrow", - "damage": 9 - }, - { - "id": "minecraft:arrow", - "damage": 10 - }, - { - "id": "minecraft:arrow", - "damage": 11 - }, - { - "id": "minecraft:arrow", - "damage": 12 - }, - { - "id": "minecraft:arrow", - "damage": 13 - }, - { - "id": "minecraft:arrow", - "damage": 14 - }, - { - "id": "minecraft:arrow", - "damage": 15 - }, - { - "id": "minecraft:arrow", - "damage": 16 - }, - { - "id": "minecraft:arrow", - "damage": 17 - }, - { - "id": "minecraft:arrow", - "damage": 18 - }, - { - "id": "minecraft:arrow", - "damage": 19 - }, - { - "id": "minecraft:arrow", - "damage": 20 - }, - { - "id": "minecraft:arrow", - "damage": 21 - }, - { - "id": "minecraft:arrow", - "damage": 22 - }, - { - "id": "minecraft:arrow", - "damage": 23 - }, - { - "id": "minecraft:arrow", - "damage": 24 - }, - { - "id": "minecraft:arrow", - "damage": 25 - }, - { - "id": "minecraft:arrow", - "damage": 26 - }, - { - "id": "minecraft:arrow", - "damage": 27 - }, - { - "id": "minecraft:arrow", - "damage": 28 - }, - { - "id": "minecraft:arrow", - "damage": 29 - }, - { - "id": "minecraft:arrow", - "damage": 30 - }, - { - "id": "minecraft:arrow", - "damage": 31 - }, - { - "id": "minecraft:arrow", - "damage": 32 - }, - { - "id": "minecraft:arrow", - "damage": 33 - }, - { - "id": "minecraft:arrow", - "damage": 34 - }, - { - "id": "minecraft:arrow", - "damage": 35 - }, - { - "id": "minecraft:arrow", - "damage": 36 - }, - { - "id": "minecraft:arrow", - "damage": 37 - }, - { - "id": "minecraft:arrow", - "damage": 38 - }, - { - "id": "minecraft:arrow", - "damage": 39 - }, - { - "id": "minecraft:arrow", - "damage": 40 - }, - { - "id": "minecraft:arrow", - "damage": 41 - }, - { - "id": "minecraft:arrow", - "damage": 42 - }, - { - "id": "minecraft:arrow", - "damage": 43 - }, - { - "id": "minecraft:shield" - }, - { - "id": "minecraft:cooked_chicken" - }, - { - "id": "minecraft:cooked_porkchop" - }, - { - "id": "minecraft:cooked_beef" - }, - { - "id": "minecraft:cooked_mutton" - }, - { - "id": "minecraft:cooked_rabbit" - }, - { - "id": "minecraft:cooked_cod" - }, - { - "id": "minecraft:cooked_salmon" - }, - { - "id": "minecraft:bread" - }, - { - "id": "minecraft:mushroom_stew" - }, - { - "id": "minecraft:beetroot_soup" - }, - { - "id": "minecraft:rabbit_stew" - }, - { - "id": "minecraft:baked_potato" - }, - { - "id": "minecraft:cookie" - }, - { - "id": "minecraft:pumpkin_pie" - }, - { - "id": "minecraft:cake" - }, - { - "id": "minecraft:dried_kelp" - }, - { - "id": "minecraft:fishing_rod" - }, - { - "id": "minecraft:carrot_on_a_stick" - }, - { - "id": "minecraft:warped_fungus_on_a_stick" - }, - { - "id": "minecraft:snowball" - }, - { - "id": "minecraft:shears" - }, - { - "id": "minecraft:flint_and_steel" - }, - { - "id": "minecraft:lead" - }, - { - "id": "minecraft:clock" - }, - { - "id": "minecraft:compass" - }, - { - "id": "minecraft:recovery_compass" - }, - { - "id": "minecraft:goat_horn" - }, - { - "id": "minecraft:goat_horn", - "damage": 1 - }, - { - "id": "minecraft:goat_horn", - "damage": 2 - }, - { - "id": "minecraft:goat_horn", - "damage": 3 - }, - { - "id": "minecraft:goat_horn", - "damage": 4 - }, - { - "id": "minecraft:goat_horn", - "damage": 5 - }, - { - "id": "minecraft:goat_horn", - "damage": 6 - }, - { - "id": "minecraft:goat_horn", - "damage": 7 - }, - { - "id": "minecraft:empty_map" - }, - { - "id": "minecraft:empty_map", - "damage": 2 - }, - { - "id": "minecraft:saddle" - }, - { - "id": "minecraft:leather_horse_armor" - }, - { - "id": "minecraft:iron_horse_armor" - }, - { - "id": "minecraft:golden_horse_armor" - }, - { - "id": "minecraft:diamond_horse_armor" - }, - { - "id": "minecraft:trident" - }, - { - "id": "minecraft:turtle_helmet" - }, - { - "id": "minecraft:elytra" - }, - { - "id": "minecraft:totem_of_undying" - }, - { - "id": "minecraft:glass_bottle" - }, - { - "id": "minecraft:experience_bottle" - }, - { - "id": "minecraft:potion" - }, - { - "id": "minecraft:potion", - "damage": 1 - }, - { - "id": "minecraft:potion", - "damage": 2 - }, - { - "id": "minecraft:potion", - "damage": 3 - }, - { - "id": "minecraft:potion", - "damage": 4 - }, - { - "id": "minecraft:potion", - "damage": 5 - }, - { - "id": "minecraft:potion", - "damage": 6 - }, - { - "id": "minecraft:potion", - "damage": 7 - }, - { - "id": "minecraft:potion", - "damage": 8 - }, - { - "id": "minecraft:potion", - "damage": 9 - }, - { - "id": "minecraft:potion", - "damage": 10 - }, - { - "id": "minecraft:potion", - "damage": 11 - }, - { - "id": "minecraft:potion", - "damage": 12 - }, - { - "id": "minecraft:potion", - "damage": 13 - }, - { - "id": "minecraft:potion", - "damage": 14 - }, - { - "id": "minecraft:potion", - "damage": 15 - }, - { - "id": "minecraft:potion", - "damage": 16 - }, - { - "id": "minecraft:potion", - "damage": 17 - }, - { - "id": "minecraft:potion", - "damage": 18 - }, - { - "id": "minecraft:potion", - "damage": 19 - }, - { - "id": "minecraft:potion", - "damage": 20 - }, - { - "id": "minecraft:potion", - "damage": 21 - }, - { - "id": "minecraft:potion", - "damage": 22 - }, - { - "id": "minecraft:potion", - "damage": 23 - }, - { - "id": "minecraft:potion", - "damage": 24 - }, - { - "id": "minecraft:potion", - "damage": 25 - }, - { - "id": "minecraft:potion", - "damage": 26 - }, - { - "id": "minecraft:potion", - "damage": 27 - }, - { - "id": "minecraft:potion", - "damage": 28 - }, - { - "id": "minecraft:potion", - "damage": 29 - }, - { - "id": "minecraft:potion", - "damage": 30 - }, - { - "id": "minecraft:potion", - "damage": 31 - }, - { - "id": "minecraft:potion", - "damage": 32 - }, - { - "id": "minecraft:potion", - "damage": 33 - }, - { - "id": "minecraft:potion", - "damage": 34 - }, - { - "id": "minecraft:potion", - "damage": 35 - }, - { - "id": "minecraft:potion", - "damage": 36 - }, - { - "id": "minecraft:potion", - "damage": 37 - }, - { - "id": "minecraft:potion", - "damage": 38 - }, - { - "id": "minecraft:potion", - "damage": 39 - }, - { - "id": "minecraft:potion", - "damage": 40 - }, - { - "id": "minecraft:potion", - "damage": 41 - }, - { - "id": "minecraft:potion", - "damage": 42 - }, - { - "id": "minecraft:splash_potion" - }, - { - "id": "minecraft:splash_potion", - "damage": 1 - }, - { - "id": "minecraft:splash_potion", - "damage": 2 - }, - { - "id": "minecraft:splash_potion", - "damage": 3 - }, - { - "id": "minecraft:splash_potion", - "damage": 4 - }, - { - "id": "minecraft:splash_potion", - "damage": 5 - }, - { - "id": "minecraft:splash_potion", - "damage": 6 - }, - { - "id": "minecraft:splash_potion", - "damage": 7 - }, - { - "id": "minecraft:splash_potion", - "damage": 8 - }, - { - "id": "minecraft:splash_potion", - "damage": 9 - }, - { - "id": "minecraft:splash_potion", - "damage": 10 - }, - { - "id": "minecraft:splash_potion", - "damage": 11 - }, - { - "id": "minecraft:splash_potion", - "damage": 12 - }, - { - "id": "minecraft:splash_potion", - "damage": 13 - }, - { - "id": "minecraft:splash_potion", - "damage": 14 - }, - { - "id": "minecraft:splash_potion", - "damage": 15 - }, - { - "id": "minecraft:splash_potion", - "damage": 16 - }, - { - "id": "minecraft:splash_potion", - "damage": 17 - }, - { - "id": "minecraft:splash_potion", - "damage": 18 - }, - { - "id": "minecraft:splash_potion", - "damage": 19 - }, - { - "id": "minecraft:splash_potion", - "damage": 20 - }, - { - "id": "minecraft:splash_potion", - "damage": 21 - }, - { - "id": "minecraft:splash_potion", - "damage": 22 - }, - { - "id": "minecraft:splash_potion", - "damage": 23 - }, - { - "id": "minecraft:splash_potion", - "damage": 24 - }, - { - "id": "minecraft:splash_potion", - "damage": 25 - }, - { - "id": "minecraft:splash_potion", - "damage": 26 - }, - { - "id": "minecraft:splash_potion", - "damage": 27 - }, - { - "id": "minecraft:splash_potion", - "damage": 28 - }, - { - "id": "minecraft:splash_potion", - "damage": 29 - }, - { - "id": "minecraft:splash_potion", - "damage": 30 - }, - { - "id": "minecraft:splash_potion", - "damage": 31 - }, - { - "id": "minecraft:splash_potion", - "damage": 32 - }, - { - "id": "minecraft:splash_potion", - "damage": 33 - }, - { - "id": "minecraft:splash_potion", - "damage": 34 - }, - { - "id": "minecraft:splash_potion", - "damage": 35 - }, - { - "id": "minecraft:splash_potion", - "damage": 36 - }, - { - "id": "minecraft:splash_potion", - "damage": 37 - }, - { - "id": "minecraft:splash_potion", - "damage": 38 - }, - { - "id": "minecraft:splash_potion", - "damage": 39 - }, - { - "id": "minecraft:splash_potion", - "damage": 40 - }, - { - "id": "minecraft:splash_potion", - "damage": 41 - }, - { - "id": "minecraft:splash_potion", - "damage": 42 - }, - { - "id": "minecraft:lingering_potion" - }, - { - "id": "minecraft:lingering_potion", - "damage": 1 - }, - { - "id": "minecraft:lingering_potion", - "damage": 2 - }, - { - "id": "minecraft:lingering_potion", - "damage": 3 - }, - { - "id": "minecraft:lingering_potion", - "damage": 4 - }, - { - "id": "minecraft:lingering_potion", - "damage": 5 - }, - { - "id": "minecraft:lingering_potion", - "damage": 6 - }, - { - "id": "minecraft:lingering_potion", - "damage": 7 - }, - { - "id": "minecraft:lingering_potion", - "damage": 8 - }, - { - "id": "minecraft:lingering_potion", - "damage": 9 - }, - { - "id": "minecraft:lingering_potion", - "damage": 10 - }, - { - "id": "minecraft:lingering_potion", - "damage": 11 - }, - { - "id": "minecraft:lingering_potion", - "damage": 12 - }, - { - "id": "minecraft:lingering_potion", - "damage": 13 - }, - { - "id": "minecraft:lingering_potion", - "damage": 14 - }, - { - "id": "minecraft:lingering_potion", - "damage": 15 - }, - { - "id": "minecraft:lingering_potion", - "damage": 16 - }, - { - "id": "minecraft:lingering_potion", - "damage": 17 - }, - { - "id": "minecraft:lingering_potion", - "damage": 18 - }, - { - "id": "minecraft:lingering_potion", - "damage": 19 - }, - { - "id": "minecraft:lingering_potion", - "damage": 20 - }, - { - "id": "minecraft:lingering_potion", - "damage": 21 - }, - { - "id": "minecraft:lingering_potion", - "damage": 22 - }, - { - "id": "minecraft:lingering_potion", - "damage": 23 - }, - { - "id": "minecraft:lingering_potion", - "damage": 24 - }, - { - "id": "minecraft:lingering_potion", - "damage": 25 - }, - { - "id": "minecraft:lingering_potion", - "damage": 26 - }, - { - "id": "minecraft:lingering_potion", - "damage": 27 - }, - { - "id": "minecraft:lingering_potion", - "damage": 28 - }, - { - "id": "minecraft:lingering_potion", - "damage": 29 - }, - { - "id": "minecraft:lingering_potion", - "damage": 30 - }, - { - "id": "minecraft:lingering_potion", - "damage": 31 - }, - { - "id": "minecraft:lingering_potion", - "damage": 32 - }, - { - "id": "minecraft:lingering_potion", - "damage": 33 - }, - { - "id": "minecraft:lingering_potion", - "damage": 34 - }, - { - "id": "minecraft:lingering_potion", - "damage": 35 - }, - { - "id": "minecraft:lingering_potion", - "damage": 36 - }, - { - "id": "minecraft:lingering_potion", - "damage": 37 - }, - { - "id": "minecraft:lingering_potion", - "damage": 38 - }, - { - "id": "minecraft:lingering_potion", - "damage": 39 - }, - { - "id": "minecraft:lingering_potion", - "damage": 40 - }, - { - "id": "minecraft:lingering_potion", - "damage": 41 - }, - { - "id": "minecraft:lingering_potion", - "damage": 42 - }, - { - "id": "minecraft:spyglass" - }, - { - "id": "minecraft:brush" - }, - { - "id": "minecraft:stick" - }, - { - "id": "minecraft:bed" - }, - { - "id": "minecraft:bed", - "damage": 8 - }, - { - "id": "minecraft:bed", - "damage": 7 - }, - { - "id": "minecraft:bed", - "damage": 15 - }, - { - "id": "minecraft:bed", - "damage": 12 - }, - { - "id": "minecraft:bed", - "damage": 14 - }, - { - "id": "minecraft:bed", - "damage": 1 - }, - { - "id": "minecraft:bed", - "damage": 4 - }, - { - "id": "minecraft:bed", - "damage": 5 - }, - { - "id": "minecraft:bed", - "damage": 13 - }, - { - "id": "minecraft:bed", - "damage": 9 - }, - { - "id": "minecraft:bed", - "damage": 3 - }, - { - "id": "minecraft:bed", - "damage": 11 - }, - { - "id": "minecraft:bed", - "damage": 10 - }, - { - "id": "minecraft:bed", - "damage": 2 - }, - { - "id": "minecraft:bed", - "damage": 6 - }, - { - "id": "minecraft:torch", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnRvcmNoBAkAbmFtZV9oYXNoagn7rmDBzisDCgBuZXR3b3JrX2lkdwgAAAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:soul_torch", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNvdWxfdG9yY2gECQBuYW1lX2hhc2huixOT04BRdQMKAG5ldHdvcmtfaWQRHwAACgYAc3RhdGVzCBYAdG9yY2hfZmFjaW5nX2RpcmVjdGlvbgcAdW5rbm93bgADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sea_pickle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAQAACAQAbmFtZRQAbWluZWNyYWZ0OnNlYV9waWNrbGUECQBuYW1lX2hhc2iONEfZJB+glgMKAG5ldHdvcmtfaWRvJwAACgYAc3RhdGVzAw0AY2x1c3Rlcl9jb3VudAAAAAABCABkZWFkX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:lantern", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAQAACAQAbmFtZREAbWluZWNyYWZ0OmxhbnRlcm4ECQBuYW1lX2hhc2hMw44VI2HWygMKAG5ldHdvcmtfaWQLMAAACgYAc3RhdGVzAQcAaGFuZ2luZwAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:soul_lantern", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNvdWxfbGFudGVybgQJAG5hbWVfaGFzaGjIpjxk9z+RAwoAbmV0d29ya19pZF4lAAAKBgBzdGF0ZXMBBwBoYW5naW5nAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZCUzAAAKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:white_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWScAgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhbmRsZQQJAG5hbWVfaGFzaN1EG5Q1mHiEAwoAbmV0d29ya19pZIQjAAAKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:orange_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSdAgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYW5kbGUECQBuYW1lX2hhc2jySEVWHgUIHQMKAG5ldHdvcmtfaWRYBAAACgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:magenta_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FuZGxlBAkAbmFtZV9oYXNoG0u6YIOoBSEDCgBuZXR3b3JrX2lklAQAAAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:light_blue_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FuZGxlBAkAbmFtZV9oYXNocXGeK0zgrG0DCgBuZXR3b3JrX2lkBB0AAAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:yellow_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYW5kbGUECQBuYW1lX2hhc2i00dtusU3CqQMKAG5ldHdvcmtfaWRMLAAACgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:lime_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FuZGxlBAkAbmFtZV9oYXNokcmrw5xvz7ADCgBuZXR3b3JrX2lk/CwAAAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:pink_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FuZGxlBAkAbmFtZV9oYXNoQJdEY4sZ0dwDCgBuZXR3b3JrX2lkAzMAAAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:gray_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FuZGxlBAkAbmFtZV9oYXNoS5poSo9wBDEDCgBuZXR3b3JrX2lkXwkAAAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:light_gray_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FuZGxlBAkAbmFtZV9oYXNo9ruTZLBNMasDCgBuZXR3b3JrX2lkaSwAAAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cyan_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FuZGxlBAkAbmFtZV9oYXNoc/M8PNVcjOwDCgBuZXR3b3JrX2lkeDQAAAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:purple_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYW5kbGUECQBuYW1lX2hhc2jaI3xUW0/myQMKAG5ldHdvcmtfaWTmLwAACgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:blue_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FuZGxlBAkAbmFtZV9oYXNoAASSPW6TgQADCgBuZXR3b3JrX2lkAgAAAAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:brown_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhbmRsZQQJAG5hbWVfaGFzaDia0l6s1+WYAwoAbmV0d29ya19pZCQpAAAKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:green_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhbmRsZQQJAG5hbWVfaGFzaLeFPO1l+fIoAwoAbmV0d29ya19pZKcHAAAKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:red_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYW5kbGUECQBuYW1lX2hhc2jjAQpGf59ZdwMKAG5ldHdvcmtfaWQ2HwAACgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:black_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhbmRsZQQJAG5hbWVfaGFzaB+wRDpOqREKAwoAbmV0d29ya19pZE0CAAAKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:crafting_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AAAACAQAbmFtZRgAbWluZWNyYWZ0OmNyYWZ0aW5nX3RhYmxlBAkAbmFtZV9oYXNoe76VAmjvbpYDCgBuZXR3b3JrX2lkbicAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cartography_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAQAACAQAbmFtZRsAbWluZWNyYWZ0OmNhcnRvZ3JhcGh5X3RhYmxlBAkAbmFtZV9oYXNomaWiiD/znP8DCgBuZXR3b3JrX2lkFDcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:fletching_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAQAACAQAbmFtZRkAbWluZWNyYWZ0OmZsZXRjaGluZ190YWJsZQQJAG5hbWVfaGFzaPFibh8unKyUAwoAbmV0d29ya19pZDUnAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:smithing_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAQAACAQAbmFtZRgAbWluZWNyYWZ0OnNtaXRoaW5nX3RhYmxlBAkAbmFtZV9oYXNo4tFES2xOXEYDCgBuZXR3b3JrX2lk6RcAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:beehive", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAQAACAQAbmFtZREAbWluZWNyYWZ0OmJlZWhpdmUECQBuYW1lX2hhc2hCcqn12UbNpwMKAG5ldHdvcmtfaWQHLAAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAMLAGhvbmV5X2xldmVsAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:suspicious_sand", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAwAACAQAbmFtZRkAbWluZWNyYWZ0OnN1c3BpY2lvdXNfc2FuZAQJAG5hbWVfaGFzaL67QsuvLP00AwoAbmV0d29ya19pZCYKAAAKBgBzdGF0ZXMDEABicnVzaGVkX3Byb2dyZXNzAAAAAAEHAGhhbmdpbmcBAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:suspicious_gravel", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AwAACAQAbmFtZRsAbWluZWNyYWZ0OnN1c3BpY2lvdXNfZ3JhdmVsBAkAbmFtZV9oYXNoJSVbGNk7C3oDCgBuZXR3b3JrX2lkix8AAAoGAHN0YXRlcwMQAGJydXNoZWRfcHJvZ3Jlc3MAAAAAAQcAaGFuZ2luZwEAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:campfire" - }, - { - "id": "minecraft:soul_campfire" - }, - { - "id": "minecraft:furnace", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AAAACAQAbmFtZREAbWluZWNyYWZ0OmZ1cm5hY2UECQBuYW1lX2hhc2ioOQrludYY8wMKAG5ldHdvcmtfaWQaNQAACgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:blast_furnace", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAQAACAQAbmFtZRcAbWluZWNyYWZ0OmJsYXN0X2Z1cm5hY2UECQBuYW1lX2hhc2ivDbnjkpGm5QMKAG5ldHdvcmtfaWTUMwAACgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:smoker", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAQAACAQAbmFtZRAAbWluZWNyYWZ0OnNtb2tlcgQJAG5hbWVfaGFzaJd1rDMkRWomAwoAbmV0d29ya19pZO0GAAAKBgBzdGF0ZXMIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:respawn_anchor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlc3Bhd25fYW5jaG9yBAkAbmFtZV9oYXNoZOdcjW05qigDCgBuZXR3b3JrX2lkoQcAAAoGAHN0YXRlcwMVAHJlc3Bhd25fYW5jaG9yX2NoYXJnZQAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:brewing_stand" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkRC4AAAoGAHN0YXRlcwgGAGRhbWFnZQkAdW5kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkSC4AAAoGAHN0YXRlcwgGAGRhbWFnZRAAc2xpZ2h0bHlfZGFtYWdlZAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:anvil", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkTC4AAAoGAHN0YXRlcwgGAGRhbWFnZQwAdmVyeV9kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:grindstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAQAACAQAbmFtZRQAbWluZWNyYWZ0OmdyaW5kc3RvbmUECQBuYW1lX2hhc2id56zc0nk99wMKAG5ldHdvcmtfaWT6NQAACgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:enchanting_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuY2hhbnRpbmdfdGFibGUECQBuYW1lX2hhc2jgIx24VLvMvwMKAG5ldHdvcmtfaWSaLgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bookshelf", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAAAACAQAbmFtZRMAbWluZWNyYWZ0OmJvb2tzaGVsZgQJAG5hbWVfaGFzaDU04DrgJCS9AwoAbmV0d29ya19pZGouAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:chiseled_bookshelf", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAwAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2Jvb2tzaGVsZgQJAG5hbWVfaGFzaNXDBnsIsywYAwoAbmV0d29ya19pZA0DAAAKBgBzdGF0ZXMDDABib29rc19zdG9yZWQAAAAAAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:lectern", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTBAQAACAQAbmFtZREAbWluZWNyYWZ0OmxlY3Rlcm4ECQBuYW1lX2hhc2j5Z4Mmi/1QxAMKAG5ldHdvcmtfaWR8LwAACgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cauldron" - }, - { - "id": "minecraft:composter", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvbXBvc3RlcgQJAG5hbWVfaGFzaPAADHptzeWJAwoAbmV0d29ya19pZO4jAAAKBgBzdGF0ZXMDFABjb21wb3N0ZXJfZmlsbF9sZXZlbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:chest", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AAAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkWDAAAAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:trapped_chest", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyYXBwZWRfY2hlc3QECQBuYW1lX2hhc2g2qpF9stsEjgMKAG5ldHdvcmtfaWS5JAAACgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAbm9ydGgAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:ender_chest", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVuZGVyX2NoZXN0BAkAbmFtZV9oYXNohEZzOFdg0WUDCgBuZXR3b3JrX2lkMhwAAAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:barrel", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhcnJlbAQJAG5hbWVfaGFzaHDkRPGymiRqAwoAbmV0d29ya19pZM8cAAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:undyed_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAAAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZLkXAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:white_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAAAACAQAbmFtZRsAbWluZWNyYWZ0OndoaXRlX3NodWxrZXJfYm94BAkAbmFtZV9oYXNosK79m1rPUBwDCgBuZXR3b3JrX2lkVQQAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:light_gray_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iBe5zq7PxHmgMKAG5ldHdvcmtfaWRGKQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:gray_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2ga2s8ctjHUhgMKAG5ldHdvcmtfaWSoIwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:black_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoPm03OZphrp8DCgBuZXR3b3JrX2lklysAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:brown_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJyb3duX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoT3DD6qAL9cADCgBuZXR3b3JrX2lkPy8AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:red_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAwAACAQAbmFtZRkAbWluZWNyYWZ0OnJlZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaMIlKSCzqSZoAwoAbmV0d29ya19pZHMcAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:orange_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAwAACAQAbmFtZRwAbWluZWNyYWZ0Om9yYW5nZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaG2MAXU67wGrAwoAbmV0d29ya19pZGgsAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:yellow_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAwAACAQAbmFtZRwAbWluZWNyYWZ0OnllbGxvd19zaHVsa2VyX2JveAQJAG5hbWVfaGFzaIsLwQHYjcIEAwoAbmV0d29ya19pZHsAAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:lime_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAwAACAQAbmFtZRoAbWluZWNyYWZ0OmxpbWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hUwBkg+faUGAMKAG5ldHdvcmtfaWQWBAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:green_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAwAACAQAbmFtZRsAbWluZWNyYWZ0OmdyZWVuX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoZgUeT3LupLUDCgBuZXR3b3JrX2lkpS0AAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:cyan_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAwAACAQAbmFtZRoAbWluZWNyYWZ0OmN5YW5fc2h1bGtlcl9ib3gECQBuYW1lX2hhc2gSfbjteXg5yAMKAG5ldHdvcmtfaWTZLwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:light_blue_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2h0VFCX0qsRxQMKAG5ldHdvcmtfaWSXLwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:blue_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hn9gS0XIe6rAMKAG5ldHdvcmtfaWSZLAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:purple_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAwAACAQAbmFtZRwAbWluZWNyYWZ0OnB1cnBsZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaEV/lkNPxRDdAwoAbmV0d29ya19pZAszAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:magenta_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAwAACAQAbmFtZR0AbWluZWNyYWZ0Om1hZ2VudGFfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iqWM7IJHxcFgMKAG5ldHdvcmtfaWTgAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:pink_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBpbmtfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2in1tkJ1GNcZgMKAG5ldHdvcmtfaWQ6HAAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:armor_stand" - }, - { - "id": "minecraft:noteblock", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAAAACAQAbmFtZRMAbWluZWNyYWZ0Om5vdGVibG9jawQJAG5hbWVfaGFzaHPA8dBBH0UaAwoAbmV0d29ya19pZEUEAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:jukebox", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAAAACAQAbmFtZREAbWluZWNyYWZ0Omp1a2Vib3gECQBuYW1lX2hhc2ieAIPExf/ZfgMKAG5ldHdvcmtfaWS1IQAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:music_disc_13" - }, - { - "id": "minecraft:music_disc_cat" - }, - { - "id": "minecraft:music_disc_blocks" - }, - { - "id": "minecraft:music_disc_chirp" - }, - { - "id": "minecraft:music_disc_far" - }, - { - "id": "minecraft:music_disc_mall" - }, - { - "id": "minecraft:music_disc_mellohi" - }, - { - "id": "minecraft:music_disc_stal" - }, - { - "id": "minecraft:music_disc_strad" - }, - { - "id": "minecraft:music_disc_ward" - }, - { - "id": "minecraft:music_disc_11" - }, - { - "id": "minecraft:music_disc_wait" - }, - { - "id": "minecraft:music_disc_otherside" - }, - { - "id": "minecraft:music_disc_5" - }, - { - "id": "minecraft:music_disc_pigstep" - }, - { - "id": "minecraft:music_disc_relic" - }, - { - "id": "minecraft:disc_fragment_5" - }, - { - "id": "minecraft:glowstone_dust" - }, - { - "id": "minecraft:glowstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAAAACAQAbmFtZRMAbWluZWNyYWZ0Omdsb3dzdG9uZQQJAG5hbWVfaGFzaFYqXNkefIlPAwoAbmV0d29ya19pZA0aAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:redstone_lamp", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZHN0b25lX2xhbXAECQBuYW1lX2hhc2hJ9V80caPvEgMKAG5ldHdvcmtfaWSnAgAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:sea_lantern", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNlYV9sYW50ZXJuBAkAbmFtZV9oYXNoLPsv1TX9M+QDCgBuZXR3b3JrX2lkuzMAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:oak_sign" - }, - { - "id": "minecraft:spruce_sign" - }, - { - "id": "minecraft:birch_sign" - }, - { - "id": "minecraft:jungle_sign" - }, - { - "id": "minecraft:acacia_sign" - }, - { - "id": "minecraft:dark_oak_sign" - }, - { - "id": "minecraft:mangrove_sign" - }, - { - "id": "minecraft:cherry_sign" - }, - { - "id": "minecraft:bamboo_sign" - }, - { - "id": "minecraft:crimson_sign" - }, - { - "id": "minecraft:warped_sign" - }, - { - "id": "minecraft:oak_hanging_sign" - }, - { - "id": "minecraft:spruce_hanging_sign" - }, - { - "id": "minecraft:birch_hanging_sign" - }, - { - "id": "minecraft:jungle_hanging_sign" - }, - { - "id": "minecraft:acacia_hanging_sign" - }, - { - "id": "minecraft:dark_oak_hanging_sign" - }, - { - "id": "minecraft:mangrove_hanging_sign" - }, - { - "id": "minecraft:cherry_hanging_sign" - }, - { - "id": "minecraft:bamboo_hanging_sign" - }, - { - "id": "minecraft:crimson_hanging_sign" - }, - { - "id": "minecraft:warped_hanging_sign" - }, - { - "id": "minecraft:painting" - }, - { - "id": "minecraft:frame" - }, - { - "id": "minecraft:glow_frame" - }, - { - "id": "minecraft:honey_bottle" - }, - { - "id": "minecraft:flower_pot" - }, - { - "id": "minecraft:bowl" - }, - { - "id": "minecraft:bucket" - }, - { - "id": "minecraft:milk_bucket" - }, - { - "id": "minecraft:water_bucket" - }, - { - "id": "minecraft:lava_bucket" - }, - { - "id": "minecraft:cod_bucket" - }, - { - "id": "minecraft:salmon_bucket" - }, - { - "id": "minecraft:tropical_fish_bucket" - }, - { - "id": "minecraft:pufferfish_bucket" - }, - { - "id": "minecraft:powder_snow_bucket" - }, - { - "id": "minecraft:axolotl_bucket" - }, - { - "id": "minecraft:tadpole_bucket" - }, - { - "id": "minecraft:skull", - "damage": 3 - }, - { - "id": "minecraft:skull", - "damage": 2 - }, - { - "id": "minecraft:skull", - "damage": 4 - }, - { - "id": "minecraft:skull", - "damage": 5 - }, - { - "id": "minecraft:skull" - }, - { - "id": "minecraft:skull", - "damage": 1 - }, - { - "id": "minecraft:skull", - "damage": 6 - }, - { - "id": "minecraft:beacon", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAAAACAQAbmFtZRAAbWluZWNyYWZ0OmJlYWNvbgQJAG5hbWVfaGFzaACwhhfSkdkHAwoAbmV0d29ya19pZDMCAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:bell", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAQAACAQAbmFtZQ4AbWluZWNyYWZ0OmJlbGwECQBuYW1lX2hhc2iPqsgDXRcsxAMKAG5ldHdvcmtfaWRcLwAACgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAQoAdG9nZ2xlX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:conduit", - "block_state_b64": "CgAAAwgAYmxvY2tfaWScAQAACAQAbmFtZREAbWluZWNyYWZ0OmNvbmR1aXQECQBuYW1lX2hhc2jqxKAxq2EaWQMKAG5ldHdvcmtfaWR1GwAACgYAc3RhdGVzAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stonecutter_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lY3V0dGVyX2Jsb2NrBAkAbmFtZV9oYXNoQAXTbAM3MeYDCgBuZXR3b3JrX2lk2zMAAAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:end_portal_frame", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9wb3J0YWxfZnJhbWUECQBuYW1lX2hhc2gqofyUIjGOpQMKAG5ldHdvcmtfaWTHKwAACgYAc3RhdGVzARIAZW5kX3BvcnRhbF9leWVfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:coal" - }, - { - "id": "minecraft:charcoal" - }, - { - "id": "minecraft:diamond" - }, - { - "id": "minecraft:iron_nugget" - }, - { - "id": "minecraft:raw_iron" - }, - { - "id": "minecraft:raw_gold" - }, - { - "id": "minecraft:raw_copper" - }, - { - "id": "minecraft:copper_ingot" - }, - { - "id": "minecraft:iron_ingot" - }, - { - "id": "minecraft:netherite_scrap" - }, - { - "id": "minecraft:netherite_ingot" - }, - { - "id": "minecraft:gold_nugget" - }, - { - "id": "minecraft:gold_ingot" - }, - { - "id": "minecraft:emerald" - }, - { - "id": "minecraft:quartz" - }, - { - "id": "minecraft:clay_ball" - }, - { - "id": "minecraft:brick" - }, - { - "id": "minecraft:netherbrick" - }, - { - "id": "minecraft:prismarine_shard" - }, - { - "id": "minecraft:amethyst_shard" - }, - { - "id": "minecraft:prismarine_crystals" - }, - { - "id": "minecraft:nautilus_shell" - }, - { - "id": "minecraft:heart_of_the_sea" - }, - { - "id": "minecraft:turtle_scute" - }, - { - "id": "minecraft:phantom_membrane" - }, - { - "id": "minecraft:string" - }, - { - "id": "minecraft:feather" - }, - { - "id": "minecraft:flint" - }, - { - "id": "minecraft:gunpowder" - }, - { - "id": "minecraft:leather" - }, - { - "id": "minecraft:rabbit_hide" - }, - { - "id": "minecraft:rabbit_foot" - }, - { - "id": "minecraft:fire_charge" - }, - { - "id": "minecraft:blaze_rod" - }, - { - "id": "minecraft:blaze_powder" - }, - { - "id": "minecraft:magma_cream" - }, - { - "id": "minecraft:fermented_spider_eye" - }, - { - "id": "minecraft:echo_shard" - }, - { - "id": "minecraft:dragon_breath" - }, - { - "id": "minecraft:shulker_shell" - }, - { - "id": "minecraft:ghast_tear" - }, - { - "id": "minecraft:slime_ball" - }, - { - "id": "minecraft:ender_pearl" - }, - { - "id": "minecraft:ender_eye" - }, - { - "id": "minecraft:nether_star" - }, - { - "id": "minecraft:end_rod", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAAAACAQAbmFtZREAbWluZWNyYWZ0OmVuZF9yb2QECQBuYW1lX2hhc2jx/q5cEA0hmQMKAG5ldHdvcmtfaWQ0KQAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:lightning_rod", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpZ2h0bmluZ19yb2QECQBuYW1lX2hhc2ioXQF1xvfHNQMKAG5ldHdvcmtfaWQ+CgAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:end_crystal" - }, - { - "id": "minecraft:paper" - }, - { - "id": "minecraft:book" - }, - { - "id": "minecraft:writable_book" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" - }, - { - "id": "minecraft:enchanted_book", - "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" - }, - { - "id": "minecraft:oak_boat" - }, - { - "id": "minecraft:spruce_boat" - }, - { - "id": "minecraft:birch_boat" - }, - { - "id": "minecraft:jungle_boat" - }, - { - "id": "minecraft:acacia_boat" - }, - { - "id": "minecraft:dark_oak_boat" - }, - { - "id": "minecraft:mangrove_boat" - }, - { - "id": "minecraft:cherry_boat" - }, - { - "id": "minecraft:bamboo_raft" - }, - { - "id": "minecraft:oak_chest_boat" - }, - { - "id": "minecraft:spruce_chest_boat" - }, - { - "id": "minecraft:birch_chest_boat" - }, - { - "id": "minecraft:jungle_chest_boat" - }, - { - "id": "minecraft:acacia_chest_boat" - }, - { - "id": "minecraft:dark_oak_chest_boat" - }, - { - "id": "minecraft:mangrove_chest_boat" - }, - { - "id": "minecraft:cherry_chest_boat" - }, - { - "id": "minecraft:bamboo_chest_raft" - }, - { - "id": "minecraft:rail", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWQxGgAACgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:golden_rail", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdvbGRlbl9yYWlsBAkAbmFtZV9oYXNoOoV5MaKipoUDCgBuZXR3b3JrX2lklSMAAAoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:detector_rail", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAAAACAQAbmFtZRcAbWluZWNyYWZ0OmRldGVjdG9yX3JhaWwECQBuYW1lX2hhc2gVUk31qOysUQMKAG5ldHdvcmtfaWQGGwAACgYAc3RhdGVzAQ0AcmFpbF9kYXRhX2JpdAADDgByYWlsX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:activator_rail", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjdGl2YXRvcl9yYWlsBAkAbmFtZV9oYXNosIL91qriCRkDCgBuZXR3b3JrX2lkHgQAAAoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:minecart" - }, - { - "id": "minecraft:chest_minecart" - }, - { - "id": "minecraft:hopper_minecart" - }, - { - "id": "minecraft:tnt_minecart" - }, - { - "id": "minecraft:redstone" - }, - { - "id": "minecraft:redstone_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX2Jsb2NrBAkAbmFtZV9oYXNoRhULL0r8o0sDCgBuZXR3b3JrX2lkIxgAAAoGAHN0YXRlcwADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:redstone_torch", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX3RvcmNoBAkAbmFtZV9oYXNoizFRjpYMIDgDCgBuZXR3b3JrX2lkgxUAAAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:lever", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxldmVyBAkAbmFtZV9oYXNoGMJeLJsUMLYDCgBuZXR3b3JrX2lktS0AAAoGAHN0YXRlcwgPAGxldmVyX2RpcmVjdGlvbg4AZG93bl9lYXN0X3dlc3QBCABvcGVuX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wooden_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAAAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWQULQAACgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:spruce_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAQAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9idXR0b24ECQBuYW1lX2hhc2jBW9Z8aYE7YQMKAG5ldHdvcmtfaWT4GwAACgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:birch_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAQAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2J1dHRvbgQJAG5hbWVfaGFzaJXYgGuSHbTwAwoAbmV0d29ya19pZMU0AAAKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:jungle_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAQAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9idXR0b24ECQBuYW1lX2hhc2iCgNANcJs+BQMKAG5ldHdvcmtfaWSAAAAACgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:acacia_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAQAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9idXR0b24ECQBuYW1lX2hhc2gVvmcT7LTO0wMKAG5ldHdvcmtfaWRqMgAACgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dark_oak_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAQAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaIV10ZGGrCIEAwoAbmV0d29ya19pZGYAAAAKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:mangrove_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2J1dHRvbgQJAG5hbWVfaGFzaNzeYYKLgOzJAwoAbmV0d29ya19pZP4vAAAKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cherry_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9idXR0b24ECQBuYW1lX2hhc2j2/IHjeAbUcwMKAG5ldHdvcmtfaWRQHQAACgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bamboo_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19idXR0b24ECQBuYW1lX2hhc2j7AddMi+6nsgMKAG5ldHdvcmtfaWSOLQAACgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2J1dHRvbgQJAG5hbWVfaGFzaM4ejMctmvohAwoAbmV0d29ya19pZEkFAAAKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:crimson_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fYnV0dG9uBAkAbmFtZV9oYXNofnjYHaYIeWgDCgBuZXR3b3JrX2lkdxwAAAoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:warped_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9idXR0b24ECQBuYW1lX2hhc2jwkV2EU6Cn1QMKAG5ldHdvcmtfaWR8MgAACgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:polished_blackstone_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnV0dG9uBAkAbmFtZV9oYXNojmxzQKS0S/EDCgBuZXR3b3JrX2lk3TQAAAoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:tripwire_hook", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaXB3aXJlX2hvb2sECQBuYW1lX2hhc2gQdp+oGZLNnAMKAG5ldHdvcmtfaWR7KQAACgYAc3RhdGVzAQwAYXR0YWNoZWRfYml0AAMJAGRpcmVjdGlvbgAAAAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:wooden_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAAAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZBM2AAAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:spruce_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAQAACAQAbmFtZR8AbWluZWNyYWZ0OnNwcnVjZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNmwuq549fJKAwoAbmV0d29ya19pZBEYAAAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:birch_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAQAACAQAbmFtZR4AbWluZWNyYWZ0OmJpcmNoX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNorQkT9kDdlTwDCgBuZXR3b3JrX2lkNBcAAAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:jungle_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAQAACAQAbmFtZR8AbWluZWNyYWZ0Omp1bmdsZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaJ7DcteCkb8/AwoAbmV0d29ya19pZIoXAAAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:acacia_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAQAACAQAbmFtZR8AbWluZWNyYWZ0OmFjYWNpYV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaC2frZtfoYqCAwoAbmV0d29ya19pZD4jAAAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:dark_oak_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAQAACAQAbmFtZSEAbWluZWNyYWZ0OmRhcmtfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoHUCJsTy52pwDCgBuZXR3b3JrX2lkpSkAAAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:mangrove_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hbmdyb3ZlX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoiDsTfJaX100DCgBuZXR3b3JrX2lk/BkAAAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:cherry_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAwAACAQAbmFtZR8AbWluZWNyYWZ0OmNoZXJyeV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaALMqYEZDUQHAwoAbmV0d29ya19pZJoAAAAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:bamboo_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJhbWJvb19wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNvxJ7NIAaqlAwoAbmV0d29ya19pZM8rAAAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:crimson_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNyaW1zb25fcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2hqBDVDAd31/gMKAG5ldHdvcmtfaWQANwAACgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:warped_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAgAACAQAbmFtZR8AbWluZWNyYWZ0OndhcnBlZF9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaBxFoQksWtYUAwoAbmV0d29ya19pZMECAAAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:stone_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0b25lX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNounJuTBUTrU8DCgBuZXR3b3JrX2lkDhoAAAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:light_weighted_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAAAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoOyOJkNxLtkEDCgBuZXR3b3JrX2lkqRcAAAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:heavy_weighted_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAAAACAQAbmFtZScAbWluZWNyYWZ0OmhlYXZ5X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoltgDmDvTajUDCgBuZXR3b3JrX2lkLQoAAAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:polished_blackstone_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAgAACAQAbmFtZSwAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2h65Ci6/CeGqwMKAG5ldHdvcmtfaWRxLAAACgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:observer", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2VydmVyBAkAbmFtZV9oYXNoYhlh1lpmHTgDCgBuZXR3b3JrX2lkdxUAAAoGAHN0YXRlcwgaAG1pbmVjcmFmdDpmYWNpbmdfZGlyZWN0aW9uBABkb3duAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:daylight_detector", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAAAACAQAbmFtZRsAbWluZWNyYWZ0OmRheWxpZ2h0X2RldGVjdG9yBAkAbmFtZV9oYXNoV0F0s7B7PVgDCgBuZXR3b3JrX2lkUhsAAAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:repeater" - }, - { - "id": "minecraft:comparator" - }, - { - "id": "minecraft:hopper" - }, - { - "id": "minecraft:dropper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AAAACAQAbmFtZREAbWluZWNyYWZ0OmRyb3BwZXIECQBuYW1lX2hhc2joXP7XqU0l3QMKAG5ldHdvcmtfaWQTMwAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgMAAAABDQB0cmlnZ2VyZWRfYml0AAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:dispenser", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRpc3BlbnNlcgQJAG5hbWVfaGFzaP1RR+zAbYP2AwoAbmV0d29ya19pZO81AAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAwAAAAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24BPBQBAA==" - }, - { - "id": "minecraft:piston", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBpc3RvbgQJAG5hbWVfaGFzaDs3AFh1fL0uAwoAbmV0d29ya19pZE0JAAAKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAQAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:sticky_piston", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQdAAAACAQAbmFtZRcAbWluZWNyYWZ0OnN0aWNreV9waXN0b24ECQBuYW1lX2hhc2hPFJFJSiJ0ZQMKAG5ldHdvcmtfaWQrHAAACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgEAAAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:tnt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAAAACAQAbmFtZQ0AbWluZWNyYWZ0OnRudAQJAG5hbWVfaGFzaEYOHwCvJH29AwoAbmV0d29ya19pZIMuAAAKBgBzdGF0ZXMBFABhbGxvd191bmRlcndhdGVyX2JpdAABCwBleHBsb2RlX2JpdAAAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:name_tag" - }, - { - "id": "minecraft:loom", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAQAACAQAbmFtZQ4AbWluZWNyYWZ0Omxvb20ECQBuYW1lX2hhc2i7DKjAXNq8TAMKAG5ldHdvcmtfaWTVGQAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:banner" - }, - { - "id": "minecraft:banner", - "damage": 8 - }, - { - "id": "minecraft:banner", - "damage": 7 - }, - { - "id": "minecraft:banner", - "damage": 15 - }, - { - "id": "minecraft:banner", - "damage": 12 - }, - { - "id": "minecraft:banner", - "damage": 14 - }, - { - "id": "minecraft:banner", - "damage": 1 - }, - { - "id": "minecraft:banner", - "damage": 4 - }, - { - "id": "minecraft:banner", - "damage": 5 - }, - { - "id": "minecraft:banner", - "damage": 13 - }, - { - "id": "minecraft:banner", - "damage": 9 - }, - { - "id": "minecraft:banner", - "damage": 3 - }, - { - "id": "minecraft:banner", - "damage": 11 - }, - { - "id": "minecraft:banner", - "damage": 10 - }, - { - "id": "minecraft:banner", - "damage": 2 - }, - { - "id": "minecraft:banner", - "damage": 6 - }, - { - "id": "minecraft:banner", - "damage": 15, - "nbt_b64": "CgAAAwQAVHlwZQEAAAAA" - }, - { - "id": "minecraft:creeper_banner_pattern" - }, - { - "id": "minecraft:skull_banner_pattern" - }, - { - "id": "minecraft:flower_banner_pattern" - }, - { - "id": "minecraft:mojang_banner_pattern" - }, - { - "id": "minecraft:field_masoned_banner_pattern" - }, - { - "id": "minecraft:bordure_indented_banner_pattern" - }, - { - "id": "minecraft:piglin_banner_pattern" - }, - { - "id": "minecraft:globe_banner_pattern" - }, - { - "id": "minecraft:angler_pottery_sherd" - }, - { - "id": "minecraft:archer_pottery_sherd" - }, - { - "id": "minecraft:arms_up_pottery_sherd" - }, - { - "id": "minecraft:blade_pottery_sherd" - }, - { - "id": "minecraft:brewer_pottery_sherd" - }, - { - "id": "minecraft:burn_pottery_sherd" - }, - { - "id": "minecraft:danger_pottery_sherd" - }, - { - "id": "minecraft:explorer_pottery_sherd" - }, - { - "id": "minecraft:friend_pottery_sherd" - }, - { - "id": "minecraft:heart_pottery_sherd" - }, - { - "id": "minecraft:heartbreak_pottery_sherd" - }, - { - "id": "minecraft:howl_pottery_sherd" - }, - { - "id": "minecraft:miner_pottery_sherd" - }, - { - "id": "minecraft:mourner_pottery_sherd" - }, - { - "id": "minecraft:plenty_pottery_sherd" - }, - { - "id": "minecraft:prize_pottery_sherd" - }, - { - "id": "minecraft:sheaf_pottery_sherd" - }, - { - "id": "minecraft:shelter_pottery_sherd" - }, - { - "id": "minecraft:skull_pottery_sherd" - }, - { - "id": "minecraft:snort_pottery_sherd" - }, - { - "id": "minecraft:netherite_upgrade_smithing_template" - }, - { - "id": "minecraft:sentry_armor_trim_smithing_template" - }, - { - "id": "minecraft:vex_armor_trim_smithing_template" - }, - { - "id": "minecraft:wild_armor_trim_smithing_template" - }, - { - "id": "minecraft:coast_armor_trim_smithing_template" - }, - { - "id": "minecraft:dune_armor_trim_smithing_template" - }, - { - "id": "minecraft:wayfinder_armor_trim_smithing_template" - }, - { - "id": "minecraft:shaper_armor_trim_smithing_template" - }, - { - "id": "minecraft:raiser_armor_trim_smithing_template" - }, - { - "id": "minecraft:host_armor_trim_smithing_template" - }, - { - "id": "minecraft:ward_armor_trim_smithing_template" - }, - { - "id": "minecraft:silence_armor_trim_smithing_template" - }, - { - "id": "minecraft:tide_armor_trim_smithing_template" - }, - { - "id": "minecraft:snout_armor_trim_smithing_template" - }, - { - "id": "minecraft:rib_armor_trim_smithing_template" - }, - { - "id": "minecraft:eye_armor_trim_smithing_template" - }, - { - "id": "minecraft:spire_armor_trim_smithing_template" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_rocket", - "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id": "minecraft:firework_star", - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 8, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 7, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 15, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 12, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 14, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 1, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 4, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 5, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 13, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 9, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 3, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 11, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 10, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 2, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" - }, - { - "id": "minecraft:firework_star", - "damage": 6, - "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" - }, - { - "id": "minecraft:chain" - }, - { - "id": "minecraft:target", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAQAACAQAbmFtZRAAbWluZWNyYWZ0OnRhcmdldAQJAG5hbWVfaGFzaJc66SVbYlaxAwoAbmV0d29ya19pZBMtAAAKBgBzdGF0ZXMAAwcAdmVyc2lvbgE8FAEA" - }, - { - "id": "minecraft:decorated_pot", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAwAACAQAbmFtZRcAbWluZWNyYWZ0OmRlY29yYXRlZF9wb3QECQBuYW1lX2hhc2jjQgckn8VTvwMKAG5ldHdvcmtfaWSWLgAACgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uATwUAQA=" - }, - { - "id": "minecraft:lodestone_compass" - }, - { - "id": "minecraft:wither_spawn_egg" - }, - { - "id": "minecraft:ender_dragon_spawn_egg" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/creative_items.1_20_70.json b/core/src/main/resources/bedrock/creative_items.1_21_0.json similarity index 78% rename from core/src/main/resources/bedrock/creative_items.1_20_70.json rename to core/src/main/resources/bedrock/creative_items.1_21_0.json index ed498b782..4bd0ab60e 100644 --- a/core/src/main/resources/bedrock/creative_items.1_20_70.json +++ b/core/src/main/resources/bedrock/creative_items.1_21_0.json @@ -2,443 +2,443 @@ "items": [ { "id": "minecraft:oak_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19wbGFua3MECQBuYW1lX2hhc2ilMDLR92rQ4wMKAG5ldHdvcmtfaWS2GotyCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19wbGFua3MECQBuYW1lX2hhc2ilMDLR92rQ4wMKAG5ldHdvcmtfaWS2GotyCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:spruce_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAwAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9wbGFua3MECQBuYW1lX2hhc2iumBkmFGFE8gMKAG5ldHdvcmtfaWSo8TFgCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAwAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9wbGFua3MECQBuYW1lX2hhc2iumBkmFGFE8gMKAG5ldHdvcmtfaWSo8TFgCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:birch_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3BsYW5rcwQJAG5hbWVfaGFzaLrrAKJqV2WFAwoAbmV0d29ya19pZL+e3ZAKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3BsYW5rcwQJAG5hbWVfaGFzaLrrAKJqV2WFAwoAbmV0d29ya19pZL+e3ZAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:jungle_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAwAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9wbGFua3MECQBuYW1lX2hhc2iBM3k4T3FAugMKAG5ldHdvcmtfaWSXUmBCCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAwAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9wbGFua3MECQBuYW1lX2hhc2iBM3k4T3FAugMKAG5ldHdvcmtfaWSXUmBCCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:acacia_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAwAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9wbGFua3MECQBuYW1lX2hhc2g60edJxO5/aAMKAG5ldHdvcmtfaWTUXozECgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAwAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9wbGFua3MECQBuYW1lX2hhc2g60edJxO5/aAMKAG5ldHdvcmtfaWTUXozECgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dark_oak_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3BsYW5rcwQJAG5hbWVfaGFzaAr64wkQ9cA7AwoAbmV0d29ya19pZFbMeR0KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3BsYW5rcwQJAG5hbWVfaGFzaAr64wkQ9cA7AwoAbmV0d29ya19pZFbMeR0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mangrove_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3BsYW5rcwQJAG5hbWVfaGFzaPvLtcEA0F8xAwoAbmV0d29ya19pZEvnlCYKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3BsYW5rcwQJAG5hbWVfaGFzaPvLtcEA0F8xAwoAbmV0d29ya19pZEvnlCYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cherry_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9wbGFua3MECQBuYW1lX2hhc2hNIvVh/lVW7gMKAG5ldHdvcmtfaWQTXpRoCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9wbGFua3MECQBuYW1lX2hhc2hNIvVh/lVW7gMKAG5ldHdvcmtfaWQTXpRoCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bamboo_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19wbGFua3MECQBuYW1lX2hhc2gYnjNz7SCCjgMKAG5ldHdvcmtfaWTi8ySSCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19wbGFua3MECQBuYW1lX2hhc2gYnjNz7SCCjgMKAG5ldHdvcmtfaWTi8ySSCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bamboo_mosaic", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWMECQBuYW1lX2hhc2izSEgiMKOp/AMKAG5ldHdvcmtfaWQZ/p8xCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWMECQBuYW1lX2hhc2izSEgiMKOp/AMKAG5ldHdvcmtfaWQZ/p8xCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:crimson_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fcGxhbmtzBAkAbmFtZV9oYXNoJc5IKqNXJnwDCgBuZXR3b3JrX2lkwtJDdQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fcGxhbmtzBAkAbmFtZV9oYXNoJc5IKqNXJnwDCgBuZXR3b3JrX2lkwtJDdQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:warped_planks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9wbGFua3MECQBuYW1lX2hhc2g3yGXEWhe6LgMKAG5ldHdvcmtfaWStTABvCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9wbGFua3MECQBuYW1lX2hhc2g3yGXEWhe6LgMKAG5ldHdvcmtfaWStTABvCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSE4JosCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBjb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSE4JosCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBjb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWTUvV6XCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9jb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWTUvV6XCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9jb2JibGVzdG9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWT4opb2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBncmFuaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWT4opb2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBncmFuaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQAMQTVCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBkaW9yaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQAMQTVCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBwBkaW9yaXRlCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQIbDOcCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCABhbmRlc2l0ZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQIbDOcCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCABhbmRlc2l0ZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSZKhusCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBzYW5kc3RvbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSZKhusCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBzYW5kc3RvbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSp4zgCCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDQByZWRfc2FuZHN0b25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSp4zgCCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDQByZWRfc2FuZHN0b25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRbqVHTCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBzdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRbqVHTCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCwBzdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRr0ZT/CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9zdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRr0ZT/CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEQBtb3NzeV9zdG9uZV9icmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRnLis3CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBQBicmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRnLis3CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlBQBicmljawgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQNLzfSCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDABuZXRoZXJfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQNLzfSCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlDABuZXRoZXJfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQ5h0xwCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEAByZWRfbmV0aGVyX2JyaWNrCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWQ5h0xwCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlEAByZWRfbmV0aGVyX2JyaWNrCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWS9J0B2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBlbmRfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWS9J0B2CgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCQBlbmRfYnJpY2sIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cobblestone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRPbkJeCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCgBwcmlzbWFyaW5lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWRPbkJeCgYAc3RhdGVzCA8Ad2FsbF9ibG9ja190eXBlCgBwcmlzbWFyaW5lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:blackstone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaMP8XppUSU1RAwoAbmV0d29ya19pZMbeBBsKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaMP8XppUSU1RAwoAbmV0d29ya19pZMbeBBsKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_blackstone_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaP6SwV08YwzAAwoAbmV0d29ya19pZAJLsz8KBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaP6SwV08YwzAAwoAbmV0d29ya19pZAJLsz8KBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_blackstone_brick_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBBIDZbHxiEzAwoAbmV0d29ya19pZEbLV8cKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBBIDZbHxiEzAwoAbmV0d29ya19pZEbLV8cKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cobbled_deepslate_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3dhbGwECQBuYW1lX2hhc2iECY5oKxeT+gMKAG5ldHdvcmtfaWRCnPrFCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3dhbGwECQBuYW1lX2hhc2iECY5oKxeT+gMKAG5ldHdvcmtfaWRCnPrFCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:deepslate_tile_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3dhbGwECQBuYW1lX2hhc2jz7N+PeuEXgQMKAG5ldHdvcmtfaWTqw4s4CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3dhbGwECQBuYW1lX2hhc2jz7N+PeuEXgQMKAG5ldHdvcmtfaWTqw4s4CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:polished_deepslate_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV93YWxsBAkAbmFtZV9oYXNoHxjTdj9pevMDCgBuZXR3b3JrX2lkIvBYYwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV93YWxsBAkAbmFtZV9oYXNoHxjTdj9pevMDCgBuZXR3b3JrX2lkIvBYYwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:deepslate_brick_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja193YWxsBAkAbmFtZV9oYXNoEs3EQrjroyEDCgBuZXR3b3JrX2lkwlrCGwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja193YWxsBAkAbmFtZV9oYXNoEs3EQrjroyEDCgBuZXR3b3JrX2lkwlrCGwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:mud_brick_wall", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja193YWxsBAkAbmFtZV9oYXNov9b98ATpUSwDCgBuZXR3b3JrX2lkH/1WZQoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja193YWxsBAkAbmFtZV9oYXNov9b98ATpUSwDCgBuZXR3b3JrX2lkH/1WZQoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:oak_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAAAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZDvPEXcKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAAAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZDvPEXcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:spruce_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAwAACAQAbmFtZRYAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZQQJAG5hbWVfaGFzaPQCm+aX1ZQeAwoAbmV0d29ya19pZD1QUEoKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAwAACAQAbmFtZRYAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZQQJAG5hbWVfaGFzaPQCm+aX1ZQeAwoAbmV0d29ya19pZD1QUEoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:birch_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AwAACAQAbmFtZRUAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlBAkAbmFtZV9oYXNo6CJ2ATpANfgDCgBuZXR3b3JrX2lkmCUV2QoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AwAACAQAbmFtZRUAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlBAkAbmFtZV9oYXNo6CJ2ATpANfgDCgBuZXR3b3JrX2lkmCUV2QoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:jungle_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAwAACAQAbmFtZRYAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZQQJAG5hbWVfaGFzaOX4cD9uAmsdAwoAbmV0d29ya19pZHz1VxkKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAwAACAQAbmFtZRYAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZQQJAG5hbWVfaGFzaOX4cD9uAmsdAwoAbmV0d29ya19pZHz1VxkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:acacia_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AwAACAQAbmFtZRYAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZQQJAG5hbWVfaGFzaGjn+RlKVDH6AwoAbmV0d29ya19pZNVGubwKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AwAACAQAbmFtZRYAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZQQJAG5hbWVfaGFzaGjn+RlKVDH6AwoAbmV0d29ya19pZNVGubwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dark_oak_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAwAACAQAbmFtZRgAbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlBAkAbmFtZV9oYXNoGPj0gCgM0c0DCgBuZXR3b3JrX2lk2w+gEwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAwAACAQAbmFtZRgAbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlBAkAbmFtZV9oYXNoGPj0gCgM0c0DCgBuZXR3b3JrX2lk2w+gEwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:mangrove_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlBAkAbmFtZV9oYXNowwAd7tPu9bsDCgBuZXR3b3JrX2lkKEcd0goGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlBAkAbmFtZV9oYXNowwAd7tPu9bsDCgBuZXR3b3JrX2lkKEcd0goGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cherry_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAwAACAQAbmFtZRYAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZQQJAG5hbWVfaGFzaFmtUfHfTxcxAwoAbmV0d29ya19pZPCBxAIKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAwAACAQAbmFtZRYAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZQQJAG5hbWVfaGFzaFmtUfHfTxcxAwoAbmV0d29ya19pZPCBxAIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:bamboo_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19mZW5jZQQJAG5hbWVfaGFzaCKRbxfXsfkiAwoAbmV0d29ya19pZJNXKFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19mZW5jZQQJAG5hbWVfaGFzaCKRbxfXsfkiAwoAbmV0d29ya19pZJNXKFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:nether_brick_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAAAACAQAbmFtZRwAbWluZWNyYWZ0Om5ldGhlcl9icmlja19mZW5jZQQJAG5hbWVfaGFzaA6030ngawxcAwoAbmV0d29ya19pZLnjLF4KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAAAACAQAbmFtZRwAbWluZWNyYWZ0Om5ldGhlcl9icmlja19mZW5jZQQJAG5hbWVfaGFzaA6030ngawxcAwoAbmV0d29ya19pZLnjLF4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crimson_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2UECQBuYW1lX2hhc2jhUhKv1HGj9AMKAG5ldHdvcmtfaWR3OH3OCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2UECQBuYW1lX2hhc2jhUhKv1HGj9AMKAG5ldHdvcmtfaWR3OH3OCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:warped_fence", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9mZW5jZQQJAG5hbWVfaGFzaJfb3/YuKmOWAwoAbmV0d29ya19pZCpaGC8KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9mZW5jZQQJAG5hbWVfaGFzaJfb3/YuKmOWAwoAbmV0d29ya19pZCpaGC8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAAAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWR+T9kTCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAAAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWR+T9kTCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:spruce_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AAAACAQAbmFtZRsAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoanTVB84HRbkDCgBuZXR3b3JrX2lkEnw5egoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AAAACAQAbmFtZRsAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoanTVB84HRbkDCgBuZXR3b3JrX2lkEnw5egoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:birch_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2jmfPklI8azSwMKAG5ldHdvcmtfaWQL77/BCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2jmfPklI8azSwMKAG5ldHdvcmtfaWQL77/BCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:jungle_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS5AAAACAQAbmFtZRsAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNobYVQkfBomIcDCgBuZXR3b3JrX2lkA1zgtgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS5AAAACAQAbmFtZRsAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNobYVQkfBomIcDCgBuZXR3b3JrX2lkA1zgtgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:acacia_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS7AAAACAQAbmFtZRsAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoZnrLUx/XSekDCgBuZXR3b3JrX2lkHg/kTgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS7AAAACAQAbmFtZRsAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoZnrLUx/XSekDCgBuZXR3b3JrX2lkHg/kTgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dark_oak_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS6AAAACAQAbmFtZR0AbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2j2PTvdJJHcVQMKAG5ldHdvcmtfaWTwjOCeCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS6AAAACAQAbmFtZR0AbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2j2PTvdJJHcVQMKAG5ldHdvcmtfaWTwjOCeCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:mangrove_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2i/kOhBKiI/dAMKAG5ldHdvcmtfaWSfweCSCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2i/kOhBKiI/dAMKAG5ldHdvcmtfaWSfweCSCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cherry_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAwAACAQAbmFtZRsAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoKWLgCk0z+PsDCgBuZXR3b3JrX2lk/9bTZQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAwAACAQAbmFtZRsAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoKWLgCk0z+PsDCgBuZXR3b3JrX2lk/9bTZQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:bamboo_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJhbWJvb19mZW5jZV9nYXRlBAkAbmFtZV9oYXNopH1JrUgwdIADCgBuZXR3b3JrX2lkzIpPywoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJhbWJvb19mZW5jZV9nYXRlBAkAbmFtZV9oYXNopH1JrUgwdIADCgBuZXR3b3JrX2lkzIpPywoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crimson_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2VfZ2F0ZQQJAG5hbWVfaGFzaHE3Gfd0Z2d2AwoAbmV0d29ya19pZDQzVbEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQsAaW5fd2FsbF9iaXQAAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2VfZ2F0ZQQJAG5hbWVfaGFzaHE3Gfd0Z2d2AwoAbmV0d29ya19pZDQzVbEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQsAaW5fd2FsbF9iaXQAAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:warped_fence_gate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoy0oIBjDIG4kDCgBuZXR3b3JrX2lkkf+/3QoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoy0oIBjDIG4kDCgBuZXR3b3JrX2lkkf+/3QoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:normal_stone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAQAACAQAbmFtZR0AbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hAEktZZOkGIwMKAG5ldHdvcmtfaWQeH1ALCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAQAACAQAbmFtZR0AbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hAEktZZOkGIwMKAG5ldHdvcmtfaWQeH1ALCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZDcCv+MKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZDcCv+MKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mossy_cobblestone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSyAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3N0YWlycwQJAG5hbWVfaGFzaMVSTq5z9n1RAwoAbmV0d29ya19pZFIfrhkKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSyAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3N0YWlycwQJAG5hbWVfaGFzaMVSTq5z9n1RAwoAbmV0d29ya19pZFIfrhkKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:oak_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19zdGFpcnMECQBuYW1lX2hhc2jk/HFzdXy0FQMKAG5ldHdvcmtfaWQJjyzBCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19zdGFpcnMECQBuYW1lX2hhc2jk/HFzdXy0FQMKAG5ldHdvcmtfaWQJjyzBCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:spruce_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9zdGFpcnMECQBuYW1lX2hhc2iznygw7uBPBQMKAG5ldHdvcmtfaWTv+is3CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9zdGFpcnMECQBuYW1lX2hhc2iznygw7uBPBQMKAG5ldHdvcmtfaWTv+is3CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:birch_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3N0YWlycwQJAG5hbWVfaGFzaPfhbL619a3GAwoAbmV0d29ya19pZFyPlHAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3N0YWlycwQJAG5hbWVfaGFzaPfhbL619a3GAwoAbmV0d29ya19pZFyPlHAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:jungle_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9zdGFpcnMECQBuYW1lX2hhc2jodJsHUbOVxQMKAG5ldHdvcmtfaWR0z5d4CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9zdGFpcnMECQBuYW1lX2hhc2jodJsHUbOVxQMKAG5ldHdvcmtfaWR0z5d4CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:acacia_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9zdGFpcnMECQBuYW1lX2hhc2h3x1NmD43IqQMKAG5ldHdvcmtfaWS7Jwz6CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9zdGFpcnMECQBuYW1lX2hhc2h3x1NmD43IqQMKAG5ldHdvcmtfaWS7Jwz6CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dark_oak_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3N0YWlycwQJAG5hbWVfaGFzaMfwkbYPbNmAAwoAbmV0d29ya19pZCmBYKAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3N0YWlycwQJAG5hbWVfaGFzaMfwkbYPbNmAAwoAbmV0d29ya19pZCmBYKAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mangrove_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3N0YWlycwQJAG5hbWVfaGFzaNpUDY+uGMpyAwoAbmV0d29ya19pZChzUAsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3N0YWlycwQJAG5hbWVfaGFzaNpUDY+uGMpyAwoAbmV0d29ya19pZChzUAsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cherry_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9zdGFpcnMECQBuYW1lX2hhc2jMtr0v9JY4zwMKAG5ldHdvcmtfaWRQwq31CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9zdGFpcnMECQBuYW1lX2hhc2jMtr0v9JY4zwMKAG5ldHdvcmtfaWRQwq31CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bamboo_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19zdGFpcnMECQBuYW1lX2hhc2jFOzWL8PalKwMKAG5ldHdvcmtfaWTVPh42CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19zdGFpcnMECQBuYW1lX2hhc2jFOzWL8PalKwMKAG5ldHdvcmtfaWTVPh42CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bamboo_mosaic_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc3RhaXJzBAkAbmFtZV9oYXNoNLPiveSHPaoDCgBuZXR3b3JrX2lk44PHjgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc3RhaXJzBAkAbmFtZV9oYXNoNLPiveSHPaoDCgBuZXR3b3JrX2lk44PHjgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAAAACAQAbmFtZRwAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaN6tQViRo5cwAwoAbmV0d29ya19pZDMyMgIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAAAACAQAbmFtZRwAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaN6tQViRo5cwAwoAbmV0d29ya19pZDMyMgIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mossy_stone_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaIB/Zv5YBPuYAwoAbmV0d29ya19pZANTOsMKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaIB/Zv5YBPuYAwoAbmV0d29ya19pZANTOsMKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:sandstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAAAACAQAbmFtZRoAbWluZWNyYWZ0OnNhbmRzdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hOyA0BoYUOPQMKAG5ldHdvcmtfaWSV/834CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAAAACAQAbmFtZRoAbWluZWNyYWZ0OnNhbmRzdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hOyA0BoYUOPQMKAG5ldHdvcmtfaWSV/834CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:smooth_sandstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSwAQAACAQAbmFtZSEAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoB+CuCd8Ruz8DCgBuZXR3b3JrX2lksR+m8QoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSwAQAACAQAbmFtZSEAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoB+CuCd8Ruz8DCgBuZXR3b3JrX2lksR+m8QoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:red_sandstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS0AAAACAQAbmFtZR4AbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoPs0LpHPL24YDCgBuZXR3b3JrX2lkLYVt3woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS0AAAACAQAbmFtZR4AbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoPs0LpHPL24YDCgBuZXR3b3JrX2lkLYVt3woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:smooth_red_sandstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAQAACAQAbmFtZSUAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3N0YWlycwQJAG5hbWVfaGFzaBvjtQv5pf+MAwoAbmV0d29ya19pZMHNND8KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAQAACAQAbmFtZSUAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3N0YWlycwQJAG5hbWVfaGFzaBvjtQv5pf+MAwoAbmV0d29ya19pZMHNND8KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:granite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAQAACAQAbmFtZRgAbWluZWNyYWZ0OmdyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNoGzpvtoqKQjgDCgBuZXR3b3JrX2lkPkcB1goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAQAACAQAbmFtZRgAbWluZWNyYWZ0OmdyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNoGzpvtoqKQjgDCgBuZXR3b3JrX2lkPkcB1goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_granite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNo3PvbSfEQklIDCgBuZXR3b3JrX2lkMmEm3AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNo3PvbSfEQklIDCgBuZXR3b3JrX2lkMmEm3AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:diorite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAQAACAQAbmFtZRgAbWluZWNyYWZ0OmRpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoi73T8VQuZmcDCgBuZXR3b3JrX2lk6i6nBQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAQAACAQAbmFtZRgAbWluZWNyYWZ0OmRpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoi73T8VQuZmcDCgBuZXR3b3JrX2lk6i6nBQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_diorite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoFKRJd5Wk5L0DCgBuZXR3b3JrX2lkbt2ioAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoFKRJd5Wk5L0DCgBuZXR3b3JrX2lkbt2ioAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:andesite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaO5w2FKBw76EAwoAbmV0d29ya19pZKhXEgUKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaO5w2FKBw76EAwoAbmV0d29ya19pZKhXEgUKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:polished_andesite_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWStAQAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaNcZZ/zmLInIAwoAbmV0d29ya19pZJTHrlEKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAQAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaNcZZ/zmLInIAwoAbmV0d29ya19pZJTHrlEKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJyaWNrX3N0YWlycwQJAG5hbWVfaGFzaMyt+cRDk5O2AwoAbmV0d29ya19pZNeMh58KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJyaWNrX3N0YWlycwQJAG5hbWVfaGFzaMyt+cRDk5O2AwoAbmV0d29ya19pZNeMh58KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:nether_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAAAACAQAbmFtZR0AbWluZWNyYWZ0Om5ldGhlcl9icmlja19zdGFpcnMECQBuYW1lX2hhc2jRqIoOXgifBAMKAG5ldHdvcmtfaWQDiw5yCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAAAACAQAbmFtZR0AbWluZWNyYWZ0Om5ldGhlcl9icmlja19zdGFpcnMECQBuYW1lX2hhc2jRqIoOXgifBAMKAG5ldHdvcmtfaWQDiw5yCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:red_nether_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AQAACAQAbmFtZSEAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNogQvosSbcj7kDCgBuZXR3b3JrX2lkx2IMtAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AQAACAQAbmFtZSEAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNogQvosSbcj7kDCgBuZXR3b3JrX2lkx2IMtAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:end_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSxAQAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2hmlAk+QhsUsQMKAG5ldHdvcmtfaWTN7KFaCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSxAQAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2hmlAk+QhsUsQMKAG5ldHdvcmtfaWTN7KFaCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:quartz_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWScAAAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9zdGFpcnMECQBuYW1lX2hhc2hmvpvOqGi6egMKAG5ldHdvcmtfaWRmUTh7CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAAAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9zdGFpcnMECQBuYW1lX2hhc2hmvpvOqGi6egMKAG5ldHdvcmtfaWRmUTh7CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:smooth_quartz_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AQAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc3RhaXJzBAkAbmFtZV9oYXNoNZZ9rX0qZOsDCgBuZXR3b3JrX2lkzsgQyQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AQAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc3RhaXJzBAkAbmFtZV9oYXNoNZZ9rX0qZOsDCgBuZXR3b3JrX2lkzsgQyQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:purpur_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAAAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9zdGFpcnMECQBuYW1lX2hhc2ifwDxeezXD7gMKAG5ldHdvcmtfaWTT+rxiCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAAAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9zdGFpcnMECQBuYW1lX2hhc2ifwDxeezXD7gMKAG5ldHdvcmtfaWTT+rxiCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:prismarine_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAQAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfc3RhaXJzBAkAbmFtZV9oYXNooTHSZ+IrYtcDCgBuZXR3b3JrX2lkxTJfeAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAQAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfc3RhaXJzBAkAbmFtZV9oYXNooTHSZ+IrYtcDCgBuZXR3b3JrX2lkxTJfeAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:dark_prismarine_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAQAACAQAbmFtZSAAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zdGFpcnMECQBuYW1lX2hhc2hIciLmam4o4AMKAG5ldHdvcmtfaWTVu7TCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAQAACAQAbmFtZSAAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zdGFpcnMECQBuYW1lX2hhc2hIciLmam4o4AMKAG5ldHdvcmtfaWTVu7TCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:prismarine_bricks_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAQAACAQAbmFtZSIAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzX3N0YWlycwQJAG5hbWVfaGFzaNIjq1oBlZMMAwoAbmV0d29ya19pZGEFwLYKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAQAACAQAbmFtZSIAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzX3N0YWlycwQJAG5hbWVfaGFzaNIjq1oBlZMMAwoAbmV0d29ya19pZGEFwLYKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crimson_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fc3RhaXJzBAkAbmFtZV9oYXNoZJqIzCBpCq4DCgBuZXR3b3JrX2lktXE00AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fc3RhaXJzBAkAbmFtZV9oYXNoZJqIzCBpCq4DCgBuZXR3b3JrX2lktXE00AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:warped_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9zdGFpcnMECQBuYW1lX2hhc2hOkY27jLD4RQMKAG5ldHdvcmtfaWQ+E5VrCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9zdGFpcnMECQBuYW1lX2hhc2hOkY27jLD4RQMKAG5ldHdvcmtfaWQ+E5VrCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:blackstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNokdoUb76p9McDCgBuZXR3b3JrX2lk5fWI5goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNokdoUb76p9McDCgBuZXR3b3JrX2lk5fWI5goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_blackstone_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNolCFtFIE8MmADCgBuZXR3b3JrX2lkGTf7sgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNolCFtFIE8MmADCgBuZXR3b3JrX2lkGTf7sgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_blackstone_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAgAACAQAbmFtZSoAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNonks6UlfpOmkDCgBuZXR3b3JrX2lkgYeOdAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAgAACAQAbmFtZSoAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNonks6UlfpOmkDCgBuZXR3b3JrX2lkgYeOdAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAgAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoHfoAXYq5G3MDCgBuZXR3b3JrX2lkeetf7woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAgAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoHfoAXYq5G3MDCgBuZXR3b3JrX2lkeetf7woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:exposed_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAgAACAQAbmFtZSMAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2howneQGtZ9cgMKAG5ldHdvcmtfaWSg73zdCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAgAACAQAbmFtZSMAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2howneQGtZ9cgMKAG5ldHdvcmtfaWSg73zdCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:weathered_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAgAACAQAbmFtZSUAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaP+R5loXxrVgAwoAbmV0d29ya19pZOnbRf4KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAgAACAQAbmFtZSUAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaP+R5loXxrVgAwoAbmV0d29ya19pZOnbRf4KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:oxidized_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAgAACAQAbmFtZSQAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNo6Jeoq5rsPxsDCgBuZXR3b3JrX2lkmRjDnQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAgAACAQAbmFtZSQAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNo6Jeoq5rsPxsDCgBuZXR3b3JrX2lkmRjDnQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:waxed_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAgAACAQAbmFtZSEAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoh07CQj0/SR8DCgBuZXR3b3JrX2lkmYqoqAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAgAACAQAbmFtZSEAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoh07CQj0/SR8DCgBuZXR3b3JrX2lkmYqoqAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:waxed_exposed_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2guVct1ilmxTwMKAG5ldHdvcmtfaWQgCPROCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2guVct1ilmxTwMKAG5ldHdvcmtfaWQgCPROCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:waxed_weathered_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAgAACAQAbmFtZSsAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaPXC8Sz/phCpAwoAbmV0d29ya19pZHlwHVsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAgAACAQAbmFtZSsAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaPXC8Sz/phCpAwoAbmV0d29ya19pZHlwHVsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:waxed_oxidized_cut_copper_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS/AgAACAQAbmFtZSoAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoaqGdkuhxVZUDCgBuZXR3b3JrX2lkYQXzzgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS/AgAACAQAbmFtZSoAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoaqGdkuhxVZUDCgBuZXR3b3JrX2lkYQXzzgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cobbled_deepslate_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AgAACAQAbmFtZSIAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3N0YWlycwQJAG5hbWVfaGFzaPIfa+TpyJcIAwoAbmV0d29ya19pZJUvOYIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AgAACAQAbmFtZSIAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3N0YWlycwQJAG5hbWVfaGFzaPIfa+TpyJcIAwoAbmV0d29ya19pZJUvOYIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:deepslate_tile_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3N0YWlycwQJAG5hbWVfaGFzaGFRFzB72mN2AwoAbmV0d29ya19pZJEOgIsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3N0YWlycwQJAG5hbWVfaGFzaGFRFzB72mN2AwoAbmV0d29ya19pZJEOgIsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:polished_deepslate_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAgAACAQAbmFtZSMAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zdGFpcnMECQBuYW1lX2hhc2iNCYxVik9sGAMKAG5ldHdvcmtfaWSRVPnYCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAgAACAQAbmFtZSMAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zdGFpcnMECQBuYW1lX2hhc2iNCYxVik9sGAMKAG5ldHdvcmtfaWSRVPnYCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:deepslate_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zdGFpcnMECQBuYW1lX2hhc2hIasOahEf83wMKAG5ldHdvcmtfaWQ1qEDCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zdGFpcnMECQBuYW1lX2hhc2hIasOahEf83wMKAG5ldHdvcmtfaWQ1qEDCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:mud_brick_stairs", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAgAACAQAbmFtZRoAbWluZWNyYWZ0Om11ZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2gt3qxK1NWajAMKAG5ldHdvcmtfaWSm9N3MCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAgAACAQAbmFtZRoAbWluZWNyYWZ0Om11ZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2gt3qxK1NWajAMKAG5ldHdvcmtfaWSm9N3MCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:wooden_door" @@ -478,1575 +478,1727 @@ }, { "id": "minecraft:trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAAAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkyTAWkAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAAAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkyTAWkAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:spruce_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAQAACAQAbmFtZRkAbWluZWNyYWZ0OnNwcnVjZV90cmFwZG9vcgQJAG5hbWVfaGFzaOwlfbgBkUW4AwoAbmV0d29ya19pZPHy1K0KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAQAACAQAbmFtZRkAbWluZWNyYWZ0OnNwcnVjZV90cmFwZG9vcgQJAG5hbWVfaGFzaOwlfbgBkUW4AwoAbmV0d29ya19pZPHy1K0KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:birch_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAQAACAQAbmFtZRgAbWluZWNyYWZ0OmJpcmNoX3RyYXBkb29yBAkAbmFtZV9oYXNoSLtLweOLJ7wDCgBuZXR3b3JrX2lkeJWDfgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAQAACAQAbmFtZRgAbWluZWNyYWZ0OmJpcmNoX3RyYXBkb29yBAkAbmFtZV9oYXNoSLtLweOLJ7wDCgBuZXR3b3JrX2lkeJWDfgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:jungle_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAQAACAQAbmFtZRkAbWluZWNyYWZ0Omp1bmdsZV90cmFwZG9vcgQJAG5hbWVfaGFzaDP/TnM9wyCIAwoAbmV0d29ya19pZEy2fJoKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAQAACAQAbmFtZRkAbWluZWNyYWZ0Omp1bmdsZV90cmFwZG9vcgQJAG5hbWVfaGFzaDP/TnM9wyCIAwoAbmV0d29ya19pZEy2fJoKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:acacia_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFjYWNpYV90cmFwZG9vcgQJAG5hbWVfaGFzaMj8xi3vmEKOAwoAbmV0d29ya19pZOHj8E8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFjYWNpYV90cmFwZG9vcgQJAG5hbWVfaGFzaMj8xi3vmEKOAwoAbmV0d29ya19pZOHj8E8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:dark_oak_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAQAACAQAbmFtZRsAbWluZWNyYWZ0OmRhcmtfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNomB2GGJQ2aOMDCgBuZXR3b3JrX2lko5ZHTwoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAQAACAQAbmFtZRsAbWluZWNyYWZ0OmRhcmtfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNomB2GGJQ2aOMDCgBuZXR3b3JrX2lko5ZHTwoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:mangrove_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAgAACAQAbmFtZRsAbWluZWNyYWZ0Om1hbmdyb3ZlX3RyYXBkb29yBAkAbmFtZV9oYXNooV3kQsQUUmkDCgBuZXR3b3JrX2lkkF/mxAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAgAACAQAbmFtZRsAbWluZWNyYWZ0Om1hbmdyb3ZlX3RyYXBkb29yBAkAbmFtZV9oYXNooV3kQsQUUmkDCgBuZXR3b3JrX2lkkF/mxAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cherry_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoZXJyeV90cmFwZG9vcgQJAG5hbWVfaGFzaH/PefpfdHgtAwoAbmV0d29ya19pZOA7eNgKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoZXJyeV90cmFwZG9vcgQJAG5hbWVfaGFzaH/PefpfdHgtAwoAbmV0d29ya19pZOA7eNgKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:bamboo_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJhbWJvb190cmFwZG9vcgQJAG5hbWVfaGFzaJrEOpsTwtKCAwoAbmV0d29ya19pZLvbPz8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJhbWJvb190cmFwZG9vcgQJAG5hbWVfaGFzaJrEOpsTwtKCAwoAbmV0d29ya19pZLvbPz8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:iron_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAAAACAQAbmFtZRcAbWluZWNyYWZ0Omlyb25fdHJhcGRvb3IECQBuYW1lX2hhc2gwA+IumsEiGQMKAG5ldHdvcmtfaWTvSVl/CgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAAAACAQAbmFtZRcAbWluZWNyYWZ0Omlyb25fdHJhcGRvb3IECQBuYW1lX2hhc2gwA+IumsEiGQMKAG5ldHdvcmtfaWTvSVl/CgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crimson_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AQAACAQAbmFtZRoAbWluZWNyYWZ0OmNyaW1zb25fdHJhcGRvb3IECQBuYW1lX2hhc2jHXufTnwUkYgMKAG5ldHdvcmtfaWQLjMYVCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AQAACAQAbmFtZRoAbWluZWNyYWZ0OmNyaW1zb25fdHJhcGRvb3IECQBuYW1lX2hhc2jHXufTnwUkYgMKAG5ldHdvcmtfaWQLjMYVCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:warped_trapdoor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AQAACAQAbmFtZRkAbWluZWNyYWZ0OndhcnBlZF90cmFwZG9vcgQJAG5hbWVfaGFzaA20wG/+vkd6AwoAbmV0d29ya19pZHKR/hYKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AQAACAQAbmFtZRkAbWluZWNyYWZ0OndhcnBlZF90cmFwZG9vcgQJAG5hbWVfaGFzaA20wG/+vkd6AwoAbmV0d29ya19pZHKR/hYKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:iron_bars", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAAAACAQAbmFtZRMAbWluZWNyYWZ0Omlyb25fYmFycwQJAG5hbWVfaGFzaPuefWSNAe56AwoAbmV0d29ya19pZN2LB5IKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAAAACAQAbmFtZRMAbWluZWNyYWZ0Omlyb25fYmFycwQJAG5hbWVfaGFzaPuefWSNAe56AwoAbmV0d29ya19pZN2LB5IKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lk0hdLNwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lk0hdLNwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:white_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAAAACAQAbmFtZR0AbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iHubqoMbu9fAMKAG5ldHdvcmtfaWRndBrUCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAAAACAQAbmFtZR0AbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iHubqoMbu9fAMKAG5ldHdvcmtfaWRndBrUCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:light_gray_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaKKa+LrRsHQhAwoAbmV0d29ya19pZEv2giYKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaKKa+LrRsHQhAwoAbmV0d29ya19pZEv2giYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:gray_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAwAACAQAbmFtZRwAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaIETy7Y/HZREAwoAbmV0d29ya19pZDomVrUKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAwAACAQAbmFtZRwAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaIETy7Y/HZREAwoAbmV0d29ya19pZDomVrUKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:black_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iV6BCwpfDMmwMKAG5ldHdvcmtfaWSV7doJCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iV6BCwpfDMmwMKAG5ldHdvcmtfaWSV7doJCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:brown_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2igsEiq5np8JgMKAG5ldHdvcmtfaWRMzE/lCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2igsEiq5np8JgMKAG5ldHdvcmtfaWRMzE/lCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:red_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWStAwAACAQAbmFtZRsAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoCa2J12/lQoIDCgBuZXR3b3JrX2lk283lWAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAwAACAQAbmFtZRsAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoCa2J12/lQoIDCgBuZXR3b3JrX2lk283lWAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:orange_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAwAACAQAbmFtZR4AbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNozgjAuvzhxGsDCgBuZXR3b3JrX2lkW5CkhQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAwAACAQAbmFtZR4AbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNozgjAuvzhxGsDCgBuZXR3b3JrX2lkW5CkhQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:yellow_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAwAACAQAbmFtZR4AbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNo7EbHMd5WVugDCgBuZXR3b3JrX2lkkdDyXQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAwAACAQAbmFtZR4AbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNo7EbHMd5WVugDCgBuZXR3b3JrX2lkkdDyXQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:lime_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAwAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBtZA1nZtwcFAwoAbmV0d29ya19pZDxX85UKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAwAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBtZA1nZtwcFAwoAbmV0d29ya19pZDxX85UKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:green_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAwAACAQAbmFtZR0AbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2h91ptDgbehWwMKAG5ldHdvcmtfaWTlDhnECgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAwAACAQAbmFtZR0AbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2h91ptDgbehWwMKAG5ldHdvcmtfaWTlDhnECgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cyan_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAwAACAQAbmFtZRwAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBkIYQ8nQLqbAwoAbmV0d29ya19pZOL1lHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAwAACAQAbmFtZRwAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBkIYQ8nQLqbAwoAbmV0d29ya19pZOL1lHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:light_blue_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaLt05n1G0fiSAwoAbmV0d29ya19pZNbwulIKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaLt05n1G0fiSAwoAbmV0d29ya19pZNbwulIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:blue_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaPhLocSfzduRAwoAbmV0d29ya19pZENsjFwKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaPhLocSfzduRAwoAbmV0d29ya19pZENsjFwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:purple_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAwAACAQAbmFtZR4AbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoJk0DhRO0szUDCgBuZXR3b3JrX2lkD98ZxgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAwAACAQAbmFtZR4AbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoJk0DhRO0szUDCgBuZXR3b3JrX2lkD98ZxgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:magenta_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAwAACAQAbmFtZR8AbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaFEDeFiJj3zSAwoAbmV0d29ya19pZG+iFRoKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAwAACAQAbmFtZR8AbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaFEDeFiJj3zSAwoAbmV0d29ya19pZG+iFRoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:pink_stained_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaDijTX87ywxhAwoAbmV0d29ya19pZKdEricKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaDijTX87ywxhAwoAbmV0d29ya19pZKdEricKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:tinted_glass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAgAACAQAbmFtZRYAbWluZWNyYWZ0OnRpbnRlZF9nbGFzcwQJAG5hbWVfaGFzaAFZWSamk6KdAwoAbmV0d29ya19pZGSvWX8KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAgAACAQAbmFtZRYAbWluZWNyYWZ0OnRpbnRlZF9nbGFzcwQJAG5hbWVfaGFzaAFZWSamk6KdAwoAbmV0d29ya19pZGSvWX8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWRGwixuCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWRGwixuCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:white_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAAAACAQAbmFtZSIAbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaHgxQmgJVtRrAwoAbmV0d29ya19pZBEr/DYKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAAAACAQAbmFtZSIAbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaHgxQmgJVtRrAwoAbmV0d29ya19pZBEr/DYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:light_gray_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNon0aQw9lNkSEDCgBuZXR3b3JrX2lk9dp5VgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNon0aQw9lNkSEDCgBuZXR3b3JrX2lk9dp5VgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:gray_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAwAACAQAbmFtZSEAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNors74IIw+2MMDCgBuZXR3b3JrX2lkmrGO5woGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAwAACAQAbmFtZSEAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNors74IIw+2MMDCgBuZXR3b3JrX2lkmrGO5woGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:black_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaOK/5ZRRd+M1AwoAbmV0d29ya19pZDv++oQKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaOK/5ZRRd+M1AwoAbmV0d29ya19pZDv++oQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:brown_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaLHeGJyRFTIWAwoAbmV0d29ya19pZMz9L0wKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaLHeGJyRFTIWAwoAbmV0d29ya19pZMz9L0wKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:red_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAwAACAQAbmFtZSAAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2gGr4x6JheAywMKAG5ldHdvcmtfaWQBjCTmCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAwAACAQAbmFtZSAAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2gGr4x6JheAywMKAG5ldHdvcmtfaWQBjCTmCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:orange_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAwAACAQAbmFtZSMAbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hbHxPD2gEbEAMKAG5ldHdvcmtfaWSt/7a5CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAwAACAQAbmFtZSMAbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hbHxPD2gEbEAMKAG5ldHdvcmtfaWSt/7a5CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:yellow_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAwAACAQAbmFtZSMAbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2g9tl4aOCyZBwMKAG5ldHdvcmtfaWTXRAS7CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAwAACAQAbmFtZSMAbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2g9tl4aOCyZBwMKAG5ldHdvcmtfaWTXRAS7CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:lime_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAwAACAQAbmFtZSEAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3CtUyLwoGegDCgBuZXR3b3JrX2lkYJDnggoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAwAACAQAbmFtZSEAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3CtUyLwoGegDCgBuZXR3b3JrX2lkYJDnggoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:green_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAwAACAQAbmFtZSIAbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaJo6YP7IMy9SAwoAbmV0d29ya19pZHOnixoKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAwAACAQAbmFtZSIAbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaJo6YP7IMy9SAwoAbmV0d29ya19pZHOnixoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cyan_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAwAACAQAbmFtZSEAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoti97c6QrbLQDCgBuZXR3b3JrX2lkUqFUeQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAwAACAQAbmFtZSEAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoti97c6QrbLQDCgBuZXR3b3JrX2lkUqFUeQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:light_blue_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNovDg/gQle104DCgBuZXR3b3JrX2lkFuy4MQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNovDg/gQle104DCgBuZXR3b3JrX2lkFuy4MQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:blue_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAwAACAQAbmFtZSEAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoGc57tiexbQMDCgBuZXR3b3JrX2lk1eBLUAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAwAACAQAbmFtZSEAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoGc57tiexbQMDCgBuZXR3b3JrX2lk1eBLUAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:purple_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAwAACAQAbmFtZSMAbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hDJHYdd0FdfQMKAG5ldHdvcmtfaWSNsdK5CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAwAACAQAbmFtZSMAbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hDJHYdd0FdfQMKAG5ldHdvcmtfaWSNsdK5CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:magenta_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAwAACAQAbmFtZSQAbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3pcOw5bs5XoDCgBuZXR3b3JrX2lkVbOR7AoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAwAACAQAbmFtZSQAbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3pcOw5bs5XoDCgBuZXR3b3JrX2lkVbOR7AoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:pink_stained_glass_pane", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAwAACAQAbmFtZSEAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoWRhSACMWgswDCgBuZXR3b3JrX2lkIR92xwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAwAACAQAbmFtZSEAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoWRhSACMWgswDCgBuZXR3b3JrX2lkIR92xwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:ladder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxhZGRlcgQJAG5hbWVfaGFzaKBhqheJVOz+AwoAbmV0d29ya19pZCgvzlsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxhZGRlcgQJAG5hbWVfaGFzaKBhqheJVOz+AwoAbmV0d29ya19pZCgvzlsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:scaffolding", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNjYWZmb2xkaW5nBAkAbmFtZV9oYXNoYrkevrqcljwDCgBuZXR3b3JrX2lkD13mlAoGAHN0YXRlcwMJAHN0YWJpbGl0eQAAAAABDwBzdGFiaWxpdHlfY2hlY2sAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNjYWZmb2xkaW5nBAkAbmFtZV9oYXNoYrkevrqcljwDCgBuZXR3b3JrX2lkD13mlAoGAHN0YXRlcwMJAHN0YWJpbGl0eQAAAAABDwBzdGFiaWxpdHlfY2hlY2sAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWTkNl0JCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAc21vb3RoX3N0b25lAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:smooth_stone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRsAbWluZWNyYWZ0OnNtb290aF9zdG9uZV9zbGFiBAkAbmFtZV9oYXNon5I1yVw74uMDCgBuZXR3b3JrX2lkqvjcBQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkQJoxlgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNAUAc3RvbmUAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkQJoxlgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNAUAc3RvbmUAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWRHh04KCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAY29iYmxlc3RvbmUAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:cobblestone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoBAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3NsYWIECQBuYW1lX2hhc2h5CXtW7vlQVgMKAG5ldHdvcmtfaWRDGyj2CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkVRZB+woGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhEAbW9zc3lfY29iYmxlc3RvbmUAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkVRZB+woGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhEAbW9zc3lfY29iYmxlc3RvbmUAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:oak_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha19zbGFiBAkAbmFtZV9oYXNoJp1Cp1M4jlwDCgBuZXR3b3JrX2lkZH6+owoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha19zbGFiBAkAbmFtZV9oYXNoJp1Cp1M4jlwDCgBuZXR3b3JrX2lkZH6+owoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:spruce_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQjBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV9zbGFiBAkAbmFtZV9oYXNodQi70jB238cDCgBuZXR3b3JrX2lkrriOYQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV9zbGFiBAkAbmFtZV9oYXNodQi70jB238cDCgBuZXR3b3JrX2lkrriOYQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:birch_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQkBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3NsYWIECQBuYW1lX2hhc2gZPpfMxoOsTAMKAG5ldHdvcmtfaWThR9jyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3NsYWIECQBuYW1lX2hhc2gZPpfMxoOsTAMKAG5ldHdvcmtfaWThR9jyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:jungle_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQlBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV9zbGFiBAkAbmFtZV9oYXNo6gLs79NXak4DCgBuZXR3b3JrX2lk5ZiKgwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV9zbGFiBAkAbmFtZV9oYXNo6gLs79NXak4DCgBuZXR3b3JrX2lk5ZiKgwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:acacia_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV9zbGFiBAkAbmFtZV9oYXNomSdFmDnv4OUDCgBuZXR3b3JrX2lkHttaXAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV9zbGFiBAkAbmFtZV9oYXNomSdFmDnv4OUDCgBuZXR3b3JrX2lkHttaXAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dark_oak_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQnBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3NsYWIECQBuYW1lX2hhc2hJjTohRFyhIQMKAG5ldHdvcmtfaWRMzDTyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3NsYWIECQBuYW1lX2hhc2hJjTohRFyhIQMKAG5ldHdvcmtfaWRMzDTyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:mangrove_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWToAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3NsYWIECQBuYW1lX2hhc2jYCcmhJPeNMwMKAG5ldHdvcmtfaWQx6U1yCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3NsYWIECQBuYW1lX2hhc2jYCcmhJPeNMwMKAG5ldHdvcmtfaWQx6U1yCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cherry_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV9zbGFiBAkAbmFtZV9oYXNoTt0MmVn/mqoDCgBuZXR3b3JrX2lk2VVsZQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV9zbGFiBAkAbmFtZV9oYXNoTt0MmVn/mqoDCgBuZXR3b3JrX2lk2VVsZQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:bamboo_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJhbWJvb19zbGFiBAkAbmFtZV9oYXNoo1xuFqINeLYDCgBuZXR3b3JrX2lkVC+0twoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJhbWJvb19zbGFiBAkAbmFtZV9oYXNoo1xuFqINeLYDCgBuZXR3b3JrX2lkVC+0twoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:bamboo_mosaic_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc2xhYgQJAG5hbWVfaGFzaNbVRBZ/ChI3AwoAbmV0d29ya19pZOLZHFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc2xhYgQJAG5hbWVfaGFzaNbVRBZ/ChI3AwoAbmV0d29ya19pZOLZHFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWQSiInOCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQsAc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:stone_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqBAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3NsYWIECQBuYW1lX2hhc2js6EexuKuzrQMKAG5ldHdvcmtfaWRSsMxaCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkoF89tgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAbW9zc3lfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkoF89tgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAbW9zc3lfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWSkoAE4CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQkAc2FuZHN0b25lAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:sandstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnBAAACAQAbmFtZRgAbWluZWNyYWZ0OnNhbmRzdG9uZV9zbGFiBAkAbmFtZV9oYXNo/GMI0MZnrhsDCgBuZXR3b3JrX2lkFP8WmwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkWfF7pgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0AY3V0X3NhbmRzdG9uZQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkWfF7pgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0AY3V0X3NhbmRzdG9uZQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkbKRChAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAc21vb3RoX3NhbmRzdG9uZQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkbKRChAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAc21vb3RoX3NhbmRzdG9uZQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkBlrvqAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg0AcmVkX3NhbmRzdG9uZQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkBlrvqAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg0AcmVkX3NhbmRzdG9uZQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkRWFXuwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAY3V0X3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkRWFXuwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNBEAY3V0X3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkom8neQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxQAc21vb3RoX3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkom8neQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxQAc21vb3RoX3JlZF9zYW5kc3RvbmUAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkd1ZaWgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZ3Jhbml0ZQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkd1ZaWgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZ3Jhbml0ZQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkISH4iwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZ3Jhbml0ZQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkISH4iwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZ3Jhbml0ZQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkqxEDMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZGlvcml0ZQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkqxEDMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwcAZGlvcml0ZQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkSYs86QoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZGlvcml0ZQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkSYs86QoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxAAcG9saXNoZWRfZGlvcml0ZQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkq6BU6goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwgAYW5kZXNpdGUAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkq6BU6goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMwgAYW5kZXNpdGUAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkTSXY8AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxEAcG9saXNoZWRfYW5kZXNpdGUAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkTSXY8AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMxEAcG9saXNoZWRfYW5kZXNpdGUAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWQiYHKTCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQUAYnJpY2sAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJyaWNrX3NsYWIECQBuYW1lX2hhc2hO/Da4jU2v4wMKAG5ldHdvcmtfaWRG/qphCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWTk/0LfCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQwAbmV0aGVyX2JyaWNrAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:nether_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsBAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl9icmlja19zbGFiBAkAbmFtZV9oYXNonymoa2zbbqMDCgBuZXR3b3JrX2lkquvR1QoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk/hXQ7AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcmVkX25ldGhlcl9icmljawADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk/hXQ7AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcmVkX25ldGhlcl9icmljawADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab3", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkYJNxrwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMw8AZW5kX3N0b25lX2JyaWNrAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIzBAkAbmFtZV9oYXNoMw3274NQmpMDCgBuZXR3b3JrX2lkYJNxrwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMw8AZW5kX3N0b25lX2JyaWNrAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:stone_block_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIECQBuYW1lX2hhc2gAP8n+Ya6BWgMKAG5ldHdvcmtfaWRlj0/sCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQgPAHN0b25lX3NsYWJfdHlwZQYAcXVhcnR6AAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:quartz_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrBAAACAQAbmFtZRUAbWluZWNyYWZ0OnF1YXJ0el9zbGFiBAkAbmFtZV9oYXNo9JMj3upfsbwDCgBuZXR3b3JrX2lkn2g2VAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stone_block_slab4", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkMae+2goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0Ac21vb3RoX3F1YXJ0egADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWI0BAkAbmFtZV9oYXNoNA3274NQmpMDCgBuZXR3b3JrX2lkMae+2goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfNA0Ac21vb3RoX3F1YXJ0egADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk+kMHGAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMgYAcHVycHVyAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk+kMHGAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMgYAcHVycHVyAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkKOSOMAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9yb3VnaAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkKOSOMAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9yb3VnaAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk8igLCQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg8AcHJpc21hcmluZV9kYXJrAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lk8igLCQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMg8AcHJpc21hcmluZV9kYXJrAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stone_block_slab2", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkSFbyEwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9icmljawADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lX2Jsb2NrX3NsYWIyBAkAbmFtZV9oYXNoMg3274NQmpMDCgBuZXR3b3JrX2lkSFbyEwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20IEQBzdG9uZV9zbGFiX3R5cGVfMhAAcHJpc21hcmluZV9icmljawADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:crimson_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc2xhYgQJAG5hbWVfaGFzaKZ+EfP0ZYOZAwoAbmV0d29ya19pZAxRUWAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc2xhYgQJAG5hbWVfaGFzaKZ+EfP0ZYOZAwoAbmV0d29ya19pZAxRUWAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:warped_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zbGFiBAkAbmFtZV9oYXNo/AT0e/Z9W7UDCgBuZXR3b3JrX2lk1yq11AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zbGFiBAkAbmFtZV9oYXNo/AT0e/Z9W7UDCgBuZXR3b3JrX2lk1yq11AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:blackstone_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaF/DD4ZUlNgtAwoAbmV0d29ya19pZGy1DjwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaF/DD4ZUlNgtAwoAbmV0d29ya19pZGy1DjwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:polished_blackstone_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaDYnuUs86EWfAwoAbmV0d29ya19pZJj2bXIKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaDYnuUs86EWfAwoAbmV0d29ya19pZJj2bXIKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:polished_blackstone_brick_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaKySLqvHc4xXAwoAbmV0d29ya19pZOyWX94KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaKySLqvHc4xXAwoAbmV0d29ya19pZOyWX94KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAgAACAQAbmFtZRkAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaDsNpb2qs4iBAwoAbmV0d29ya19pZOTm2nsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAgAACAQAbmFtZRkAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaDsNpb2qs4iBAwoAbmV0d29ya19pZOTm2nsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:exposed_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNoahQ5OwIQb7kDCgBuZXR3b3JrX2lkrUlZLwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNoahQ5OwIQb7kDCgBuZXR3b3JrX2lkrUlZLwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:weathered_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2hBIuGIOVVXogMKAG5ldHdvcmtfaWQgnaDiCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2hBIuGIOVVXogMKAG5ldHdvcmtfaWQgnaDiCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:oxidized_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaOptj9ycfpaDAwoAbmV0d29ya19pZMzFSRgKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaOptj9ycfpaDAwoAbmV0d29ya19pZMzFSRgKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:waxed_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaAlx6DZOCTHzAwoAbmV0d29ya19pZFRBvDAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaAlx6DZOCTHzAwoAbmV0d29ya19pZFRBvDAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:waxed_exposed_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNo3KqS5OnhtRIDCgBuZXR3b3JrX2lkHTGcTgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNo3KqS5OnhtRIDCgBuZXR3b3JrX2lkHTGcTgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:waxed_weathered_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2gzZ1oX0HCFtwMKAG5ldHdvcmtfaWSgJR+XCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2gzZ1oX0HCFtwMKAG5ldHdvcmtfaWSgJR+XCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:waxed_oxidized_cut_copper_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTAAgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaMjjTnLu1KcqAwoAbmV0d29ya19pZIxsnFYKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTAAgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaMjjTnLu1KcqAwoAbmV0d29ya19pZIxsnFYKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cobbled_deepslate_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3NsYWIECQBuYW1lX2hhc2gwJIVWK1TM2QMKAG5ldHdvcmtfaWTYAoX5CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3NsYWIECQBuYW1lX2hhc2gwJIVWK1TM2QMKAG5ldHdvcmtfaWTYAoX5CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_deepslate_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zbGFiBAkAbmFtZV9oYXNoC/Adiz8k6RYDCgBuZXR3b3JrX2lkuFYMAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zbGFiBAkAbmFtZV9oYXNoC/Adiz8k6RYDCgBuZXR3b3JrX2lkuFYMAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:deepslate_tile_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3NsYWIECQBuYW1lX2hhc2hPydV6emzIXAMKAG5ldHdvcmtfaWQwlbFCCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3NsYWIECQBuYW1lX2hhc2hPydV6emzIXAMKAG5ldHdvcmtfaWQwlbFCCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:deepslate_brick_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zbGFiBAkAbmFtZV9oYXNoSv62V7iw10UDCgBuZXR3b3JrX2lkWMoragoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zbGFiBAkAbmFtZV9oYXNoSv62V7iw10UDCgBuZXR3b3JrX2lkWMoragoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mud_brick_slab", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja19zbGFiBAkAbmFtZV9oYXNoq/tGBQWkv08DCgBuZXR3b3JrX2lkl4nnMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja19zbGFiBAkAbmFtZV9oYXNoq/tGBQWkv08DCgBuZXR3b3JrX2lkl4nnMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:brick_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAAAACAQAbmFtZRUAbWluZWNyYWZ0OmJyaWNrX2Jsb2NrBAkAbmFtZV9oYXNo5Qc2E005S3oDCgBuZXR3b3JrX2lkqeGWRgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAAAACAQAbmFtZRUAbWluZWNyYWZ0OmJyaWNrX2Jsb2NrBAkAbmFtZV9oYXNo5Qc2E005S3oDCgBuZXR3b3JrX2lkqeGWRgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:chiseled_nether_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX25ldGhlcl9icmlja3MECQBuYW1lX2hhc2g31SBPTcUK1QMKAG5ldHdvcmtfaWS8TJ+TCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX25ldGhlcl9icmlja3MECQBuYW1lX2hhc2g31SBPTcUK1QMKAG5ldHdvcmtfaWS8TJ+TCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cracked_nether_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAgAACAQAbmFtZR8AbWluZWNyYWZ0OmNyYWNrZWRfbmV0aGVyX2JyaWNrcwQJAG5hbWVfaGFzaAdC6eKzXT5tAwoAbmV0d29ya19pZIUSejwKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAgAACAQAbmFtZR8AbWluZWNyYWZ0OmNyYWNrZWRfbmV0aGVyX2JyaWNrcwQJAG5hbWVfaGFzaAdC6eKzXT5tAwoAbmV0d29ya19pZIUSejwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:quartz_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9icmlja3MECQBuYW1lX2hhc2jSZO590dd8sAMKAG5ldHdvcmtfaWSc5xCLCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9icmlja3MECQBuYW1lX2hhc2jSZO590dd8sAMKAG5ldHdvcmtfaWSc5xCLCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stonebrick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQ5kni1CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAZGVmYXVsdAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQ5kni1CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAZGVmYXVsdAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stonebrick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTDw813CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQUAbW9zc3kAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWTDw813CgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQUAbW9zc3kAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stonebrick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWSTvQGECgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAY3JhY2tlZAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWSTvQGECgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQcAY3JhY2tlZAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stonebrick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQIM0OwCgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQgAY2hpc2VsZWQAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRQAbWluZWNyYWZ0OnN0b25lYnJpY2sECQBuYW1lX2hhc2ii9DAAVXKptwMKAG5ldHdvcmtfaWQIM0OwCgYAc3RhdGVzCBAAc3RvbmVfYnJpY2tfdHlwZQgAY2hpc2VsZWQAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:end_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAAAACAQAbmFtZRQAbWluZWNyYWZ0OmVuZF9icmlja3MECQBuYW1lX2hhc2hIUFfxNLZaFgMKAG5ldHdvcmtfaWQ/vDihCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAAAACAQAbmFtZRQAbWluZWNyYWZ0OmVuZF9icmlja3MECQBuYW1lX2hhc2hIUFfxNLZaFgMKAG5ldHdvcmtfaWQ/vDihCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:prismarine", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWSH021WCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBgBicmlja3MAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWSH021WCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBgBicmlja3MAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:polished_blackstone_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoIHgsgIdzKXcDCgBuZXR3b3JrX2lkUw9b3woGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoIHgsgIdzKXcDCgBuZXR3b3JrX2lkUw9b3woGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cracked_polished_blackstone_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAgAACAQAbmFtZSwAbWluZWNyYWZ0OmNyYWNrZWRfcG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3MECQBuYW1lX2hhc2jQIO1GQDk80AMKAG5ldHdvcmtfaWQ3UlRYCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAgAACAQAbmFtZSwAbWluZWNyYWZ0OmNyYWNrZWRfcG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3MECQBuYW1lX2hhc2jQIO1GQDk80AMKAG5ldHdvcmtfaWQ3UlRYCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:gilded_blackstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAgAACAQAbmFtZRsAbWluZWNyYWZ0OmdpbGRlZF9ibGFja3N0b25lBAkAbmFtZV9oYXNoNoWt1ocG0HEDCgBuZXR3b3JrX2lktL8gUwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAgAACAQAbmFtZRsAbWluZWNyYWZ0OmdpbGRlZF9ibGFja3N0b25lBAkAbmFtZV9oYXNoNoWt1ocG0HEDCgBuZXR3b3JrX2lktL8gUwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:chiseled_polished_blackstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAgAACAQAbmFtZSYAbWluZWNyYWZ0OmNoaXNlbGVkX3BvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2gzFa+kEjCJgAMKAG5ldHdvcmtfaWR2NJX2CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAgAACAQAbmFtZSYAbWluZWNyYWZ0OmNoaXNlbGVkX3BvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2gzFa+kEjCJgAMKAG5ldHdvcmtfaWR2NJX2CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:deepslate_tiles", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlcwQJAG5hbWVfaGFzaGcLLx3NXAFvAwoAbmV0d29ya19pZI/G/xYKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlcwQJAG5hbWVfaGFzaGcLLx3NXAFvAwoAbmV0d29ya19pZI/G/xYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cracked_deepslate_tiles", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAgAACAQAbmFtZSEAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX3RpbGVzBAkAbmFtZV9oYXNo9zWgkFuMM1QDCgBuZXR3b3JrX2lkGwY6OgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAgAACAQAbmFtZSEAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX3RpbGVzBAkAbmFtZV9oYXNo9zWgkFuMM1QDCgBuZXR3b3JrX2lkGwY6OgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:deepslate_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja3MECQBuYW1lX2hhc2gucvFmPdZxigMKAG5ldHdvcmtfaWSH4HDPCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja3MECQBuYW1lX2hhc2gucvFmPdZxigMKAG5ldHdvcmtfaWSH4HDPCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cracked_deepslate_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAgAACAQAbmFtZSIAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX2JyaWNrcwQJAG5hbWVfaGFzaN40aqhh9WqHAwoAbmV0d29ya19pZO9GPBQKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAgAACAQAbmFtZSIAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX2JyaWNrcwQJAG5hbWVfaGFzaN40aqhh9WqHAwoAbmV0d29ya19pZO9GPBQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:chiseled_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaEU7/uRG8HSBAwoAbmV0d29ya19pZEqmI0EKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaEU7/uRG8HSBAwoAbmV0d29ya19pZEqmI0EKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cobblestone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYmJsZXN0b25lBAkAbmFtZV9oYXNoPoK7mGlSUz4DCgBuZXR3b3JrX2lkLm7RZwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYmJsZXN0b25lBAkAbmFtZV9oYXNoPoK7mGlSUz4DCgBuZXR3b3JrX2lkLm7RZwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:mossy_cobblestone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAAAACAQAbmFtZRsAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoGJ67FCbkChMDCgBuZXR3b3JrX2lk/pYs1AoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAAAACAQAbmFtZRsAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoGJ67FCbkChMDCgBuZXR3b3JrX2lk/pYs1AoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cobbled_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AgAACAQAbmFtZRsAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoLUz9Y/ywmLwDCgBuZXR3b3JrX2lkNwzZ+AoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AgAACAQAbmFtZRsAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoLUz9Y/ywmLwDCgBuZXR3b3JrX2lkNwzZ+AoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:smooth_stone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AQAACAQAbmFtZRYAbWluZWNyYWZ0OnNtb290aF9zdG9uZQQJAG5hbWVfaGFzaMwf87/JaTNvAwoAbmV0d29ya19pZLkZICEKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AQAACAQAbmFtZRYAbWluZWNyYWZ0OnNtb290aF9zdG9uZQQJAG5hbWVfaGFzaMwf87/JaTNvAwoAbmV0d29ya19pZLkZICEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB2wApMKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUHAGRlZmF1bHQAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB2wApMKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUHAGRlZmF1bHQAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB7E+eQKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGULAGhlaXJvZ2x5cGhzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZB7E+eQKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGULAGhlaXJvZ2x5cGhzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZFQnDaEKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUDAGN1dAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZFQnDaEKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUDAGN1dAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZPO4A3IKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUGAHNtb290aAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZPO4A3IKBgBzdGF0ZXMIDwBzYW5kX3N0b25lX3R5cGUGAHNtb290aAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:red_sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWRhNYiFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWRhNYiFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:red_sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTqXJr1CgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlCwBoZWlyb2dseXBocwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTqXJr1CgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlCwBoZWlyb2dseXBocwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:red_sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTQRGkFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlAwBjdXQAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTQRGkFCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlAwBjdXQAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:red_sandstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTvAHWDCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBgBzbW9vdGgAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWTvAHWDCgYAc3RhdGVzCA8Ac2FuZF9zdG9uZV90eXBlBgBzbW9vdGgAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:coal_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWStAAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvYWxfYmxvY2sECQBuYW1lX2hhc2jH8QQP3t5PiAMKAG5ldHdvcmtfaWRo+sR+CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvYWxfYmxvY2sECQBuYW1lX2hhc2jH8QQP3t5PiAMKAG5ldHdvcmtfaWRo+sR+CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dried_kelp_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAQAACAQAbmFtZRoAbWluZWNyYWZ0OmRyaWVkX2tlbHBfYmxvY2sECQBuYW1lX2hhc2iRoucexkrl8wMKAG5ldHdvcmtfaWQQCCrvCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAQAACAQAbmFtZRoAbWluZWNyYWZ0OmRyaWVkX2tlbHBfYmxvY2sECQBuYW1lX2hhc2iRoucexkrl8wMKAG5ldHdvcmtfaWQQCCrvCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:gold_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdvbGRfYmxvY2sECQBuYW1lX2hhc2iYLshvjtXzFwMKAG5ldHdvcmtfaWTDJGBcCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdvbGRfYmxvY2sECQBuYW1lX2hhc2iYLshvjtXzFwMKAG5ldHdvcmtfaWTDJGBcCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:iron_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAAAACAQAbmFtZRQAbWluZWNyYWZ0Omlyb25fYmxvY2sECQBuYW1lX2hhc2jYINmJQbvV/gMKAG5ldHdvcmtfaWRf7AbICgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAAAACAQAbmFtZRQAbWluZWNyYWZ0Omlyb25fYmxvY2sECQBuYW1lX2hhc2jYINmJQbvV/gMKAG5ldHdvcmtfaWRf7AbICgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:copper_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZIiUodwKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZIiUodwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:copper_door" + }, + { + "id": "minecraft:copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXBAAACAQAbmFtZRkAbWluZWNyYWZ0OmNvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaO9fXio+svKVAwoAbmV0d29ya19pZMCoRjEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AwAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaC/JEFOWnmEcAwoAbmV0d29ya19pZC6YiiMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:exposed_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAgAACAQAbmFtZRgAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoQH3Fukmu3CEDCgBuZXR3b3JrX2lk72jFIwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAgAACAQAbmFtZRgAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoQH3Fukmu3CEDCgBuZXR3b3JrX2lk72jFIwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:exposed_copper_door" + }, + { + "id": "minecraft:exposed_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYBAAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX3RyYXBkb29yBAkAbmFtZV9oYXNoYhDFUysN7qUDCgBuZXR3b3JrX2lkMzwGJgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:exposed_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQABAAACAQAbmFtZR4AbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX2dyYXRlBAkAbmFtZV9oYXNolFIBYLYU0IcDCgBuZXR3b3JrX2lk4UqptAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:weathered_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAgAACAQAbmFtZRoAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2hJCQXbvobv+gMKAG5ldHdvcmtfaWQwM0lJCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAgAACAQAbmFtZRoAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2hJCQXbvobv+gMKAG5ldHdvcmtfaWQwM0lJCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:weathered_copper_door" + }, + { + "id": "minecraft:weathered_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZBAAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfdHJhcGRvb3IECQBuYW1lX2hhc2hFnEC282a1tgMKAG5ldHdvcmtfaWTk70oiCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:weathered_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBBAAACAQAbmFtZSAAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfZ3JhdGUECQBuYW1lX2hhc2jB3o8enlv1RgMKAG5ldHdvcmtfaWRih2pOCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:oxidized_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMDtJqR0G5Y7AwoAbmV0d29ya19pZGjN8bUKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMDtJqR0G5Y7AwoAbmV0d29ya19pZGjN8bUKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:oxidized_copper_door" + }, + { + "id": "minecraft:oxidized_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQaBAAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaOJpG/XFexVwAwoAbmV0d29ya19pZPhi0J4KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:oxidized_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCBAAACAQAbmFtZR8AbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaBRfNhyndve7AwoAbmV0d29ya19pZKY2cnEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:waxed_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAgAACAQAbmFtZRYAbWluZWNyYWZ0OndheGVkX2NvcHBlcgQJAG5hbWVfaGFzaPF+FG6Eh5fsAwoAbmV0d29ya19pZIjtz/0KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAgAACAQAbmFtZRYAbWluZWNyYWZ0OndheGVkX2NvcHBlcgQJAG5hbWVfaGFzaPF+FG6Eh5fsAwoAbmV0d29ya19pZIjtz/0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:waxed_copper_door" + }, + { + "id": "minecraft:waxed_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbBAAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaO0JUKUHqNU6AwoAbmV0d29ya19pZJC3ZuMKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:waxed_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDBAAACAQAbmFtZRwAbWluZWNyYWZ0OndheGVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaDmC92M2RO+HAwoAbmV0d29ya19pZH4og2AKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:waxed_exposed_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAgAACAQAbmFtZR4AbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoig8IOc+SCikDCgBuZXR3b3JrX2lklz8yWQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAgAACAQAbmFtZR4AbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoig8IOc+SCikDCgBuZXR3b3JrX2lklz8yWQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:waxed_exposed_copper_door" + }, + { + "id": "minecraft:waxed_exposed_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcBAAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX3RyYXBkb29yBAkAbmFtZV9oYXNoBHHxCpkUzpgDCgBuZXR3b3JrX2lkw2XBGQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:waxed_exposed_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEBAAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX2dyYXRlBAkAbmFtZV9oYXNoWmd6B+hWwiEDCgBuZXR3b3JrX2lk8d4ZQwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:waxed_weathered_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAgAACAQAbmFtZSAAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2gjtPq8MOdvKgMKAG5ldHdvcmtfaWSQ9Ln9CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAgAACAQAbmFtZSAAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2gjtPq8MOdvKgMKAG5ldHdvcmtfaWSQ9Ln9CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:waxed_weathered_copper_door" + }, + { + "id": "minecraft:waxed_weathered_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQdBAAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfdHJhcGRvb3IECQBuYW1lX2hhc2gH9Fi3JCF4egMKAG5ldHdvcmtfaWRkGU6TCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:waxed_weathered_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFBAAACAQAbmFtZSYAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfZ3JhdGUECQBuYW1lX2hhc2hXfilVFDAiYQMKAG5ldHdvcmtfaWQqTGC1CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:waxed_oxidized_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS9AgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMaORhsO+LzjAwoAbmV0d29ya19pZJhGfLEKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS9AgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMaORhsO+LzjAwoAbmV0d29ya19pZJhGfLEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:waxed_oxidized_copper_door" + }, + { + "id": "minecraft:waxed_oxidized_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeBAAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaNA/q9qAy6Z9AwoAbmV0d29ya19pZDgExS8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:waxed_oxidized_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGBAAACAQAbmFtZSUAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaEbeMT605GP4AwoAbmV0d29ya19pZOZjpkkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAgAACAQAbmFtZRQAbWluZWNyYWZ0OmN1dF9jb3BwZXIECQBuYW1lX2hhc2hAfN3NGax3eAMKAG5ldHdvcmtfaWTnFBtYCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAgAACAQAbmFtZRQAbWluZWNyYWZ0OmN1dF9jb3BwZXIECQBuYW1lX2hhc2hAfN3NGax3eAMKAG5ldHdvcmtfaWTnFBtYCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:exposed_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAgAACAQAbmFtZRwAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaA85G3yv/w6pAwoAbmV0d29ya19pZMQhr0QKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAgAACAQAbmFtZRwAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaA85G3yv/w6pAwoAbmV0d29ya19pZMQhr0QKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:weathered_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAgAACAQAbmFtZR4AbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoVgRV0fBaz88DCgBuZXR3b3JrX2lk/0cYugoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAgAACAQAbmFtZR4AbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoVgRV0fBaz88DCgBuZXR3b3JrX2lk/0cYugoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:oxidized_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAgAACAQAbmFtZR0AbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2iP8WmFWOkriwMKAG5ldHdvcmtfaWQPdce7CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAgAACAQAbmFtZR0AbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2iP8WmFWOkriwMKAG5ldHdvcmtfaWQPdce7CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:waxed_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWReAgAACAQAbmFtZRoAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2jumiwOZIqv2AMKAG5ldHdvcmtfaWQvuxx9CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWReAgAACAQAbmFtZRoAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2jumiwOZIqv2AMKAG5ldHdvcmtfaWQvuxx9CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:waxed_exposed_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAgAACAQAbmFtZSIAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaPE/OfK6IoVMAwoAbmV0d29ya19pZHy5HkcKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAgAACAQAbmFtZSIAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaPE/OfK6IoVMAwoAbmV0d29ya19pZHy5HkcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:waxed_weathered_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoCA1xDp11bnwDCgBuZXR3b3JrX2lkDyEDVQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoCA1xDp11bnwDCgBuZXR3b3JrX2lkDyEDVQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:waxed_oxidized_cut_copper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWS+AgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2i1pZAsZYHLDAMKAG5ldHdvcmtfaWQ/wSkCCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWS+AgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2i1pZAsZYHLDAMKAG5ldHdvcmtfaWQ/wSkCCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT3AwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaIsW5pmpJEuQAwoAbmV0d29ya19pZHetwrkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:exposed_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT4AwAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY2hpc2VsZWRfY29wcGVyBAkAbmFtZV9oYXNoOvrLJ0UowbgDCgBuZXR3b3JrX2lkZj7cPwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:weathered_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT5AwAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jaGlzZWxlZF9jb3BwZXIECQBuYW1lX2hhc2hh+42XlsWvGAMKAG5ldHdvcmtfaWS7Cy59CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:oxidized_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT6AwAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaLpTIsnfluiCAwoAbmV0d29ya19pZB9/jS8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:waxed_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AwAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaFnXvXY5OinzAwoAbmV0d29ya19pZAcKtHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:waxed_exposed_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AwAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY2hpc2VsZWRfY29wcGVyBAkAbmFtZV9oYXNoHJdq+Pph6hMDCgBuZXR3b3JrX2lkdge7IAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:waxed_oxidized_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AwAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaMj49OvlTpgCAwoAbmV0d29ya19pZN/r+roKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:waxed_weathered_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AwAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jaGlzZWxlZF9jb3BwZXIECQBuYW1lX2hhc2hzuO+Sg9LYQwMKAG5ldHdvcmtfaWQ7AN7iCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHBAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcHBlcl9idWxiBAkAbmFtZV9oYXNo41TimHOsMWcDCgBuZXR3b3JrX2lkJnZvAgoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:exposed_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIBAAACAQAbmFtZR0AbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX2J1bGIECQBuYW1lX2hhc2g++f1wYLLCrAMKAG5ldHdvcmtfaWRLdMmGCgYAc3RhdGVzAQMAbGl0AAELAHBvd2VyZWRfYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:weathered_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQJBAAACAQAbmFtZR8AbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfYnVsYgQJAG5hbWVfaGFzaMEtsYfwRTXlAwoAbmV0d29ya19pZAp51LQKBgBzdGF0ZXMBAwBsaXQAAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:oxidized_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKBAAACAQAbmFtZR4AbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNovnrBQZs8nDIDCgBuZXR3b3JrX2lkPsj0AAoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:waxed_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLBAAACAQAbmFtZRsAbWluZWNyYWZ0OndheGVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNoGTg6TYllMiIDCgBuZXR3b3JrX2lk9m0WhgoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgMAFQEA" + }, + { + "id": "minecraft:waxed_exposed_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMBAAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX2J1bGIECQBuYW1lX2hhc2gI6xkPcvBDVwMKAG5ldHdvcmtfaWR7BRcACgYAc3RhdGVzAQMAbGl0AAELAHBvd2VyZWRfYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:waxed_weathered_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNBAAACAQAbmFtZSUAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfYnVsYgQJAG5hbWVfaGFzaMsUnmp3/VqVAwoAbmV0d29ya19pZEoworoKBgBzdGF0ZXMBAwBsaXQAAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:waxed_oxidized_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOBAAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNoBFKxY3fjVq4DCgBuZXR3b3JrX2lkzrJ6aAoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:emerald_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAAAACAQAbmFtZRcAbWluZWNyYWZ0OmVtZXJhbGRfYmxvY2sECQBuYW1lX2hhc2hK6QunqJznNAMKAG5ldHdvcmtfaWRk5+otCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAAAACAQAbmFtZRcAbWluZWNyYWZ0OmVtZXJhbGRfYmxvY2sECQBuYW1lX2hhc2hK6QunqJznNAMKAG5ldHdvcmtfaWRk5+otCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:diamond_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AAAACAQAbmFtZRcAbWluZWNyYWZ0OmRpYW1vbmRfYmxvY2sECQBuYW1lX2hhc2iGKrxuvkytFQMKAG5ldHdvcmtfaWQQeQZXCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AAAACAQAbmFtZRcAbWluZWNyYWZ0OmRpYW1vbmRfYmxvY2sECQBuYW1lX2hhc2iGKrxuvkytFQMKAG5ldHdvcmtfaWQQeQZXCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:lapis_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxhcGlzX2Jsb2NrBAkAbmFtZV9oYXNoDZ44xdb2zVoDCgBuZXR3b3JrX2lktVy0BAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxhcGlzX2Jsb2NrBAkAbmFtZV9oYXNoDZ44xdb2zVoDCgBuZXR3b3JrX2lktVy0BAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:raw_iron_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19pcm9uX2Jsb2NrBAkAbmFtZV9oYXNo9XyzNIQXxvwDCgBuZXR3b3JrX2lknms1QAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19pcm9uX2Jsb2NrBAkAbmFtZV9oYXNo9XyzNIQXxvwDCgBuZXR3b3JrX2lknms1QAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:raw_copper_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAgAACAQAbmFtZRoAbWluZWNyYWZ0OnJhd19jb3BwZXJfYmxvY2sECQBuYW1lX2hhc2hw1KG0TNUGgwMKAG5ldHdvcmtfaWS1vGo/CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAgAACAQAbmFtZRoAbWluZWNyYWZ0OnJhd19jb3BwZXJfYmxvY2sECQBuYW1lX2hhc2hw1KG0TNUGgwMKAG5ldHdvcmtfaWS1vGo/CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:raw_gold_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19nb2xkX2Jsb2NrBAkAbmFtZV9oYXNo6YuwuLwfOBwDCgBuZXR3b3JrX2lkLiQ5gQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19nb2xkX2Jsb2NrBAkAbmFtZV9oYXNo6YuwuLwfOBwDCgBuZXR3b3JrX2lkLiQ5gQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:quartz_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZEupC1AKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZEupC1AKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:quartz_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZM97+l0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZM97+l0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:quartz_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZCbTfssKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQgAY2hpc2VsZWQICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZCbTfssKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQgAY2hpc2VsZWQICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:quartz_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZJss8V0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQYAc21vb3RoCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZJss8V0KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQYAc21vb3RoCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:prismarine", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWRFIsoGCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWRFIsoGCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:prismarine", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWTDNWOvCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBABkYXJrAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWTDNWOvCgYAc3RhdGVzCBUAcHJpc21hcmluZV9ibG9ja190eXBlBABkYXJrAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:slime", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnNsaW1lBAkAbmFtZV9oYXNoHJiEEJx+JlkDCgBuZXR3b3JrX2lkfgfVzAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnNsaW1lBAkAbmFtZV9oYXNoHJiEEJx+JlkDCgBuZXR3b3JrX2lkfgfVzAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:honey_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAQAACAQAbmFtZRUAbWluZWNyYWZ0OmhvbmV5X2Jsb2NrBAkAbmFtZV9oYXNo9zLYSUlelywDCgBuZXR3b3JrX2lko+dyWgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAQAACAQAbmFtZRUAbWluZWNyYWZ0OmhvbmV5X2Jsb2NrBAkAbmFtZV9oYXNo9zLYSUlelywDCgBuZXR3b3JrX2lko+dyWgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:honeycomb_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAQAACAQAbmFtZRkAbWluZWNyYWZ0OmhvbmV5Y29tYl9ibG9jawQJAG5hbWVfaGFzaASIPuOCYd1oAwoAbmV0d29ya19pZKys4n4KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAQAACAQAbmFtZRkAbWluZWNyYWZ0OmhvbmV5Y29tYl9ibG9jawQJAG5hbWVfaGFzaASIPuOCYd1oAwoAbmV0d29ya19pZKys4n4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:hay_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAAAACAQAbmFtZRMAbWluZWNyYWZ0OmhheV9ibG9jawQJAG5hbWVfaGFzaIB2VxKxX8EpAwoAbmV0d29ya19pZKuQSloKBgBzdGF0ZXMDCgBkZXByZWNhdGVkAAAAAAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAAAACAQAbmFtZRMAbWluZWNyYWZ0OmhheV9ibG9jawQJAG5hbWVfaGFzaIB2VxKxX8EpAwoAbmV0d29ya19pZKuQSloKBgBzdGF0ZXMDCgBkZXByZWNhdGVkAAAAAAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bone_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAAAACAQAbmFtZRQAbWluZWNyYWZ0OmJvbmVfYmxvY2sECQBuYW1lX2hhc2i4ZX576W9AWgMKAG5ldHdvcmtfaWTWGacQCgYAc3RhdGVzAwoAZGVwcmVjYXRlZAAAAAAICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAAAACAQAbmFtZRQAbWluZWNyYWZ0OmJvbmVfYmxvY2sECQBuYW1lX2hhc2i4ZX576W9AWgMKAG5ldHdvcmtfaWTWGacQCgYAc3RhdGVzAwoAZGVwcmVjYXRlZAAAAAAICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:nether_brick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAAAACAQAbmFtZRYAbWluZWNyYWZ0Om5ldGhlcl9icmljawQJAG5hbWVfaGFzaMxcRiheU+nXAwoAbmV0d29ya19pZMkmzloKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAAAACAQAbmFtZRYAbWluZWNyYWZ0Om5ldGhlcl9icmljawQJAG5hbWVfaGFzaMxcRiheU+nXAwoAbmV0d29ya19pZMkmzloKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:red_nether_brick", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAAAACAQAbmFtZRoAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2sECQBuYW1lX2hhc2j8pRO4LfoECAMKAG5ldHdvcmtfaWRpdF0YCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAAAACAQAbmFtZRoAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2sECQBuYW1lX2hhc2j8pRO4LfoECAMKAG5ldHdvcmtfaWRpdF0YCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:netherite_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcml0ZV9ibG9jawQJAG5hbWVfaGFzaMghh6Zib/ZKAwoAbmV0d29ya19pZIz0mq0KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcml0ZV9ibG9jawQJAG5hbWVfaGFzaMghh6Zib/ZKAwoAbmV0d29ya19pZIz0mq0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:lodestone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAQAACAQAbmFtZRMAbWluZWNyYWZ0OmxvZGVzdG9uZQQJAG5hbWVfaGFzaJ2gmHOTlXv8AwoAbmV0d29ya19pZEfgB4wKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAQAACAQAbmFtZRMAbWluZWNyYWZ0OmxvZGVzdG9uZQQJAG5hbWVfaGFzaJ2gmHOTlXv8AwoAbmV0d29ya19pZEfgB4wKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:white_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAAAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWSO8paQCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAAAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWSO8paQCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:light_gray_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfd29vbAQJAG5hbWVfaGFzaOpdQ1a2v4b3AwoAbmV0d29ya19pZIqZCYEKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfd29vbAQJAG5hbWVfaGFzaOpdQ1a2v4b3AwoAbmV0d29ya19pZIqZCYEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:gray_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAwAACAQAbmFtZRMAbWluZWNyYWZ0OmdyYXlfd29vbAQJAG5hbWVfaGFzaLsc1Lp1xdIOAwoAbmV0d29ya19pZFUs+HgKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAwAACAQAbmFtZRMAbWluZWNyYWZ0OmdyYXlfd29vbAQJAG5hbWVfaGFzaLsc1Lp1xdIOAwoAbmV0d29ya19pZFUs+HgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:black_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrX3dvb2wECQBuYW1lX2hhc2hP2HC6o0X4HAMKAG5ldHdvcmtfaWRUbORcCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrX3dvb2wECQBuYW1lX2hhc2hP2HC6o0X4HAMKAG5ldHdvcmtfaWRUbORcCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:brown_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJyb3duX3dvb2wECQBuYW1lX2hhc2ig5IW89PrREwMKAG5ldHdvcmtfaWRjT9j8CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJyb3duX3dvb2wECQBuYW1lX2hhc2ig5IW89PrREwMKAG5ldHdvcmtfaWRjT9j8CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:red_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAwAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF93b29sBAkAbmFtZV9oYXNoY4TBDq+mFgUDCgBuZXR3b3JrX2lktn9lcAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAwAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF93b29sBAkAbmFtZV9oYXNoY4TBDq+mFgUDCgBuZXR3b3JrX2lktn9lcAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:orange_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAwAACAQAbmFtZRUAbWluZWNyYWZ0Om9yYW5nZV93b29sBAkAbmFtZV9oYXNoFstfrTZfSCgDCgBuZXR3b3JrX2lk+rqywwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAwAACAQAbmFtZRUAbWluZWNyYWZ0Om9yYW5nZV93b29sBAkAbmFtZV9oYXNoFstfrTZfSCgDCgBuZXR3b3JrX2lk+rqywwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:yellow_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAwAACAQAbmFtZRUAbWluZWNyYWZ0OnllbGxvd193b29sBAkAbmFtZV9oYXNoTFyus2RHegcDCgBuZXR3b3JrX2lkkKBhXAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAwAACAQAbmFtZRUAbWluZWNyYWZ0OnllbGxvd193b29sBAkAbmFtZV9oYXNoTFyus2RHegcDCgBuZXR3b3JrX2lkkKBhXAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:lime_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAwAACAQAbmFtZRMAbWluZWNyYWZ0OmxpbWVfd29vbAQJAG5hbWVfaGFzaNVnnzKiMxmeAwoAbmV0d29ya19pZG9b32kKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAwAACAQAbmFtZRMAbWluZWNyYWZ0OmxpbWVfd29vbAQJAG5hbWVfaGFzaNVnnzKiMxmeAwoAbmV0d29ya19pZG9b32kKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:green_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAwAACAQAbmFtZRQAbWluZWNyYWZ0OmdyZWVuX3dvb2wECQBuYW1lX2hhc2i3mElRYHIcSQMKAG5ldHdvcmtfaWSssprwCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAwAACAQAbmFtZRQAbWluZWNyYWZ0OmdyZWVuX3dvb2wECQBuYW1lX2hhc2i3mElRYHIcSQMKAG5ldHdvcmtfaWSssprwCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cyan_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAwAACAQAbmFtZRMAbWluZWNyYWZ0OmN5YW5fd29vbAQJAG5hbWVfaGFzaBNDfvHn8dqFAwoAbmV0d29ya19pZK0hAbgKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAwAACAQAbmFtZRMAbWluZWNyYWZ0OmN5YW5fd29vbAQJAG5hbWVfaGFzaBNDfvHn8dqFAwoAbmV0d29ya19pZK0hAbgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:light_blue_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfd29vbAQJAG5hbWVfaGFzaLWFAUfyxFPNAwoAbmV0d29ya19pZL2oEugKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfd29vbAQJAG5hbWVfaGFzaLWFAUfyxFPNAwoAbmV0d29ya19pZL2oEugKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:blue_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAwAACAQAbmFtZRMAbWluZWNyYWZ0OmJsdWVfd29vbAQJAG5hbWVfaGFzaLjHyxxbTWCLAwoAbmV0d29ya19pZPaLdFQKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAwAACAQAbmFtZRMAbWluZWNyYWZ0OmJsdWVfd29vbAQJAG5hbWVfaGFzaLjHyxxbTWCLAwoAbmV0d29ya19pZPaLdFQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:purple_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAwAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnBsZV93b29sBAkAbmFtZV9oYXNojvFtqzjAf/4DCgBuZXR3b3JrX2lklqASNQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAwAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnBsZV93b29sBAkAbmFtZV9oYXNojvFtqzjAf/4DCgBuZXR3b3JrX2lklqASNQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:magenta_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AwAACAQAbmFtZRYAbWluZWNyYWZ0Om1hZ2VudGFfd29vbAQJAG5hbWVfaGFzaGuOHvf+Pd4yAwoAbmV0d29ya19pZI4UoDQKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AwAACAQAbmFtZRYAbWluZWNyYWZ0Om1hZ2VudGFfd29vbAQJAG5hbWVfaGFzaGuOHvf+Pd4yAwoAbmV0d29ya19pZI4UoDQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:pink_wool", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AwAACAQAbmFtZRMAbWluZWNyYWZ0OnBpbmtfd29vbAQJAG5hbWVfaGFzaPiVA2pFeoFLAwoAbmV0d29ya19pZOZRO6oKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AwAACAQAbmFtZRMAbWluZWNyYWZ0OnBpbmtfd29vbAQJAG5hbWVfaGFzaPiVA2pFeoFLAwoAbmV0d29ya19pZOZRO6oKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:white_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAAAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZEahDFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAAAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZEahDFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:light_gray_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0BAkAbmFtZV9oYXNoHPw6ArBAsP0DCgBuZXR3b3JrX2lkQoAeUAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0BAkAbmFtZV9oYXNoHPw6ArBAsP0DCgBuZXR3b3JrX2lkQoAeUAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:gray_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FycGV0BAkAbmFtZV9oYXNoZVR0OI+1VRADCgBuZXR3b3JrX2lkETF4WwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FycGV0BAkAbmFtZV9oYXNoZVR0OI+1VRADCgBuZXR3b3JrX2lkETF4WwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:black_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhcnBldAQJAG5hbWVfaGFzaOk7LP9NptyhAwoAbmV0d29ya19pZFjmXtIKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhcnBldAQJAG5hbWVfaGFzaOk7LP9NptyhAwoAbmV0d29ya19pZFjmXtIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:brown_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhcnBldAQJAG5hbWVfaGFzaNaXFyOsAvIvAwoAbmV0d29ya19pZHPjFuoKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhcnBldAQJAG5hbWVfaGFzaNaXFyOsAvIvAwoAbmV0d29ya19pZHPjFuoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:red_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAwAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYXJwZXQECQBuYW1lX2hhc2i9eSKBf6SO3wMKAG5ldHdvcmtfaWQuhI/KCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAwAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYXJwZXQECQBuYW1lX2hhc2i9eSKBf6SO3wMKAG5ldHdvcmtfaWQuhI/KCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:orange_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAwAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQECQBuYW1lX2hhc2hIUkO4HlAdygMKAG5ldHdvcmtfaWSyKV9OCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAwAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQECQBuYW1lX2hhc2hIUkO4HlAdygMKAG5ldHdvcmtfaWSyKV9OCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:yellow_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAwAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYXJwZXQECQBuYW1lX2hhc2hSDKX3scCamwMKAG5ldHdvcmtfaWT8nq+ECgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAwAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYXJwZXQECQBuYW1lX2hhc2hSDKX3scCamwMKAG5ldHdvcmtfaWT8nq+ECgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:lime_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAwAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FycGV0BAkAbmFtZV9oYXNo+6KFOpzsib4DCgBuZXR3b3JrX2lkT+DS4woGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAwAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FycGV0BAkAbmFtZV9oYXNo+6KFOpzsib4DCgBuZXR3b3JrX2lkT+DS4woGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:green_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAwAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhcnBldAQJAG5hbWVfaGFzaCHPMP9ltqFJAwoAbmV0d29ya19pZBgwAvAKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAwAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhcnBldAQJAG5hbWVfaGFzaCHPMP9ltqFJAwoAbmV0d29ya19pZBgwAvAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cyan_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAwAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FycGV0BAkAbmFtZV9oYXNobXf62dQBJj8DCgBuZXR3b3JrX2lkKVppLgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAwAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FycGV0BAkAbmFtZV9oYXNobXf62dQBJj8DCgBuZXR3b3JrX2lkKVppLgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:light_blue_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0BAkAbmFtZV9oYXNo20l4oktdZ3sDCgBuZXR3b3JrX2lkjdeMiwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0BAkAbmFtZV9oYXNo20l4oktdZ3sDCgBuZXR3b3JrX2lkjdeMiwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:blue_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWReAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FycGV0BAkAbmFtZV9oYXNo3p3lsW0eQwsDCgBuZXR3b3JrX2lkAovdPQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWReAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FycGV0BAkAbmFtZV9oYXNo3p3lsW0eQwsDCgBuZXR3b3JrX2lkAovdPQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:purple_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAwAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQECQBuYW1lX2hhc2jwIA9pW/qp7QMKAG5ldHdvcmtfaWTqJqhjCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAwAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQECQBuYW1lX2hhc2jwIA9pW/qp7QMKAG5ldHdvcmtfaWTqJqhjCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:magenta_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAwAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0BAkAbmFtZV9oYXNoFXT36YNNZhMDCgBuZXR3b3JrX2lk+tqsGAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAwAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0BAkAbmFtZV9oYXNoFXT36YNNZhMDCgBuZXR3b3JrX2lk+tqsGAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:pink_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FycGV0BAkAbmFtZV9oYXNoHll72oqk+OoDCgBuZXR3b3JrX2lkrnBYDwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FycGV0BAkAbmFtZV9oYXNoHll72oqk+OoDCgBuZXR3b3JrX2lkrnBYDwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:white_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTtAAAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZJPZY8AKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTtAAAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZJPZY8AKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:light_gray_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo7EUk30hmUtYDCgBuZXR3b3JrX2lkh8jVIwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo7EUk30hmUtYDCgBuZXR3b3JrX2lkh8jVIwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:gray_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmdyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoW77af6WihdwDCgBuZXR3b3JrX2lkSsqC1woGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmdyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoW77af6WihdwDCgBuZXR3b3JrX2lkSsqC1woGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:black_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTSAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaAfWYp0xtgcfAwoAbmV0d29ya19pZMWTC8EKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTSAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaAfWYp0xtgcfAwoAbmV0d29ya19pZMWTC8EKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:brown_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaB74EeiLO46XAwoAbmV0d29ya19pZEDHKqwKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaB74EeiLO46XAwoAbmV0d29ya19pZEDHKqwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:red_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAwAACAQAbmFtZR0AbWluZWNyYWZ0OnJlZF9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gjFut6Z/VH1gMKAG5ldHdvcmtfaWSvcmwYCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAwAACAQAbmFtZR0AbWluZWNyYWZ0OnJlZF9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gjFut6Z/VH1gMKAG5ldHdvcmtfaWSvcmwYCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:orange_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAwAACAQAbmFtZSAAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gADDj2IJiw+gMKAG5ldHdvcmtfaWTHph0FCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAwAACAQAbmFtZSAAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gADDj2IJiw+gMKAG5ldHdvcmtfaWTHph0FCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:yellow_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAwAACAQAbmFtZSAAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iy6qKNn3ob5wMKAG5ldHdvcmtfaWQZAI39CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAwAACAQAbmFtZSAAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iy6qKNn3ob5wMKAG5ldHdvcmtfaWQZAI39CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:lime_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAwAACAQAbmFtZR4AbWluZWNyYWZ0OmxpbWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo4dYIPslbXPUDCgBuZXR3b3JrX2lk2O8X0AoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAwAACAQAbmFtZR4AbWluZWNyYWZ0OmxpbWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo4dYIPslbXPUDCgBuZXR3b3JrX2lk2O8X0AoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:green_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAwAACAQAbmFtZR8AbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaM/c9x2aJh3HAwoAbmV0d29ya19pZA0VfBMKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAwAACAQAbmFtZR8AbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaM/c9x2aJh3HAwoAbmV0d29ya19pZA0VfBMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cyan_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAwAACAQAbmFtZR4AbWluZWNyYWZ0OmN5YW5fY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNok+xKAe7XXjoDCgBuZXR3b3JrX2lkmkn6uwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAwAACAQAbmFtZR4AbWluZWNyYWZ0OmN5YW5fY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNok+xKAe7XXjoDCgBuZXR3b3JrX2lkmkn6uwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:light_blue_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNogScpIQceyAEDCgBuZXR3b3JrX2lkOmVSbgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNogScpIQceyAEDCgBuZXR3b3JrX2lkOmVSbgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:blue_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoFp7mmeL86r0DCgBuZXR3b3JrX2lkS3b3RQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoFp7mmeL86r0DCgBuZXR3b3JrX2lkS3b3RQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:purple_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAwAACAQAbmFtZSAAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iYcVU04hoStwMKAG5ldHdvcmtfaWQXimEjCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAwAACAQAbmFtZSAAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iYcVU04hoStwMKAG5ldHdvcmtfaWQXimEjCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:magenta_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAwAACAQAbmFtZSEAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoy/70q6VPsWgDCgBuZXR3b3JrX2lkf9mxQwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAwAACAQAbmFtZSEAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoy/70q6VPsWgDCgBuZXR3b3JrX2lkf9mxQwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:pink_concrete_powder", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBpbmtfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoVikSAf8DwV0DCgBuZXR3b3JrX2lku2MivwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBpbmtfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoVikSAf8DwV0DCgBuZXR3b3JrX2lku2MivwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:white_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAAAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lk3MAYQAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAAAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lk3MAYQAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:light_gray_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGUECQBuYW1lX2hhc2hEtet5wuDIKAMKAG5ldHdvcmtfaWQISs02CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGUECQBuYW1lX2hhc2hEtet5wuDIKAMKAG5ldHdvcmtfaWQISs02CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:gray_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AwAACAQAbmFtZRcAbWluZWNyYWZ0OmdyYXlfY29uY3JldGUECQBuYW1lX2hhc2j92INnb0a83AMKAG5ldHdvcmtfaWQj8RHwCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AwAACAQAbmFtZRcAbWluZWNyYWZ0OmdyYXlfY29uY3JldGUECQBuYW1lX2hhc2j92INnb0a83AMKAG5ldHdvcmtfaWQj8RHwCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:black_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAwAACAQAbmFtZRgAbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlBAkAbmFtZV9oYXNo2X7NDIQmZ70DCgBuZXR3b3JrX2lk2uiVDQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAwAACAQAbmFtZRgAbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlBAkAbmFtZV9oYXNo2X7NDIQmZ70DCgBuZXR3b3JrX2lk2uiVDQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:brown_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AwAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlBAkAbmFtZV9oYXNoeka02BwXf6oDCgBuZXR3b3JrX2lkYf+xDQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AwAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlBAkAbmFtZV9oYXNoeka02BwXf6oDCgBuZXR3b3JrX2lkYf+xDQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:red_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAwAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9jb25jcmV0ZQQJAG5hbWVfaGFzaPWmNowLGubqAwoAbmV0d29ya19pZKwyx58KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAwAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9jb25jcmV0ZQQJAG5hbWVfaGFzaPWmNowLGubqAwoAbmV0d29ya19pZKwyx58KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:orange_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRzAwAACAQAbmFtZRkAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZQQJAG5hbWVfaGFzaAgE8XmaAi6+AwoAbmV0d29ya19pZMDQNz8KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRzAwAACAQAbmFtZRkAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZQQJAG5hbWVfaGFzaAgE8XmaAi6+AwoAbmV0d29ya19pZMDQNz8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:yellow_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR2AwAACAQAbmFtZRkAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZQQJAG5hbWVfaGFzaE6ONfJPBd0+AwoAbmV0d29ya19pZMarutwKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR2AwAACAQAbmFtZRkAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZQQJAG5hbWVfaGFzaE6ONfJPBd0+AwoAbmV0d29ya19pZMarutwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:lime_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR3AwAACAQAbmFtZRcAbWluZWNyYWZ0OmxpbWVfY29uY3JldGUECQBuYW1lX2hhc2gnd8JW6wmJcAMKAG5ldHdvcmtfaWTd47aoCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR3AwAACAQAbmFtZRcAbWluZWNyYWZ0OmxpbWVfY29uY3JldGUECQBuYW1lX2hhc2gnd8JW6wmJcAMKAG5ldHdvcmtfaWTd47aoCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:green_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AwAACAQAbmFtZRgAbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlBAkAbmFtZV9oYXNokbFxRKchQZkDCgBuZXR3b3JrX2lkmhZWUgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AwAACAQAbmFtZRgAbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlBAkAbmFtZV9oYXNokbFxRKchQZkDCgBuZXR3b3JrX2lkmhZWUgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cyan_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AwAACAQAbmFtZRcAbWluZWNyYWZ0OmN5YW5fY29uY3JldGUECQBuYW1lX2hhc2hFRrWJ33qj1wMKAG5ldHdvcmtfaWQbi5b8CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AwAACAQAbmFtZRcAbWluZWNyYWZ0OmN5YW5fY29uY3JldGUECQBuYW1lX2hhc2hFRrWJ33qj1wMKAG5ldHdvcmtfaWQbi5b8CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:light_blue_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR1AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGUECQBuYW1lX2hhc2gHAe0kl0SE4AMKAG5ldHdvcmtfaWRL/GbSCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR1AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGUECQBuYW1lX2hhc2gHAe0kl0SE4AMKAG5ldHdvcmtfaWRL/GbSCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:blue_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AwAACAQAbmFtZRcAbWluZWNyYWZ0OmJsdWVfY29uY3JldGUECQBuYW1lX2hhc2hiay301nnj1wMKAG5ldHdvcmtfaWRMvFXNCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AwAACAQAbmFtZRcAbWluZWNyYWZ0OmJsdWVfY29uY3JldGUECQBuYW1lX2hhc2hiay301nnj1wMKAG5ldHdvcmtfaWRMvFXNCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:purple_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AwAACAQAbmFtZRkAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZQQJAG5hbWVfaGFzaHBHflsPIwdXAwoAbmV0d29ya19pZCyKA5gKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AwAACAQAbmFtZRkAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZQQJAG5hbWVfaGFzaHBHflsPIwdXAwoAbmV0d29ya19pZCyKA5gKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:magenta_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AwAACAQAbmFtZRoAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGUECQBuYW1lX2hhc2gN7LuB/OvdZAMKAG5ldHdvcmtfaWTc6ZOdCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AwAACAQAbmFtZRoAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGUECQBuYW1lX2hhc2gN7LuB/OvdZAMKAG5ldHdvcmtfaWTc6ZOdCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:pink_concrete", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpbmtfY29uY3JldGUECQBuYW1lX2hhc2ii2G5F0u3SOAMKAG5ldHdvcmtfaWSszGgrCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpbmtfY29uY3JldGUECQBuYW1lX2hhc2ii2G5F0u3SOAMKAG5ldHdvcmtfaWSszGgrCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:clay", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmNsYXkECQBuYW1lX2hhc2j/S6sKXRcpzwMKAG5ldHdvcmtfaWRmsb8nCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmNsYXkECQBuYW1lX2hhc2j/S6sKXRcpzwMKAG5ldHdvcmtfaWRmsb8nCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:hardened_clay", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAAAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRBCOrrCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAAAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRBCOrrCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:white_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAAAACAQAbmFtZRoAbWluZWNyYWZ0OndoaXRlX3RlcnJhY290dGEECQBuYW1lX2hhc2j3RSdgmnAIewMKAG5ldHdvcmtfaWSimKw+CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAAAACAQAbmFtZRoAbWluZWNyYWZ0OndoaXRlX3RlcnJhY290dGEECQBuYW1lX2hhc2j3RSdgmnAIewMKAG5ldHdvcmtfaWSimKw+CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:light_gray_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAz1Ri3wIxomAwoAbmV0d29ya19pZH5qgOcKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAz1Ri3wIxomAwoAbmV0d29ya19pZH5qgOcKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:gray_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAwAACAQAbmFtZRkAbWluZWNyYWZ0OmdyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAXdSLAaNZ9vAwoAbmV0d29ya19pZM1QDV0KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAwAACAQAbmFtZRkAbWluZWNyYWZ0OmdyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAXdSLAaNZ9vAwoAbmV0d29ya19pZM1QDV0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:black_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWThAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsYWNrX3RlcnJhY290dGEECQBuYW1lX2hhc2jxssdv5vlbpgMKAG5ldHdvcmtfaWRE3Ru/CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsYWNrX3RlcnJhY290dGEECQBuYW1lX2hhc2jxssdv5vlbpgMKAG5ldHdvcmtfaWRE3Ru/CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:brown_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJyb3duX3RlcnJhY290dGEECQBuYW1lX2hhc2gG4kPenmOF9gMKAG5ldHdvcmtfaWQ/i0iNCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJyb3duX3RlcnJhY290dGEECQBuYW1lX2hhc2gG4kPenmOF9gMKAG5ldHdvcmtfaWQ/i0iNCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:red_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAwAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo7fX56HXFejEDCgBuZXR3b3JrX2lk8tTF8QoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAwAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo7fX56HXFejEDCgBuZXR3b3JrX2lk8tTF8QoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:orange_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAwAACAQAbmFtZRsAbWluZWNyYWZ0Om9yYW5nZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo0Hjmql3sruMDCgBuZXR3b3JrX2lklmqmkAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAwAACAQAbmFtZRsAbWluZWNyYWZ0Om9yYW5nZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo0Hjmql3sruMDCgBuZXR3b3JrX2lklmqmkAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:yellow_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAwAACAQAbmFtZRsAbWluZWNyYWZ0OnllbGxvd190ZXJyYWNvdHRhBAkAbmFtZV9oYXNoqkyKKrmA3VcDCgBuZXR3b3JrX2lkaM/orAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAwAACAQAbmFtZRsAbWluZWNyYWZ0OnllbGxvd190ZXJyYWNvdHRhBAkAbmFtZV9oYXNoqkyKKrmA3VcDCgBuZXR3b3JrX2lkaM/orAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:lime_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpbWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaANjADFOF9v7AwoAbmV0d29ya19pZJt0XsgKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpbWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaANjADFOF9v7AwoAbmV0d29ya19pZJt0XsgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:green_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyZWVuX3RlcnJhY290dGEECQBuYW1lX2hhc2j5Ybq36yYwRQMKAG5ldHdvcmtfaWQ8kGdHCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyZWVuX3RlcnJhY290dGEECQBuYW1lX2hhc2j5Ybq36yYwRQMKAG5ldHdvcmtfaWQ8kGdHCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cyan_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAwAACAQAbmFtZRkAbWluZWNyYWZ0OmN5YW5fdGVycmFjb3R0YQQJAG5hbWVfaGFzaN09COzMuHwAAwoAbmV0d29ya19pZIWPCzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAwAACAQAbmFtZRkAbWluZWNyYWZ0OmN5YW5fdGVycmFjb3R0YQQJAG5hbWVfaGFzaN09COzMuHwAAwoAbmV0d29ya19pZIWPCzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:light_blue_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaOMytez7cOZiAwoAbmV0d29ya19pZFHK1UsKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaOMytez7cOZiAwoAbmV0d29ya19pZFHK1UsKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:blue_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaF6inyTK5RpAAwoAbmV0d29ya19pZF5mVZIKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaF6inyTK5RpAAwoAbmV0d29ya19pZF5mVZIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:purple_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAwAACAQAbmFtZRsAbWluZWNyYWZ0OnB1cnBsZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoKF7YG61yTbEDCgBuZXR3b3JrX2lkhtRDlwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAwAACAQAbmFtZRsAbWluZWNyYWZ0OnB1cnBsZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoKF7YG61yTbEDCgBuZXR3b3JrX2lkhtRDlwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:magenta_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAwAACAQAbmFtZRwAbWluZWNyYWZ0Om1hZ2VudGFfdGVycmFjb3R0YQQJAG5hbWVfaGFzaLWvtpAVtztyAwoAbmV0d29ya19pZN5SoakKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAwAACAQAbmFtZRwAbWluZWNyYWZ0Om1hZ2VudGFfdGVycmFjb3R0YQQJAG5hbWVfaGFzaLWvtpAVtztyAwoAbmV0d29ya19pZN5SoakKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:pink_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAwAACAQAbmFtZRkAbWluZWNyYWZ0OnBpbmtfdGVycmFjb3R0YQQJAG5hbWVfaGFzaJ7mzvyzSQZTAwoAbmV0d29ya19pZDJWe4YKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAwAACAQAbmFtZRkAbWluZWNyYWZ0OnBpbmtfdGVycmFjb3R0YQQJAG5hbWVfaGFzaJ7mzvyzSQZTAwoAbmV0d29ya19pZDJWe4YKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:white_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAAAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkIlj9AAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAAAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkIlj9AAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:silver_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAAAACAQAbmFtZSIAbWluZWNyYWZ0OnNpbHZlcl9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAVsA0CnhzA4AwoAbmV0d29ya19pZPnxtJEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAAAACAQAbmFtZSIAbWluZWNyYWZ0OnNpbHZlcl9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAVsA0CnhzA4AwoAbmV0d29ya19pZPnxtJEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:gray_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAAAACAQAbmFtZSAAbWluZWNyYWZ0OmdyYXlfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2jvLZt9u/lF/AMKAG5ldHdvcmtfaWQVU8eFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAAAACAQAbmFtZSAAbWluZWNyYWZ0OmdyYXlfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2jvLZt9u/lF/AMKAG5ldHdvcmtfaWQVU8eFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:black_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJsYWNrX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoe8I4xAXbO5UDCgBuZXR3b3JrX2lk2Icb9AoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJsYWNrX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoe8I4xAXbO5UDCgBuZXR3b3JrX2lk2Icb9AoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:brown_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWToAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJyb3duX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoSiNZOobbpjoDCgBuZXR3b3JrX2lkJy0jwgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJyb3duX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoSiNZOobbpjoDCgBuZXR3b3JrX2lkJy0jwgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:red_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaBdWFGLmCLFVAwoAbmV0d29ya19pZMYBJSEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaBdWFGLmCLFVAwoAbmV0d29ya19pZMYBJSEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:orange_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAAAACAQAbmFtZSIAbWluZWNyYWZ0Om9yYW5nZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaMyJMrnPr7szAwoAbmV0d29ya19pZN6+7TUKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAAAACAQAbmFtZSIAbWluZWNyYWZ0Om9yYW5nZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaMyJMrnPr7szAwoAbmV0d29ya19pZN6+7TUKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:yellow_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAAAACAQAbmFtZSIAbWluZWNyYWZ0OnllbGxvd19nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaN6NaIhf6m0uAwoAbmV0d29ya19pZKRHXeoKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAAAACAQAbmFtZSIAbWluZWNyYWZ0OnllbGxvd19nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaN6NaIhf6m0uAwoAbmV0d29ya19pZKRHXeoKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:lime_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWThAAAACAQAbmFtZSAAbWluZWNyYWZ0OmxpbWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2iF3E68/rB2EAMKAG5ldHdvcmtfaWSP7qQWCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAAAACAQAbmFtZSAAbWluZWNyYWZ0OmxpbWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2iF3E68/rB2EAMKAG5ldHdvcmtfaWSP7qQWCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:green_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAAAACAQAbmFtZSEAbWluZWNyYWZ0OmdyZWVuX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNow5mo8aQDFboDCgBuZXR3b3JrX2lkoF11kgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAAAACAQAbmFtZSEAbWluZWNyYWZ0OmdyZWVuX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNow5mo8aQDFboDCgBuZXR3b3JrX2lkoF11kgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:cyan_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAAAACAQAbmFtZSAAbWluZWNyYWZ0OmN5YW5fZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gnNB+cCFRJhwMKAG5ldHdvcmtfaWT9buMtCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAAAACAQAbmFtZSAAbWluZWNyYWZ0OmN5YW5fZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gnNB+cCFRJhwMKAG5ldHdvcmtfaWT9buMtCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:light_blue_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAAAACAQAbmFtZSYAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gladnCDBKCigMKAG5ldHdvcmtfaWS5CszFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAAAACAQAbmFtZSYAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gladnCDBKCigMKAG5ldHdvcmtfaWS5CszFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:blue_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAAAACAQAbmFtZSAAbWluZWNyYWZ0OmJsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2giOZK+2nB1igMKAG5ldHdvcmtfaWR+e22CCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAAAACAQAbmFtZSAAbWluZWNyYWZ0OmJsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2giOZK+2nB1igMKAG5ldHdvcmtfaWR+e22CCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:purple_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAAAACAQAbmFtZSIAbWluZWNyYWZ0OnB1cnBsZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaIQU03txeAfHAwoAbmV0d29ya19pZLKbSE4KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAAAACAQAbmFtZSIAbWluZWNyYWZ0OnB1cnBsZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaIQU03txeAfHAwoAbmV0d29ya19pZLKbSE4KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:magenta_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAAAACAQAbmFtZSMAbWluZWNyYWZ0Om1hZ2VudGFfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2i/SNqDJbfjMgMKAG5ldHdvcmtfaWQKf9UvCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAAAACAQAbmFtZSMAbWluZWNyYWZ0Om1hZ2VudGFfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2i/SNqDJbfjMgMKAG5ldHdvcmtfaWQKf9UvCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:pink_glazed_terracotta", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAAAACAQAbmFtZSAAbWluZWNyYWZ0OnBpbmtfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2hik8DVt4g+twMKAG5ldHdvcmtfaWTKzav2CgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAAAACAQAbmFtZSAAbWluZWNyYWZ0OnBpbmtfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2hik8DVt4g+twMKAG5ldHdvcmtfaWTKzav2CgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:purpur_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZLD8ox4KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZLD8ox4KBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQcAZGVmYXVsdAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:purpur_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZPSAFFsKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZPSAFFsKBgBzdGF0ZXMICwBjaGlzZWxfdHlwZQUAbGluZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:packed_mud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9tdWQECQBuYW1lX2hhc2gHOMa121h4FgMKAG5ldHdvcmtfaWTUb6LyCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9tdWQECQBuYW1lX2hhc2gHOMa121h4FgMKAG5ldHdvcmtfaWTUb6LyCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:mud_bricks", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAgAACAQAbmFtZRQAbWluZWNyYWZ0Om11ZF9icmlja3MECQBuYW1lX2hhc2iDL/SVl/PewQMKAG5ldHdvcmtfaWSkBjaDCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAgAACAQAbmFtZRQAbWluZWNyYWZ0Om11ZF9icmlja3MECQBuYW1lX2hhc2iDL/SVl/PewQMKAG5ldHdvcmtfaWSkBjaDCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:nether_wart_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9XGS4GNnlV4DCgBuZXR3b3JrX2lkh3apIgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9XGS4GNnlV4DCgBuZXR3b3JrX2lkh3apIgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:warped_wart_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAQAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9IqDS9yUPJoDCgBuZXR3b3JrX2lkMpKAbAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAQAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9IqDS9yUPJoDCgBuZXR3b3JrX2lkMpKAbAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:shroomlight", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNocm9vbWxpZ2h0BAkAbmFtZV9oYXNoZHCHcHX/HYADCgBuZXR3b3JrX2lkLG2JiwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNocm9vbWxpZ2h0BAkAbmFtZV9oYXNoZHCHcHX/HYADCgBuZXR3b3JrX2lkLG2JiwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:crimson_nylium", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fbnlsaXVtBAkAbmFtZV9oYXNoOr6DJYW2bFYDCgBuZXR3b3JrX2lkuWpRDgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fbnlsaXVtBAkAbmFtZV9oYXNoOr6DJYW2bFYDCgBuZXR3b3JrX2lkuWpRDgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:warped_nylium", - "block_state_b64": "CgAAAwgAYmxvY2tfaWToAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9ueWxpdW0ECQBuYW1lX2hhc2g0Zf89cfr3rwMKAG5ldHdvcmtfaWSu/kekCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9ueWxpdW0ECQBuYW1lX2hhc2g0Zf89cfr3rwMKAG5ldHdvcmtfaWSu/kekCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:netherrack", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAAAACAQAbmFtZRQAbWluZWNyYWZ0Om5ldGhlcnJhY2sECQBuYW1lX2hhc2i/r5ZyRsvPyQMKAG5ldHdvcmtfaWTAiTOACgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAAAACAQAbmFtZRQAbWluZWNyYWZ0Om5ldGhlcnJhY2sECQBuYW1lX2hhc2i/r5ZyRsvPyQMKAG5ldHdvcmtfaWTAiTOACgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:basalt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhc2FsdAQJAG5hbWVfaGFzaH+UQO2yWodiAwoAbmV0d29ya19pZBPNSV4KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhc2FsdAQJAG5hbWVfaGFzaH+UQO2yWodiAwoAbmV0d29ya19pZBPNSV4KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_basalt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAQAACAQAbmFtZRkAbWluZWNyYWZ0OnBvbGlzaGVkX2Jhc2FsdAQJAG5hbWVfaGFzaMS+L0gMnRcBAwoAbmV0d29ya19pZF+/mHwKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAQAACAQAbmFtZRkAbWluZWNyYWZ0OnBvbGlzaGVkX2Jhc2FsdAQJAG5hbWVfaGFzaMS+L0gMnRcBAwoAbmV0d29ya19pZF+/mHwKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:smooth_basalt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AgAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9iYXNhbHQECQBuYW1lX2hhc2jKPUdz89kuNAMKAG5ldHdvcmtfaWTkb/oVCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AgAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9iYXNhbHQECQBuYW1lX2hhc2jKPUdz89kuNAMKAG5ldHdvcmtfaWTkb/oVCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:soul_soil", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAQAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc29pbAQJAG5hbWVfaGFzaC1/87ccutuTAwoAbmV0d29ya19pZKc63SMKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAQAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc29pbAQJAG5hbWVfaGFzaC1/87ccutuTAwoAbmV0d29ya19pZKc63SMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dirt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQmkQtoCgYAc3RhdGVzCAkAZGlydF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQmkQtoCgYAc3RhdGVzCAkAZGlydF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dirt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQId9pLCgYAc3RhdGVzCAkAZGlydF90eXBlBgBjb2Fyc2UAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWQId9pLCgYAc3RhdGVzCAkAZGlydF90eXBlBgBjb2Fyc2UAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:farmland", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AAAACAQAbmFtZRIAbWluZWNyYWZ0OmZhcm1sYW5kBAkAbmFtZV9oYXNoxyQ5ag7LolADCgBuZXR3b3JrX2lkX618FQoGAHN0YXRlcwMSAG1vaXN0dXJpemVkX2Ftb3VudAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AAAACAQAbmFtZRIAbWluZWNyYWZ0OmZhcm1sYW5kBAkAbmFtZV9oYXNoxyQ5ag7LolADCgBuZXR3b3JrX2lkX618FQoGAHN0YXRlcwMSAG1vaXN0dXJpemVkX2Ftb3VudAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:grass_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXNzX2Jsb2NrBAkAbmFtZV9oYXNojPyGp3/CSZwDCgBuZXR3b3JrX2lktCgx3goGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXNzX2Jsb2NrBAkAbmFtZV9oYXNojPyGp3/CSZwDCgBuZXR3b3JrX2lktCgx3goGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:grass_path", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdyYXNzX3BhdGgECQBuYW1lX2hhc2i0/KZV8Qsy+gMKAG5ldHdvcmtfaWT7CcdzCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdyYXNzX3BhdGgECQBuYW1lX2hhc2i0/KZV8Qsy+gMKAG5ldHdvcmtfaWT7CcdzCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:podzol", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTzAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBvZHpvbAQJAG5hbWVfaGFzaBzqokRjH4Z1AwoAbmV0d29ya19pZPPS/GUKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTzAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBvZHpvbAQJAG5hbWVfaGFzaBzqokRjH4Z1AwoAbmV0d29ya19pZPPS/GUKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mycelium", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAAAACAQAbmFtZRIAbWluZWNyYWZ0Om15Y2VsaXVtBAkAbmFtZV9oYXNojTN09cKickIDCgBuZXR3b3JrX2lkLNPxXQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAAAACAQAbmFtZRIAbWluZWNyYWZ0Om15Y2VsaXVtBAkAbmFtZV9oYXNojTN09cKickIDCgBuZXR3b3JrX2lkLNPxXQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:mud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAgAACAQAbmFtZQ0AbWluZWNyYWZ0Om11ZAQJAG5hbWVfaGFzaPb/3P+uLy+9AwoAbmV0d29ya19pZPIUlUkKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAgAACAQAbmFtZQ0AbWluZWNyYWZ0Om11ZAQJAG5hbWVfaGFzaPb/3P+uLy+9AwoAbmV0d29ya19pZPIUlUkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkIQ4xgAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkIQ4xgAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:iron_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAAAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lk3loneQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAAAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lk3loneQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:gold_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAAAACAQAbmFtZRIAbWluZWNyYWZ0OmdvbGRfb3JlBAkAbmFtZV9oYXNoC5Y+DUGXLC4DCgBuZXR3b3JrX2lkNhvMfwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAAAACAQAbmFtZRIAbWluZWNyYWZ0OmdvbGRfb3JlBAkAbmFtZV9oYXNoC5Y+DUGXLC4DCgBuZXR3b3JrX2lkNhvMfwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:diamond_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AAAACAQAbmFtZRUAbWluZWNyYWZ0OmRpYW1vbmRfb3JlBAkAbmFtZV9oYXNokUOJ2wZZrGQDCgBuZXR3b3JrX2lk/dChVAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AAAACAQAbmFtZRUAbWluZWNyYWZ0OmRpYW1vbmRfb3JlBAkAbmFtZV9oYXNokUOJ2wZZrGQDCgBuZXR3b3JrX2lk/dChVAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:lapis_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAAAACAQAbmFtZRMAbWluZWNyYWZ0OmxhcGlzX29yZQQJAG5hbWVfaGFzaMrmrUrSzb7qAwoAbmV0d29ya19pZMg+qK4KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAAAACAQAbmFtZRMAbWluZWNyYWZ0OmxhcGlzX29yZQQJAG5hbWVfaGFzaMrmrUrSzb7qAwoAbmV0d29ya19pZMg+qK4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:redstone_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZHN0b25lX29yZQQJAG5hbWVfaGFzaFHVnp8Wc4JbAwoAbmV0d29ya19pZKDYvQoKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZHN0b25lX29yZQQJAG5hbWVfaGFzaFHVnp8Wc4JbAwoAbmV0d29ya19pZKDYvQoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:coal_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAAAACAQAbmFtZRIAbWluZWNyYWZ0OmNvYWxfb3JlBAkAbmFtZV9oYXNo1OjA+Iuy51oDCgBuZXR3b3JrX2lk+R/aKAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAAAACAQAbmFtZRIAbWluZWNyYWZ0OmNvYWxfb3JlBAkAbmFtZV9oYXNo1OjA+Iuy51oDCgBuZXR3b3JrX2lk+R/aKAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:copper_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcHBlcl9vcmUECQBuYW1lX2hhc2iSZduSntOzOwMKAG5ldHdvcmtfaWQtIuCnCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcHBlcl9vcmUECQBuYW1lX2hhc2iSZduSntOzOwMKAG5ldHdvcmtfaWQtIuCnCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:emerald_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVtZXJhbGRfb3JlBAkAbmFtZV9oYXNoJTovr+VgINsDCgBuZXR3b3JrX2lknbkqCgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVtZXJhbGRfb3JlBAkAbmFtZV9oYXNoJTovr+VgINsDCgBuZXR3b3JrX2lknbkqCgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:quartz_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAAAACAQAbmFtZRQAbWluZWNyYWZ0OnF1YXJ0el9vcmUECQBuYW1lX2hhc2g0yNHLMK9TaQMKAG5ldHdvcmtfaWSzN7nzCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAAAACAQAbmFtZRQAbWluZWNyYWZ0OnF1YXJ0el9vcmUECQBuYW1lX2hhc2g0yNHLMK9TaQMKAG5ldHdvcmtfaWSzN7nzCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:nether_gold_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcl9nb2xkX29yZQQJAG5hbWVfaGFzaEJZ7segIBgBAwoAbmV0d29ya19pZNI9pDgKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcl9nb2xkX29yZQQJAG5hbWVfaGFzaEJZ7segIBgBAwoAbmV0d29ya19pZNI9pDgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:ancient_debris", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFuY2llbnRfZGVicmlzBAkAbmFtZV9oYXNoNrbxMc9AwKcDCgBuZXR3b3JrX2lkrSNjEAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFuY2llbnRfZGVicmlzBAkAbmFtZV9oYXNoNrbxMc9AwKcDCgBuZXR3b3JrX2lkrSNjEAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:deepslate_iron_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9pcm9uX29yZQQJAG5hbWVfaGFzaB/fDL9pgvXXAwoAbmV0d29ya19pZFA0bz4KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9pcm9uX29yZQQJAG5hbWVfaGFzaB/fDL9pgvXXAwoAbmV0d29ya19pZFA0bz4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:deepslate_gold_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9nb2xkX29yZQQJAG5hbWVfaGFzaF9G7WYhKFinAwoAbmV0d29ya19pZHQTfBUKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9nb2xkX29yZQQJAG5hbWVfaGFzaF9G7WYhKFinAwoAbmV0d29ya19pZHQTfBUKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:deepslate_diamond_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9kaWFtb25kX29yZQQJAG5hbWVfaGFzaEUH5USh+iD3AwoAbmV0d29ya19pZHP6VzAKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9kaWFtb25kX29yZQQJAG5hbWVfaGFzaEUH5USh+iD3AwoAbmV0d29ya19pZHP6VzAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:deepslate_lapis_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV9sYXBpc19vcmUECQBuYW1lX2hhc2j+yFxU/KZs1gMKAG5ldHdvcmtfaWRKINzICgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV9sYXBpc19vcmUECQBuYW1lX2hhc2j+yFxU/KZs1gMKAG5ldHdvcmtfaWRKINzICgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:deepslate_redstone_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9yZWRzdG9uZV9vcmUECQBuYW1lX2hhc2iVgM3wWWD6ugMKAG5ldHdvcmtfaWReBdYRCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9yZWRzdG9uZV9vcmUECQBuYW1lX2hhc2iVgM3wWWD6ugMKAG5ldHdvcmtfaWReBdYRCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:deepslate_emerald_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9lbWVyYWxkX29yZQQJAG5hbWVfaGFzaNlfo5HTwS6wAwoAbmV0d29ya19pZNeie6sKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9lbWVyYWxkX29yZQQJAG5hbWVfaGFzaNlfo5HTwS6wAwoAbmV0d29ya19pZNeie6sKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:deepslate_coal_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb2FsX29yZQQJAG5hbWVfaGFzaIjikmcbRrPPAwoAbmV0d29ya19pZD9TiygKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb2FsX29yZQQJAG5hbWVfaGFzaIjikmcbRrPPAwoAbmV0d29ya19pZD9TiygKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:deepslate_copper_ore", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb3BwZXJfb3JlBAkAbmFtZV9oYXNottjV4Ev5LAQDCgBuZXR3b3JrX2lkP23rgQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb3BwZXJfb3JlBAkAbmFtZV9oYXNottjV4Ev5LAQDCgBuZXR3b3JrX2lkP23rgQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:gravel", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAAAACAQAbmFtZRAAbWluZWNyYWZ0OmdyYXZlbAQJAG5hbWVfaGFzaOFxz8XJd2r/AwoAbmV0d29ya19pZBpfI1sKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAAAACAQAbmFtZRAAbWluZWNyYWZ0OmdyYXZlbAQJAG5hbWVfaGFzaOFxz8XJd2r/AwoAbmV0d29ya19pZBpfI1sKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:granite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAwAACAQAbmFtZREAbWluZWNyYWZ0OmdyYW5pdGUECQBuYW1lX2hhc2iq+Dur2pw4AwMKAG5ldHdvcmtfaWT2NMfJCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAwAACAQAbmFtZREAbWluZWNyYWZ0OmdyYW5pdGUECQBuYW1lX2hhc2iq+Dur2pw4AwMKAG5ldHdvcmtfaWT2NMfJCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:diorite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAwAACAQAbmFtZREAbWluZWNyYWZ0OmRpb3JpdGUECQBuYW1lX2hhc2iaFsq2iinZBQMKAG5ldHdvcmtfaWQqGE6XCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAwAACAQAbmFtZREAbWluZWNyYWZ0OmRpb3JpdGUECQBuYW1lX2hhc2iaFsq2iinZBQMKAG5ldHdvcmtfaWQqGE6XCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:andesite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAwAACAQAbmFtZRIAbWluZWNyYWZ0OmFuZGVzaXRlBAkAbmFtZV9oYXNosaLIEnQQoSYDCgBuZXR3b3JrX2lkEApRZAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAwAACAQAbmFtZRIAbWluZWNyYWZ0OmFuZGVzaXRlBAkAbmFtZV9oYXNosaLIEnQQoSYDCgBuZXR3b3JrX2lkEApRZAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:blackstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrc3RvbmUECQBuYW1lX2hhc2iMFYziD80D6QMKAG5ldHdvcmtfaWSrUryHCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrc3RvbmUECQBuYW1lX2hhc2iMFYziD80D6QMKAG5ldHdvcmtfaWSrUryHCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AgAACAQAbmFtZRMAbWluZWNyYWZ0OmRlZXBzbGF0ZQQJAG5hbWVfaGFzaKX5pAblxz8TAwoAbmV0d29ya19pZOJoQjsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AgAACAQAbmFtZRMAbWluZWNyYWZ0OmRlZXBzbGF0ZQQJAG5hbWVfaGFzaKX5pAblxz8TAwoAbmV0d29ya19pZOJoQjsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_granite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWROAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGUECQBuYW1lX2hhc2iLiEfys8pFIAMKAG5ldHdvcmtfaWTCxxcHCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGUECQBuYW1lX2hhc2iLiEfys8pFIAMKAG5ldHdvcmtfaWTCxxcHCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:polished_diorite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGUECQBuYW1lX2hhc2hTxY4fKmNmlAMKAG5ldHdvcmtfaWTmtjdRCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGUECQBuYW1lX2hhc2hTxY4fKmNmlAMKAG5ldHdvcmtfaWTmtjdRCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:polished_andesite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAwAACAQAbmFtZRsAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlBAkAbmFtZV9oYXNovl28uFk4HuQDCgBuZXR3b3JrX2lklFjuCwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAwAACAQAbmFtZRsAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlBAkAbmFtZV9oYXNovl28uFk4HuQDCgBuZXR3b3JrX2lklFjuCwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:polished_blackstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAgAACAQAbmFtZR0AbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2jT9fHCl6vWQQMKAG5ldHdvcmtfaWR/Ho6oCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAgAACAQAbmFtZR0AbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2jT9fHCl6vWQQMKAG5ldHdvcmtfaWR/Ho6oCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:polished_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaHC1edoaWF3uAwoAbmV0d29ya19pZCPeQsEKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaHC1edoaWF3uAwoAbmV0d29ya19pZCPeQsEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:sand", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWTekU/mCgYAc3RhdGVzCAkAc2FuZF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWTekU/mCgYAc3RhdGVzCAkAc2FuZF90eXBlBgBub3JtYWwAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:sand", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWSTgcqmCgYAc3RhdGVzCAkAc2FuZF90eXBlAwByZWQAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWSTgcqmCgYAc3RhdGVzCAkAc2FuZF90eXBlAwByZWQAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cactus", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAAAACAQAbmFtZRAAbWluZWNyYWZ0OmNhY3R1cwQJAG5hbWVfaGFzaCG9zL0N4wvGAwoAbmV0d29ya19pZDeCERAKBgBzdGF0ZXMDAwBhZ2UAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAAAACAQAbmFtZRAAbWluZWNyYWZ0OmNhY3R1cwQJAG5hbWVfaGFzaCG9zL0N4wvGAwoAbmV0d29ya19pZDeCERAKBgBzdGF0ZXMDAwBhZ2UAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:oak_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAAAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWQjfjoxCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAAAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWQjfjoxCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stripped_oak_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQJAQAACAQAbmFtZRoAbWluZWNyYWZ0OnN0cmlwcGVkX29ha19sb2cECQBuYW1lX2hhc2h8dqh+OOHU4wMKAG5ldHdvcmtfaWSYKjdrCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQJAQAACAQAbmFtZRoAbWluZWNyYWZ0OnN0cmlwcGVkX29ha19sb2cECQBuYW1lX2hhc2h8dqh+OOHU4wMKAG5ldHdvcmtfaWSYKjdrCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:spruce_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AwAACAQAbmFtZRQAbWluZWNyYWZ0OnNwcnVjZV9sb2cECQBuYW1lX2hhc2hZ03qaLoF3WgMKAG5ldHdvcmtfaWRlFD8eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AwAACAQAbmFtZRQAbWluZWNyYWZ0OnNwcnVjZV9sb2cECQBuYW1lX2hhc2hZ03qaLoF3WgMKAG5ldHdvcmtfaWRlFD8eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stripped_spruce_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV9sb2cECQBuYW1lX2hhc2iNrhKjS5IyrgMKAG5ldHdvcmtfaWRQcEC3CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV9sb2cECQBuYW1lX2hhc2iNrhKjS5IyrgMKAG5ldHdvcmtfaWRQcEC3CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:birch_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AwAACAQAbmFtZRMAbWluZWNyYWZ0OmJpcmNoX2xvZwQJAG5hbWVfaGFzaBUzT3NxsZAnAwoAbmV0d29ya19pZBKN3VQKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AwAACAQAbmFtZRMAbWluZWNyYWZ0OmJpcmNoX2xvZwQJAG5hbWVfaGFzaBUzT3NxsZAnAwoAbmV0d29ya19pZBKN3VQKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stripped_birch_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAQAACAQAbmFtZRwAbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX2xvZwQJAG5hbWVfaGFzaCFKS4AeuSidAwoAbmV0d29ya19pZN0IONIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAQAACAQAbmFtZRwAbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX2xvZwQJAG5hbWVfaGFzaCFKS4AeuSidAwoAbmV0d29ya19pZN0IONIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:jungle_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AwAACAQAbmFtZRQAbWluZWNyYWZ0Omp1bmdsZV9sb2cECQBuYW1lX2hhc2gkwW0KNulqDgMKAG5ldHdvcmtfaWQaziU/CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AwAACAQAbmFtZRQAbWluZWNyYWZ0Omp1bmdsZV9sb2cECQBuYW1lX2hhc2gkwW0KNulqDgMKAG5ldHdvcmtfaWQaziU/CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stripped_jungle_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV9sb2cECQBuYW1lX2hhc2hAwMsgOk02JAMKAG5ldHdvcmtfaWQvls0eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV9sb2cECQBuYW1lX2hhc2hAwMsgOk02JAMKAG5ldHdvcmtfaWQvls0eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:acacia_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAAAACAQAbmFtZRQAbWluZWNyYWZ0OmFjYWNpYV9sb2cECQBuYW1lX2hhc2iV48VpYhjoYQMKAG5ldHdvcmtfaWRxEqe0CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAAAACAQAbmFtZRQAbWluZWNyYWZ0OmFjYWNpYV9sb2cECQBuYW1lX2hhc2iV48VpYhjoYQMKAG5ldHdvcmtfaWRxEqe0CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stripped_acacia_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV9sb2cECQBuYW1lX2hhc2hJb0lQqnEqlgMKAG5ldHdvcmtfaWRg3IdRCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV9sb2cECQBuYW1lX2hhc2hJb0lQqnEqlgMKAG5ldHdvcmtfaWRg3IdRCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dark_oak_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AwAACAQAbmFtZRYAbWluZWNyYWZ0OmRhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaIWfVRd0XUo3AwoAbmV0d29ya19pZPMM7LYKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AwAACAQAbmFtZRYAbWluZWNyYWZ0OmRhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaIWfVRd0XUo3AwoAbmV0d29ya19pZPMM7LYKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stripped_dark_oak_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaPFTdxRdPwkOAwoAbmV0d29ya19pZDIzenIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaPFTdxRdPwkOAwoAbmV0d29ya19pZDIzenIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:mangrove_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaHZe6DzPZBobAwoAbmV0d29ya19pZG6DuYkKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaHZe6DzPZBobAwoAbmV0d29ya19pZG6DuYkKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stripped_mangrove_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaLqIBo4hwA//AwoAbmV0d29ya19pZPtRn7UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaLqIBo4hwA//AwoAbmV0d29ya19pZPtRn7UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cherry_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAwAACAQAbmFtZRQAbWluZWNyYWZ0OmNoZXJyeV9sb2cECQBuYW1lX2hhc2hwFlaioppB1wMKAG5ldHdvcmtfaWS2sdXECgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAwAACAQAbmFtZRQAbWluZWNyYWZ0OmNoZXJyeV9sb2cECQBuYW1lX2hhc2hwFlaioppB1wMKAG5ldHdvcmtfaWS2sdXECgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stripped_cherry_log", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAwAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV9sb2cECQBuYW1lX2hhc2i85H6G+WhXaAMKAG5ldHdvcmtfaWRjzoglCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAwAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV9sb2cECQBuYW1lX2hhc2i85H6G+WhXaAMKAG5ldHdvcmtfaWRjzoglCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crimson_stem", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAQAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc3RlbQQJAG5hbWVfaGFzaM0FzfL0UTKZAwoAbmV0d29ya19pZKvzID0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAQAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc3RlbQQJAG5hbWVfaGFzaM0FzfL0UTKZAwoAbmV0d29ya19pZKvzID0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stripped_crimson_stem", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25fc3RlbQQJAG5hbWVfaGFzaDlA6nood57EAwoAbmV0d29ya19pZHrIqjIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25fc3RlbQQJAG5hbWVfaGFzaDlA6nood57EAwoAbmV0d29ya19pZHrIqjIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:warped_stem", - "block_state_b64": "CgAAAwgAYmxvY2tfaWThAQAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zdGVtBAkAbmFtZV9oYXNon7cKfPZxdrUDCgBuZXR3b3JrX2lkerWyMwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAQAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zdGVtBAkAbmFtZV9oYXNon7cKfPZxdrUDCgBuZXR3b3JrX2lkerWyMwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stripped_warped_stem", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAQAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9zdGVtBAkAbmFtZV9oYXNoEw+y0dDPSd8DCgBuZXR3b3JrX2lkIQ9vBAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAQAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9zdGVtBAkAbmFtZV9oYXNoEw+y0dDPSd8DCgBuZXR3b3JrX2lkIQ9vBAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:oak_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha193b29kBAkAbmFtZV9oYXNoqQIkuVPyJX0DCgBuZXR3b3JrX2lku2G1YAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha193b29kBAkAbmFtZV9oYXNoqQIkuVPyJX0DCgBuZXR3b3JrX2lku2G1YAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:spruce_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQtBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV93b29kBAkAbmFtZV9oYXNoTrIJ5TAQ+OgDCgBuZXR3b3JrX2lkaXLxCwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV93b29kBAkAbmFtZV9oYXNoTrIJ5TAQ+OgDCgBuZXR3b3JrX2lkaXLxCwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:birch_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQuBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3dvb2QECQBuYW1lX2hhc2iqVjG4xt0cKQMKAG5ldHdvcmtfaWS06c5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3dvb2QECQBuYW1lX2hhc2iqVjG4xt0cKQMKAG5ldHdvcmtfaWS06c5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:jungle_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQvBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV93b29kBAkAbmFtZV9oYXNo9bYW29ORWCoDCgBuZXR3b3JrX2lkyFyKLQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV93b29kBAkAbmFtZV9oYXNo9bYW29ORWCoDCgBuZXR3b3JrX2lkyFyKLQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:acacia_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQwBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV93b29kBAkAbmFtZV9oYXNoKkDfgzlJUcIDCgBuZXR3b3JrX2lkuTWlcgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV93b29kBAkAbmFtZV9oYXNoKkDfgzlJUcIDCgBuZXR3b3JrX2lkuTWlcgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dark_oak_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQxBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2jaKv4ORLadAAMKAG5ldHdvcmtfaWSDrNQ8CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2jaKv4ORLadAAMKAG5ldHdvcmtfaWSDrNQ8CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stripped_oak_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQyBAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0cmlwcGVkX29ha193b29kBAkAbmFtZV9oYXNovW6KCv+VZnsDCgBuZXR3b3JrX2lkkhWGegoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyBAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0cmlwcGVkX29ha193b29kBAkAbmFtZV9oYXNovW6KCv+VZnsDCgBuZXR3b3JrX2lkkhWGegoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stripped_spruce_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQzBAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV93b29kBAkAbmFtZV9oYXNoMnuUk4Xo6icDCgBuZXR3b3JrX2lkes2ydAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzBAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV93b29kBAkAbmFtZV9oYXNoMnuUk4Xo6icDCgBuZXR3b3JrX2lkes2ydAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stripped_birch_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0BAAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX3dvb2QECQBuYW1lX2hhc2hm88R604TKbAMKAG5ldHdvcmtfaWRleEMJCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0BAAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX3dvb2QECQBuYW1lX2hhc2hm88R604TKbAMKAG5ldHdvcmtfaWRleEMJCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stripped_jungle_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV93b29kBAkAbmFtZV9oYXNoUVs6KsZQRBoDCgBuZXR3b3JrX2lk92k8HQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV93b29kBAkAbmFtZV9oYXNoUVs6KsZQRBoDCgBuZXR3b3JrX2lk92k8HQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stripped_acacia_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV93b29kBAkAbmFtZV9oYXNo/kOPN2bCJhUDCgBuZXR3b3JrX2lktl6LwQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV93b29kBAkAbmFtZV9oYXNo/kOPN2bCJhUDCgBuZXR3b3JrX2lktl6LwQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stripped_dark_oak_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3BAAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2h2jFDfKVFgfAMKAG5ldHdvcmtfaWTgZQ5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3BAAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2h2jFDfKVFgfAMKAG5ldHdvcmtfaWTgZQ5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mangrove_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2iXVxG0JG2fVAMKAG5ldHdvcmtfaWTok1JCCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2iXVxG0JG2fVAMKAG5ldHdvcmtfaWTok1JCCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkBDABzdHJpcHBlZF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stripped_mangrove_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2h7CkbaBF7/WAMKAG5ldHdvcmtfaWQLAX88CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2h7CkbaBF7/WAMKAG5ldHdvcmtfaWQLAX88CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cherry_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV93b29kBAkAbmFtZV9oYXNoAW8srlmpBM8DCgBuZXR3b3JrX2lkEALMfAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AQwAc3RyaXBwZWRfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV93b29kBAkAbmFtZV9oYXNoAW8srlmpBM8DCgBuZXR3b3JrX2lkEALMfAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AQwAc3RyaXBwZWRfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stripped_cherry_wood", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAwAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV93b29kBAkAbmFtZV9oYXNo/e7KXv+CB38DCgBuZXR3b3JrX2lkg5aVtQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAwAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV93b29kBAkAbmFtZV9oYXNo/e7KXv+CB38DCgBuZXR3b3JrX2lkg5aVtQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:crimson_hyphae", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNouRmKmfSqEWADCgBuZXR3b3JrX2lk+Tm5rQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNouRmKmfSqEWADCgBuZXR3b3JrX2lk+Tm5rQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stripped_crimson_hyphae", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAgAACAQAbmFtZSEAbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNoFffwmABq4LUDCgBuZXR3b3JrX2lkZAlUbgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAgAACAQAbmFtZSEAbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNoFffwmABq4LUDCgBuZXR3b3JrX2lkZAlUbgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:warped_hyphae", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2hn8plQUr6pmQMKAG5ldHdvcmtfaWRU2AIBCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2hn8plQUr6pmQMKAG5ldHdvcmtfaWRU2AIBCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:stripped_warped_hyphae", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2irKq+HYPSgjQMKAG5ldHdvcmtfaWSbrOPDCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2irKq+HYPSgjQMKAG5ldHdvcmtfaWSbrOPDCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:bamboo_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19ibG9jawQJAG5hbWVfaGFzaAbDeur6stIBAwoAbmV0d29ya19pZCJAwn0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19ibG9jawQJAG5hbWVfaGFzaAbDeur6stIBAwoAbmV0d29ya19pZCJAwn0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:stripped_bamboo_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAwAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2JhbWJvb19ibG9jawQJAG5hbWVfaGFzaJpwytpZOZM9AwoAbmV0d29ya19pZKuRbNEKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAwAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2JhbWJvb19ibG9jawQJAG5hbWVfaGFzaJpwytpZOZM9AwoAbmV0d29ya19pZKuRbNEKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:oak_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19sZWF2ZXMECQBuYW1lX2hhc2h6O4xGqA2oKgMKAG5ldHdvcmtfaWT98c59CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19sZWF2ZXMECQBuYW1lX2hhc2h6O4xGqA2oKgMKAG5ldHdvcmtfaWT98c59CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:spruce_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQfBAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9sZWF2ZXMECQBuYW1lX2hhc2i9x1CtNAuqZwMKAG5ldHdvcmtfaWSzF7pTCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfBAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9sZWF2ZXMECQBuYW1lX2hhc2i9x1CtNAuqZwMKAG5ldHdvcmtfaWSzF7pTCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:birch_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQgBAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2xlYXZlcwQJAG5hbWVfaGFzaBlAGHaoaLZSAwoAbmV0d29ya19pZOjtvWcKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgBAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2xlYXZlcwQJAG5hbWVfaGFzaBlAGHaoaLZSAwoAbmV0d29ya19pZOjtvWcKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:jungle_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQhBAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9sZWF2ZXMECQBuYW1lX2hhc2iW1uAH07zGhgMKAG5ldHdvcmtfaWSA5KX0CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhBAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9sZWF2ZXMECQBuYW1lX2hhc2iW1uAH07zGhgMKAG5ldHdvcmtfaWSA5KX0CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:acacia_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9sZWF2ZXMECQBuYW1lX2hhc2iZJf8dAgDRNQMKAG5ldHdvcmtfaWQ/G7VuCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9sZWF2ZXMECQBuYW1lX2hhc2iZJf8dAgDRNQMKAG5ldHdvcmtfaWQ/G7VuCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dark_oak_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQiBAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2xlYXZlcwQJAG5hbWVfaGFzaCk7rDipWFSjAwoAbmV0d29ya19pZJ2AkbYKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiBAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2xlYXZlcwQJAG5hbWVfaGFzaCk7rDipWFSjAwoAbmV0d29ya19pZJ2AkbYKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:mangrove_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2xlYXZlcwQJAG5hbWVfaGFzaKyI/dWvhEG8AwoAbmV0d29ya19pZPQxCZ8KBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2xlYXZlcwQJAG5hbWVfaGFzaKyI/dWvhEG8AwoAbmV0d29ya19pZPQxCZ8KBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cherry_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9sZWF2ZXMECQBuYW1lX2hhc2giTs9ChhYBlQMKAG5ldHdvcmtfaWR8bPpwCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9sZWF2ZXMECQBuYW1lX2hhc2giTs9ChhYBlQMKAG5ldHdvcmtfaWR8bPpwCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:azalea_leaves", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAgAACAQAbmFtZRcAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXMECQBuYW1lX2hhc2iXFhD57wFS7AMKAG5ldHdvcmtfaWTNB/9ECgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAgAACAQAbmFtZRcAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXMECQBuYW1lX2hhc2iXFhD57wFS7AMKAG5ldHdvcmtfaWTNB/9ECgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:azalea_leaves_flowered", - "block_state_b64": "CgAAAwgAYmxvY2tfaWREAgAACAQAbmFtZSAAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXNfZmxvd2VyZWQECQBuYW1lX2hhc2gs8jxlS/pMrwMKAG5ldHdvcmtfaWQ7W4PyCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWREAgAACAQAbmFtZSAAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXNfZmxvd2VyZWQECQBuYW1lX2hhc2gs8jxlS/pMrwMKAG5ldHdvcmtfaWQ7W4PyCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQmoOEvCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUDAG9hawADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:oak_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZRUAbWluZWNyYWZ0Om9ha19zYXBsaW5nBAkAbmFtZV9oYXNoogXcT9QfjiUDCgBuZXR3b3JrX2lkG22C+AoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQO8pAmCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAHNwcnVjZQADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:spruce_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4BAAACAQAbmFtZRgAbWluZWNyYWZ0OnNwcnVjZV9zYXBsaW5nBAkAbmFtZV9oYXNoe8hz4uYP0FcDCgBuZXR3b3JrX2lkUQmhaQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWQDHhokCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUFAGJpcmNoAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:birch_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5BAAACAQAbmFtZRcAbWluZWNyYWZ0OmJpcmNoX3NhcGxpbmcECQBuYW1lX2hhc2h348iJQ/tK4wMKAG5ldHdvcmtfaWQ2Uh53CgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWTdQrcyCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAGp1bmdsZQADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:jungle_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6BAAACAQAbmFtZRgAbWluZWNyYWZ0Omp1bmdsZV9zYXBsaW5nBAkAbmFtZV9oYXNo7tyTOdSrxaADCgBuZXR3b3JrX2lkXmBAdAoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWRCDffNCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUGAGFjYWNpYQADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:acacia_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7BAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjYWNpYV9zYXBsaW5nBAkAbmFtZV9oYXNo99sg15uoX7ADCgBuZXR3b3JrX2lkPXX1KgoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZREAbWluZWNyYWZ0OnNhcGxpbmcECQBuYW1lX2hhc2goZxi1oICLKwMKAG5ldHdvcmtfaWR0BRzPCgYAc3RhdGVzAQcAYWdlX2JpdAAIDABzYXBsaW5nX3R5cGUIAGRhcmtfb2FrAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:dark_oak_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8BAAACAQAbmFtZRoAbWluZWNyYWZ0OmRhcmtfb2FrX3NhcGxpbmcECQBuYW1lX2hhc2jnVzFplW7cHgMKAG5ldHdvcmtfaWTD4giHCgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mangrove_propagule", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hbmdyb3ZlX3Byb3BhZ3VsZQQJAG5hbWVfaGFzaJGeox6hkfLFAwoAbmV0d29ya19pZAIpvpYKBgBzdGF0ZXMBBwBoYW5naW5nAAMPAHByb3BhZ3VsZV9zdGFnZQAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hbmdyb3ZlX3Byb3BhZ3VsZQQJAG5hbWVfaGFzaJGeox6hkfLFAwoAbmV0d29ya19pZAIpvpYKBgBzdGF0ZXMBBwBoYW5naW5nAAMPAHByb3BhZ3VsZV9zdGFnZQAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cherry_sapling", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAwAACAQAbmFtZRgAbWluZWNyYWZ0OmNoZXJyeV9zYXBsaW5nBAkAbmFtZV9oYXNoGrPpNMf1LtcDCgBuZXR3b3JrX2lkypakXQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAwAACAQAbmFtZRgAbWluZWNyYWZ0OmNoZXJyeV9zYXBsaW5nBAkAbmFtZV9oYXNoGrPpNMf1LtcDCgBuZXR3b3JrX2lkypakXQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bee_nest", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJlZV9uZXN0BAkAbmFtZV9oYXNo2R2WBxUHEZIDCgBuZXR3b3JrX2lkiXWLEAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAADCwBob25leV9sZXZlbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJlZV9uZXN0BAkAbmFtZV9oYXNo2R2WBxUHEZIDCgBuZXR3b3JrX2lkiXWLEAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAADCwBob25leV9sZXZlbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:wheat_seeds" @@ -2095,7 +2247,7 @@ }, { "id": "minecraft:melon_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1lbG9uX2Jsb2NrBAkAbmFtZV9oYXNoXxSm0iYpAx8DCgBuZXR3b3JrX2lkC9rqygoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1lbG9uX2Jsb2NrBAkAbmFtZV9oYXNoXxSm0iYpAx8DCgBuZXR3b3JrX2lkC9rqygoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:melon_slice" @@ -2111,205 +2263,205 @@ }, { "id": "minecraft:pumpkin", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAAAACAQAbmFtZREAbWluZWNyYWZ0OnB1bXBraW4ECQBuYW1lX2hhc2gc8A3jaSzWbgMKAG5ldHdvcmtfaWRFGA+xCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAAAACAQAbmFtZREAbWluZWNyYWZ0OnB1bXBraW4ECQBuYW1lX2hhc2gc8A3jaSzWbgMKAG5ldHdvcmtfaWRFGA+xCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:carved_pumpkin", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNhcnZlZF9wdW1wa2luBAkAbmFtZV9oYXNoPu1T0MJuG90DCgBuZXR3b3JrX2lkXNNn5QoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNhcnZlZF9wdW1wa2luBAkAbmFtZV9oYXNoPu1T0MJuG90DCgBuZXR3b3JrX2lkXNNn5QoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:lit_pumpkin", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxpdF9wdW1wa2luBAkAbmFtZV9oYXNo7gWtEm2uPL0DCgBuZXR3b3JrX2lki8sU4AoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxpdF9wdW1wa2luBAkAbmFtZV9oYXNo7gWtEm2uPL0DCgBuZXR3b3JrX2lki8sU4AoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:honeycomb" }, { - "id": "minecraft:tallgrass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZOh33DMKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAGZlcm4AAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:fern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPBAAACAQAbmFtZQ4AbWluZWNyYWZ0OmZlcm4ECQBuYW1lX2hhc2iHbj3yXFn4owMKAG5ldHdvcmtfaWQKC6u7CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZMx1sfgKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAZmVybgEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:large_fern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgBAAACAQAbmFtZRQAbWluZWNyYWZ0OmxhcmdlX2Zlcm4ECQBuYW1lX2hhc2gnE9sd0LzHtQMKAG5ldHdvcmtfaWTS9hG4CgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:tallgrass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRMAbWluZWNyYWZ0OnRhbGxncmFzcwQJAG5hbWVfaGFzaC3PXpAXXYswAwoAbmV0d29ya19pZErptfIKBgBzdGF0ZXMIDwB0YWxsX2dyYXNzX3R5cGUEAHRhbGwAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:short_grass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNob3J0X2dyYXNzBAkAbmFtZV9oYXNobWQghLH0bLcDCgBuZXR3b3JrX2lkJWOOqAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZAbadmIKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQUAZ3Jhc3MBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:tall_grass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfBAAACAQAbmFtZRQAbWluZWNyYWZ0OnRhbGxfZ3Jhc3MECQBuYW1lX2hhc2ii5MyZJpv4sgMKAG5ldHdvcmtfaWRRfeH4CgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:nether_sprouts" }, { "id": "minecraft:fire_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAwAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWS9vF0UCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAwAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWS9vF0UCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:brain_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWREAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJyYWluX2NvcmFsBAkAbmFtZV9oYXNoRiWlLCwA2ycDCgBuZXR3b3JrX2lkrjAuhgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWREAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJyYWluX2NvcmFsBAkAbmFtZV9oYXNoRiWlLCwA2ycDCgBuZXR3b3JrX2lkrjAuhgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:bubble_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbAQJAG5hbWVfaGFzaJz6rWnl+v2qAwoAbmV0d29ya19pZImIWy0KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbAQJAG5hbWVfaGFzaJz6rWnl+v2qAwoAbmV0d29ya19pZImIWy0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:tube_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1YmVfY29yYWwECQBuYW1lX2hhc2iYa8oO/tgk7wMKAG5ldHdvcmtfaWRTfND5CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1YmVfY29yYWwECQBuYW1lX2hhc2iYa8oO/tgk7wMKAG5ldHdvcmtfaWRTfND5CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:horn_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAwAACAQAbmFtZRQAbWluZWNyYWZ0Omhvcm5fY29yYWwECQBuYW1lX2hhc2iZnRHjZbnLPgMKAG5ldHdvcmtfaWR+GGp8CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAwAACAQAbmFtZRQAbWluZWNyYWZ0Omhvcm5fY29yYWwECQBuYW1lX2hhc2iZnRHjZbnLPgMKAG5ldHdvcmtfaWR+GGp8CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dead_fire_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbAQJAG5hbWVfaGFzaEPU6tFy/latAwoAbmV0d29ya19pZNMa7V4KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbAQJAG5hbWVfaGFzaEPU6tFy/latAwoAbmV0d29ya19pZNMa7V4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dead_brain_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAwAACAQAbmFtZRoAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWwECQBuYW1lX2hhc2j5L6QJCISvzwMKAG5ldHdvcmtfaWQkKzeiCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAwAACAQAbmFtZRoAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWwECQBuYW1lX2hhc2j5L6QJCISvzwMKAG5ldHdvcmtfaWQkKzeiCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dead_bubble_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAwAACAQAbmFtZRsAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsBAkAbmFtZV9oYXNoSTOZ/8wpeNYDCgBuZXR3b3JrX2lka6w9DAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAwAACAQAbmFtZRsAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsBAkAbmFtZV9oYXNoSTOZ/8wpeNYDCgBuZXR3b3JrX2lka6w9DAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:dead_tube_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbAQJAG5hbWVfaGFzaJGjNWhlaIJeAwoAbmV0d29ya19pZO3Z0ygKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbAQJAG5hbWVfaGFzaJGjNWhlaIJeAwoAbmV0d29ya19pZO3Z0ygKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:dead_horn_coral", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbAQJAG5hbWVfaGFzaJBkz3qt+g2cAwoAbmV0d29ya19pZBAN+eYKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbAQJAG5hbWVfaGFzaJBkz3qt+g2cAwoAbmV0d29ya19pZBAN+eYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZOg7iS4KBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgMAcmVkAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:fire_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJBAAACAQAbmFtZRgAbWluZWNyYWZ0OmZpcmVfY29yYWxfZmFuBAkAbmFtZV9oYXNosOTxYYxsDLgDCgBuZXR3b3JrX2lkFKxbEgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZIDj8HMKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgQAcGluawMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:brain_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHBAAACAQAbmFtZRkAbWluZWNyYWZ0OmJyYWluX2NvcmFsX2ZhbgQJAG5hbWVfaGFzaAi5uHizSNcqAwoAbmV0d29ya19pZFtLjNwKBgBzdGF0ZXMDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZLCJP0kKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgYAcHVycGxlAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:bubble_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIBAAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hy/rX2on17DgMKAG5ldHdvcmtfaWQof60VCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZFz2ly4KBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgQAYmx1ZQMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:tube_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRgAbWluZWNyYWZ0OnR1YmVfY29yYWxfZmFuBAkAbmFtZV9oYXNo9pbJbo+PphIDCgBuZXR3b3JrX2lkenDTYgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_fan", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvcmFsX2ZhbgQJAG5hbWVfaGFzaAFROjbTm8JzAwoAbmV0d29ya19pZE4TgnYKBgBzdGF0ZXMICwBjb3JhbF9jb2xvcgYAeWVsbG93AxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:horn_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKBAAACAQAbmFtZRgAbWluZWNyYWZ0Omhvcm5fY29yYWxfZmFuBAkAbmFtZV9oYXNoA+ri6NPDkbUDCgBuZXR3b3JrX2lkezoHNwoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkdhLQzwoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:dead_fire_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNBAAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hpQO02NDxPvwMKAG5ldHdvcmtfaWTaOJgLCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkSi6srQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:dead_brain_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLBAAACAQAbmFtZR4AbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWxfZmFuBAkAbmFtZV9oYXNoI9/+Z4YqMhIDCgBuZXR3b3JrX2lkqYXxYgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkGiGSzAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:dead_bubble_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsX2ZhbgQJAG5hbWVfaGFzaBNECtIM6VIOAwoAbmV0d29ya19pZLrNtBEKBgBzdGF0ZXMDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lkmvZKOgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:dead_tube_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hbBBM9jFKWvQMKAG5ldHdvcmtfaWSkJKUWCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:coral_fan_dead", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNvcmFsX2Zhbl9kZWFkBAkAbmFtZV9oYXNo3kgokLV4uQIDCgBuZXR3b3JrX2lknLw+4QoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:dead_horn_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROBAAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbF9mYW4ECQBuYW1lX2hhc2hObElFrHfPygMKAG5ldHdvcmtfaWQ1ZxvmCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crimson_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fcm9vdHMECQBuYW1lX2hhc2j1fWgQLViv5QMKAG5ldHdvcmtfaWRLh5DXCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fcm9vdHMECQBuYW1lX2hhc2j1fWgQLViv5QMKAG5ldHdvcmtfaWRLh5DXCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:warped_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAQAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9yb290cwQJAG5hbWVfaGFzaBc3WvbJOLlkAwoAbmV0d29ya19pZNLgDnAKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAQAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9yb290cwQJAG5hbWVfaGFzaBc3WvbJOLlkAwoAbmV0d29ya19pZNLgDnAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:yellow_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQlAAAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19mbG93ZXIECQBuYW1lX2hhc2jWbU1pF0OUGAMKAG5ldHdvcmtfaWQgO3hpCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlAAAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19mbG93ZXIECQBuYW1lX2hhc2jWbU1pF0OUGAMKAG5ldHdvcmtfaWQgO3hpCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWSqsqQGCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUFAHBvcHB5AAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:poppy", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnBvcHB5BAkAbmFtZV9oYXNocMF8pITMbkcDCgBuZXR3b3JrX2lk8im6ywoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTqDajjCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUGAG9yY2hpZAADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:blue_orchid", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9BAAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfb3JjaGlkBAkAbmFtZV9oYXNoBjz2MsgB21EDCgBuZXR3b3JrX2lk/iLsSwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWT5CjveCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUGAGFsbGl1bQADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:allium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+BAAACAQAbmFtZRAAbWluZWNyYWZ0OmFsbGl1bQQJAG5hbWVfaGFzaDCGQBHNDTkcAwoAbmV0d29ya19pZD9Dgr0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTORIBJCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUJAGhvdXN0b25pYQADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:azure_bluet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/BAAACAQAbmFtZRUAbWluZWNyYWZ0OmF6dXJlX2JsdWV0BAkAbmFtZV9oYXNo9N5egqMT2QcDCgBuZXR3b3JrX2lkwIgDnwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTuNhmYCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUJAHR1bGlwX3JlZAADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:red_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRABAAACAQAbmFtZRMAbWluZWNyYWZ0OnJlZF90dWxpcAQJAG5hbWVfaGFzaAjMi9Rd+6rhAwoAbmV0d29ya19pZAZCnt8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWT0O4nfCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUMAHR1bGlwX29yYW5nZQADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:orange_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBBAAACAQAbmFtZRYAbWluZWNyYWZ0Om9yYW5nZV90dWxpcAQJAG5hbWVfaGFzaP+NjxMBZ8vAAwoAbmV0d29ya19pZPYatsMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWTqkthyCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGULAHR1bGlwX3doaXRlAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:white_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCBAAACAQAbmFtZRUAbWluZWNyYWZ0OndoaXRlX3R1bGlwBAkAbmFtZV9oYXNo5vbU4VRPh3ADCgBuZXR3b3JrX2lkok+4rQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRMbBA7CgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUKAHR1bGlwX3BpbmsAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:pink_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDBAAACAQAbmFtZRQAbWluZWNyYWZ0OnBpbmtfdHVsaXAECQBuYW1lX2hhc2hxDHZa6OaNXAMKAG5ldHdvcmtfaWTiOT+VCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRexMAuCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUFAG94ZXllAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:oxeye_daisy", + "block_state_b64": "CgAAAwgAYmxvY2tfaWREBAAACAQAbmFtZRUAbWluZWNyYWZ0Om94ZXllX2RhaXN5BAkAbmFtZV9oYXNoXwxsqNQTN9gDCgBuZXR3b3JrX2lkw7R7dwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWQgs7BECgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUKAGNvcm5mbG93ZXIAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:cornflower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFBAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcm5mbG93ZXIECQBuYW1lX2hhc2gnhyC3EeqHgAMKAG5ldHdvcmtfaWR4VrvACgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:red_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9mbG93ZXIECQBuYW1lX2hhc2ixeWoRT8FNPwMKAG5ldHdvcmtfaWRvDuNbCgYAc3RhdGVzCAsAZmxvd2VyX3R5cGUSAGxpbHlfb2ZfdGhlX3ZhbGxleQADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:lily_of_the_valley", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGBAAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbHlfb2ZfdGhlX3ZhbGxleQQJAG5hbWVfaGFzaI64TJSf9mgQAwoAbmV0d29ya19pZFE9+nwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZOemRt4KBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQkAc3VuZmxvd2VyAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "id": "minecraft:sunflower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRMAbWluZWNyYWZ0OnN1bmZsb3dlcgQJAG5hbWVfaGFzaAMxYQLoqlZ0AwoAbmV0d29ya19pZA10iSoKBgBzdGF0ZXMBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZOFugoEKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAc3lyaW5nYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:lilac", + "block_state_b64": "CgAAAwgAYmxvY2tfaWReBAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxpbGFjBAkAbmFtZV9oYXNoD3nrQJuo7NkDCgBuZXR3b3JrX2lk5W+uFAoGAHN0YXRlcwEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZN4O+/gKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQQAcm9zZQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:rose_bush", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhBAAACAQAbmFtZRMAbWluZWNyYWZ0OnJvc2VfYnVzaAQJAG5hbWVfaGFzaLoiFk8LVpGKAwoAbmV0d29ya19pZMZPv48KBgBzdGF0ZXMBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:double_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRYAbWluZWNyYWZ0OmRvdWJsZV9wbGFudAQJAG5hbWVfaGFzaHVcUQvyXwGKAwoAbmV0d29ya19pZI3w4GMKBgBzdGF0ZXMIEQBkb3VibGVfcGxhbnRfdHlwZQcAcGFlb25pYQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:peony", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiBAAACAQAbmFtZQ8AbWluZWNyYWZ0OnBlb255BAkAbmFtZV9oYXNoR4dYc4QquPADCgBuZXR3b3JrX2lkrTe7RwoGAHN0YXRlcwEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:pitcher_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpdGNoZXJfcGxhbnQECQBuYW1lX2hhc2hRJHzsbDH+SQMKAG5ldHdvcmtfaWRnY76VCgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpdGNoZXJfcGxhbnQECQBuYW1lX2hhc2hRJHzsbDH+SQMKAG5ldHdvcmtfaWRnY76VCgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:pink_petals", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfcGV0YWxzBAkAbmFtZV9oYXNo6DQwN9SwV3QDCgBuZXR3b3JrX2lkNWneGgoGAHN0YXRlcwMGAGdyb3d0aAAAAAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfcGV0YWxzBAkAbmFtZV9oYXNo6DQwN9SwV3QDCgBuZXR3b3JrX2lkNWneGgoGAHN0YXRlcwMGAGdyb3d0aAAAAAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:wither_rose", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAQAACAQAbmFtZRUAbWluZWNyYWZ0OndpdGhlcl9yb3NlBAkAbmFtZV9oYXNoaSKxl3I516gDCgBuZXR3b3JrX2lkATXLPwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAQAACAQAbmFtZRUAbWluZWNyYWZ0OndpdGhlcl9yb3NlBAkAbmFtZV9oYXNoaSKxl3I516gDCgBuZXR3b3JrX2lkATXLPwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:torchflower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AwAACAQAbmFtZRUAbWluZWNyYWZ0OnRvcmNoZmxvd2VyBAkAbmFtZV9oYXNoL+mHtElwbqQDCgBuZXR3b3JrX2lkI34O+AoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AwAACAQAbmFtZRUAbWluZWNyYWZ0OnRvcmNoZmxvd2VyBAkAbmFtZV9oYXNoL+mHtElwbqQDCgBuZXR3b3JrX2lkI34O+AoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:white_dye" @@ -2376,142 +2528,194 @@ }, { "id": "minecraft:vine", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnZpbmUECQBuYW1lX2hhc2j0Sj8/XeXOLAMKAG5ldHdvcmtfaWSUkDtbCgYAc3RhdGVzAxMAdmluZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnZpbmUECQBuYW1lX2hhc2j0Sj8/XeXOLAMKAG5ldHdvcmtfaWSUkDtbCgYAc3RhdGVzAxMAdmluZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:weeping_vines", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAQAACAQAbmFtZRcAbWluZWNyYWZ0OndlZXBpbmdfdmluZXMECQBuYW1lX2hhc2jrLgLHkQygiwMKAG5ldHdvcmtfaWQ8NHSJCgYAc3RhdGVzAxEAd2VlcGluZ192aW5lc19hZ2UAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAQAACAQAbmFtZRcAbWluZWNyYWZ0OndlZXBpbmdfdmluZXMECQBuYW1lX2hhc2jrLgLHkQygiwMKAG5ldHdvcmtfaWQ8NHSJCgYAc3RhdGVzAxEAd2VlcGluZ192aW5lc19hZ2UAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:twisting_vines", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAgAACAQAbmFtZRgAbWluZWNyYWZ0OnR3aXN0aW5nX3ZpbmVzBAkAbmFtZV9oYXNoDYR5QgVUQJADCgBuZXR3b3JrX2lk5kYVIQoGAHN0YXRlcwMSAHR3aXN0aW5nX3ZpbmVzX2FnZQAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAgAACAQAbmFtZRgAbWluZWNyYWZ0OnR3aXN0aW5nX3ZpbmVzBAkAbmFtZV9oYXNoDYR5QgVUQJADCgBuZXR3b3JrX2lk5kYVIQoGAHN0YXRlcwMSAHR3aXN0aW5nX3ZpbmVzX2FnZQAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:waterlily", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAAAACAQAbmFtZRMAbWluZWNyYWZ0OndhdGVybGlseQQJAG5hbWVfaGFzaEHgC4c1SXg0AwoAbmV0d29ya19pZOOerp8KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAAAACAQAbmFtZRMAbWluZWNyYWZ0OndhdGVybGlseQQJAG5hbWVfaGFzaEHgC4c1SXg0AwoAbmV0d29ya19pZOOerp8KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:seagrass", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAQAACAQAbmFtZRIAbWluZWNyYWZ0OnNlYWdyYXNzBAkAbmFtZV9oYXNoHSBFtoHdWxIDCgBuZXR3b3JrX2lkd3lhEAoGAHN0YXRlcwgOAHNlYV9ncmFzc190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAQAACAQAbmFtZRIAbWluZWNyYWZ0OnNlYWdyYXNzBAkAbmFtZV9oYXNoHSBFtoHdWxIDCgBuZXR3b3JrX2lkd3lhEAoGAHN0YXRlcwgOAHNlYV9ncmFzc190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:kelp" }, { "id": "minecraft:deadbush", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAAAACAQAbmFtZRIAbWluZWNyYWZ0OmRlYWRidXNoBAkAbmFtZV9oYXNoPFODe4IScnYDCgBuZXR3b3JrX2lkVfnl+goGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAAAACAQAbmFtZRIAbWluZWNyYWZ0OmRlYWRidXNoBAkAbmFtZV9oYXNoPFODe4IScnYDCgBuZXR3b3JrX2lkVfnl+goGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:bamboo", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhbWJvbwQJAG5hbWVfaGFzaBgpGmyzhedCAwoAbmV0d29ya19pZIZv1nYKBgBzdGF0ZXMBBwBhZ2VfYml0AAgQAGJhbWJvb19sZWFmX3NpemUJAG5vX2xlYXZlcwgWAGJhbWJvb19zdGFsa190aGlja25lc3MEAHRoaW4AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhbWJvbwQJAG5hbWVfaGFzaBgpGmyzhedCAwoAbmV0d29ya19pZIZv1nYKBgBzdGF0ZXMBBwBhZ2VfYml0AAgQAGJhbWJvb19sZWFmX3NpemUJAG5vX2xlYXZlcwgWAGJhbWJvb19zdGFsa190aGlja25lc3MEAHRoaW4AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:snow", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNub3cECQBuYW1lX2hhc2gVHr5XXdETWAMKAG5ldHdvcmtfaWQ0zCeHCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNub3cECQBuYW1lX2hhc2gVHr5XXdETWAMKAG5ldHdvcmtfaWQ0zCeHCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:ice", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAAAACAQAbmFtZQ0AbWluZWNyYWZ0OmljZQQJAG5hbWVfaGFzaNF26f+uUT29AwoAbmV0d29ya19pZOUMaQYKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAAAACAQAbmFtZQ0AbWluZWNyYWZ0OmljZQQJAG5hbWVfaGFzaNF26f+uUT29AwoAbmV0d29ya19pZOUMaQYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:packed_ice", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAAAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9pY2UECQBuYW1lX2hhc2hk4bu123ZrFgMKAG5ldHdvcmtfaWTr/ooaCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAAAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9pY2UECQBuYW1lX2hhc2hk4bu123ZrFgMKAG5ldHdvcmtfaWTr/ooaCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:blue_ice", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJsdWVfaWNlBAkAbmFtZV9oYXNo+EKxYgFhKcgDCgBuZXR3b3JrX2lkxfsA8goGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJsdWVfaWNlBAkAbmFtZV9oYXNo+EKxYgFhKcgDCgBuZXR3b3JrX2lkxfsA8goGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:snow_layer", - "block_state_b64": "CgAAAwgAYmxvY2tfaWROAAAACAQAbmFtZRQAbWluZWNyYWZ0OnNub3dfbGF5ZXIECQBuYW1lX2hhc2hXka6atMYUCQMKAG5ldHdvcmtfaWRCrIPcCgYAc3RhdGVzAQsAY292ZXJlZF9iaXQAAwYAaGVpZ2h0AAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAAAACAQAbmFtZRQAbWluZWNyYWZ0OnNub3dfbGF5ZXIECQBuYW1lX2hhc2hXka6atMYUCQMKAG5ldHdvcmtfaWRCrIPcCgYAc3RhdGVzAQsAY292ZXJlZF9iaXQAAwYAaGVpZ2h0AAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:pointed_dripstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvaW50ZWRfZHJpcHN0b25lBAkAbmFtZV9oYXNoJMISzmHQgt8DCgBuZXR3b3JrX2lkbWrtYgoGAHN0YXRlcwgTAGRyaXBzdG9uZV90aGlja25lc3MDAHRpcAEHAGhhbmdpbmcBAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvaW50ZWRfZHJpcHN0b25lBAkAbmFtZV9oYXNoJMISzmHQgt8DCgBuZXR3b3JrX2lkbWrtYgoGAHN0YXRlcwgTAGRyaXBzdG9uZV90aGlja25lc3MDAHRpcAEHAGhhbmdpbmcBAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dripstone_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRyaXBzdG9uZV9ibG9jawQJAG5hbWVfaGFzaIIXnEqY77YsAwoAbmV0d29ya19pZMZi2kwKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRyaXBzdG9uZV9ibG9jawQJAG5hbWVfaGFzaIIXnEqY77YsAwoAbmV0d29ya19pZMZi2kwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:moss_carpet", - "block_state_b64": "CgAAAwgAYmxvY2tfaWROAgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vc3NfY2FycGV0BAkAbmFtZV9oYXNo/NEDxRPTshYDCgBuZXR3b3JrX2lkaGG3QwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vc3NfY2FycGV0BAkAbmFtZV9oYXNo/NEDxRPTshYDCgBuZXR3b3JrX2lkaGG3QwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:moss_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AgAACAQAbmFtZRQAbWluZWNyYWZ0Om1vc3NfYmxvY2sECQBuYW1lX2hhc2iovcsPUYX2tgMKAG5ldHdvcmtfaWT3JSbfCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AgAACAQAbmFtZRQAbWluZWNyYWZ0Om1vc3NfYmxvY2sECQBuYW1lX2hhc2iovcsPUYX2tgMKAG5ldHdvcmtfaWT3JSbfCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dirt_with_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRpcnRfd2l0aF9yb290cwQJAG5hbWVfaGFzaLCNDYPviDCIAwoAbmV0d29ya19pZNCkwzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRpcnRfd2l0aF9yb290cwQJAG5hbWVfaGFzaLCNDYPviDCIAwoAbmV0d29ya19pZNCkwzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:hanging_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AgAACAQAbmFtZRcAbWluZWNyYWZ0Omhhbmdpbmdfcm9vdHMECQBuYW1lX2hhc2jaXn+Y5UZpDAMKAG5ldHdvcmtfaWRU4c2vCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AgAACAQAbmFtZRcAbWluZWNyYWZ0Omhhbmdpbmdfcm9vdHMECQBuYW1lX2hhc2jaXn+Y5UZpDAMKAG5ldHdvcmtfaWRU4c2vCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:mangrove_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWThAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNoa786PzQGZ6kDCgBuZXR3b3JrX2lklA0AHgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNoa786PzQGZ6kDCgBuZXR3b3JrX2lklA0AHgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:muddy_mangrove_roots", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAgAACAQAbmFtZR4AbWluZWNyYWZ0Om11ZGR5X21hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNo9YApdHpo1RkDCgBuZXR3b3JrX2lkH0Oc4woGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAgAACAQAbmFtZR4AbWluZWNyYWZ0Om11ZGR5X21hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNo9YApdHpo1RkDCgBuZXR3b3JrX2lkH0Oc4woGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:big_dripleaf", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpZ19kcmlwbGVhZgQJAG5hbWVfaGFzaGBEhXjo6qSdAwoAbmV0d29ya19pZMETsb8KBgBzdGF0ZXMBEQBiaWdfZHJpcGxlYWZfaGVhZAEIEQBiaWdfZHJpcGxlYWZfdGlsdAQAbm9uZQgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpZ19kcmlwbGVhZgQJAG5hbWVfaGFzaGBEhXjo6qSdAwoAbmV0d29ya19pZMETsb8KBgBzdGF0ZXMBEQBiaWdfZHJpcGxlYWZfaGVhZAEIEQBiaWdfZHJpcGxlYWZfdGlsdAQAbm9uZQgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:small_dripleaf_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtYWxsX2RyaXBsZWFmX2Jsb2NrBAkAbmFtZV9oYXNojxRAgXP9uWADCgBuZXR3b3JrX2lkozbVPwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24EAGVhc3QBDwB1cHBlcl9ibG9ja19iaXQBAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtYWxsX2RyaXBsZWFmX2Jsb2NrBAkAbmFtZV9oYXNojxRAgXP9uWADCgBuZXR3b3JrX2lkozbVPwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24EAGVhc3QBDwB1cHBlcl9ibG9ja19iaXQBAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:spore_blossom", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwb3JlX2Jsb3Nzb20ECQBuYW1lX2hhc2il3U72Gbco2gMKAG5ldHdvcmtfaWSbbbgcCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwb3JlX2Jsb3Nzb20ECQBuYW1lX2hhc2il3U72Gbco2gMKAG5ldHdvcmtfaWSbbbgcCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:azalea", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAgAACAQAbmFtZRAAbWluZWNyYWZ0OmF6YWxlYQQJAG5hbWVfaGFzaNyUl+BW9JrBAwoAbmV0d29ya19pZO/XZtQKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAgAACAQAbmFtZRAAbWluZWNyYWZ0OmF6YWxlYQQJAG5hbWVfaGFzaNyUl+BW9JrBAwoAbmV0d29ya19pZO/XZtQKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:flowering_azalea", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAgAACAQAbmFtZRoAbWluZWNyYWZ0OmZsb3dlcmluZ19hemFsZWEECQBuYW1lX2hhc2ie9r33wz8kiwMKAG5ldHdvcmtfaWQ3ij0VCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAgAACAQAbmFtZRoAbWluZWNyYWZ0OmZsb3dlcmluZ19hemFsZWEECQBuYW1lX2hhc2ie9r33wz8kiwMKAG5ldHdvcmtfaWQ3ij0VCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:glow_lichen", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAgAACAQAbmFtZRUAbWluZWNyYWZ0Omdsb3dfbGljaGVuBAkAbmFtZV9oYXNobyPUrIYlo44DCgBuZXR3b3JrX2lkCh8lSAoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHM/AAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAgAACAQAbmFtZRUAbWluZWNyYWZ0Omdsb3dfbGljaGVuBAkAbmFtZV9oYXNobyPUrIYlo44DCgBuZXR3b3JrX2lkCh8lSAoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHM/AAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:amethyst_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFtZXRoeXN0X2Jsb2NrBAkAbmFtZV9oYXNob+JK1iiAthcDCgBuZXR3b3JrX2lk8HtpzgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFtZXRoeXN0X2Jsb2NrBAkAbmFtZV9oYXNob+JK1iiAthcDCgBuZXR3b3JrX2lk8HtpzgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:budding_amethyst", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAgAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1ZGRpbmdfYW1ldGh5c3QECQBuYW1lX2hhc2gJvAwfI14fxgMKAG5ldHdvcmtfaWTQYqfACgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAgAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1ZGRpbmdfYW1ldGh5c3QECQBuYW1lX2hhc2gJvAwfI14fxgMKAG5ldHdvcmtfaWTQYqfACgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:amethyst_cluster", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAgAACAQAbmFtZRoAbWluZWNyYWZ0OmFtZXRoeXN0X2NsdXN0ZXIECQBuYW1lX2hhc2jK82S88Jgm8wMKAG5ldHdvcmtfaWSCPMPGCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAgAACAQAbmFtZRoAbWluZWNyYWZ0OmFtZXRoeXN0X2NsdXN0ZXIECQBuYW1lX2hhc2jK82S88Jgm8wMKAG5ldHdvcmtfaWSCPMPGCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:large_amethyst_bud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAgAACAQAbmFtZRwAbWluZWNyYWZ0OmxhcmdlX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaAHhdpWD+sd5AwoAbmV0d29ya19pZKkQxOcKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAgAACAQAbmFtZRwAbWluZWNyYWZ0OmxhcmdlX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaAHhdpWD+sd5AwoAbmV0d29ya19pZKkQxOcKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:medium_amethyst_bud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1lZGl1bV9hbWV0aHlzdF9idWQECQBuYW1lX2hhc2g5lBGtC0DzZQMKAG5ldHdvcmtfaWSYiP4gCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1lZGl1bV9hbWV0aHlzdF9idWQECQBuYW1lX2hhc2g5lBGtC0DzZQMKAG5ldHdvcmtfaWSYiP4gCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:small_amethyst_bud", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAgAACAQAbmFtZRwAbWluZWNyYWZ0OnNtYWxsX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaEnb4+q9PO4YAwoAbmV0d29ya19pZGWzxrQKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAgAACAQAbmFtZRwAbWluZWNyYWZ0OnNtYWxsX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaEnb4+q9PO4YAwoAbmV0d29ya19pZGWzxrQKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:tuff", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAgAACAQAbmFtZQ4AbWluZWNyYWZ0OnR1ZmYECQBuYW1lX2hhc2h1Rwc1XYsBGwMKAG5ldHdvcmtfaWRwQGn0CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAgAACAQAbmFtZQ4AbWluZWNyYWZ0OnR1ZmYECQBuYW1lX2hhc2h1Rwc1XYsBGwMKAG5ldHdvcmtfaWRwQGn0CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:tuff_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAwAACAQAbmFtZRUAbWluZWNyYWZ0OnR1ZmZfc3RhaXJzBAkAbmFtZV9oYXNoKjyNUBjcfZsDCgBuZXR3b3JrX2lk+LsycgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:tuff_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAwAACAQAbmFtZRMAbWluZWNyYWZ0OnR1ZmZfc2xhYgQJAG5hbWVfaGFzaIhCGdlIsnMUAwoAbmV0d29ya19pZN1dUL4KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:tuff_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAwAACAQAbmFtZRMAbWluZWNyYWZ0OnR1ZmZfd2FsbAQJAG5hbWVfaGFzaMyeeu1IRf03AwoAbmV0d29ya19pZDkIrosKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:chiseled_tuff", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoaXNlbGVkX3R1ZmYECQBuYW1lX2hhc2iVliOT8OTQ9AMKAG5ldHdvcmtfaWTLNKOiCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:polished_tuff", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmYECQBuYW1lX2hhc2hyaLe/KEVZ0gMKAG5ldHdvcmtfaWTcX3NrCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:polished_tuff_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfc3RhaXJzBAkAbmFtZV9oYXNo8yuah8QI1dcDCgBuZXR3b3JrX2lkjLoU4AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:polished_tuff_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfc2xhYgQJAG5hbWVfaGFzaLXdb48YvAsHAwoAbmV0d29ya19pZAnJ7W0KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:polished_tuff_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfd2FsbAQJAG5hbWVfaGFzaJVZj6QYWXUrAwoAbmV0d29ya19pZLU7dooKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:tuff_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAwAACAQAbmFtZRUAbWluZWNyYWZ0OnR1ZmZfYnJpY2tzBAkAbmFtZV9oYXNo/hbQ+mXSK7wDCgBuZXR3b3JrX2lk6gmIwQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:tuff_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT0AwAACAQAbmFtZRsAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNoWJpkAurUfKwDCgBuZXR3b3JrX2lkUMcjiwoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:tuff_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAwAACAQAbmFtZRkAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaLqPMjVCv5dIAwoAbmV0d29ya19pZOmeRhcKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:tuff_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AwAACAQAbmFtZRkAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaIL0IyNCOsonAwoAbmV0d29ya19pZJW4T5UKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:chiseled_tuff_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AwAACAQAbmFtZR4AbWluZWNyYWZ0OmNoaXNlbGVkX3R1ZmZfYnJpY2tzBAkAbmFtZV9oYXNo3oQw6gmxYuADCgBuZXR3b3JrX2lkm3D8AgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:calcite", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAgAACAQAbmFtZREAbWluZWNyYWZ0OmNhbGNpdGUECQBuYW1lX2hhc2ixKLu8ZIdzDQMKAG5ldHdvcmtfaWQlSbJDCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAgAACAQAbmFtZREAbWluZWNyYWZ0OmNhbGNpdGUECQBuYW1lX2hhc2ixKLu8ZIdzDQMKAG5ldHdvcmtfaWQlSbJDCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:chicken" @@ -2542,35 +2746,35 @@ }, { "id": "minecraft:brown_mushroom", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAAAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkLh1OXAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAAAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkLh1OXAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:red_mushroom", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9tdXNocm9vbQQJAG5hbWVfaGFzaPpzJua7669xAwoAbmV0d29ya19pZCvWPYkKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9tdXNocm9vbQQJAG5hbWVfaGFzaPpzJua7669xAwoAbmV0d29ya19pZCvWPYkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crimson_fungus", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fZnVuZ3VzBAkAbmFtZV9oYXNolIcCUuFM2u0DCgBuZXR3b3JrX2lkD2NN0QoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fZnVuZ3VzBAkAbmFtZV9oYXNolIcCUuFM2u0DCgBuZXR3b3JrX2lkD2NN0QoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:warped_fungus", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9mdW5ndXMECQBuYW1lX2hhc2gq8bSnRVTAFgMKAG5ldHdvcmtfaWTkwS+rCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9mdW5ndXMECQBuYW1lX2hhc2gq8bSnRVTAFgMKAG5ldHdvcmtfaWTkwS+rCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkdOMhDAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw4AAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkdOMhDAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw4AAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:red_mushroom_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9tdXNocm9vbV9ibG9jawQJAG5hbWVfaGFzaJTTyJbth9M9AwoAbmV0d29ya19pZM+AyboKBgBzdGF0ZXMDEgBodWdlX211c2hyb29tX2JpdHMOAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9tdXNocm9vbV9ibG9jawQJAG5hbWVfaGFzaJTTyJbth9M9AwoAbmV0d29ya19pZM+AyboKBgBzdGF0ZXMDEgBodWdlX211c2hyb29tX2JpdHMOAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkbdt3CAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw8AAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkbdt3CAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw8AAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:brown_mushroom_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkSrMl9goGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cwAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkSrMl9goGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cwAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:egg" @@ -2589,74 +2793,82 @@ }, { "id": "minecraft:web", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAAAACAQAbmFtZQ0AbWluZWNyYWZ0OndlYgQJAG5hbWVfaGFzaA4GKQCvG4i9AwoAbmV0d29ya19pZApt+jgKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAAAACAQAbmFtZQ0AbWluZWNyYWZ0OndlYgQJAG5hbWVfaGFzaA4GKQCvG4i9AwoAbmV0d29ya19pZApt+jgKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:spider_eye" }, { "id": "minecraft:mob_spawner", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vYl9zcGF3bmVyBAkAbmFtZV9oYXNoNwGrCV/Fkh8DCgBuZXR3b3JrX2lkM1wTmgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vYl9zcGF3bmVyBAkAbmFtZV9oYXNoNwGrCV/Fkh8DCgBuZXR3b3JrX2lkM1wTmgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:trial_spawner", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AgAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaWFsX3NwYXduZXIECQBuYW1lX2hhc2iNLRPB4ACz+QMKAG5ldHdvcmtfaWTWFYHGCgYAc3RhdGVzAQcAb21pbm91cwADEwB0cmlhbF9zcGF3bmVyX3N0YXRlAAAAAAADBwB2ZXJzaW9uAwAVAQA=" + }, + { + "id": "minecraft:vault", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AgAACAQAbmFtZQ8AbWluZWNyYWZ0OnZhdWx0BAkAbmFtZV9oYXNoCAp9n3IAyqcDCgBuZXR3b3JrX2lk6/P+vwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQcAb21pbm91cwAICwB2YXVsdF9zdGF0ZQgAaW5hY3RpdmUAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:end_portal_frame", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9wb3J0YWxfZnJhbWUECQBuYW1lX2hhc2gqofyUIjGOpQMKAG5ldHdvcmtfaWRbGHf8CgYAc3RhdGVzARIAZW5kX3BvcnRhbF9leWVfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9wb3J0YWxfZnJhbWUECQBuYW1lX2hhc2gqofyUIjGOpQMKAG5ldHdvcmtfaWRbGHf8CgYAc3RhdGVzARIAZW5kX3BvcnRhbF9leWVfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqXH7RgoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUFAHN0b25lAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqXH7RgoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUFAHN0b25lAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkeIBb6QoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAGNvYmJsZXN0b25lAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkeIBb6QoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAGNvYmJsZXN0b25lAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkDZ2cFQoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAHN0b25lX2JyaWNrAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkDZ2cFQoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGULAHN0b25lX2JyaWNrAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkOR/cTAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGURAG1vc3N5X3N0b25lX2JyaWNrAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkOR/cTAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGURAG1vc3N5X3N0b25lX2JyaWNrAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqdwlHAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUTAGNyYWNrZWRfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkqdwlHAoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUTAGNyYWNrZWRfc3RvbmVfYnJpY2sAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:monster_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFqqPggoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUUAGNoaXNlbGVkX3N0b25lX2JyaWNrAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vbnN0ZXJfZWdnBAkAbmFtZV9oYXNoFMxMALksxVEDCgBuZXR3b3JrX2lkFqqPggoGAHN0YXRlcwgWAG1vbnN0ZXJfZWdnX3N0b25lX3R5cGUUAGNoaXNlbGVkX3N0b25lX2JyaWNrAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:infested_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAgAACAQAbmFtZRwAbWluZWNyYWZ0OmluZmVzdGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaICF2VYccxF1AwoAbmV0d29ya19pZDa/624KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAgAACAQAbmFtZRwAbWluZWNyYWZ0OmluZmVzdGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaICF2VYccxF1AwoAbmV0d29ya19pZDa/624KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:dragon_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AAAACAQAbmFtZRQAbWluZWNyYWZ0OmRyYWdvbl9lZ2cECQBuYW1lX2hhc2inMzXrV+/e1wMKAG5ldHdvcmtfaWTgO1yRCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AAAACAQAbmFtZRQAbWluZWNyYWZ0OmRyYWdvbl9lZ2cECQBuYW1lX2hhc2inMzXrV+/e1wMKAG5ldHdvcmtfaWTgO1yRCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:turtle_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1cnRsZV9lZ2cECQBuYW1lX2hhc2iwSRcxOJIJ9gMKAG5ldHdvcmtfaWSIRNUhCgYAc3RhdGVzCA0AY3JhY2tlZF9zdGF0ZQkAbm9fY3JhY2tzCBAAdHVydGxlX2VnZ19jb3VudAcAb25lX2VnZwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1cnRsZV9lZ2cECQBuYW1lX2hhc2iwSRcxOJIJ9gMKAG5ldHdvcmtfaWSIRNUhCgYAc3RhdGVzCA0AY3JhY2tlZF9zdGF0ZQkAbm9fY3JhY2tzCBAAdHVydGxlX2VnZ19jb3VudAcAb25lX2VnZwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:sniffer_egg", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAwAACAQAbmFtZRUAbWluZWNyYWZ0OnNuaWZmZXJfZWdnBAkAbmFtZV9oYXNoY1lozc8lPcYDCgBuZXR3b3JrX2lk7yb/2QoGAHN0YXRlcwgNAGNyYWNrZWRfc3RhdGUJAG5vX2NyYWNrcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAwAACAQAbmFtZRUAbWluZWNyYWZ0OnNuaWZmZXJfZWdnBAkAbmFtZV9oYXNoY1lozc8lPcYDCgBuZXR3b3JrX2lk7yb/2QoGAHN0YXRlcwgNAGNyYWNrZWRfc3RhdGUJAG5vX2NyYWNrcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:frog_spawn", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAgAACAQAbmFtZRQAbWluZWNyYWZ0OmZyb2dfc3Bhd24ECQBuYW1lX2hhc2iWmd7idp3ZZwMKAG5ldHdvcmtfaWRFzJudCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAgAACAQAbmFtZRQAbWluZWNyYWZ0OmZyb2dfc3Bhd24ECQBuYW1lX2hhc2iWmd7idp3ZZwMKAG5ldHdvcmtfaWRFzJudCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:pearlescent_froglight", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAgAACAQAbmFtZR8AbWluZWNyYWZ0OnBlYXJsZXNjZW50X2Zyb2dsaWdodAQJAG5hbWVfaGFzaKkcFRyycYGyAwoAbmV0d29ya19pZJqYakAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAgAACAQAbmFtZR8AbWluZWNyYWZ0OnBlYXJsZXNjZW50X2Zyb2dsaWdodAQJAG5hbWVfaGFzaKkcFRyycYGyAwoAbmV0d29ya19pZJqYakAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:verdant_froglight", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAgAACAQAbmFtZRsAbWluZWNyYWZ0OnZlcmRhbnRfZnJvZ2xpZ2h0BAkAbmFtZV9oYXNoA+eXuTBohrQDCgBuZXR3b3JrX2lkDIVnsQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAgAACAQAbmFtZRsAbWluZWNyYWZ0OnZlcmRhbnRfZnJvZ2xpZ2h0BAkAbmFtZV9oYXNoA+eXuTBohrQDCgBuZXR3b3JrX2lkDIVnsQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:ochre_froglight", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om9jaHJlX2Zyb2dsaWdodAQJAG5hbWVfaGFzaMY59kjPe+c3AwoAbmV0d29ya19pZO2TD50KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om9jaHJlX2Zyb2dsaWdodAQJAG5hbWVfaGFzaMY59kjPe+c3AwoAbmV0d29ya19pZO2TD50KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:chicken_spawn_egg" @@ -2883,40 +3095,49 @@ { "id": "minecraft:sniffer_spawn_egg" }, + { + "id": "minecraft:breeze_spawn_egg" + }, + { + "id": "minecraft:armadillo_spawn_egg" + }, + { + "id": "minecraft:bogged_spawn_egg" + }, { "id": "minecraft:obsidian", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2lkaWFuBAkAbmFtZV9oYXNoiz4qrb8QjyEDCgBuZXR3b3JrX2lkuqnPpQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2lkaWFuBAkAbmFtZV9oYXNoiz4qrb8QjyEDCgBuZXR3b3JrX2lkuqnPpQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:crying_obsidian", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAgAACAQAbmFtZRkAbWluZWNyYWZ0OmNyeWluZ19vYnNpZGlhbgQJAG5hbWVfaGFzaKT0JlA7Z1K+AwoAbmV0d29ya19pZCjbPV4KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAgAACAQAbmFtZRkAbWluZWNyYWZ0OmNyeWluZ19vYnNpZGlhbgQJAG5hbWVfaGFzaKT0JlA7Z1K+AwoAbmV0d29ya19pZCjbPV4KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:bedrock", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAAAACAQAbmFtZREAbWluZWNyYWZ0OmJlZHJvY2sECQBuYW1lX2hhc2hWfFrh4LVtxwMKAG5ldHdvcmtfaWT7fKz1CgYAc3RhdGVzAQ4AaW5maW5pYnVybl9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAAAACAQAbmFtZREAbWluZWNyYWZ0OmJlZHJvY2sECQBuYW1lX2hhc2hWfFrh4LVtxwMKAG5ldHdvcmtfaWT7fKz1CgYAc3RhdGVzAQ4AaW5maW5pYnVybl9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:soul_sand", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc2FuZAQJAG5hbWVfaGFzaMaf+bccu+KTAwoAbmV0d29ya19pZBQSHrMKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc2FuZAQJAG5hbWVfaGFzaMaf+bccu+KTAwoAbmV0d29ya19pZBQSHrMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:magma", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAAAACAQAbmFtZQ8AbWluZWNyYWZ0Om1hZ21hBAkAbmFtZV9oYXNoqyTjKaIsWfYDCgBuZXR3b3JrX2lkyfWAZgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAAAACAQAbmFtZQ8AbWluZWNyYWZ0Om1hZ21hBAkAbmFtZV9oYXNoqyTjKaIsWfYDCgBuZXR3b3JrX2lkyfWAZgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:nether_wart" }, { "id": "minecraft:end_stone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AAAACAQAbmFtZRMAbWluZWNyYWZ0OmVuZF9zdG9uZQQJAG5hbWVfaGFzaH1J9jA39GJNAwoAbmV0d29ya19pZFeFQ7UKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AAAACAQAbmFtZRMAbWluZWNyYWZ0OmVuZF9zdG9uZQQJAG5hbWVfaGFzaH1J9jA39GJNAwoAbmV0d29ya19pZFeFQ7UKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:chorus_flower", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAAAACAQAbmFtZRcAbWluZWNyYWZ0OmNob3J1c19mbG93ZXIECQBuYW1lX2hhc2iMpSodli5uawMKAG5ldHdvcmtfaWRnd1ZWCgYAc3RhdGVzAwMAYWdlAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAAAACAQAbmFtZRcAbWluZWNyYWZ0OmNob3J1c19mbG93ZXIECQBuYW1lX2hhc2iMpSodli5uawMKAG5ldHdvcmtfaWRnd1ZWCgYAc3RhdGVzAwMAYWdlAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:chorus_plant", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAAAACAQAbmFtZRYAbWluZWNyYWZ0OmNob3J1c19wbGFudAQJAG5hbWVfaGFzaJhSrmNGKwaMAwoAbmV0d29ya19pZA3uVqMKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAAAACAQAbmFtZRYAbWluZWNyYWZ0OmNob3J1c19wbGFudAQJAG5hbWVfaGFzaJhSrmNGKwaMAwoAbmV0d29ya19pZA3uVqMKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:chorus_fruit" @@ -2926,79 +3147,79 @@ }, { "id": "minecraft:sponge", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZF01rO0KBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAZHJ5AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZF01rO0KBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAZHJ5AAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:sponge", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZPiOc4QKBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAd2V0AAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZPiOc4QKBgBzdGF0ZXMICwBzcG9uZ2VfdHlwZQMAd2V0AAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkGnlaAwoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:tube_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRoAbWluZWNyYWZ0OnR1YmVfY29yYWxfYmxvY2sECQBuYW1lX2hhc2iGkaiR7Eot4wMKAG5ldHdvcmtfaWQPNJ6sCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkSnHuagoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:brain_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQBAAACAQAbmFtZRsAbWluZWNyYWZ0OmJyYWluX2NvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoeDNAK18yUo4DCgBuZXR3b3JrX2lkloN1vgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkmkHyegoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:bubble_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRBAAACAQAbmFtZRwAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaAI2mwMlvcNbAwoAbmV0d29ya19pZBlkxKIKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkdpUDxgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:fire_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSBAAACAQAbmFtZRoAbWluZWNyYWZ0OmZpcmVfY29yYWxfYmxvY2sECQBuYW1lX2hhc2gg1gLeXLmKaAMKAG5ldHdvcmtfaWSp3W57CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkYNWvYgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:horn_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTBAAACAQAbmFtZRoAbWluZWNyYWZ0Omhvcm5fY29yYWxfYmxvY2sECQBuYW1lX2hhc2hnZSLRWUwGhAMKAG5ldHdvcmtfaWRSK6ccCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkZSxBQgoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABibHVlAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:dead_tube_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaB9+lY3hAkNNAwoAbmV0d29ya19pZF0hKKYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lklSTVqQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBABwaW5rAQgAZGVhZF9iaXQBAAMHAHZlcnNpb24ERhQBAA==" + "id": "minecraft:dead_brain_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVBAAACAQAbmFtZSAAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWxfYmxvY2sECQBuYW1lX2hhc2iHyDn52AO8uwMKAG5ldHdvcmtfaWQw7yCaCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lk5fTYuQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgBwdXJwbGUBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:dead_bubble_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWBAAACAQAbmFtZSEAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsX2Jsb2NrBAkAbmFtZV9oYXNotwkk/ITrsjADCgBuZXR3b3JrX2lk56mXUgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkwUjqBAoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yAwByZWQBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:dead_fire_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaG0qHxbIrBEyAwoAbmV0d29ya19pZFvnH88KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { - "id": "minecraft:coral_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoxTOVIjqYOYIDCgBuZXR3b3JrX2lkq4iWoQoGAHN0YXRlcwgLAGNvcmFsX2NvbG9yBgB5ZWxsb3cBCABkZWFkX2JpdAEAAwcAdmVyc2lvbgRGFAEA" + "id": "minecraft:dead_horn_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaL7D8bu4Fm+0AwoAbmV0d29ya19pZEALRLoKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:sculk", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lkyqUPPgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lkyqUPPgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:sculk_vein", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNjdWxrX3ZlaW4ECQBuYW1lX2hhc2gJUdhVooV4zwMKAG5ldHdvcmtfaWSUfn1XCgYAc3RhdGVzAxkAbXVsdGlfZmFjZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNjdWxrX3ZlaW4ECQBuYW1lX2hhc2gJUdhVooV4zwMKAG5ldHdvcmtfaWSUfn1XCgYAc3RhdGVzAxkAbXVsdGlfZmFjZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:sculk_catalyst", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX2NhdGFseXN0BAkAbmFtZV9oYXNo+gCpbrCHST4DCgBuZXR3b3JrX2lkMJ2n/woGAHN0YXRlcwEFAGJsb29tAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX2NhdGFseXN0BAkAbmFtZV9oYXNo+gCpbrCHST4DCgBuZXR3b3JrX2lkMJ2n/woGAHN0YXRlcwEFAGJsb29tAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:sculk_shrieker", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX3Nocmlla2VyBAkAbmFtZV9oYXNo5OXtyObniQ4DCgBuZXR3b3JrX2lkxapoNAoGAHN0YXRlcwEGAGFjdGl2ZQABCgBjYW5fc3VtbW9uAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX3Nocmlla2VyBAkAbmFtZV9oYXNo5OXtyObniQ4DCgBuZXR3b3JrX2lkxapoNAoGAHN0YXRlcwEGAGFjdGl2ZQABCgBjYW5fc3VtbW9uAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:sculk_sensor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNjdWxrX3NlbnNvcgQJAG5hbWVfaGFzaCkmHreeTgNnAwoAbmV0d29ya19pZLj2WPcKBgBzdGF0ZXMDEgBzY3Vsa19zZW5zb3JfcGhhc2UAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNjdWxrX3NlbnNvcgQJAG5hbWVfaGFzaCkmHreeTgNnAwoAbmV0d29ya19pZLj2WPcKBgBzdGF0ZXMDEgBzY3Vsa19zZW5zb3JfcGhhc2UAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:calibrated_sculk_sensor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAwAACAQAbmFtZSEAbWluZWNyYWZ0OmNhbGlicmF0ZWRfc2N1bGtfc2Vuc29yBAkAbmFtZV9oYXNoffAcXXN/iJUDCgBuZXR3b3JrX2lkwOx3QQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAxIAc2N1bGtfc2Vuc29yX3BoYXNlAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAwAACAQAbmFtZSEAbWluZWNyYWZ0OmNhbGlicmF0ZWRfc2N1bGtfc2Vuc29yBAkAbmFtZV9oYXNoffAcXXN/iJUDCgBuZXR3b3JrX2lkwOx3QQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAxIAc2N1bGtfc2Vuc29yX3BoYXNlAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:reinforced_deepslate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlaW5mb3JjZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoldDmj91EapQDCgBuZXR3b3JrX2lkHIt+aQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlaW5mb3JjZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoldDmj91EapQDCgBuZXR3b3JrX2lkHIt+aQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:leather_helmet" @@ -3168,6 +3389,9 @@ { "id": "minecraft:crossbow" }, + { + "id": "minecraft:mace" + }, { "id": "minecraft:arrow" }, @@ -3323,6 +3547,41 @@ "id": "minecraft:arrow", "damage": 43 }, + { + "id": "minecraft:arrow", + "damage": 44 + }, + { + "id": "minecraft:arrow", + "damage": 45 + }, + { + "id": "minecraft:arrow", + "damage": 46 + }, + { + "id": "minecraft:arrow", + "damage": 47 + }, + { + "id": "minecraft:ominous_bottle" + }, + { + "id": "minecraft:ominous_bottle", + "damage": 1 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 2 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 3 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 4 + }, { "id": "minecraft:shield" }, @@ -3386,6 +3645,9 @@ { "id": "minecraft:snowball" }, + { + "id": "minecraft:wind_charge" + }, { "id": "minecraft:shears" }, @@ -3457,6 +3719,9 @@ { "id": "minecraft:diamond_horse_armor" }, + { + "id": "minecraft:wolf_armor" + }, { "id": "minecraft:trident" }, @@ -3646,6 +3911,22 @@ "id": "minecraft:potion", "damage": 42 }, + { + "id": "minecraft:potion", + "damage": 43 + }, + { + "id": "minecraft:potion", + "damage": 44 + }, + { + "id": "minecraft:potion", + "damage": 45 + }, + { + "id": "minecraft:potion", + "damage": 46 + }, { "id": "minecraft:splash_potion" }, @@ -3817,6 +4098,22 @@ "id": "minecraft:splash_potion", "damage": 42 }, + { + "id": "minecraft:splash_potion", + "damage": 43 + }, + { + "id": "minecraft:splash_potion", + "damage": 44 + }, + { + "id": "minecraft:splash_potion", + "damage": 45 + }, + { + "id": "minecraft:splash_potion", + "damage": 46 + }, { "id": "minecraft:lingering_potion" }, @@ -3988,6 +4285,22 @@ "id": "minecraft:lingering_potion", "damage": 42 }, + { + "id": "minecraft:lingering_potion", + "damage": 43 + }, + { + "id": "minecraft:lingering_potion", + "damage": 44 + }, + { + "id": "minecraft:lingering_potion", + "damage": 45 + }, + { + "id": "minecraft:lingering_potion", + "damage": 46 + }, { "id": "minecraft:spyglass" }, @@ -4062,119 +4375,119 @@ }, { "id": "minecraft:torch", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnRvcmNoBAkAbmFtZV9oYXNoagn7rmDBzisDCgBuZXR3b3JrX2lk+BwwuQoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnRvcmNoBAkAbmFtZV9oYXNoagn7rmDBzisDCgBuZXR3b3JrX2lk+BwwuQoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:soul_torch", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNvdWxfdG9yY2gECQBuYW1lX2hhc2huixOT04BRdQMKAG5ldHdvcmtfaWShbFILCgYAc3RhdGVzCBYAdG9yY2hfZmFjaW5nX2RpcmVjdGlvbgcAdW5rbm93bgADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNvdWxfdG9yY2gECQBuYW1lX2hhc2huixOT04BRdQMKAG5ldHdvcmtfaWShbFILCgYAc3RhdGVzCBYAdG9yY2hfZmFjaW5nX2RpcmVjdGlvbgcAdW5rbm93bgADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:sea_pickle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAQAACAQAbmFtZRQAbWluZWNyYWZ0OnNlYV9waWNrbGUECQBuYW1lX2hhc2iONEfZJB+glgMKAG5ldHdvcmtfaWSINWQyCgYAc3RhdGVzAw0AY2x1c3Rlcl9jb3VudAAAAAABCABkZWFkX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAQAACAQAbmFtZRQAbWluZWNyYWZ0OnNlYV9waWNrbGUECQBuYW1lX2hhc2iONEfZJB+glgMKAG5ldHdvcmtfaWSINWQyCgYAc3RhdGVzAw0AY2x1c3Rlcl9jb3VudAAAAAABCABkZWFkX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:lantern", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAQAACAQAbmFtZREAbWluZWNyYWZ0OmxhbnRlcm4ECQBuYW1lX2hhc2hMw44VI2HWygMKAG5ldHdvcmtfaWRkjQvzCgYAc3RhdGVzAQcAaGFuZ2luZwAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAQAACAQAbmFtZREAbWluZWNyYWZ0OmxhbnRlcm4ECQBuYW1lX2hhc2hMw44VI2HWygMKAG5ldHdvcmtfaWRkjQvzCgYAc3RhdGVzAQcAaGFuZ2luZwAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:soul_lantern", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNvdWxfbGFudGVybgQJAG5hbWVfaGFzaGjIpjxk9z+RAwoAbmV0d29ya19pZGfoP8cKBgBzdGF0ZXMBBwBoYW5naW5nAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNvdWxfbGFudGVybgQJAG5hbWVfaGFzaGjIpjxk9z+RAwoAbmV0d29ya19pZGfoP8cKBgBzdGF0ZXMBBwBoYW5naW5nAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZHsBMA0KBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZHsBMA0KBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:white_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWScAgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhbmRsZQQJAG5hbWVfaGFzaN1EG5Q1mHiEAwoAbmV0d29ya19pZKN1mmgKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhbmRsZQQJAG5hbWVfaGFzaN1EG5Q1mHiEAwoAbmV0d29ya19pZKN1mmgKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:orange_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSdAgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYW5kbGUECQBuYW1lX2hhc2jySEVWHgUIHQMKAG5ldHdvcmtfaWSfVz82CgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSdAgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYW5kbGUECQBuYW1lX2hhc2jySEVWHgUIHQMKAG5ldHdvcmtfaWSfVz82CgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:magenta_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FuZGxlBAkAbmFtZV9oYXNoG0u6YIOoBSEDCgBuZXR3b3JrX2lk9xGNkQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FuZGxlBAkAbmFtZV9oYXNoG0u6YIOoBSEDCgBuZXR3b3JrX2lk9xGNkQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:light_blue_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FuZGxlBAkAbmFtZV9oYXNocXGeK0zgrG0DCgBuZXR3b3JrX2lk2m1y8goGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FuZGxlBAkAbmFtZV9oYXNocXGeK0zgrG0DCgBuZXR3b3JrX2lk2m1y8goGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:yellow_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYW5kbGUECQBuYW1lX2hhc2i00dtusU3CqQMKAG5ldHdvcmtfaWR9LTmpCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYW5kbGUECQBuYW1lX2hhc2i00dtusU3CqQMKAG5ldHdvcmtfaWR9LTmpCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:lime_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWShAgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FuZGxlBAkAbmFtZV9oYXNokcmrw5xvz7ADCgBuZXR3b3JrX2lkIAUu6QoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FuZGxlBAkAbmFtZV9oYXNokcmrw5xvz7ADCgBuZXR3b3JrX2lkIAUu6QoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:pink_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FuZGxlBAkAbmFtZV9oYXNoQJdEY4sZ0dwDCgBuZXR3b3JrX2lk23Rn5AoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FuZGxlBAkAbmFtZV9oYXNoQJdEY4sZ0dwDCgBuZXR3b3JrX2lk23Rn5AoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:gray_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FuZGxlBAkAbmFtZV9oYXNoS5poSo9wBDEDCgBuZXR3b3JrX2lk3trRCAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FuZGxlBAkAbmFtZV9oYXNoS5poSo9wBDEDCgBuZXR3b3JrX2lk3trRCAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:light_gray_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FuZGxlBAkAbmFtZV9oYXNo9ruTZLBNMasDCgBuZXR3b3JrX2lkb6DOegoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FuZGxlBAkAbmFtZV9oYXNo9ruTZLBNMasDCgBuZXR3b3JrX2lkb6DOegoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cyan_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FuZGxlBAkAbmFtZV9oYXNoc/M8PNVcjOwDCgBuZXR3b3JrX2lkZoIQOQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FuZGxlBAkAbmFtZV9oYXNoc/M8PNVcjOwDCgBuZXR3b3JrX2lkZoIQOQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:purple_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYW5kbGUECQBuYW1lX2hhc2jaI3xUW0/myQMKAG5ldHdvcmtfaWSnLI2BCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYW5kbGUECQBuYW1lX2hhc2jaI3xUW0/myQMKAG5ldHdvcmtfaWSnLI2BCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:blue_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FuZGxlBAkAbmFtZV9oYXNoAASSPW6TgQADCgBuZXR3b3JrX2lkrxrjQAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FuZGxlBAkAbmFtZV9oYXNoAASSPW6TgQADCgBuZXR3b3JrX2lkrxrjQAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:brown_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhbmRsZQQJAG5hbWVfaGFzaDia0l6s1+WYAwoAbmV0d29ya19pZKSkBXYKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhbmRsZQQJAG5hbWVfaGFzaDia0l6s1+WYAwoAbmV0d29ya19pZKSkBXYKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:green_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhbmRsZQQJAG5hbWVfaGFzaLeFPO1l+fIoAwoAbmV0d29ya19pZBkznDsKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhbmRsZQQJAG5hbWVfaGFzaLeFPO1l+fIoAwoAbmV0d29ya19pZBkznDsKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:red_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYW5kbGUECQBuYW1lX2hhc2jjAQpGf59ZdwMKAG5ldHdvcmtfaWRbb88GCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYW5kbGUECQBuYW1lX2hhc2jjAQpGf59ZdwMKAG5ldHdvcmtfaWRbb88GCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:black_candle", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhbmRsZQQJAG5hbWVfaGFzaB+wRDpOqREKAwoAbmV0d29ya19pZNnOnuEKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhbmRsZQQJAG5hbWVfaGFzaB+wRDpOqREKAwoAbmV0d29ya19pZNnOnuEKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crafting_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AAAACAQAbmFtZRgAbWluZWNyYWZ0OmNyYWZ0aW5nX3RhYmxlBAkAbmFtZV9oYXNoe76VAmjvbpYDCgBuZXR3b3JrX2lkwCxwaAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AAAACAQAbmFtZRgAbWluZWNyYWZ0OmNyYWZ0aW5nX3RhYmxlBAkAbmFtZV9oYXNoe76VAmjvbpYDCgBuZXR3b3JrX2lkwCxwaAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cartography_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAQAACAQAbmFtZRsAbWluZWNyYWZ0OmNhcnRvZ3JhcGh5X3RhYmxlBAkAbmFtZV9oYXNomaWiiD/znP8DCgBuZXR3b3JrX2lkI6FzMwoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAQAACAQAbmFtZRsAbWluZWNyYWZ0OmNhcnRvZ3JhcGh5X3RhYmxlBAkAbmFtZV9oYXNomaWiiD/znP8DCgBuZXR3b3JrX2lkI6FzMwoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:fletching_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAQAACAQAbmFtZRkAbWluZWNyYWZ0OmZsZXRjaGluZ190YWJsZQQJAG5hbWVfaGFzaPFibh8unKyUAwoAbmV0d29ya19pZJ2mW0oKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAQAACAQAbmFtZRkAbWluZWNyYWZ0OmZsZXRjaGluZ190YWJsZQQJAG5hbWVfaGFzaPFibh8unKyUAwoAbmV0d29ya19pZJ2mW0oKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:smithing_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAQAACAQAbmFtZRgAbWluZWNyYWZ0OnNtaXRoaW5nX3RhYmxlBAkAbmFtZV9oYXNo4tFES2xOXEYDCgBuZXR3b3JrX2lkXWMBzQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAQAACAQAbmFtZRgAbWluZWNyYWZ0OnNtaXRoaW5nX3RhYmxlBAkAbmFtZV9oYXNo4tFES2xOXEYDCgBuZXR3b3JrX2lkXWMBzQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:beehive", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAQAACAQAbmFtZREAbWluZWNyYWZ0OmJlZWhpdmUECQBuYW1lX2hhc2hCcqn12UbNpwMKAG5ldHdvcmtfaWR/idcaCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAMLAGhvbmV5X2xldmVsAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAQAACAQAbmFtZREAbWluZWNyYWZ0OmJlZWhpdmUECQBuYW1lX2hhc2hCcqn12UbNpwMKAG5ldHdvcmtfaWR/idcaCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAMLAGhvbmV5X2xldmVsAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:suspicious_sand", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAwAACAQAbmFtZRkAbWluZWNyYWZ0OnN1c3BpY2lvdXNfc2FuZAQJAG5hbWVfaGFzaL67QsuvLP00AwoAbmV0d29ya19pZKnkaIAKBgBzdGF0ZXMDEABicnVzaGVkX3Byb2dyZXNzAAAAAAEHAGhhbmdpbmcBAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAwAACAQAbmFtZRkAbWluZWNyYWZ0OnN1c3BpY2lvdXNfc2FuZAQJAG5hbWVfaGFzaL67QsuvLP00AwoAbmV0d29ya19pZKnkaIAKBgBzdGF0ZXMDEABicnVzaGVkX3Byb2dyZXNzAAAAAAEHAGhhbmdpbmcBAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:suspicious_gravel", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AwAACAQAbmFtZRsAbWluZWNyYWZ0OnN1c3BpY2lvdXNfZ3JhdmVsBAkAbmFtZV9oYXNoJSVbGNk7C3oDCgBuZXR3b3JrX2lkvIEJAAoGAHN0YXRlcwMQAGJydXNoZWRfcHJvZ3Jlc3MAAAAAAQcAaGFuZ2luZwEAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AwAACAQAbmFtZRsAbWluZWNyYWZ0OnN1c3BpY2lvdXNfZ3JhdmVsBAkAbmFtZV9oYXNoJSVbGNk7C3oDCgBuZXR3b3JrX2lkvIEJAAoGAHN0YXRlcwMQAGJydXNoZWRfcHJvZ3Jlc3MAAAAAAQcAaGFuZ2luZwEAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:campfire" @@ -4184,156 +4497,156 @@ }, { "id": "minecraft:furnace", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AAAACAQAbmFtZREAbWluZWNyYWZ0OmZ1cm5hY2UECQBuYW1lX2hhc2ioOQrludYY8wMKAG5ldHdvcmtfaWRZxnDOCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AAAACAQAbmFtZREAbWluZWNyYWZ0OmZ1cm5hY2UECQBuYW1lX2hhc2ioOQrludYY8wMKAG5ldHdvcmtfaWRZxnDOCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:blast_furnace", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAQAACAQAbmFtZRcAbWluZWNyYWZ0OmJsYXN0X2Z1cm5hY2UECQBuYW1lX2hhc2ivDbnjkpGm5QMKAG5ldHdvcmtfaWTcEbV/CgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAQAACAQAbmFtZRcAbWluZWNyYWZ0OmJsYXN0X2Z1cm5hY2UECQBuYW1lX2hhc2ivDbnjkpGm5QMKAG5ldHdvcmtfaWTcEbV/CgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:smoker", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAQAACAQAbmFtZRAAbWluZWNyYWZ0OnNtb2tlcgQJAG5hbWVfaGFzaJd1rDMkRWomAwoAbmV0d29ya19pZGWswMwKBgBzdGF0ZXMIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAQAACAQAbmFtZRAAbWluZWNyYWZ0OnNtb2tlcgQJAG5hbWVfaGFzaJd1rDMkRWomAwoAbmV0d29ya19pZGWswMwKBgBzdGF0ZXMIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:respawn_anchor", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlc3Bhd25fYW5jaG9yBAkAbmFtZV9oYXNoZOdcjW05qigDCgBuZXR3b3JrX2lkmhMcaQoGAHN0YXRlcwMVAHJlc3Bhd25fYW5jaG9yX2NoYXJnZQAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlc3Bhd25fYW5jaG9yBAkAbmFtZV9oYXNoZOdcjW05qigDCgBuZXR3b3JrX2lkmhMcaQoGAHN0YXRlcwMVAHJlc3Bhd25fYW5jaG9yX2NoYXJnZQAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:brewing_stand" }, { "id": "minecraft:anvil", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lk8Z3VowoGAHN0YXRlcwgGAGRhbWFnZQkAdW5kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lk8Z3VowoGAHN0YXRlcwgGAGRhbWFnZQkAdW5kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:anvil", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkpiv8BAoGAHN0YXRlcwgGAGRhbWFnZRAAc2xpZ2h0bHlfZGFtYWdlZAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkpiv8BAoGAHN0YXRlcwgGAGRhbWFnZRAAc2xpZ2h0bHlfZGFtYWdlZAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:anvil", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkFu+pdwoGAHN0YXRlcwgGAGRhbWFnZQwAdmVyeV9kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkFu+pdwoGAHN0YXRlcwgGAGRhbWFnZQwAdmVyeV9kYW1hZ2VkCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:grindstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAQAACAQAbmFtZRQAbWluZWNyYWZ0OmdyaW5kc3RvbmUECQBuYW1lX2hhc2id56zc0nk99wMKAG5ldHdvcmtfaWS4Es07CgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAQAACAQAbmFtZRQAbWluZWNyYWZ0OmdyaW5kc3RvbmUECQBuYW1lX2hhc2id56zc0nk99wMKAG5ldHdvcmtfaWS4Es07CgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:enchanting_table", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuY2hhbnRpbmdfdGFibGUECQBuYW1lX2hhc2jgIx24VLvMvwMKAG5ldHdvcmtfaWRliFFJCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuY2hhbnRpbmdfdGFibGUECQBuYW1lX2hhc2jgIx24VLvMvwMKAG5ldHdvcmtfaWRliFFJCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bookshelf", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAAAACAQAbmFtZRMAbWluZWNyYWZ0OmJvb2tzaGVsZgQJAG5hbWVfaGFzaDU04DrgJCS9AwoAbmV0d29ya19pZBcWwIwKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAAAACAQAbmFtZRMAbWluZWNyYWZ0OmJvb2tzaGVsZgQJAG5hbWVfaGFzaDU04DrgJCS9AwoAbmV0d29ya19pZBcWwIwKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:chiseled_bookshelf", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAwAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2Jvb2tzaGVsZgQJAG5hbWVfaGFzaNXDBnsIsywYAwoAbmV0d29ya19pZIprt5IKBgBzdGF0ZXMDDABib29rc19zdG9yZWQAAAAAAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAwAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2Jvb2tzaGVsZgQJAG5hbWVfaGFzaNXDBnsIsywYAwoAbmV0d29ya19pZIprt5IKBgBzdGF0ZXMDDABib29rc19zdG9yZWQAAAAAAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:lectern", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTBAQAACAQAbmFtZREAbWluZWNyYWZ0OmxlY3Rlcm4ECQBuYW1lX2hhc2j5Z4Mmi/1QxAMKAG5ldHdvcmtfaWR4JfDHCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTBAQAACAQAbmFtZREAbWluZWNyYWZ0OmxlY3Rlcm4ECQBuYW1lX2hhc2j5Z4Mmi/1QxAMKAG5ldHdvcmtfaWR4JfDHCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cauldron" }, { "id": "minecraft:composter", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvbXBvc3RlcgQJAG5hbWVfaGFzaPAADHptzeWJAwoAbmV0d29ya19pZHIL6i4KBgBzdGF0ZXMDFABjb21wb3N0ZXJfZmlsbF9sZXZlbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvbXBvc3RlcgQJAG5hbWVfaGFzaPAADHptzeWJAwoAbmV0d29ya19pZHIL6i4KBgBzdGF0ZXMDFABjb21wb3N0ZXJfZmlsbF9sZXZlbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:chest", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AAAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkDkOFvAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AAAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkDkOFvAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:trapped_chest", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyYXBwZWRfY2hlc3QECQBuYW1lX2hhc2g2qpF9stsEjgMKAG5ldHdvcmtfaWTjJWYxCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAbm9ydGgAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyYXBwZWRfY2hlc3QECQBuYW1lX2hhc2g2qpF9stsEjgMKAG5ldHdvcmtfaWTjJWYxCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAbm9ydGgAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:ender_chest", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVuZGVyX2NoZXN0BAkAbmFtZV9oYXNohEZzOFdg0WUDCgBuZXR3b3JrX2lkx4jiSQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVuZGVyX2NoZXN0BAkAbmFtZV9oYXNohEZzOFdg0WUDCgBuZXR3b3JrX2lkx4jiSQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:barrel", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhcnJlbAQJAG5hbWVfaGFzaHDkRPGymiRqAwoAbmV0d29ya19pZPnxzgsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhcnJlbAQJAG5hbWVfaGFzaHDkRPGymiRqAwoAbmV0d29ya19pZPnxzgsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:undyed_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAAAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZJ8rxp0KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAAAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZJ8rxp0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:white_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAAAACAQAbmFtZRsAbWluZWNyYWZ0OndoaXRlX3NodWxrZXJfYm94BAkAbmFtZV9oYXNosK79m1rPUBwDCgBuZXR3b3JrX2lkjrET6goGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAAAACAQAbmFtZRsAbWluZWNyYWZ0OndoaXRlX3NodWxrZXJfYm94BAkAbmFtZV9oYXNosK79m1rPUBwDCgBuZXR3b3JrX2lkjrET6goGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:light_gray_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iBe5zq7PxHmgMKAG5ldHdvcmtfaWSCVJv0CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iBe5zq7PxHmgMKAG5ldHdvcmtfaWSCVJv0CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:gray_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2ga2s8ctjHUhgMKAG5ldHdvcmtfaWS3WMsWCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2ga2s8ctjHUhgMKAG5ldHdvcmtfaWS3WMsWCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:black_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoPm03OZphrp8DCgBuZXR3b3JrX2lkXHztNAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoPm03OZphrp8DCgBuZXR3b3JrX2lkXHztNAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:brown_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJyb3duX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoT3DD6qAL9cADCgBuZXR3b3JrX2lkaXxpYQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJyb3duX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoT3DD6qAL9cADCgBuZXR3b3JrX2lkaXxpYQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:red_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAwAACAQAbmFtZRkAbWluZWNyYWZ0OnJlZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaMIlKSCzqSZoAwoAbmV0d29ya19pZNrf+icKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAwAACAQAbmFtZRkAbWluZWNyYWZ0OnJlZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaMIlKSCzqSZoAwoAbmV0d29ya19pZNrf+icKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:orange_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAwAACAQAbmFtZRwAbWluZWNyYWZ0Om9yYW5nZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaG2MAXU67wGrAwoAbmV0d29ya19pZGoO05gKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAwAACAQAbmFtZRwAbWluZWNyYWZ0Om9yYW5nZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaG2MAXU67wGrAwoAbmV0d29ya19pZGoO05gKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:yellow_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAwAACAQAbmFtZRwAbWluZWNyYWZ0OnllbGxvd19zaHVsa2VyX2JveAQJAG5hbWVfaGFzaIsLwQHYjcIEAwoAbmV0d29ya19pZBCBSiYKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAwAACAQAbmFtZRwAbWluZWNyYWZ0OnllbGxvd19zaHVsa2VyX2JveAQJAG5hbWVfaGFzaIsLwQHYjcIEAwoAbmV0d29ya19pZBCBSiYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:lime_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAwAACAQAbmFtZRoAbWluZWNyYWZ0OmxpbWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hUwBkg+faUGAMKAG5ldHdvcmtfaWRJeKqqCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAwAACAQAbmFtZRoAbWluZWNyYWZ0OmxpbWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hUwBkg+faUGAMKAG5ldHdvcmtfaWRJeKqqCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:green_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAwAACAQAbmFtZRsAbWluZWNyYWZ0OmdyZWVuX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoZgUeT3LupLUDCgBuZXR3b3JrX2lkzJiohQoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAwAACAQAbmFtZRsAbWluZWNyYWZ0OmdyZWVuX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoZgUeT3LupLUDCgBuZXR3b3JrX2lkzJiohQoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:cyan_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAwAACAQAbmFtZRoAbWluZWNyYWZ0OmN5YW5fc2h1bGtlcl9ib3gECQBuYW1lX2hhc2gSfbjteXg5yAMKAG5ldHdvcmtfaWTHeliECgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAwAACAQAbmFtZRoAbWluZWNyYWZ0OmN5YW5fc2h1bGtlcl9ib3gECQBuYW1lX2hhc2gSfbjteXg5yAMKAG5ldHdvcmtfaWTHeliECgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:light_blue_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2h0VFCX0qsRxQMKAG5ldHdvcmtfaWQXD8U0CgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2h0VFCX0qsRxQMKAG5ldHdvcmtfaWQXD8U0CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:blue_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hn9gS0XIe6rAMKAG5ldHdvcmtfaWTO4PJaCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hn9gS0XIe6rAMKAG5ldHdvcmtfaWTO4PJaCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:purple_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAwAACAQAbmFtZRwAbWluZWNyYWZ0OnB1cnBsZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaEV/lkNPxRDdAwoAbmV0d29ya19pZFK25GAKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAwAACAQAbmFtZRwAbWluZWNyYWZ0OnB1cnBsZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaEV/lkNPxRDdAwoAbmV0d29ya19pZFK25GAKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:magenta_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAwAACAQAbmFtZR0AbWluZWNyYWZ0Om1hZ2VudGFfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iqWM7IJHxcFgMKAG5ldHdvcmtfaWTyyudTCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAwAACAQAbmFtZR0AbWluZWNyYWZ0Om1hZ2VudGFfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iqWM7IJHxcFgMKAG5ldHdvcmtfaWTyyudTCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:pink_shulker_box", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBpbmtfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2in1tkJ1GNcZgMKAG5ldHdvcmtfaWQOEGXjCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBpbmtfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2in1tkJ1GNcZgMKAG5ldHdvcmtfaWQOEGXjCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:armor_stand" }, { "id": "minecraft:noteblock", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAAAACAQAbmFtZRMAbWluZWNyYWZ0Om5vdGVibG9jawQJAG5hbWVfaGFzaHPA8dBBH0UaAwoAbmV0d29ya19pZH1U5QkKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAAAACAQAbmFtZRMAbWluZWNyYWZ0Om5vdGVibG9jawQJAG5hbWVfaGFzaHPA8dBBH0UaAwoAbmV0d29ya19pZH1U5QkKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:jukebox", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAAAACAQAbmFtZREAbWluZWNyYWZ0Omp1a2Vib3gECQBuYW1lX2hhc2ieAIPExf/ZfgMKAG5ldHdvcmtfaWSmR7JfCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAAAACAQAbmFtZREAbWluZWNyYWZ0Omp1a2Vib3gECQBuYW1lX2hhc2ieAIPExf/ZfgMKAG5ldHdvcmtfaWSmR7JfCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:music_disc_13" @@ -4383,6 +4696,15 @@ { "id": "minecraft:music_disc_relic" }, + { + "id": "minecraft:music_disc_creator" + }, + { + "id": "minecraft:music_disc_creator_music_box" + }, + { + "id": "minecraft:music_disc_precipice" + }, { "id": "minecraft:disc_fragment_5" }, @@ -4391,15 +4713,15 @@ }, { "id": "minecraft:glowstone", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAAAACAQAbmFtZRMAbWluZWNyYWZ0Omdsb3dzdG9uZQQJAG5hbWVfaGFzaFYqXNkefIlPAwoAbmV0d29ya19pZGT7WYYKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAAAACAQAbmFtZRMAbWluZWNyYWZ0Omdsb3dzdG9uZQQJAG5hbWVfaGFzaFYqXNkefIlPAwoAbmV0d29ya19pZGT7WYYKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:redstone_lamp", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZHN0b25lX2xhbXAECQBuYW1lX2hhc2hJ9V80caPvEgMKAG5ldHdvcmtfaWRvNPwnCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZHN0b25lX2xhbXAECQBuYW1lX2hhc2hJ9V80caPvEgMKAG5ldHdvcmtfaWRvNPwnCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:sea_lantern", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNlYV9sYW50ZXJuBAkAbmFtZV9oYXNoLPsv1TX9M+QDCgBuZXR3b3JrX2lk1PPVyAoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNlYV9sYW50ZXJuBAkAbmFtZV9oYXNoLPsv1TX9M+QDCgBuZXR3b3JrX2lk1PPVyAoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:oak_sign" @@ -4547,19 +4869,19 @@ }, { "id": "minecraft:beacon", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAAAACAQAbmFtZRAAbWluZWNyYWZ0OmJlYWNvbgQJAG5hbWVfaGFzaACwhhfSkdkHAwoAbmV0d29ya19pZF8jfiEKBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAAAACAQAbmFtZRAAbWluZWNyYWZ0OmJlYWNvbgQJAG5hbWVfaGFzaACwhhfSkdkHAwoAbmV0d29ya19pZF8jfiEKBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:bell", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAQAACAQAbmFtZQ4AbWluZWNyYWZ0OmJlbGwECQBuYW1lX2hhc2iPqsgDXRcsxAMKAG5ldHdvcmtfaWT7zhOoCgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAQoAdG9nZ2xlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAQAACAQAbmFtZQ4AbWluZWNyYWZ0OmJlbGwECQBuYW1lX2hhc2iPqsgDXRcsxAMKAG5ldHdvcmtfaWT7zhOoCgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAQoAdG9nZ2xlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:conduit", - "block_state_b64": "CgAAAwgAYmxvY2tfaWScAQAACAQAbmFtZREAbWluZWNyYWZ0OmNvbmR1aXQECQBuYW1lX2hhc2jqxKAxq2EaWQMKAG5ldHdvcmtfaWTWcBVnCgYAc3RhdGVzAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAQAACAQAbmFtZREAbWluZWNyYWZ0OmNvbmR1aXQECQBuYW1lX2hhc2jqxKAxq2EaWQMKAG5ldHdvcmtfaWTWcBVnCgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stonecutter_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lY3V0dGVyX2Jsb2NrBAkAbmFtZV9oYXNoQAXTbAM3MeYDCgBuZXR3b3JrX2lkWS4RjAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lY3V0dGVyX2Jsb2NrBAkAbmFtZV9oYXNoQAXTbAM3MeYDCgBuZXR3b3JrX2lkWS4RjAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:coal" @@ -4633,6 +4955,9 @@ { "id": "minecraft:turtle_scute" }, + { + "id": "minecraft:armadillo_scute" + }, { "id": "minecraft:phantom_membrane" }, @@ -4663,6 +4988,13 @@ { "id": "minecraft:blaze_rod" }, + { + "id": "minecraft:breeze_rod" + }, + { + "id": "minecraft:heavy_core", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AgAACAQAbmFtZRQAbWluZWNyYWZ0OmhlYXZ5X2NvcmUECQBuYW1lX2hhc2hhz/uNCtrC2QMKAG5ldHdvcmtfaWRaFu+8CgYAc3RhdGVzAAMHAHZlcnNpb24DABUBAA==" + }, { "id": "minecraft:blaze_powder" }, @@ -4698,11 +5030,11 @@ }, { "id": "minecraft:end_rod", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAAAACAQAbmFtZREAbWluZWNyYWZ0OmVuZF9yb2QECQBuYW1lX2hhc2jx/q5cEA0hmQMKAG5ldHdvcmtfaWQ2eM8kCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAAAACAQAbmFtZREAbWluZWNyYWZ0OmVuZF9yb2QECQBuYW1lX2hhc2jx/q5cEA0hmQMKAG5ldHdvcmtfaWQ2eM8kCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:lightning_rod", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpZ2h0bmluZ19yb2QECQBuYW1lX2hhc2ioXQF1xvfHNQMKAG5ldHdvcmtfaWRLuHyACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpZ2h0bmluZ19yb2QECQBuYW1lX2hhc2ioXQF1xvfHNQMKAG5ldHdvcmtfaWRLuHyACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:end_crystal" @@ -4716,6 +5048,9 @@ { "id": "minecraft:writable_book" }, + { + "id": "minecraft:trial_key" + }, { "id": "minecraft:enchanted_book", "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" @@ -5156,6 +5491,54 @@ "id": "minecraft:enchanted_book", "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAQAAAA=" + }, { "id": "minecraft:oak_boat" }, @@ -5212,19 +5595,19 @@ }, { "id": "minecraft:rail", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWR+Sp6YCgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWR+Sp6YCgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:golden_rail", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdvbGRlbl9yYWlsBAkAbmFtZV9oYXNoOoV5MaKipoUDCgBuZXR3b3JrX2lkfAcxLwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdvbGRlbl9yYWlsBAkAbmFtZV9oYXNoOoV5MaKipoUDCgBuZXR3b3JrX2lkfAcxLwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:detector_rail", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAAAACAQAbmFtZRcAbWluZWNyYWZ0OmRldGVjdG9yX3JhaWwECQBuYW1lX2hhc2gVUk31qOysUQMKAG5ldHdvcmtfaWRVW/aICgYAc3RhdGVzAQ0AcmFpbF9kYXRhX2JpdAADDgByYWlsX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAAAACAQAbmFtZRcAbWluZWNyYWZ0OmRldGVjdG9yX3JhaWwECQBuYW1lX2hhc2gVUk31qOysUQMKAG5ldHdvcmtfaWRVW/aICgYAc3RhdGVzAQ0AcmFpbF9kYXRhX2JpdAADDgByYWlsX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:activator_rail", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjdGl2YXRvcl9yYWlsBAkAbmFtZV9oYXNosIL91qriCRkDCgBuZXR3b3JrX2lkZfckmwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjdGl2YXRvcl9yYWlsBAkAbmFtZV9oYXNosIL91qriCRkDCgBuZXR3b3JrX2lkZfckmwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:minecart" @@ -5243,139 +5626,139 @@ }, { "id": "minecraft:redstone_block", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX2Jsb2NrBAkAbmFtZV9oYXNoRhULL0r8o0sDCgBuZXR3b3JrX2lklayOHgoGAHN0YXRlcwADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX2Jsb2NrBAkAbmFtZV9oYXNoRhULL0r8o0sDCgBuZXR3b3JrX2lklayOHgoGAHN0YXRlcwADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:redstone_torch", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX3RvcmNoBAkAbmFtZV9oYXNoizFRjpYMIDgDCgBuZXR3b3JrX2lkuHz7yAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX3RvcmNoBAkAbmFtZV9oYXNoizFRjpYMIDgDCgBuZXR3b3JrX2lkuHz7yAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:lever", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxldmVyBAkAbmFtZV9oYXNoGMJeLJsUMLYDCgBuZXR3b3JrX2lkEF/GuAoGAHN0YXRlcwgPAGxldmVyX2RpcmVjdGlvbg4AZG93bl9lYXN0X3dlc3QBCABvcGVuX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxldmVyBAkAbmFtZV9oYXNoGMJeLJsUMLYDCgBuZXR3b3JrX2lkEF/GuAoGAHN0YXRlcwgPAGxldmVyX2RpcmVjdGlvbg4AZG93bl9lYXN0X3dlc3QBCABvcGVuX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:wooden_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAAAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWSU07kYCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAAAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWSU07kYCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:spruce_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAQAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9idXR0b24ECQBuYW1lX2hhc2jBW9Z8aYE7YQMKAG5ldHdvcmtfaWTkUIGuCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAQAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9idXR0b24ECQBuYW1lX2hhc2jBW9Z8aYE7YQMKAG5ldHdvcmtfaWTkUIGuCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:birch_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAQAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2J1dHRvbgQJAG5hbWVfaGFzaJXYgGuSHbTwAwoAbmV0d29ya19pZGWp3yoKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAQAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2J1dHRvbgQJAG5hbWVfaGFzaJXYgGuSHbTwAwoAbmV0d29ya19pZGWp3yoKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:jungle_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAQAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9idXR0b24ECQBuYW1lX2hhc2iCgNANcJs+BQMKAG5ldHdvcmtfaWT9fImWCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAQAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9idXR0b24ECQBuYW1lX2hhc2iCgNANcJs+BQMKAG5ldHdvcmtfaWT9fImWCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:acacia_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAQAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9idXR0b24ECQBuYW1lX2hhc2gVvmcT7LTO0wMKAG5ldHdvcmtfaWRQnxIJCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAQAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9idXR0b24ECQBuYW1lX2hhc2gVvmcT7LTO0wMKAG5ldHdvcmtfaWRQnxIJCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dark_oak_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAQAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaIV10ZGGrCIEAwoAbmV0d29ya19pZN5vAmIKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAQAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaIV10ZGGrCIEAwoAbmV0d29ya19pZN5vAmIKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mangrove_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2J1dHRvbgQJAG5hbWVfaGFzaNzeYYKLgOzJAwoAbmV0d29ya19pZAFEGQ0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2J1dHRvbgQJAG5hbWVfaGFzaNzeYYKLgOzJAwoAbmV0d29ya19pZAFEGQ0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cherry_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9idXR0b24ECQBuYW1lX2hhc2j2/IHjeAbUcwMKAG5ldHdvcmtfaWRJ1irQCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9idXR0b24ECQBuYW1lX2hhc2j2/IHjeAbUcwMKAG5ldHdvcmtfaWRJ1irQCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bamboo_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19idXR0b24ECQBuYW1lX2hhc2j7AddMi+6nsgMKAG5ldHdvcmtfaWSa9w4/CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19idXR0b24ECQBuYW1lX2hhc2j7AddMi+6nsgMKAG5ldHdvcmtfaWSa9w4/CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stone_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2J1dHRvbgQJAG5hbWVfaGFzaM4ejMctmvohAwoAbmV0d29ya19pZMw+aC0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2J1dHRvbgQJAG5hbWVfaGFzaM4ejMctmvohAwoAbmV0d29ya19pZMw+aC0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:crimson_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fYnV0dG9uBAkAbmFtZV9oYXNofnjYHaYIeWgDCgBuZXR3b3JrX2lk+n1vyQoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fYnV0dG9uBAkAbmFtZV9oYXNofnjYHaYIeWgDCgBuZXR3b3JrX2lk+n1vyQoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:warped_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9idXR0b24ECQBuYW1lX2hhc2jwkV2EU6Cn1QMKAG5ldHdvcmtfaWTnHnk1CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9idXR0b24ECQBuYW1lX2hhc2jwkV2EU6Cn1QMKAG5ldHdvcmtfaWTnHnk1CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:polished_blackstone_button", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnV0dG9uBAkAbmFtZV9oYXNojmxzQKS0S/EDCgBuZXR3b3JrX2lkDtQ95woGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnV0dG9uBAkAbmFtZV9oYXNojmxzQKS0S/EDCgBuZXR3b3JrX2lkDtQ95woGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:tripwire_hook", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaXB3aXJlX2hvb2sECQBuYW1lX2hhc2gQdp+oGZLNnAMKAG5ldHdvcmtfaWSy+1KJCgYAc3RhdGVzAQwAYXR0YWNoZWRfYml0AAMJAGRpcmVjdGlvbgAAAAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaXB3aXJlX2hvb2sECQBuYW1lX2hhc2gQdp+oGZLNnAMKAG5ldHdvcmtfaWSy+1KJCgYAc3RhdGVzAQwAYXR0YWNoZWRfYml0AAMJAGRpcmVjdGlvbgAAAAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:wooden_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAAAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZDRzPNwKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAAAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZDRzPNwKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:spruce_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAQAACAQAbmFtZR8AbWluZWNyYWZ0OnNwcnVjZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNmwuq549fJKAwoAbmV0d29ya19pZLQMCw0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAQAACAQAbmFtZR8AbWluZWNyYWZ0OnNwcnVjZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNmwuq549fJKAwoAbmV0d29ya19pZLQMCw0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:birch_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAQAACAQAbmFtZR4AbWluZWNyYWZ0OmJpcmNoX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNorQkT9kDdlTwDCgBuZXR3b3JrX2lkH0G97AoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAQAACAQAbmFtZR4AbWluZWNyYWZ0OmJpcmNoX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNorQkT9kDdlTwDCgBuZXR3b3JrX2lkH0G97AoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:jungle_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAQAACAQAbmFtZR8AbWluZWNyYWZ0Omp1bmdsZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaJ7DcteCkb8/AwoAbmV0d29ya19pZLdPBSAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAQAACAQAbmFtZR8AbWluZWNyYWZ0Omp1bmdsZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaJ7DcteCkb8/AwoAbmV0d29ya19pZLdPBSAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:acacia_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAQAACAQAbmFtZR8AbWluZWNyYWZ0OmFjYWNpYV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaC2frZtfoYqCAwoAbmV0d29ya19pZIDdI18KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAQAACAQAbmFtZR8AbWluZWNyYWZ0OmFjYWNpYV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaC2frZtfoYqCAwoAbmV0d29ya19pZIDdI18KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:dark_oak_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAQAACAQAbmFtZSEAbWluZWNyYWZ0OmRhcmtfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoHUCJsTy52pwDCgBuZXR3b3JrX2lkKpi8rAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAQAACAQAbmFtZSEAbWluZWNyYWZ0OmRhcmtfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoHUCJsTy52pwDCgBuZXR3b3JrX2lkKpi8rAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:mangrove_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hbmdyb3ZlX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoiDsTfJaX100DCgBuZXR3b3JrX2lkuwWDyQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hbmdyb3ZlX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoiDsTfJaX100DCgBuZXR3b3JrX2lkuwWDyQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:cherry_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAwAACAQAbmFtZR8AbWluZWNyYWZ0OmNoZXJyeV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaALMqYEZDUQHAwoAbmV0d29ya19pZPNT+r0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAwAACAQAbmFtZR8AbWluZWNyYWZ0OmNoZXJyeV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaALMqYEZDUQHAwoAbmV0d29ya19pZPNT+r0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:bamboo_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJhbWJvb19wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNvxJ7NIAaqlAwoAbmV0d29ya19pZIZ8XnYKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJhbWJvb19wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNvxJ7NIAaqlAwoAbmV0d29ya19pZIZ8XnYKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:crimson_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNyaW1zb25fcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2hqBDVDAd31/gMKAG5ldHdvcmtfaWRmV18LCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNyaW1zb25fcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2hqBDVDAd31/gMKAG5ldHdvcmtfaWRmV18LCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:warped_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAgAACAQAbmFtZR8AbWluZWNyYWZ0OndhcnBlZF9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaBxFoQksWtYUAwoAbmV0d29ya19pZJVRoIcKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAgAACAQAbmFtZR8AbWluZWNyYWZ0OndhcnBlZF9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaBxFoQksWtYUAwoAbmV0d29ya19pZJVRoIcKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:stone_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0b25lX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNounJuTBUTrU8DCgBuZXR3b3JrX2lkjDydwQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0b25lX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNounJuTBUTrU8DCgBuZXR3b3JrX2lkjDydwQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:light_weighted_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAAAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoOyOJkNxLtkEDCgBuZXR3b3JrX2lkrr2AjgoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAAAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoOyOJkNxLtkEDCgBuZXR3b3JrX2lkrr2AjgoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:heavy_weighted_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAAAACAQAbmFtZScAbWluZWNyYWZ0OmhlYXZ5X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoltgDmDvTajUDCgBuZXR3b3JrX2lkFxVKuQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAAAACAQAbmFtZScAbWluZWNyYWZ0OmhlYXZ5X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoltgDmDvTajUDCgBuZXR3b3JrX2lkFxVKuQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:polished_blackstone_pressure_plate", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAgAACAQAbmFtZSwAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2h65Ci6/CeGqwMKAG5ldHdvcmtfaWTaSW5xCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAgAACAQAbmFtZSwAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2h65Ci6/CeGqwMKAG5ldHdvcmtfaWTaSW5xCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:observer", - "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2VydmVyBAkAbmFtZV9oYXNoYhlh1lpmHTgDCgBuZXR3b3JrX2lkQEh55goGAHN0YXRlcwgaAG1pbmVjcmFmdDpmYWNpbmdfZGlyZWN0aW9uBABkb3duAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2VydmVyBAkAbmFtZV9oYXNoYhlh1lpmHTgDCgBuZXR3b3JrX2lkQEh55goGAHN0YXRlcwgaAG1pbmVjcmFmdDpmYWNpbmdfZGlyZWN0aW9uBABkb3duAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:daylight_detector", - "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAAAACAQAbmFtZRsAbWluZWNyYWZ0OmRheWxpZ2h0X2RldGVjdG9yBAkAbmFtZV9oYXNoV0F0s7B7PVgDCgBuZXR3b3JrX2lkri5afQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAAAACAQAbmFtZRsAbWluZWNyYWZ0OmRheWxpZ2h0X2RldGVjdG9yBAkAbmFtZV9oYXNoV0F0s7B7PVgDCgBuZXR3b3JrX2lkri5afQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:repeater" @@ -5388,30 +5771,34 @@ }, { "id": "minecraft:dropper", - "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AAAACAQAbmFtZREAbWluZWNyYWZ0OmRyb3BwZXIECQBuYW1lX2hhc2joXP7XqU0l3QMKAG5ldHdvcmtfaWQfQN6zCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgMAAAABDQB0cmlnZ2VyZWRfYml0AAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AAAACAQAbmFtZREAbWluZWNyYWZ0OmRyb3BwZXIECQBuYW1lX2hhc2joXP7XqU0l3QMKAG5ldHdvcmtfaWQfQN6zCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgMAAAABDQB0cmlnZ2VyZWRfYml0AAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:dispenser", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRpc3BlbnNlcgQJAG5hbWVfaGFzaP1RR+zAbYP2AwoAbmV0d29ya19pZGAayD0KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAwAAAAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24ERhQBAA==" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRpc3BlbnNlcgQJAG5hbWVfaGFzaP1RR+zAbYP2AwoAbmV0d29ya19pZGAayD0KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAwAAAAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24DABUBAA==" + }, + { + "id": "minecraft:crafter", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AgAACAQAbmFtZREAbWluZWNyYWZ0OmNyYWZ0ZXIECQBuYW1lX2hhc2iLCT/rJmRN8QMKAG5ldHdvcmtfaWTPTbvrCgYAc3RhdGVzAQgAY3JhZnRpbmcACAsAb3JpZW50YXRpb24JAGRvd25fZWFzdAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24DABUBAA==" }, { "id": "minecraft:piston", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBpc3RvbgQJAG5hbWVfaGFzaDs3AFh1fL0uAwoAbmV0d29ya19pZLD/5XQKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAQAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBpc3RvbgQJAG5hbWVfaGFzaDs3AFh1fL0uAwoAbmV0d29ya19pZLD/5XQKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAQAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:sticky_piston", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQdAAAACAQAbmFtZRcAbWluZWNyYWZ0OnN0aWNreV9waXN0b24ECQBuYW1lX2hhc2hPFJFJSiJ0ZQMKAG5ldHdvcmtfaWT/MzCJCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgEAAAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQdAAAACAQAbmFtZRcAbWluZWNyYWZ0OnN0aWNreV9waXN0b24ECQBuYW1lX2hhc2hPFJFJSiJ0ZQMKAG5ldHdvcmtfaWT/MzCJCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgEAAAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:tnt", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAAAACAQAbmFtZQ0AbWluZWNyYWZ0OnRudAQJAG5hbWVfaGFzaEYOHwCvJH29AwoAbmV0d29ya19pZCGfjU4KBgBzdGF0ZXMBFABhbGxvd191bmRlcndhdGVyX2JpdAABCwBleHBsb2RlX2JpdAAAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAAAACAQAbmFtZQ0AbWluZWNyYWZ0OnRudAQJAG5hbWVfaGFzaEYOHwCvJH29AwoAbmV0d29ya19pZCGfjU4KBgBzdGF0ZXMBFABhbGxvd191bmRlcndhdGVyX2JpdAABCwBleHBsb2RlX2JpdAAAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:name_tag" }, { "id": "minecraft:loom", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAQAACAQAbmFtZQ4AbWluZWNyYWZ0Omxvb20ECQBuYW1lX2hhc2i7DKjAXNq8TAMKAG5ldHdvcmtfaWR/49HXCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAQAACAQAbmFtZQ4AbWluZWNyYWZ0Omxvb20ECQBuYW1lX2hhc2i7DKjAXNq8TAMKAG5ldHdvcmtfaWR/49HXCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:banner", @@ -5521,6 +5908,12 @@ { "id": "minecraft:globe_banner_pattern" }, + { + "id": "minecraft:flow_banner_pattern" + }, + { + "id": "minecraft:guster_banner_pattern" + }, { "id": "minecraft:angler_pottery_sherd" }, @@ -5545,9 +5938,15 @@ { "id": "minecraft:explorer_pottery_sherd" }, + { + "id": "minecraft:flow_pottery_sherd" + }, { "id": "minecraft:friend_pottery_sherd" }, + { + "id": "minecraft:guster_pottery_sherd" + }, { "id": "minecraft:heart_pottery_sherd" }, @@ -5569,6 +5968,9 @@ { "id": "minecraft:prize_pottery_sherd" }, + { + "id": "minecraft:scrape_pottery_sherd" + }, { "id": "minecraft:sheaf_pottery_sherd" }, @@ -5632,6 +6034,12 @@ { "id": "minecraft:spire_armor_trim_smithing_template" }, + { + "id": "minecraft:flow_armor_trim_smithing_template" + }, + { + "id": "minecraft:bolt_armor_trim_smithing_template" + }, { "id": "minecraft:firework_rocket", "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" @@ -5784,11 +6192,11 @@ }, { "id": "minecraft:target", - "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAQAACAQAbmFtZRAAbWluZWNyYWZ0OnRhcmdldAQJAG5hbWVfaGFzaJc66SVbYlaxAwoAbmV0d29ya19pZPBozs0KBgBzdGF0ZXMAAwcAdmVyc2lvbgRGFAEA" + "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAQAACAQAbmFtZRAAbWluZWNyYWZ0OnRhcmdldAQJAG5hbWVfaGFzaJc66SVbYlaxAwoAbmV0d29ya19pZPBozs0KBgBzdGF0ZXMAAwcAdmVyc2lvbgMAFQEA" }, { "id": "minecraft:decorated_pot", - "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAwAACAQAbmFtZRcAbWluZWNyYWZ0OmRlY29yYXRlZF9wb3QECQBuYW1lX2hhc2jjQgckn8VTvwMKAG5ldHdvcmtfaWRwvkUUCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uBEYUAQA=" + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAwAACAQAbmFtZRcAbWluZWNyYWZ0OmRlY29yYXRlZF9wb3QECQBuYW1lX2hhc2jjQgckn8VTvwMKAG5ldHdvcmtfaWRwvkUUCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uAwAVAQA=" }, { "id": "minecraft:lodestone_compass" @@ -5798,6 +6206,9 @@ }, { "id": "minecraft:ender_dragon_spawn_egg" + }, + { + "id": "minecraft:ominous_trial_key" } ] } \ No newline at end of file diff --git a/core/src/main/resources/bedrock/entity_identifiers.dat b/core/src/main/resources/bedrock/entity_identifiers.dat index 9a123f8d8834e6af5c98b000778665b6e2022887..e7cdeb08e65d446bef173af7cea4bc56d5023df3 100644 GIT binary patch delta 204 zcmeCT`{lsP#lXpynUa%PT*B4BG})0+V)7Yo?u`b#lKSeonR%(nMTu!8R!K#vsa2`* z<(YXY@yQv9Md_*W1x5K;smUdoIjPLdMVTqHm?j$ts7?zsAI&p#=FT`rF%nYW<3waEAlk(HkQ&Yeq N3qT^mlTXXJ006xXMWO%z delta 39 vcmez6&~L}f#lXpynUa%PT*CE@ak3+$#N;#F+#3yeB{%Cx^|4MiQ*Z$Q^=b>+ diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_20_40.json b/core/src/main/resources/bedrock/runtime_item_states.1_20_40.json deleted file mode 100644 index 861b29c8a..000000000 --- a/core/src/main/resources/bedrock/runtime_item_states.1_20_40.json +++ /dev/null @@ -1,5570 +0,0 @@ -[ - { - "name": "minecraft:acacia_boat", - "id": 381 - }, - { - "name": "minecraft:acacia_button", - "id": -140 - }, - { - "name": "minecraft:acacia_chest_boat", - "id": 649 - }, - { - "name": "minecraft:acacia_door", - "id": 563 - }, - { - "name": "minecraft:acacia_fence", - "id": -575 - }, - { - "name": "minecraft:acacia_fence_gate", - "id": 187 - }, - { - "name": "minecraft:acacia_hanging_sign", - "id": -504 - }, - { - "name": "minecraft:acacia_log", - "id": 162 - }, - { - "name": "minecraft:acacia_pressure_plate", - "id": -150 - }, - { - "name": "minecraft:acacia_sign", - "id": 586 - }, - { - "name": "minecraft:acacia_stairs", - "id": 163 - }, - { - "name": "minecraft:acacia_standing_sign", - "id": -190 - }, - { - "name": "minecraft:acacia_trapdoor", - "id": -145 - }, - { - "name": "minecraft:acacia_wall_sign", - "id": -191 - }, - { - "name": "minecraft:activator_rail", - "id": 126 - }, - { - "name": "minecraft:agent_spawn_egg", - "id": 489 - }, - { - "name": "minecraft:air", - "id": -158 - }, - { - "name": "minecraft:allay_spawn_egg", - "id": 638 - }, - { - "name": "minecraft:allow", - "id": 210 - }, - { - "name": "minecraft:amethyst_block", - "id": -327 - }, - { - "name": "minecraft:amethyst_cluster", - "id": -329 - }, - { - "name": "minecraft:amethyst_shard", - "id": 631 - }, - { - "name": "minecraft:ancient_debris", - "id": -271 - }, - { - "name": "minecraft:andesite_stairs", - "id": -171 - }, - { - "name": "minecraft:angler_pottery_sherd", - "id": 663 - }, - { - "name": "minecraft:anvil", - "id": 145 - }, - { - "name": "minecraft:apple", - "id": 257 - }, - { - "name": "minecraft:archer_pottery_sherd", - "id": 664 - }, - { - "name": "minecraft:armor_stand", - "id": 559 - }, - { - "name": "minecraft:arms_up_pottery_sherd", - "id": 665 - }, - { - "name": "minecraft:arrow", - "id": 303 - }, - { - "name": "minecraft:axolotl_bucket", - "id": 371 - }, - { - "name": "minecraft:axolotl_spawn_egg", - "id": 503 - }, - { - "name": "minecraft:azalea", - "id": -337 - }, - { - "name": "minecraft:azalea_leaves", - "id": -324 - }, - { - "name": "minecraft:azalea_leaves_flowered", - "id": -325 - }, - { - "name": "minecraft:baked_potato", - "id": 281 - }, - { - "name": "minecraft:balloon", - "id": 605 - }, - { - "name": "minecraft:bamboo", - "id": -163 - }, - { - "name": "minecraft:bamboo_block", - "id": -527 - }, - { - "name": "minecraft:bamboo_button", - "id": -511 - }, - { - "name": "minecraft:bamboo_chest_raft", - "id": 661 - }, - { - "name": "minecraft:bamboo_door", - "id": -517 - }, - { - "name": "minecraft:bamboo_double_slab", - "id": -521 - }, - { - "name": "minecraft:bamboo_fence", - "id": -515 - }, - { - "name": "minecraft:bamboo_fence_gate", - "id": -516 - }, - { - "name": "minecraft:bamboo_hanging_sign", - "id": -522 - }, - { - "name": "minecraft:bamboo_mosaic", - "id": -509 - }, - { - "name": "minecraft:bamboo_mosaic_double_slab", - "id": -525 - }, - { - "name": "minecraft:bamboo_mosaic_slab", - "id": -524 - }, - { - "name": "minecraft:bamboo_mosaic_stairs", - "id": -523 - }, - { - "name": "minecraft:bamboo_planks", - "id": -510 - }, - { - "name": "minecraft:bamboo_pressure_plate", - "id": -514 - }, - { - "name": "minecraft:bamboo_raft", - "id": 660 - }, - { - "name": "minecraft:bamboo_sapling", - "id": -164 - }, - { - "name": "minecraft:bamboo_sign", - "id": 659 - }, - { - "name": "minecraft:bamboo_slab", - "id": -513 - }, - { - "name": "minecraft:bamboo_stairs", - "id": -512 - }, - { - "name": "minecraft:bamboo_standing_sign", - "id": -518 - }, - { - "name": "minecraft:bamboo_trapdoor", - "id": -520 - }, - { - "name": "minecraft:bamboo_wall_sign", - "id": -519 - }, - { - "name": "minecraft:banner", - "id": 574 - }, - { - "name": "minecraft:banner_pattern", - "id": 716 - }, - { - "name": "minecraft:barrel", - "id": -203 - }, - { - "name": "minecraft:barrier", - "id": -161 - }, - { - "name": "minecraft:basalt", - "id": -234 - }, - { - "name": "minecraft:bat_spawn_egg", - "id": 455 - }, - { - "name": "minecraft:beacon", - "id": 138 - }, - { - "name": "minecraft:bed", - "id": 420 - }, - { - "name": "minecraft:bedrock", - "id": 7 - }, - { - "name": "minecraft:bee_nest", - "id": -218 - }, - { - "name": "minecraft:bee_spawn_egg", - "id": 496 - }, - { - "name": "minecraft:beef", - "id": 273 - }, - { - "name": "minecraft:beehive", - "id": -219 - }, - { - "name": "minecraft:beetroot", - "id": 285 - }, - { - "name": "minecraft:beetroot_seeds", - "id": 295 - }, - { - "name": "minecraft:beetroot_soup", - "id": 286 - }, - { - "name": "minecraft:bell", - "id": -206 - }, - { - "name": "minecraft:big_dripleaf", - "id": -323 - }, - { - "name": "minecraft:birch_boat", - "id": 378 - }, - { - "name": "minecraft:birch_button", - "id": -141 - }, - { - "name": "minecraft:birch_chest_boat", - "id": 646 - }, - { - "name": "minecraft:birch_door", - "id": 561 - }, - { - "name": "minecraft:birch_fence", - "id": -576 - }, - { - "name": "minecraft:birch_fence_gate", - "id": 184 - }, - { - "name": "minecraft:birch_hanging_sign", - "id": -502 - }, - { - "name": "minecraft:birch_log", - "id": -570 - }, - { - "name": "minecraft:birch_pressure_plate", - "id": -151 - }, - { - "name": "minecraft:birch_sign", - "id": 584 - }, - { - "name": "minecraft:birch_stairs", - "id": 135 - }, - { - "name": "minecraft:birch_standing_sign", - "id": -186 - }, - { - "name": "minecraft:birch_trapdoor", - "id": -146 - }, - { - "name": "minecraft:birch_wall_sign", - "id": -187 - }, - { - "name": "minecraft:black_candle", - "id": -428 - }, - { - "name": "minecraft:black_candle_cake", - "id": -445 - }, - { - "name": "minecraft:black_carpet", - "id": -611 - }, - { - "name": "minecraft:black_concrete", - "id": -642 - }, - { - "name": "minecraft:black_concrete_powder", - "id": -723 - }, - { - "name": "minecraft:black_dye", - "id": 397 - }, - { - "name": "minecraft:black_glazed_terracotta", - "id": 235 - }, - { - "name": "minecraft:black_shulker_box", - "id": -627 - }, - { - "name": "minecraft:black_stained_glass", - "id": -687 - }, - { - "name": "minecraft:black_stained_glass_pane", - "id": -657 - }, - { - "name": "minecraft:black_terracotta", - "id": -738 - }, - { - "name": "minecraft:black_wool", - "id": -554 - }, - { - "name": "minecraft:blackstone", - "id": -273 - }, - { - "name": "minecraft:blackstone_double_slab", - "id": -283 - }, - { - "name": "minecraft:blackstone_slab", - "id": -282 - }, - { - "name": "minecraft:blackstone_stairs", - "id": -276 - }, - { - "name": "minecraft:blackstone_wall", - "id": -277 - }, - { - "name": "minecraft:blade_pottery_sherd", - "id": 666 - }, - { - "name": "minecraft:blast_furnace", - "id": -196 - }, - { - "name": "minecraft:blaze_powder", - "id": 431 - }, - { - "name": "minecraft:blaze_rod", - "id": 425 - }, - { - "name": "minecraft:blaze_spawn_egg", - "id": 458 - }, - { - "name": "minecraft:bleach", - "id": 603 - }, - { - "name": "minecraft:blue_candle", - "id": -424 - }, - { - "name": "minecraft:blue_candle_cake", - "id": -441 - }, - { - "name": "minecraft:blue_carpet", - "id": -607 - }, - { - "name": "minecraft:blue_concrete", - "id": -638 - }, - { - "name": "minecraft:blue_concrete_powder", - "id": -719 - }, - { - "name": "minecraft:blue_dye", - "id": 401 - }, - { - "name": "minecraft:blue_glazed_terracotta", - "id": 231 - }, - { - "name": "minecraft:blue_ice", - "id": -11 - }, - { - "name": "minecraft:blue_shulker_box", - "id": -623 - }, - { - "name": "minecraft:blue_stained_glass", - "id": -683 - }, - { - "name": "minecraft:blue_stained_glass_pane", - "id": -653 - }, - { - "name": "minecraft:blue_terracotta", - "id": -734 - }, - { - "name": "minecraft:blue_wool", - "id": -563 - }, - { - "name": "minecraft:boat", - "id": 714 - }, - { - "name": "minecraft:bone", - "id": 417 - }, - { - "name": "minecraft:bone_block", - "id": 216 - }, - { - "name": "minecraft:bone_meal", - "id": 413 - }, - { - "name": "minecraft:book", - "id": 389 - }, - { - "name": "minecraft:bookshelf", - "id": 47 - }, - { - "name": "minecraft:border_block", - "id": 212 - }, - { - "name": "minecraft:bordure_indented_banner_pattern", - "id": 593 - }, - { - "name": "minecraft:bow", - "id": 302 - }, - { - "name": "minecraft:bowl", - "id": 323 - }, - { - "name": "minecraft:brain_coral", - "id": -581 - }, - { - "name": "minecraft:bread", - "id": 261 - }, - { - "name": "minecraft:brewer_pottery_sherd", - "id": 667 - }, - { - "name": "minecraft:brewing_stand", - "id": 433 - }, - { - "name": "minecraft:brick", - "id": 385 - }, - { - "name": "minecraft:brick_block", - "id": 45 - }, - { - "name": "minecraft:brick_stairs", - "id": 108 - }, - { - "name": "minecraft:brown_candle", - "id": -425 - }, - { - "name": "minecraft:brown_candle_cake", - "id": -442 - }, - { - "name": "minecraft:brown_carpet", - "id": -608 - }, - { - "name": "minecraft:brown_concrete", - "id": -639 - }, - { - "name": "minecraft:brown_concrete_powder", - "id": -720 - }, - { - "name": "minecraft:brown_dye", - "id": 400 - }, - { - "name": "minecraft:brown_glazed_terracotta", - "id": 232 - }, - { - "name": "minecraft:brown_mushroom", - "id": 39 - }, - { - "name": "minecraft:brown_mushroom_block", - "id": 99 - }, - { - "name": "minecraft:brown_shulker_box", - "id": -624 - }, - { - "name": "minecraft:brown_stained_glass", - "id": -684 - }, - { - "name": "minecraft:brown_stained_glass_pane", - "id": -654 - }, - { - "name": "minecraft:brown_terracotta", - "id": -735 - }, - { - "name": "minecraft:brown_wool", - "id": -555 - }, - { - "name": "minecraft:brush", - "id": 683 - }, - { - "name": "minecraft:bubble_column", - "id": -160 - }, - { - "name": "minecraft:bubble_coral", - "id": -582 - }, - { - "name": "minecraft:bucket", - "id": 362 - }, - { - "name": "minecraft:budding_amethyst", - "id": -328 - }, - { - "name": "minecraft:burn_pottery_sherd", - "id": 668 - }, - { - "name": "minecraft:cactus", - "id": 81 - }, - { - "name": "minecraft:cake", - "id": 419 - }, - { - "name": "minecraft:calcite", - "id": -326 - }, - { - "name": "minecraft:calibrated_sculk_sensor", - "id": -580 - }, - { - "name": "minecraft:camel_spawn_egg", - "id": 662 - }, - { - "name": "minecraft:camera", - "id": 600 - }, - { - "name": "minecraft:campfire", - "id": 596 - }, - { - "name": "minecraft:candle", - "id": -412 - }, - { - "name": "minecraft:candle_cake", - "id": -429 - }, - { - "name": "minecraft:carpet", - "id": 704 - }, - { - "name": "minecraft:carrot", - "id": 279 - }, - { - "name": "minecraft:carrot_on_a_stick", - "id": 524 - }, - { - "name": "minecraft:carrots", - "id": 141 - }, - { - "name": "minecraft:cartography_table", - "id": -200 - }, - { - "name": "minecraft:carved_pumpkin", - "id": -155 - }, - { - "name": "minecraft:cat_spawn_egg", - "id": 490 - }, - { - "name": "minecraft:cauldron", - "id": 434 - }, - { - "name": "minecraft:cave_spider_spawn_egg", - "id": 459 - }, - { - "name": "minecraft:cave_vines", - "id": -322 - }, - { - "name": "minecraft:cave_vines_body_with_berries", - "id": -375 - }, - { - "name": "minecraft:cave_vines_head_with_berries", - "id": -376 - }, - { - "name": "minecraft:chain", - "id": 626 - }, - { - "name": "minecraft:chain_command_block", - "id": 189 - }, - { - "name": "minecraft:chainmail_boots", - "id": 344 - }, - { - "name": "minecraft:chainmail_chestplate", - "id": 342 - }, - { - "name": "minecraft:chainmail_helmet", - "id": 341 - }, - { - "name": "minecraft:chainmail_leggings", - "id": 343 - }, - { - "name": "minecraft:charcoal", - "id": 305 - }, - { - "name": "minecraft:chemical_heat", - "id": 192 - }, - { - "name": "minecraft:chemistry_table", - "id": 238 - }, - { - "name": "minecraft:cherry_boat", - "id": 656 - }, - { - "name": "minecraft:cherry_button", - "id": -530 - }, - { - "name": "minecraft:cherry_chest_boat", - "id": 657 - }, - { - "name": "minecraft:cherry_door", - "id": -531 - }, - { - "name": "minecraft:cherry_double_slab", - "id": -540 - }, - { - "name": "minecraft:cherry_fence", - "id": -532 - }, - { - "name": "minecraft:cherry_fence_gate", - "id": -533 - }, - { - "name": "minecraft:cherry_hanging_sign", - "id": -534 - }, - { - "name": "minecraft:cherry_leaves", - "id": -548 - }, - { - "name": "minecraft:cherry_log", - "id": -536 - }, - { - "name": "minecraft:cherry_planks", - "id": -537 - }, - { - "name": "minecraft:cherry_pressure_plate", - "id": -538 - }, - { - "name": "minecraft:cherry_sapling", - "id": -547 - }, - { - "name": "minecraft:cherry_sign", - "id": 658 - }, - { - "name": "minecraft:cherry_slab", - "id": -539 - }, - { - "name": "minecraft:cherry_stairs", - "id": -541 - }, - { - "name": "minecraft:cherry_standing_sign", - "id": -542 - }, - { - "name": "minecraft:cherry_trapdoor", - "id": -543 - }, - { - "name": "minecraft:cherry_wall_sign", - "id": -544 - }, - { - "name": "minecraft:cherry_wood", - "id": -546 - }, - { - "name": "minecraft:chest", - "id": 54 - }, - { - "name": "minecraft:chest_boat", - "id": 652 - }, - { - "name": "minecraft:chest_minecart", - "id": 391 - }, - { - "name": "minecraft:chicken", - "id": 275 - }, - { - "name": "minecraft:chicken_spawn_egg", - "id": 437 - }, - { - "name": "minecraft:chiseled_bookshelf", - "id": -526 - }, - { - "name": "minecraft:chiseled_deepslate", - "id": -395 - }, - { - "name": "minecraft:chiseled_nether_bricks", - "id": -302 - }, - { - "name": "minecraft:chiseled_polished_blackstone", - "id": -279 - }, - { - "name": "minecraft:chorus_flower", - "id": 200 - }, - { - "name": "minecraft:chorus_fruit", - "id": 565 - }, - { - "name": "minecraft:chorus_plant", - "id": 240 - }, - { - "name": "minecraft:clay", - "id": 82 - }, - { - "name": "minecraft:clay_ball", - "id": 386 - }, - { - "name": "minecraft:client_request_placeholder_block", - "id": -465 - }, - { - "name": "minecraft:clock", - "id": 395 - }, - { - "name": "minecraft:coal", - "id": 304 - }, - { - "name": "minecraft:coal_block", - "id": 173 - }, - { - "name": "minecraft:coal_ore", - "id": 16 - }, - { - "name": "minecraft:coast_armor_trim_smithing_template", - "id": 687 - }, - { - "name": "minecraft:cobbled_deepslate", - "id": -379 - }, - { - "name": "minecraft:cobbled_deepslate_double_slab", - "id": -396 - }, - { - "name": "minecraft:cobbled_deepslate_slab", - "id": -380 - }, - { - "name": "minecraft:cobbled_deepslate_stairs", - "id": -381 - }, - { - "name": "minecraft:cobbled_deepslate_wall", - "id": -382 - }, - { - "name": "minecraft:cobblestone", - "id": 4 - }, - { - "name": "minecraft:cobblestone_wall", - "id": 139 - }, - { - "name": "minecraft:cocoa", - "id": 127 - }, - { - "name": "minecraft:cocoa_beans", - "id": 414 - }, - { - "name": "minecraft:cod", - "id": 264 - }, - { - "name": "minecraft:cod_bucket", - "id": 366 - }, - { - "name": "minecraft:cod_spawn_egg", - "id": 482 - }, - { - "name": "minecraft:colored_torch_bp", - "id": 204 - }, - { - "name": "minecraft:colored_torch_rg", - "id": 202 - }, - { - "name": "minecraft:command_block", - "id": 137 - }, - { - "name": "minecraft:command_block_minecart", - "id": 570 - }, - { - "name": "minecraft:comparator", - "id": 529 - }, - { - "name": "minecraft:compass", - "id": 393 - }, - { - "name": "minecraft:composter", - "id": -213 - }, - { - "name": "minecraft:compound", - "id": 601 - }, - { - "name": "minecraft:concrete", - "id": 709 - }, - { - "name": "minecraft:concrete_powder", - "id": 710 - }, - { - "name": "minecraft:conduit", - "id": -157 - }, - { - "name": "minecraft:cooked_beef", - "id": 274 - }, - { - "name": "minecraft:cooked_chicken", - "id": 276 - }, - { - "name": "minecraft:cooked_cod", - "id": 268 - }, - { - "name": "minecraft:cooked_mutton", - "id": 558 - }, - { - "name": "minecraft:cooked_porkchop", - "id": 263 - }, - { - "name": "minecraft:cooked_rabbit", - "id": 289 - }, - { - "name": "minecraft:cooked_salmon", - "id": 269 - }, - { - "name": "minecraft:cookie", - "id": 271 - }, - { - "name": "minecraft:copper_block", - "id": -340 - }, - { - "name": "minecraft:copper_ingot", - "id": 511 - }, - { - "name": "minecraft:copper_ore", - "id": -311 - }, - { - "name": "minecraft:coral", - "id": 707 - }, - { - "name": "minecraft:coral_block", - "id": -132 - }, - { - "name": "minecraft:coral_fan", - "id": -133 - }, - { - "name": "minecraft:coral_fan_dead", - "id": -134 - }, - { - "name": "minecraft:coral_fan_hang", - "id": -135 - }, - { - "name": "minecraft:coral_fan_hang2", - "id": -136 - }, - { - "name": "minecraft:coral_fan_hang3", - "id": -137 - }, - { - "name": "minecraft:cow_spawn_egg", - "id": 438 - }, - { - "name": "minecraft:cracked_deepslate_bricks", - "id": -410 - }, - { - "name": "minecraft:cracked_deepslate_tiles", - "id": -409 - }, - { - "name": "minecraft:cracked_nether_bricks", - "id": -303 - }, - { - "name": "minecraft:cracked_polished_blackstone_bricks", - "id": -280 - }, - { - "name": "minecraft:crafting_table", - "id": 58 - }, - { - "name": "minecraft:creeper_banner_pattern", - "id": 589 - }, - { - "name": "minecraft:creeper_spawn_egg", - "id": 443 - }, - { - "name": "minecraft:crimson_button", - "id": -260 - }, - { - "name": "minecraft:crimson_door", - "id": 623 - }, - { - "name": "minecraft:crimson_double_slab", - "id": -266 - }, - { - "name": "minecraft:crimson_fence", - "id": -256 - }, - { - "name": "minecraft:crimson_fence_gate", - "id": -258 - }, - { - "name": "minecraft:crimson_fungus", - "id": -228 - }, - { - "name": "minecraft:crimson_hanging_sign", - "id": -506 - }, - { - "name": "minecraft:crimson_hyphae", - "id": -299 - }, - { - "name": "minecraft:crimson_nylium", - "id": -232 - }, - { - "name": "minecraft:crimson_planks", - "id": -242 - }, - { - "name": "minecraft:crimson_pressure_plate", - "id": -262 - }, - { - "name": "minecraft:crimson_roots", - "id": -223 - }, - { - "name": "minecraft:crimson_sign", - "id": 621 - }, - { - "name": "minecraft:crimson_slab", - "id": -264 - }, - { - "name": "minecraft:crimson_stairs", - "id": -254 - }, - { - "name": "minecraft:crimson_standing_sign", - "id": -250 - }, - { - "name": "minecraft:crimson_stem", - "id": -225 - }, - { - "name": "minecraft:crimson_trapdoor", - "id": -246 - }, - { - "name": "minecraft:crimson_wall_sign", - "id": -252 - }, - { - "name": "minecraft:crossbow", - "id": 582 - }, - { - "name": "minecraft:crying_obsidian", - "id": -289 - }, - { - "name": "minecraft:cut_copper", - "id": -347 - }, - { - "name": "minecraft:cut_copper_slab", - "id": -361 - }, - { - "name": "minecraft:cut_copper_stairs", - "id": -354 - }, - { - "name": "minecraft:cyan_candle", - "id": -422 - }, - { - "name": "minecraft:cyan_candle_cake", - "id": -439 - }, - { - "name": "minecraft:cyan_carpet", - "id": -605 - }, - { - "name": "minecraft:cyan_concrete", - "id": -636 - }, - { - "name": "minecraft:cyan_concrete_powder", - "id": -717 - }, - { - "name": "minecraft:cyan_dye", - "id": 403 - }, - { - "name": "minecraft:cyan_glazed_terracotta", - "id": 229 - }, - { - "name": "minecraft:cyan_shulker_box", - "id": -621 - }, - { - "name": "minecraft:cyan_stained_glass", - "id": -681 - }, - { - "name": "minecraft:cyan_stained_glass_pane", - "id": -651 - }, - { - "name": "minecraft:cyan_terracotta", - "id": -732 - }, - { - "name": "minecraft:cyan_wool", - "id": -561 - }, - { - "name": "minecraft:danger_pottery_sherd", - "id": 669 - }, - { - "name": "minecraft:dark_oak_boat", - "id": 382 - }, - { - "name": "minecraft:dark_oak_button", - "id": -142 - }, - { - "name": "minecraft:dark_oak_chest_boat", - "id": 650 - }, - { - "name": "minecraft:dark_oak_door", - "id": 564 - }, - { - "name": "minecraft:dark_oak_fence", - "id": -577 - }, - { - "name": "minecraft:dark_oak_fence_gate", - "id": 186 - }, - { - "name": "minecraft:dark_oak_hanging_sign", - "id": -505 - }, - { - "name": "minecraft:dark_oak_log", - "id": -572 - }, - { - "name": "minecraft:dark_oak_pressure_plate", - "id": -152 - }, - { - "name": "minecraft:dark_oak_sign", - "id": 587 - }, - { - "name": "minecraft:dark_oak_stairs", - "id": 164 - }, - { - "name": "minecraft:dark_oak_trapdoor", - "id": -147 - }, - { - "name": "minecraft:dark_prismarine_stairs", - "id": -3 - }, - { - "name": "minecraft:darkoak_standing_sign", - "id": -192 - }, - { - "name": "minecraft:darkoak_wall_sign", - "id": -193 - }, - { - "name": "minecraft:daylight_detector", - "id": 151 - }, - { - "name": "minecraft:daylight_detector_inverted", - "id": 178 - }, - { - "name": "minecraft:dead_brain_coral", - "id": -586 - }, - { - "name": "minecraft:dead_bubble_coral", - "id": -587 - }, - { - "name": "minecraft:dead_fire_coral", - "id": -588 - }, - { - "name": "minecraft:dead_horn_coral", - "id": -589 - }, - { - "name": "minecraft:dead_tube_coral", - "id": -585 - }, - { - "name": "minecraft:deadbush", - "id": 32 - }, - { - "name": "minecraft:decorated_pot", - "id": -551 - }, - { - "name": "minecraft:deepslate", - "id": -378 - }, - { - "name": "minecraft:deepslate_brick_double_slab", - "id": -399 - }, - { - "name": "minecraft:deepslate_brick_slab", - "id": -392 - }, - { - "name": "minecraft:deepslate_brick_stairs", - "id": -393 - }, - { - "name": "minecraft:deepslate_brick_wall", - "id": -394 - }, - { - "name": "minecraft:deepslate_bricks", - "id": -391 - }, - { - "name": "minecraft:deepslate_coal_ore", - "id": -406 - }, - { - "name": "minecraft:deepslate_copper_ore", - "id": -408 - }, - { - "name": "minecraft:deepslate_diamond_ore", - "id": -405 - }, - { - "name": "minecraft:deepslate_emerald_ore", - "id": -407 - }, - { - "name": "minecraft:deepslate_gold_ore", - "id": -402 - }, - { - "name": "minecraft:deepslate_iron_ore", - "id": -401 - }, - { - "name": "minecraft:deepslate_lapis_ore", - "id": -400 - }, - { - "name": "minecraft:deepslate_redstone_ore", - "id": -403 - }, - { - "name": "minecraft:deepslate_tile_double_slab", - "id": -398 - }, - { - "name": "minecraft:deepslate_tile_slab", - "id": -388 - }, - { - "name": "minecraft:deepslate_tile_stairs", - "id": -389 - }, - { - "name": "minecraft:deepslate_tile_wall", - "id": -390 - }, - { - "name": "minecraft:deepslate_tiles", - "id": -387 - }, - { - "name": "minecraft:deny", - "id": 211 - }, - { - "name": "minecraft:detector_rail", - "id": 28 - }, - { - "name": "minecraft:diamond", - "id": 306 - }, - { - "name": "minecraft:diamond_axe", - "id": 321 - }, - { - "name": "minecraft:diamond_block", - "id": 57 - }, - { - "name": "minecraft:diamond_boots", - "id": 352 - }, - { - "name": "minecraft:diamond_chestplate", - "id": 350 - }, - { - "name": "minecraft:diamond_helmet", - "id": 349 - }, - { - "name": "minecraft:diamond_hoe", - "id": 334 - }, - { - "name": "minecraft:diamond_horse_armor", - "id": 540 - }, - { - "name": "minecraft:diamond_leggings", - "id": 351 - }, - { - "name": "minecraft:diamond_ore", - "id": 56 - }, - { - "name": "minecraft:diamond_pickaxe", - "id": 320 - }, - { - "name": "minecraft:diamond_shovel", - "id": 319 - }, - { - "name": "minecraft:diamond_sword", - "id": 318 - }, - { - "name": "minecraft:diorite_stairs", - "id": -170 - }, - { - "name": "minecraft:dirt", - "id": 3 - }, - { - "name": "minecraft:dirt_with_roots", - "id": -318 - }, - { - "name": "minecraft:disc_fragment_5", - "id": 644 - }, - { - "name": "minecraft:dispenser", - "id": 23 - }, - { - "name": "minecraft:dolphin_spawn_egg", - "id": 486 - }, - { - "name": "minecraft:donkey_spawn_egg", - "id": 467 - }, - { - "name": "minecraft:double_cut_copper_slab", - "id": -368 - }, - { - "name": "minecraft:double_plant", - "id": 175 - }, - { - "name": "minecraft:double_stone_block_slab", - "id": 43 - }, - { - "name": "minecraft:double_stone_block_slab2", - "id": 181 - }, - { - "name": "minecraft:double_stone_block_slab3", - "id": -167 - }, - { - "name": "minecraft:double_stone_block_slab4", - "id": -168 - }, - { - "name": "minecraft:double_wooden_slab", - "id": 157 - }, - { - "name": "minecraft:dragon_breath", - "id": 567 - }, - { - "name": "minecraft:dragon_egg", - "id": 122 - }, - { - "name": "minecraft:dried_kelp", - "id": 270 - }, - { - "name": "minecraft:dried_kelp_block", - "id": -139 - }, - { - "name": "minecraft:dripstone_block", - "id": -317 - }, - { - "name": "minecraft:dropper", - "id": 125 - }, - { - "name": "minecraft:drowned_spawn_egg", - "id": 485 - }, - { - "name": "minecraft:dune_armor_trim_smithing_template", - "id": 686 - }, - { - "name": "minecraft:dye", - "id": 715 - }, - { - "name": "minecraft:echo_shard", - "id": 654 - }, - { - "name": "minecraft:egg", - "id": 392 - }, - { - "name": "minecraft:elder_guardian_spawn_egg", - "id": 473 - }, - { - "name": "minecraft:element_0", - "id": 36 - }, - { - "name": "minecraft:element_1", - "id": -12 - }, - { - "name": "minecraft:element_10", - "id": -21 - }, - { - "name": "minecraft:element_100", - "id": -111 - }, - { - "name": "minecraft:element_101", - "id": -112 - }, - { - "name": "minecraft:element_102", - "id": -113 - }, - { - "name": "minecraft:element_103", - "id": -114 - }, - { - "name": "minecraft:element_104", - "id": -115 - }, - { - "name": "minecraft:element_105", - "id": -116 - }, - { - "name": "minecraft:element_106", - "id": -117 - }, - { - "name": "minecraft:element_107", - "id": -118 - }, - { - "name": "minecraft:element_108", - "id": -119 - }, - { - "name": "minecraft:element_109", - "id": -120 - }, - { - "name": "minecraft:element_11", - "id": -22 - }, - { - "name": "minecraft:element_110", - "id": -121 - }, - { - "name": "minecraft:element_111", - "id": -122 - }, - { - "name": "minecraft:element_112", - "id": -123 - }, - { - "name": "minecraft:element_113", - "id": -124 - }, - { - "name": "minecraft:element_114", - "id": -125 - }, - { - "name": "minecraft:element_115", - "id": -126 - }, - { - "name": "minecraft:element_116", - "id": -127 - }, - { - "name": "minecraft:element_117", - "id": -128 - }, - { - "name": "minecraft:element_118", - "id": -129 - }, - { - "name": "minecraft:element_12", - "id": -23 - }, - { - "name": "minecraft:element_13", - "id": -24 - }, - { - "name": "minecraft:element_14", - "id": -25 - }, - { - "name": "minecraft:element_15", - "id": -26 - }, - { - "name": "minecraft:element_16", - "id": -27 - }, - { - "name": "minecraft:element_17", - "id": -28 - }, - { - "name": "minecraft:element_18", - "id": -29 - }, - { - "name": "minecraft:element_19", - "id": -30 - }, - { - "name": "minecraft:element_2", - "id": -13 - }, - { - "name": "minecraft:element_20", - "id": -31 - }, - { - "name": "minecraft:element_21", - "id": -32 - }, - { - "name": "minecraft:element_22", - "id": -33 - }, - { - "name": "minecraft:element_23", - "id": -34 - }, - { - "name": "minecraft:element_24", - "id": -35 - }, - { - "name": "minecraft:element_25", - "id": -36 - }, - { - "name": "minecraft:element_26", - "id": -37 - }, - { - "name": "minecraft:element_27", - "id": -38 - }, - { - "name": "minecraft:element_28", - "id": -39 - }, - { - "name": "minecraft:element_29", - "id": -40 - }, - { - "name": "minecraft:element_3", - "id": -14 - }, - { - "name": "minecraft:element_30", - "id": -41 - }, - { - "name": "minecraft:element_31", - "id": -42 - }, - { - "name": "minecraft:element_32", - "id": -43 - }, - { - "name": "minecraft:element_33", - "id": -44 - }, - { - "name": "minecraft:element_34", - "id": -45 - }, - { - "name": "minecraft:element_35", - "id": -46 - }, - { - "name": "minecraft:element_36", - "id": -47 - }, - { - "name": "minecraft:element_37", - "id": -48 - }, - { - "name": "minecraft:element_38", - "id": -49 - }, - { - "name": "minecraft:element_39", - "id": -50 - }, - { - "name": "minecraft:element_4", - "id": -15 - }, - { - "name": "minecraft:element_40", - "id": -51 - }, - { - "name": "minecraft:element_41", - "id": -52 - }, - { - "name": "minecraft:element_42", - "id": -53 - }, - { - "name": "minecraft:element_43", - "id": -54 - }, - { - "name": "minecraft:element_44", - "id": -55 - }, - { - "name": "minecraft:element_45", - "id": -56 - }, - { - "name": "minecraft:element_46", - "id": -57 - }, - { - "name": "minecraft:element_47", - "id": -58 - }, - { - "name": "minecraft:element_48", - "id": -59 - }, - { - "name": "minecraft:element_49", - "id": -60 - }, - { - "name": "minecraft:element_5", - "id": -16 - }, - { - "name": "minecraft:element_50", - "id": -61 - }, - { - "name": "minecraft:element_51", - "id": -62 - }, - { - "name": "minecraft:element_52", - "id": -63 - }, - { - "name": "minecraft:element_53", - "id": -64 - }, - { - "name": "minecraft:element_54", - "id": -65 - }, - { - "name": "minecraft:element_55", - "id": -66 - }, - { - "name": "minecraft:element_56", - "id": -67 - }, - { - "name": "minecraft:element_57", - "id": -68 - }, - { - "name": "minecraft:element_58", - "id": -69 - }, - { - "name": "minecraft:element_59", - "id": -70 - }, - { - "name": "minecraft:element_6", - "id": -17 - }, - { - "name": "minecraft:element_60", - "id": -71 - }, - { - "name": "minecraft:element_61", - "id": -72 - }, - { - "name": "minecraft:element_62", - "id": -73 - }, - { - "name": "minecraft:element_63", - "id": -74 - }, - { - "name": "minecraft:element_64", - "id": -75 - }, - { - "name": "minecraft:element_65", - "id": -76 - }, - { - "name": "minecraft:element_66", - "id": -77 - }, - { - "name": "minecraft:element_67", - "id": -78 - }, - { - "name": "minecraft:element_68", - "id": -79 - }, - { - "name": "minecraft:element_69", - "id": -80 - }, - { - "name": "minecraft:element_7", - "id": -18 - }, - { - "name": "minecraft:element_70", - "id": -81 - }, - { - "name": "minecraft:element_71", - "id": -82 - }, - { - "name": "minecraft:element_72", - "id": -83 - }, - { - "name": "minecraft:element_73", - "id": -84 - }, - { - "name": "minecraft:element_74", - "id": -85 - }, - { - "name": "minecraft:element_75", - "id": -86 - }, - { - "name": "minecraft:element_76", - "id": -87 - }, - { - "name": "minecraft:element_77", - "id": -88 - }, - { - "name": "minecraft:element_78", - "id": -89 - }, - { - "name": "minecraft:element_79", - "id": -90 - }, - { - "name": "minecraft:element_8", - "id": -19 - }, - { - "name": "minecraft:element_80", - "id": -91 - }, - { - "name": "minecraft:element_81", - "id": -92 - }, - { - "name": "minecraft:element_82", - "id": -93 - }, - { - "name": "minecraft:element_83", - "id": -94 - }, - { - "name": "minecraft:element_84", - "id": -95 - }, - { - "name": "minecraft:element_85", - "id": -96 - }, - { - "name": "minecraft:element_86", - "id": -97 - }, - { - "name": "minecraft:element_87", - "id": -98 - }, - { - "name": "minecraft:element_88", - "id": -99 - }, - { - "name": "minecraft:element_89", - "id": -100 - }, - { - "name": "minecraft:element_9", - "id": -20 - }, - { - "name": "minecraft:element_90", - "id": -101 - }, - { - "name": "minecraft:element_91", - "id": -102 - }, - { - "name": "minecraft:element_92", - "id": -103 - }, - { - "name": "minecraft:element_93", - "id": -104 - }, - { - "name": "minecraft:element_94", - "id": -105 - }, - { - "name": "minecraft:element_95", - "id": -106 - }, - { - "name": "minecraft:element_96", - "id": -107 - }, - { - "name": "minecraft:element_97", - "id": -108 - }, - { - "name": "minecraft:element_98", - "id": -109 - }, - { - "name": "minecraft:element_99", - "id": -110 - }, - { - "name": "minecraft:elytra", - "id": 571 - }, - { - "name": "minecraft:emerald", - "id": 519 - }, - { - "name": "minecraft:emerald_block", - "id": 133 - }, - { - "name": "minecraft:emerald_ore", - "id": 129 - }, - { - "name": "minecraft:empty_map", - "id": 522 - }, - { - "name": "minecraft:enchanted_book", - "id": 528 - }, - { - "name": "minecraft:enchanted_golden_apple", - "id": 259 - }, - { - "name": "minecraft:enchanting_table", - "id": 116 - }, - { - "name": "minecraft:end_brick_stairs", - "id": -178 - }, - { - "name": "minecraft:end_bricks", - "id": 206 - }, - { - "name": "minecraft:end_crystal", - "id": 718 - }, - { - "name": "minecraft:end_gateway", - "id": 209 - }, - { - "name": "minecraft:end_portal", - "id": 119 - }, - { - "name": "minecraft:end_portal_frame", - "id": 120 - }, - { - "name": "minecraft:end_rod", - "id": 208 - }, - { - "name": "minecraft:end_stone", - "id": 121 - }, - { - "name": "minecraft:ender_chest", - "id": 130 - }, - { - "name": "minecraft:ender_dragon_spawn_egg", - "id": 508 - }, - { - "name": "minecraft:ender_eye", - "id": 435 - }, - { - "name": "minecraft:ender_pearl", - "id": 424 - }, - { - "name": "minecraft:enderman_spawn_egg", - "id": 444 - }, - { - "name": "minecraft:endermite_spawn_egg", - "id": 462 - }, - { - "name": "minecraft:evoker_spawn_egg", - "id": 477 - }, - { - "name": "minecraft:experience_bottle", - "id": 515 - }, - { - "name": "minecraft:explorer_pottery_sherd", - "id": 670 - }, - { - "name": "minecraft:exposed_copper", - "id": -341 - }, - { - "name": "minecraft:exposed_cut_copper", - "id": -348 - }, - { - "name": "minecraft:exposed_cut_copper_slab", - "id": -362 - }, - { - "name": "minecraft:exposed_cut_copper_stairs", - "id": -355 - }, - { - "name": "minecraft:exposed_double_cut_copper_slab", - "id": -369 - }, - { - "name": "minecraft:eye_armor_trim_smithing_template", - "id": 690 - }, - { - "name": "minecraft:farmland", - "id": 60 - }, - { - "name": "minecraft:feather", - "id": 329 - }, - { - "name": "minecraft:fence", - "id": 706 - }, - { - "name": "minecraft:fence_gate", - "id": 107 - }, - { - "name": "minecraft:fermented_spider_eye", - "id": 430 - }, - { - "name": "minecraft:field_masoned_banner_pattern", - "id": 592 - }, - { - "name": "minecraft:filled_map", - "id": 422 - }, - { - "name": "minecraft:fire", - "id": 51 - }, - { - "name": "minecraft:fire_charge", - "id": 516 - }, - { - "name": "minecraft:fire_coral", - "id": -583 - }, - { - "name": "minecraft:firework_rocket", - "id": 526 - }, - { - "name": "minecraft:firework_star", - "id": 527 - }, - { - "name": "minecraft:fishing_rod", - "id": 394 - }, - { - "name": "minecraft:fletching_table", - "id": -201 - }, - { - "name": "minecraft:flint", - "id": 358 - }, - { - "name": "minecraft:flint_and_steel", - "id": 301 - }, - { - "name": "minecraft:flower_banner_pattern", - "id": 588 - }, - { - "name": "minecraft:flower_pot", - "id": 521 - }, - { - "name": "minecraft:flowering_azalea", - "id": -338 - }, - { - "name": "minecraft:flowing_lava", - "id": 10 - }, - { - "name": "minecraft:flowing_water", - "id": 8 - }, - { - "name": "minecraft:fox_spawn_egg", - "id": 492 - }, - { - "name": "minecraft:frame", - "id": 520 - }, - { - "name": "minecraft:friend_pottery_sherd", - "id": 671 - }, - { - "name": "minecraft:frog_spawn", - "id": -468 - }, - { - "name": "minecraft:frog_spawn_egg", - "id": 635 - }, - { - "name": "minecraft:frosted_ice", - "id": 207 - }, - { - "name": "minecraft:furnace", - "id": 61 - }, - { - "name": "minecraft:ghast_spawn_egg", - "id": 456 - }, - { - "name": "minecraft:ghast_tear", - "id": 426 - }, - { - "name": "minecraft:gilded_blackstone", - "id": -281 - }, - { - "name": "minecraft:glass", - "id": 20 - }, - { - "name": "minecraft:glass_bottle", - "id": 429 - }, - { - "name": "minecraft:glass_pane", - "id": 102 - }, - { - "name": "minecraft:glistering_melon_slice", - "id": 436 - }, - { - "name": "minecraft:globe_banner_pattern", - "id": 595 - }, - { - "name": "minecraft:glow_berries", - "id": 719 - }, - { - "name": "minecraft:glow_frame", - "id": 630 - }, - { - "name": "minecraft:glow_ink_sac", - "id": 510 - }, - { - "name": "minecraft:glow_lichen", - "id": -411 - }, - { - "name": "minecraft:glow_squid_spawn_egg", - "id": 505 - }, - { - "name": "minecraft:glow_stick", - "id": 608 - }, - { - "name": "minecraft:glowingobsidian", - "id": 246 - }, - { - "name": "minecraft:glowstone", - "id": 89 - }, - { - "name": "minecraft:glowstone_dust", - "id": 396 - }, - { - "name": "minecraft:goat_horn", - "id": 634 - }, - { - "name": "minecraft:goat_spawn_egg", - "id": 504 - }, - { - "name": "minecraft:gold_block", - "id": 41 - }, - { - "name": "minecraft:gold_ingot", - "id": 308 - }, - { - "name": "minecraft:gold_nugget", - "id": 427 - }, - { - "name": "minecraft:gold_ore", - "id": 14 - }, - { - "name": "minecraft:golden_apple", - "id": 258 - }, - { - "name": "minecraft:golden_axe", - "id": 327 - }, - { - "name": "minecraft:golden_boots", - "id": 356 - }, - { - "name": "minecraft:golden_carrot", - "id": 283 - }, - { - "name": "minecraft:golden_chestplate", - "id": 354 - }, - { - "name": "minecraft:golden_helmet", - "id": 353 - }, - { - "name": "minecraft:golden_hoe", - "id": 335 - }, - { - "name": "minecraft:golden_horse_armor", - "id": 539 - }, - { - "name": "minecraft:golden_leggings", - "id": 355 - }, - { - "name": "minecraft:golden_pickaxe", - "id": 326 - }, - { - "name": "minecraft:golden_rail", - "id": 27 - }, - { - "name": "minecraft:golden_shovel", - "id": 325 - }, - { - "name": "minecraft:golden_sword", - "id": 324 - }, - { - "name": "minecraft:granite_stairs", - "id": -169 - }, - { - "name": "minecraft:grass", - "id": 2 - }, - { - "name": "minecraft:grass_path", - "id": 198 - }, - { - "name": "minecraft:gravel", - "id": 13 - }, - { - "name": "minecraft:gray_candle", - "id": -420 - }, - { - "name": "minecraft:gray_candle_cake", - "id": -437 - }, - { - "name": "minecraft:gray_carpet", - "id": -603 - }, - { - "name": "minecraft:gray_concrete", - "id": -634 - }, - { - "name": "minecraft:gray_concrete_powder", - "id": -715 - }, - { - "name": "minecraft:gray_dye", - "id": 405 - }, - { - "name": "minecraft:gray_glazed_terracotta", - "id": 227 - }, - { - "name": "minecraft:gray_shulker_box", - "id": -619 - }, - { - "name": "minecraft:gray_stained_glass", - "id": -679 - }, - { - "name": "minecraft:gray_stained_glass_pane", - "id": -649 - }, - { - "name": "minecraft:gray_terracotta", - "id": -730 - }, - { - "name": "minecraft:gray_wool", - "id": -553 - }, - { - "name": "minecraft:green_candle", - "id": -426 - }, - { - "name": "minecraft:green_candle_cake", - "id": -443 - }, - { - "name": "minecraft:green_carpet", - "id": -609 - }, - { - "name": "minecraft:green_concrete", - "id": -640 - }, - { - "name": "minecraft:green_concrete_powder", - "id": -721 - }, - { - "name": "minecraft:green_dye", - "id": 399 - }, - { - "name": "minecraft:green_glazed_terracotta", - "id": 233 - }, - { - "name": "minecraft:green_shulker_box", - "id": -625 - }, - { - "name": "minecraft:green_stained_glass", - "id": -685 - }, - { - "name": "minecraft:green_stained_glass_pane", - "id": -655 - }, - { - "name": "minecraft:green_terracotta", - "id": -736 - }, - { - "name": "minecraft:green_wool", - "id": -560 - }, - { - "name": "minecraft:grindstone", - "id": -195 - }, - { - "name": "minecraft:guardian_spawn_egg", - "id": 463 - }, - { - "name": "minecraft:gunpowder", - "id": 330 - }, - { - "name": "minecraft:hanging_roots", - "id": -319 - }, - { - "name": "minecraft:hard_glass", - "id": 253 - }, - { - "name": "minecraft:hard_glass_pane", - "id": 190 - }, - { - "name": "minecraft:hard_stained_glass", - "id": 254 - }, - { - "name": "minecraft:hard_stained_glass_pane", - "id": 191 - }, - { - "name": "minecraft:hardened_clay", - "id": 172 - }, - { - "name": "minecraft:hay_block", - "id": 170 - }, - { - "name": "minecraft:heart_of_the_sea", - "id": 578 - }, - { - "name": "minecraft:heart_pottery_sherd", - "id": 672 - }, - { - "name": "minecraft:heartbreak_pottery_sherd", - "id": 673 - }, - { - "name": "minecraft:heavy_weighted_pressure_plate", - "id": 148 - }, - { - "name": "minecraft:hoglin_spawn_egg", - "id": 498 - }, - { - "name": "minecraft:honey_block", - "id": -220 - }, - { - "name": "minecraft:honey_bottle", - "id": 599 - }, - { - "name": "minecraft:honeycomb", - "id": 598 - }, - { - "name": "minecraft:honeycomb_block", - "id": -221 - }, - { - "name": "minecraft:hopper", - "id": 534 - }, - { - "name": "minecraft:hopper_minecart", - "id": 533 - }, - { - "name": "minecraft:horn_coral", - "id": -584 - }, - { - "name": "minecraft:horse_spawn_egg", - "id": 460 - }, - { - "name": "minecraft:host_armor_trim_smithing_template", - "id": 700 - }, - { - "name": "minecraft:howl_pottery_sherd", - "id": 674 - }, - { - "name": "minecraft:husk_spawn_egg", - "id": 465 - }, - { - "name": "minecraft:ice", - "id": 79 - }, - { - "name": "minecraft:ice_bomb", - "id": 602 - }, - { - "name": "minecraft:infested_deepslate", - "id": -454 - }, - { - "name": "minecraft:info_update", - "id": 248 - }, - { - "name": "minecraft:info_update2", - "id": 249 - }, - { - "name": "minecraft:ink_sac", - "id": 415 - }, - { - "name": "minecraft:invisible_bedrock", - "id": 95 - }, - { - "name": "minecraft:iron_axe", - "id": 300 - }, - { - "name": "minecraft:iron_bars", - "id": 101 - }, - { - "name": "minecraft:iron_block", - "id": 42 - }, - { - "name": "minecraft:iron_boots", - "id": 348 - }, - { - "name": "minecraft:iron_chestplate", - "id": 346 - }, - { - "name": "minecraft:iron_door", - "id": 374 - }, - { - "name": "minecraft:iron_golem_spawn_egg", - "id": 506 - }, - { - "name": "minecraft:iron_helmet", - "id": 345 - }, - { - "name": "minecraft:iron_hoe", - "id": 333 - }, - { - "name": "minecraft:iron_horse_armor", - "id": 538 - }, - { - "name": "minecraft:iron_ingot", - "id": 307 - }, - { - "name": "minecraft:iron_leggings", - "id": 347 - }, - { - "name": "minecraft:iron_nugget", - "id": 576 - }, - { - "name": "minecraft:iron_ore", - "id": 15 - }, - { - "name": "minecraft:iron_pickaxe", - "id": 299 - }, - { - "name": "minecraft:iron_shovel", - "id": 298 - }, - { - "name": "minecraft:iron_sword", - "id": 309 - }, - { - "name": "minecraft:iron_trapdoor", - "id": 167 - }, - { - "name": "minecraft:item.acacia_door", - "id": 196 - }, - { - "name": "minecraft:item.bed", - "id": 26 - }, - { - "name": "minecraft:item.beetroot", - "id": 244 - }, - { - "name": "minecraft:item.birch_door", - "id": 194 - }, - { - "name": "minecraft:item.brewing_stand", - "id": 117 - }, - { - "name": "minecraft:item.cake", - "id": 92 - }, - { - "name": "minecraft:item.camera", - "id": 242 - }, - { - "name": "minecraft:item.campfire", - "id": -209 - }, - { - "name": "minecraft:item.cauldron", - "id": 118 - }, - { - "name": "minecraft:item.chain", - "id": -286 - }, - { - "name": "minecraft:item.crimson_door", - "id": -244 - }, - { - "name": "minecraft:item.dark_oak_door", - "id": 197 - }, - { - "name": "minecraft:item.flower_pot", - "id": 140 - }, - { - "name": "minecraft:item.frame", - "id": 199 - }, - { - "name": "minecraft:item.glow_frame", - "id": -339 - }, - { - "name": "minecraft:item.hopper", - "id": 154 - }, - { - "name": "minecraft:item.iron_door", - "id": 71 - }, - { - "name": "minecraft:item.jungle_door", - "id": 195 - }, - { - "name": "minecraft:item.kelp", - "id": -138 - }, - { - "name": "minecraft:item.mangrove_door", - "id": -493 - }, - { - "name": "minecraft:item.nether_sprouts", - "id": -238 - }, - { - "name": "minecraft:item.nether_wart", - "id": 115 - }, - { - "name": "minecraft:item.reeds", - "id": 83 - }, - { - "name": "minecraft:item.skull", - "id": 144 - }, - { - "name": "minecraft:item.soul_campfire", - "id": -290 - }, - { - "name": "minecraft:item.spruce_door", - "id": 193 - }, - { - "name": "minecraft:item.warped_door", - "id": -245 - }, - { - "name": "minecraft:item.wheat", - "id": 59 - }, - { - "name": "minecraft:item.wooden_door", - "id": 64 - }, - { - "name": "minecraft:jigsaw", - "id": -211 - }, - { - "name": "minecraft:jukebox", - "id": 84 - }, - { - "name": "minecraft:jungle_boat", - "id": 379 - }, - { - "name": "minecraft:jungle_button", - "id": -143 - }, - { - "name": "minecraft:jungle_chest_boat", - "id": 647 - }, - { - "name": "minecraft:jungle_door", - "id": 562 - }, - { - "name": "minecraft:jungle_fence", - "id": -578 - }, - { - "name": "minecraft:jungle_fence_gate", - "id": 185 - }, - { - "name": "minecraft:jungle_hanging_sign", - "id": -503 - }, - { - "name": "minecraft:jungle_log", - "id": -571 - }, - { - "name": "minecraft:jungle_pressure_plate", - "id": -153 - }, - { - "name": "minecraft:jungle_sign", - "id": 585 - }, - { - "name": "minecraft:jungle_stairs", - "id": 136 - }, - { - "name": "minecraft:jungle_standing_sign", - "id": -188 - }, - { - "name": "minecraft:jungle_trapdoor", - "id": -148 - }, - { - "name": "minecraft:jungle_wall_sign", - "id": -189 - }, - { - "name": "minecraft:kelp", - "id": 384 - }, - { - "name": "minecraft:ladder", - "id": 65 - }, - { - "name": "minecraft:lantern", - "id": -208 - }, - { - "name": "minecraft:lapis_block", - "id": 22 - }, - { - "name": "minecraft:lapis_lazuli", - "id": 416 - }, - { - "name": "minecraft:lapis_ore", - "id": 21 - }, - { - "name": "minecraft:large_amethyst_bud", - "id": -330 - }, - { - "name": "minecraft:lava", - "id": 11 - }, - { - "name": "minecraft:lava_bucket", - "id": 365 - }, - { - "name": "minecraft:lead", - "id": 554 - }, - { - "name": "minecraft:leather", - "id": 383 - }, - { - "name": "minecraft:leather_boots", - "id": 340 - }, - { - "name": "minecraft:leather_chestplate", - "id": 338 - }, - { - "name": "minecraft:leather_helmet", - "id": 337 - }, - { - "name": "minecraft:leather_horse_armor", - "id": 537 - }, - { - "name": "minecraft:leather_leggings", - "id": 339 - }, - { - "name": "minecraft:leaves", - "id": 18 - }, - { - "name": "minecraft:leaves2", - "id": 161 - }, - { - "name": "minecraft:lectern", - "id": -194 - }, - { - "name": "minecraft:lever", - "id": 69 - }, - { - "name": "minecraft:light_block", - "id": -215 - }, - { - "name": "minecraft:light_blue_candle", - "id": -416 - }, - { - "name": "minecraft:light_blue_candle_cake", - "id": -433 - }, - { - "name": "minecraft:light_blue_carpet", - "id": -599 - }, - { - "name": "minecraft:light_blue_concrete", - "id": -630 - }, - { - "name": "minecraft:light_blue_concrete_powder", - "id": -711 - }, - { - "name": "minecraft:light_blue_dye", - "id": 409 - }, - { - "name": "minecraft:light_blue_glazed_terracotta", - "id": 223 - }, - { - "name": "minecraft:light_blue_shulker_box", - "id": -615 - }, - { - "name": "minecraft:light_blue_stained_glass", - "id": -675 - }, - { - "name": "minecraft:light_blue_stained_glass_pane", - "id": -645 - }, - { - "name": "minecraft:light_blue_terracotta", - "id": -726 - }, - { - "name": "minecraft:light_blue_wool", - "id": -562 - }, - { - "name": "minecraft:light_gray_candle", - "id": -421 - }, - { - "name": "minecraft:light_gray_candle_cake", - "id": -438 - }, - { - "name": "minecraft:light_gray_carpet", - "id": -604 - }, - { - "name": "minecraft:light_gray_concrete", - "id": -635 - }, - { - "name": "minecraft:light_gray_concrete_powder", - "id": -716 - }, - { - "name": "minecraft:light_gray_dye", - "id": 404 - }, - { - "name": "minecraft:light_gray_shulker_box", - "id": -620 - }, - { - "name": "minecraft:light_gray_stained_glass", - "id": -680 - }, - { - "name": "minecraft:light_gray_stained_glass_pane", - "id": -650 - }, - { - "name": "minecraft:light_gray_terracotta", - "id": -731 - }, - { - "name": "minecraft:light_gray_wool", - "id": -552 - }, - { - "name": "minecraft:light_weighted_pressure_plate", - "id": 147 - }, - { - "name": "minecraft:lightning_rod", - "id": -312 - }, - { - "name": "minecraft:lime_candle", - "id": -418 - }, - { - "name": "minecraft:lime_candle_cake", - "id": -435 - }, - { - "name": "minecraft:lime_carpet", - "id": -601 - }, - { - "name": "minecraft:lime_concrete", - "id": -632 - }, - { - "name": "minecraft:lime_concrete_powder", - "id": -713 - }, - { - "name": "minecraft:lime_dye", - "id": 407 - }, - { - "name": "minecraft:lime_glazed_terracotta", - "id": 225 - }, - { - "name": "minecraft:lime_shulker_box", - "id": -617 - }, - { - "name": "minecraft:lime_stained_glass", - "id": -677 - }, - { - "name": "minecraft:lime_stained_glass_pane", - "id": -647 - }, - { - "name": "minecraft:lime_terracotta", - "id": -728 - }, - { - "name": "minecraft:lime_wool", - "id": -559 - }, - { - "name": "minecraft:lingering_potion", - "id": 569 - }, - { - "name": "minecraft:lit_blast_furnace", - "id": -214 - }, - { - "name": "minecraft:lit_deepslate_redstone_ore", - "id": -404 - }, - { - "name": "minecraft:lit_furnace", - "id": 62 - }, - { - "name": "minecraft:lit_pumpkin", - "id": 91 - }, - { - "name": "minecraft:lit_redstone_lamp", - "id": 124 - }, - { - "name": "minecraft:lit_redstone_ore", - "id": 74 - }, - { - "name": "minecraft:lit_smoker", - "id": -199 - }, - { - "name": "minecraft:llama_spawn_egg", - "id": 475 - }, - { - "name": "minecraft:lodestone", - "id": -222 - }, - { - "name": "minecraft:lodestone_compass", - "id": 609 - }, - { - "name": "minecraft:log", - "id": 705 - }, - { - "name": "minecraft:log2", - "id": 708 - }, - { - "name": "minecraft:loom", - "id": -204 - }, - { - "name": "minecraft:magenta_candle", - "id": -415 - }, - { - "name": "minecraft:magenta_candle_cake", - "id": -432 - }, - { - "name": "minecraft:magenta_carpet", - "id": -598 - }, - { - "name": "minecraft:magenta_concrete", - "id": -629 - }, - { - "name": "minecraft:magenta_concrete_powder", - "id": -710 - }, - { - "name": "minecraft:magenta_dye", - "id": 410 - }, - { - "name": "minecraft:magenta_glazed_terracotta", - "id": 222 - }, - { - "name": "minecraft:magenta_shulker_box", - "id": -614 - }, - { - "name": "minecraft:magenta_stained_glass", - "id": -674 - }, - { - "name": "minecraft:magenta_stained_glass_pane", - "id": -644 - }, - { - "name": "minecraft:magenta_terracotta", - "id": -725 - }, - { - "name": "minecraft:magenta_wool", - "id": -565 - }, - { - "name": "minecraft:magma", - "id": 213 - }, - { - "name": "minecraft:magma_cream", - "id": 432 - }, - { - "name": "minecraft:magma_cube_spawn_egg", - "id": 457 - }, - { - "name": "minecraft:mangrove_boat", - "id": 642 - }, - { - "name": "minecraft:mangrove_button", - "id": -487 - }, - { - "name": "minecraft:mangrove_chest_boat", - "id": 651 - }, - { - "name": "minecraft:mangrove_door", - "id": 640 - }, - { - "name": "minecraft:mangrove_double_slab", - "id": -499 - }, - { - "name": "minecraft:mangrove_fence", - "id": -491 - }, - { - "name": "minecraft:mangrove_fence_gate", - "id": -492 - }, - { - "name": "minecraft:mangrove_hanging_sign", - "id": -508 - }, - { - "name": "minecraft:mangrove_leaves", - "id": -472 - }, - { - "name": "minecraft:mangrove_log", - "id": -484 - }, - { - "name": "minecraft:mangrove_planks", - "id": -486 - }, - { - "name": "minecraft:mangrove_pressure_plate", - "id": -490 - }, - { - "name": "minecraft:mangrove_propagule", - "id": -474 - }, - { - "name": "minecraft:mangrove_roots", - "id": -482 - }, - { - "name": "minecraft:mangrove_sign", - "id": 641 - }, - { - "name": "minecraft:mangrove_slab", - "id": -489 - }, - { - "name": "minecraft:mangrove_stairs", - "id": -488 - }, - { - "name": "minecraft:mangrove_standing_sign", - "id": -494 - }, - { - "name": "minecraft:mangrove_trapdoor", - "id": -496 - }, - { - "name": "minecraft:mangrove_wall_sign", - "id": -495 - }, - { - "name": "minecraft:mangrove_wood", - "id": -497 - }, - { - "name": "minecraft:medicine", - "id": 606 - }, - { - "name": "minecraft:medium_amethyst_bud", - "id": -331 - }, - { - "name": "minecraft:melon_block", - "id": 103 - }, - { - "name": "minecraft:melon_seeds", - "id": 293 - }, - { - "name": "minecraft:melon_slice", - "id": 272 - }, - { - "name": "minecraft:melon_stem", - "id": 105 - }, - { - "name": "minecraft:milk_bucket", - "id": 363 - }, - { - "name": "minecraft:minecart", - "id": 372 - }, - { - "name": "minecraft:miner_pottery_sherd", - "id": 675 - }, - { - "name": "minecraft:mob_spawner", - "id": 52 - }, - { - "name": "minecraft:mojang_banner_pattern", - "id": 591 - }, - { - "name": "minecraft:monster_egg", - "id": 97 - }, - { - "name": "minecraft:mooshroom_spawn_egg", - "id": 442 - }, - { - "name": "minecraft:moss_block", - "id": -320 - }, - { - "name": "minecraft:moss_carpet", - "id": -335 - }, - { - "name": "minecraft:mossy_cobblestone", - "id": 48 - }, - { - "name": "minecraft:mossy_cobblestone_stairs", - "id": -179 - }, - { - "name": "minecraft:mossy_stone_brick_stairs", - "id": -175 - }, - { - "name": "minecraft:mourner_pottery_sherd", - "id": 676 - }, - { - "name": "minecraft:moving_block", - "id": 250 - }, - { - "name": "minecraft:mud", - "id": -473 - }, - { - "name": "minecraft:mud_brick_double_slab", - "id": -479 - }, - { - "name": "minecraft:mud_brick_slab", - "id": -478 - }, - { - "name": "minecraft:mud_brick_stairs", - "id": -480 - }, - { - "name": "minecraft:mud_brick_wall", - "id": -481 - }, - { - "name": "minecraft:mud_bricks", - "id": -475 - }, - { - "name": "minecraft:muddy_mangrove_roots", - "id": -483 - }, - { - "name": "minecraft:mule_spawn_egg", - "id": 468 - }, - { - "name": "minecraft:mushroom_stew", - "id": 260 - }, - { - "name": "minecraft:music_disc_11", - "id": 551 - }, - { - "name": "minecraft:music_disc_13", - "id": 541 - }, - { - "name": "minecraft:music_disc_5", - "id": 643 - }, - { - "name": "minecraft:music_disc_blocks", - "id": 543 - }, - { - "name": "minecraft:music_disc_cat", - "id": 542 - }, - { - "name": "minecraft:music_disc_chirp", - "id": 544 - }, - { - "name": "minecraft:music_disc_far", - "id": 545 - }, - { - "name": "minecraft:music_disc_mall", - "id": 546 - }, - { - "name": "minecraft:music_disc_mellohi", - "id": 547 - }, - { - "name": "minecraft:music_disc_otherside", - "id": 633 - }, - { - "name": "minecraft:music_disc_pigstep", - "id": 627 - }, - { - "name": "minecraft:music_disc_relic", - "id": 701 - }, - { - "name": "minecraft:music_disc_stal", - "id": 548 - }, - { - "name": "minecraft:music_disc_strad", - "id": 549 - }, - { - "name": "minecraft:music_disc_wait", - "id": 552 - }, - { - "name": "minecraft:music_disc_ward", - "id": 550 - }, - { - "name": "minecraft:mutton", - "id": 557 - }, - { - "name": "minecraft:mycelium", - "id": 110 - }, - { - "name": "minecraft:name_tag", - "id": 555 - }, - { - "name": "minecraft:nautilus_shell", - "id": 577 - }, - { - "name": "minecraft:nether_brick", - "id": 112 - }, - { - "name": "minecraft:nether_brick_fence", - "id": 113 - }, - { - "name": "minecraft:nether_brick_stairs", - "id": 114 - }, - { - "name": "minecraft:nether_gold_ore", - "id": -288 - }, - { - "name": "minecraft:nether_sprouts", - "id": 628 - }, - { - "name": "minecraft:nether_star", - "id": 525 - }, - { - "name": "minecraft:nether_wart", - "id": 294 - }, - { - "name": "minecraft:nether_wart_block", - "id": 214 - }, - { - "name": "minecraft:netherbrick", - "id": 530 - }, - { - "name": "minecraft:netherite_axe", - "id": 613 - }, - { - "name": "minecraft:netherite_block", - "id": -270 - }, - { - "name": "minecraft:netherite_boots", - "id": 619 - }, - { - "name": "minecraft:netherite_chestplate", - "id": 617 - }, - { - "name": "minecraft:netherite_helmet", - "id": 616 - }, - { - "name": "minecraft:netherite_hoe", - "id": 614 - }, - { - "name": "minecraft:netherite_ingot", - "id": 615 - }, - { - "name": "minecraft:netherite_leggings", - "id": 618 - }, - { - "name": "minecraft:netherite_pickaxe", - "id": 612 - }, - { - "name": "minecraft:netherite_scrap", - "id": 620 - }, - { - "name": "minecraft:netherite_shovel", - "id": 611 - }, - { - "name": "minecraft:netherite_sword", - "id": 610 - }, - { - "name": "minecraft:netherite_upgrade_smithing_template", - "id": 684 - }, - { - "name": "minecraft:netherrack", - "id": 87 - }, - { - "name": "minecraft:netherreactor", - "id": 247 - }, - { - "name": "minecraft:normal_stone_stairs", - "id": -180 - }, - { - "name": "minecraft:noteblock", - "id": 25 - }, - { - "name": "minecraft:npc_spawn_egg", - "id": 472 - }, - { - "name": "minecraft:oak_boat", - "id": 377 - }, - { - "name": "minecraft:oak_chest_boat", - "id": 645 - }, - { - "name": "minecraft:oak_fence", - "id": 85 - }, - { - "name": "minecraft:oak_hanging_sign", - "id": -500 - }, - { - "name": "minecraft:oak_log", - "id": 17 - }, - { - "name": "minecraft:oak_sign", - "id": 360 - }, - { - "name": "minecraft:oak_stairs", - "id": 53 - }, - { - "name": "minecraft:observer", - "id": 251 - }, - { - "name": "minecraft:obsidian", - "id": 49 - }, - { - "name": "minecraft:ocelot_spawn_egg", - "id": 453 - }, - { - "name": "minecraft:ochre_froglight", - "id": -471 - }, - { - "name": "minecraft:orange_candle", - "id": -414 - }, - { - "name": "minecraft:orange_candle_cake", - "id": -431 - }, - { - "name": "minecraft:orange_carpet", - "id": -597 - }, - { - "name": "minecraft:orange_concrete", - "id": -628 - }, - { - "name": "minecraft:orange_concrete_powder", - "id": -709 - }, - { - "name": "minecraft:orange_dye", - "id": 411 - }, - { - "name": "minecraft:orange_glazed_terracotta", - "id": 221 - }, - { - "name": "minecraft:orange_shulker_box", - "id": -613 - }, - { - "name": "minecraft:orange_stained_glass", - "id": -673 - }, - { - "name": "minecraft:orange_stained_glass_pane", - "id": -643 - }, - { - "name": "minecraft:orange_terracotta", - "id": -724 - }, - { - "name": "minecraft:orange_wool", - "id": -557 - }, - { - "name": "minecraft:oxidized_copper", - "id": -343 - }, - { - "name": "minecraft:oxidized_cut_copper", - "id": -350 - }, - { - "name": "minecraft:oxidized_cut_copper_slab", - "id": -364 - }, - { - "name": "minecraft:oxidized_cut_copper_stairs", - "id": -357 - }, - { - "name": "minecraft:oxidized_double_cut_copper_slab", - "id": -371 - }, - { - "name": "minecraft:packed_ice", - "id": 174 - }, - { - "name": "minecraft:packed_mud", - "id": -477 - }, - { - "name": "minecraft:painting", - "id": 359 - }, - { - "name": "minecraft:panda_spawn_egg", - "id": 491 - }, - { - "name": "minecraft:paper", - "id": 388 - }, - { - "name": "minecraft:parrot_spawn_egg", - "id": 480 - }, - { - "name": "minecraft:pearlescent_froglight", - "id": -469 - }, - { - "name": "minecraft:phantom_membrane", - "id": 581 - }, - { - "name": "minecraft:phantom_spawn_egg", - "id": 488 - }, - { - "name": "minecraft:pig_spawn_egg", - "id": 439 - }, - { - "name": "minecraft:piglin_banner_pattern", - "id": 594 - }, - { - "name": "minecraft:piglin_brute_spawn_egg", - "id": 501 - }, - { - "name": "minecraft:piglin_spawn_egg", - "id": 499 - }, - { - "name": "minecraft:pillager_spawn_egg", - "id": 493 - }, - { - "name": "minecraft:pink_candle", - "id": -419 - }, - { - "name": "minecraft:pink_candle_cake", - "id": -436 - }, - { - "name": "minecraft:pink_carpet", - "id": -602 - }, - { - "name": "minecraft:pink_concrete", - "id": -633 - }, - { - "name": "minecraft:pink_concrete_powder", - "id": -714 - }, - { - "name": "minecraft:pink_dye", - "id": 406 - }, - { - "name": "minecraft:pink_glazed_terracotta", - "id": 226 - }, - { - "name": "minecraft:pink_petals", - "id": -549 - }, - { - "name": "minecraft:pink_shulker_box", - "id": -618 - }, - { - "name": "minecraft:pink_stained_glass", - "id": -678 - }, - { - "name": "minecraft:pink_stained_glass_pane", - "id": -648 - }, - { - "name": "minecraft:pink_terracotta", - "id": -729 - }, - { - "name": "minecraft:pink_wool", - "id": -566 - }, - { - "name": "minecraft:piston", - "id": 33 - }, - { - "name": "minecraft:piston_arm_collision", - "id": 34 - }, - { - "name": "minecraft:pitcher_crop", - "id": -574 - }, - { - "name": "minecraft:pitcher_plant", - "id": -612 - }, - { - "name": "minecraft:pitcher_pod", - "id": 297 - }, - { - "name": "minecraft:planks", - "id": 5 - }, - { - "name": "minecraft:plenty_pottery_sherd", - "id": 677 - }, - { - "name": "minecraft:podzol", - "id": 243 - }, - { - "name": "minecraft:pointed_dripstone", - "id": -308 - }, - { - "name": "minecraft:poisonous_potato", - "id": 282 - }, - { - "name": "minecraft:polar_bear_spawn_egg", - "id": 474 - }, - { - "name": "minecraft:polished_andesite_stairs", - "id": -174 - }, - { - "name": "minecraft:polished_basalt", - "id": -235 - }, - { - "name": "minecraft:polished_blackstone", - "id": -291 - }, - { - "name": "minecraft:polished_blackstone_brick_double_slab", - "id": -285 - }, - { - "name": "minecraft:polished_blackstone_brick_slab", - "id": -284 - }, - { - "name": "minecraft:polished_blackstone_brick_stairs", - "id": -275 - }, - { - "name": "minecraft:polished_blackstone_brick_wall", - "id": -278 - }, - { - "name": "minecraft:polished_blackstone_bricks", - "id": -274 - }, - { - "name": "minecraft:polished_blackstone_button", - "id": -296 - }, - { - "name": "minecraft:polished_blackstone_double_slab", - "id": -294 - }, - { - "name": "minecraft:polished_blackstone_pressure_plate", - "id": -295 - }, - { - "name": "minecraft:polished_blackstone_slab", - "id": -293 - }, - { - "name": "minecraft:polished_blackstone_stairs", - "id": -292 - }, - { - "name": "minecraft:polished_blackstone_wall", - "id": -297 - }, - { - "name": "minecraft:polished_deepslate", - "id": -383 - }, - { - "name": "minecraft:polished_deepslate_double_slab", - "id": -397 - }, - { - "name": "minecraft:polished_deepslate_slab", - "id": -384 - }, - { - "name": "minecraft:polished_deepslate_stairs", - "id": -385 - }, - { - "name": "minecraft:polished_deepslate_wall", - "id": -386 - }, - { - "name": "minecraft:polished_diorite_stairs", - "id": -173 - }, - { - "name": "minecraft:polished_granite_stairs", - "id": -172 - }, - { - "name": "minecraft:popped_chorus_fruit", - "id": 566 - }, - { - "name": "minecraft:porkchop", - "id": 262 - }, - { - "name": "minecraft:portal", - "id": 90 - }, - { - "name": "minecraft:potato", - "id": 280 - }, - { - "name": "minecraft:potatoes", - "id": 142 - }, - { - "name": "minecraft:potion", - "id": 428 - }, - { - "name": "minecraft:powder_snow", - "id": -306 - }, - { - "name": "minecraft:powder_snow_bucket", - "id": 370 - }, - { - "name": "minecraft:powered_comparator", - "id": 150 - }, - { - "name": "minecraft:powered_repeater", - "id": 94 - }, - { - "name": "minecraft:prismarine", - "id": 168 - }, - { - "name": "minecraft:prismarine_bricks_stairs", - "id": -4 - }, - { - "name": "minecraft:prismarine_crystals", - "id": 556 - }, - { - "name": "minecraft:prismarine_shard", - "id": 572 - }, - { - "name": "minecraft:prismarine_stairs", - "id": -2 - }, - { - "name": "minecraft:prize_pottery_sherd", - "id": 678 - }, - { - "name": "minecraft:pufferfish", - "id": 267 - }, - { - "name": "minecraft:pufferfish_bucket", - "id": 369 - }, - { - "name": "minecraft:pufferfish_spawn_egg", - "id": 483 - }, - { - "name": "minecraft:pumpkin", - "id": 86 - }, - { - "name": "minecraft:pumpkin_pie", - "id": 284 - }, - { - "name": "minecraft:pumpkin_seeds", - "id": 292 - }, - { - "name": "minecraft:pumpkin_stem", - "id": 104 - }, - { - "name": "minecraft:purple_candle", - "id": -423 - }, - { - "name": "minecraft:purple_candle_cake", - "id": -440 - }, - { - "name": "minecraft:purple_carpet", - "id": -606 - }, - { - "name": "minecraft:purple_concrete", - "id": -637 - }, - { - "name": "minecraft:purple_concrete_powder", - "id": -718 - }, - { - "name": "minecraft:purple_dye", - "id": 402 - }, - { - "name": "minecraft:purple_glazed_terracotta", - "id": 219 - }, - { - "name": "minecraft:purple_shulker_box", - "id": -622 - }, - { - "name": "minecraft:purple_stained_glass", - "id": -682 - }, - { - "name": "minecraft:purple_stained_glass_pane", - "id": -652 - }, - { - "name": "minecraft:purple_terracotta", - "id": -733 - }, - { - "name": "minecraft:purple_wool", - "id": -564 - }, - { - "name": "minecraft:purpur_block", - "id": 201 - }, - { - "name": "minecraft:purpur_stairs", - "id": 203 - }, - { - "name": "minecraft:quartz", - "id": 531 - }, - { - "name": "minecraft:quartz_block", - "id": 155 - }, - { - "name": "minecraft:quartz_bricks", - "id": -304 - }, - { - "name": "minecraft:quartz_ore", - "id": 153 - }, - { - "name": "minecraft:quartz_stairs", - "id": 156 - }, - { - "name": "minecraft:rabbit", - "id": 288 - }, - { - "name": "minecraft:rabbit_foot", - "id": 535 - }, - { - "name": "minecraft:rabbit_hide", - "id": 536 - }, - { - "name": "minecraft:rabbit_spawn_egg", - "id": 461 - }, - { - "name": "minecraft:rabbit_stew", - "id": 290 - }, - { - "name": "minecraft:rail", - "id": 66 - }, - { - "name": "minecraft:raiser_armor_trim_smithing_template", - "id": 698 - }, - { - "name": "minecraft:rapid_fertilizer", - "id": 604 - }, - { - "name": "minecraft:ravager_spawn_egg", - "id": 495 - }, - { - "name": "minecraft:raw_copper", - "id": 514 - }, - { - "name": "minecraft:raw_copper_block", - "id": -452 - }, - { - "name": "minecraft:raw_gold", - "id": 513 - }, - { - "name": "minecraft:raw_gold_block", - "id": -453 - }, - { - "name": "minecraft:raw_iron", - "id": 512 - }, - { - "name": "minecraft:raw_iron_block", - "id": -451 - }, - { - "name": "minecraft:recovery_compass", - "id": 653 - }, - { - "name": "minecraft:red_candle", - "id": -427 - }, - { - "name": "minecraft:red_candle_cake", - "id": -444 - }, - { - "name": "minecraft:red_carpet", - "id": -610 - }, - { - "name": "minecraft:red_concrete", - "id": -641 - }, - { - "name": "minecraft:red_concrete_powder", - "id": -722 - }, - { - "name": "minecraft:red_dye", - "id": 398 - }, - { - "name": "minecraft:red_flower", - "id": 38 - }, - { - "name": "minecraft:red_glazed_terracotta", - "id": 234 - }, - { - "name": "minecraft:red_mushroom", - "id": 40 - }, - { - "name": "minecraft:red_mushroom_block", - "id": 100 - }, - { - "name": "minecraft:red_nether_brick", - "id": 215 - }, - { - "name": "minecraft:red_nether_brick_stairs", - "id": -184 - }, - { - "name": "minecraft:red_sandstone", - "id": 179 - }, - { - "name": "minecraft:red_sandstone_stairs", - "id": 180 - }, - { - "name": "minecraft:red_shulker_box", - "id": -626 - }, - { - "name": "minecraft:red_stained_glass", - "id": -686 - }, - { - "name": "minecraft:red_stained_glass_pane", - "id": -656 - }, - { - "name": "minecraft:red_terracotta", - "id": -737 - }, - { - "name": "minecraft:red_wool", - "id": -556 - }, - { - "name": "minecraft:redstone", - "id": 375 - }, - { - "name": "minecraft:redstone_block", - "id": 152 - }, - { - "name": "minecraft:redstone_lamp", - "id": 123 - }, - { - "name": "minecraft:redstone_ore", - "id": 73 - }, - { - "name": "minecraft:redstone_torch", - "id": 76 - }, - { - "name": "minecraft:redstone_wire", - "id": 55 - }, - { - "name": "minecraft:reinforced_deepslate", - "id": -466 - }, - { - "name": "minecraft:repeater", - "id": 421 - }, - { - "name": "minecraft:repeating_command_block", - "id": 188 - }, - { - "name": "minecraft:reserved6", - "id": 255 - }, - { - "name": "minecraft:respawn_anchor", - "id": -272 - }, - { - "name": "minecraft:rib_armor_trim_smithing_template", - "id": 694 - }, - { - "name": "minecraft:rotten_flesh", - "id": 277 - }, - { - "name": "minecraft:saddle", - "id": 373 - }, - { - "name": "minecraft:salmon", - "id": 265 - }, - { - "name": "minecraft:salmon_bucket", - "id": 367 - }, - { - "name": "minecraft:salmon_spawn_egg", - "id": 484 - }, - { - "name": "minecraft:sand", - "id": 12 - }, - { - "name": "minecraft:sandstone", - "id": 24 - }, - { - "name": "minecraft:sandstone_stairs", - "id": 128 - }, - { - "name": "minecraft:sapling", - "id": 6 - }, - { - "name": "minecraft:scaffolding", - "id": -165 - }, - { - "name": "minecraft:sculk", - "id": -458 - }, - { - "name": "minecraft:sculk_catalyst", - "id": -460 - }, - { - "name": "minecraft:sculk_sensor", - "id": -307 - }, - { - "name": "minecraft:sculk_shrieker", - "id": -461 - }, - { - "name": "minecraft:sculk_vein", - "id": -459 - }, - { - "name": "minecraft:scute", - "id": 579 - }, - { - "name": "minecraft:sea_lantern", - "id": 169 - }, - { - "name": "minecraft:sea_pickle", - "id": -156 - }, - { - "name": "minecraft:seagrass", - "id": -130 - }, - { - "name": "minecraft:sentry_armor_trim_smithing_template", - "id": 685 - }, - { - "name": "minecraft:shaper_armor_trim_smithing_template", - "id": 699 - }, - { - "name": "minecraft:sheaf_pottery_sherd", - "id": 679 - }, - { - "name": "minecraft:shears", - "id": 423 - }, - { - "name": "minecraft:sheep_spawn_egg", - "id": 440 - }, - { - "name": "minecraft:shelter_pottery_sherd", - "id": 680 - }, - { - "name": "minecraft:shield", - "id": 357 - }, - { - "name": "minecraft:shroomlight", - "id": -230 - }, - { - "name": "minecraft:shulker_box", - "id": 713 - }, - { - "name": "minecraft:shulker_shell", - "id": 573 - }, - { - "name": "minecraft:shulker_spawn_egg", - "id": 471 - }, - { - "name": "minecraft:silence_armor_trim_smithing_template", - "id": 696 - }, - { - "name": "minecraft:silver_glazed_terracotta", - "id": 228 - }, - { - "name": "minecraft:silverfish_spawn_egg", - "id": 445 - }, - { - "name": "minecraft:skeleton_horse_spawn_egg", - "id": 469 - }, - { - "name": "minecraft:skeleton_spawn_egg", - "id": 446 - }, - { - "name": "minecraft:skull", - "id": 523 - }, - { - "name": "minecraft:skull_banner_pattern", - "id": 590 - }, - { - "name": "minecraft:skull_pottery_sherd", - "id": 681 - }, - { - "name": "minecraft:slime", - "id": 165 - }, - { - "name": "minecraft:slime_ball", - "id": 390 - }, - { - "name": "minecraft:slime_spawn_egg", - "id": 447 - }, - { - "name": "minecraft:small_amethyst_bud", - "id": -332 - }, - { - "name": "minecraft:small_dripleaf_block", - "id": -336 - }, - { - "name": "minecraft:smithing_table", - "id": -202 - }, - { - "name": "minecraft:smoker", - "id": -198 - }, - { - "name": "minecraft:smooth_basalt", - "id": -377 - }, - { - "name": "minecraft:smooth_quartz_stairs", - "id": -185 - }, - { - "name": "minecraft:smooth_red_sandstone_stairs", - "id": -176 - }, - { - "name": "minecraft:smooth_sandstone_stairs", - "id": -177 - }, - { - "name": "minecraft:smooth_stone", - "id": -183 - }, - { - "name": "minecraft:sniffer_egg", - "id": -596 - }, - { - "name": "minecraft:sniffer_spawn_egg", - "id": 502 - }, - { - "name": "minecraft:snort_pottery_sherd", - "id": 682 - }, - { - "name": "minecraft:snout_armor_trim_smithing_template", - "id": 693 - }, - { - "name": "minecraft:snow", - "id": 80 - }, - { - "name": "minecraft:snow_golem_spawn_egg", - "id": 507 - }, - { - "name": "minecraft:snow_layer", - "id": 78 - }, - { - "name": "minecraft:snowball", - "id": 376 - }, - { - "name": "minecraft:soul_campfire", - "id": 629 - }, - { - "name": "minecraft:soul_fire", - "id": -237 - }, - { - "name": "minecraft:soul_lantern", - "id": -269 - }, - { - "name": "minecraft:soul_sand", - "id": 88 - }, - { - "name": "minecraft:soul_soil", - "id": -236 - }, - { - "name": "minecraft:soul_torch", - "id": -268 - }, - { - "name": "minecraft:sparkler", - "id": 607 - }, - { - "name": "minecraft:spawn_egg", - "id": 717 - }, - { - "name": "minecraft:spider_eye", - "id": 278 - }, - { - "name": "minecraft:spider_spawn_egg", - "id": 448 - }, - { - "name": "minecraft:spire_armor_trim_smithing_template", - "id": 695 - }, - { - "name": "minecraft:splash_potion", - "id": 568 - }, - { - "name": "minecraft:sponge", - "id": 19 - }, - { - "name": "minecraft:spore_blossom", - "id": -321 - }, - { - "name": "minecraft:spruce_boat", - "id": 380 - }, - { - "name": "minecraft:spruce_button", - "id": -144 - }, - { - "name": "minecraft:spruce_chest_boat", - "id": 648 - }, - { - "name": "minecraft:spruce_door", - "id": 560 - }, - { - "name": "minecraft:spruce_fence", - "id": -579 - }, - { - "name": "minecraft:spruce_fence_gate", - "id": 183 - }, - { - "name": "minecraft:spruce_hanging_sign", - "id": -501 - }, - { - "name": "minecraft:spruce_log", - "id": -569 - }, - { - "name": "minecraft:spruce_pressure_plate", - "id": -154 - }, - { - "name": "minecraft:spruce_sign", - "id": 583 - }, - { - "name": "minecraft:spruce_stairs", - "id": 134 - }, - { - "name": "minecraft:spruce_standing_sign", - "id": -181 - }, - { - "name": "minecraft:spruce_trapdoor", - "id": -149 - }, - { - "name": "minecraft:spruce_wall_sign", - "id": -182 - }, - { - "name": "minecraft:spyglass", - "id": 632 - }, - { - "name": "minecraft:squid_spawn_egg", - "id": 452 - }, - { - "name": "minecraft:stained_glass", - "id": 711 - }, - { - "name": "minecraft:stained_glass_pane", - "id": 712 - }, - { - "name": "minecraft:stained_hardened_clay", - "id": 702 - }, - { - "name": "minecraft:standing_banner", - "id": 176 - }, - { - "name": "minecraft:standing_sign", - "id": 63 - }, - { - "name": "minecraft:stick", - "id": 322 - }, - { - "name": "minecraft:sticky_piston", - "id": 29 - }, - { - "name": "minecraft:sticky_piston_arm_collision", - "id": -217 - }, - { - "name": "minecraft:stone", - "id": 1 - }, - { - "name": "minecraft:stone_axe", - "id": 317 - }, - { - "name": "minecraft:stone_block_slab", - "id": 44 - }, - { - "name": "minecraft:stone_block_slab2", - "id": 182 - }, - { - "name": "minecraft:stone_block_slab3", - "id": -162 - }, - { - "name": "minecraft:stone_block_slab4", - "id": -166 - }, - { - "name": "minecraft:stone_brick_stairs", - "id": 109 - }, - { - "name": "minecraft:stone_button", - "id": 77 - }, - { - "name": "minecraft:stone_hoe", - "id": 332 - }, - { - "name": "minecraft:stone_pickaxe", - "id": 316 - }, - { - "name": "minecraft:stone_pressure_plate", - "id": 70 - }, - { - "name": "minecraft:stone_shovel", - "id": 315 - }, - { - "name": "minecraft:stone_stairs", - "id": 67 - }, - { - "name": "minecraft:stone_sword", - "id": 314 - }, - { - "name": "minecraft:stonebrick", - "id": 98 - }, - { - "name": "minecraft:stonecutter", - "id": 245 - }, - { - "name": "minecraft:stonecutter_block", - "id": -197 - }, - { - "name": "minecraft:stray_spawn_egg", - "id": 464 - }, - { - "name": "minecraft:strider_spawn_egg", - "id": 497 - }, - { - "name": "minecraft:string", - "id": 328 - }, - { - "name": "minecraft:stripped_acacia_log", - "id": -8 - }, - { - "name": "minecraft:stripped_bamboo_block", - "id": -528 - }, - { - "name": "minecraft:stripped_birch_log", - "id": -6 - }, - { - "name": "minecraft:stripped_cherry_log", - "id": -535 - }, - { - "name": "minecraft:stripped_cherry_wood", - "id": -545 - }, - { - "name": "minecraft:stripped_crimson_hyphae", - "id": -300 - }, - { - "name": "minecraft:stripped_crimson_stem", - "id": -240 - }, - { - "name": "minecraft:stripped_dark_oak_log", - "id": -9 - }, - { - "name": "minecraft:stripped_jungle_log", - "id": -7 - }, - { - "name": "minecraft:stripped_mangrove_log", - "id": -485 - }, - { - "name": "minecraft:stripped_mangrove_wood", - "id": -498 - }, - { - "name": "minecraft:stripped_oak_log", - "id": -10 - }, - { - "name": "minecraft:stripped_spruce_log", - "id": -5 - }, - { - "name": "minecraft:stripped_warped_hyphae", - "id": -301 - }, - { - "name": "minecraft:stripped_warped_stem", - "id": -241 - }, - { - "name": "minecraft:structure_block", - "id": 252 - }, - { - "name": "minecraft:structure_void", - "id": 217 - }, - { - "name": "minecraft:sugar", - "id": 418 - }, - { - "name": "minecraft:sugar_cane", - "id": 387 - }, - { - "name": "minecraft:suspicious_gravel", - "id": -573 - }, - { - "name": "minecraft:suspicious_sand", - "id": -529 - }, - { - "name": "minecraft:suspicious_stew", - "id": 597 - }, - { - "name": "minecraft:sweet_berries", - "id": 287 - }, - { - "name": "minecraft:sweet_berry_bush", - "id": -207 - }, - { - "name": "minecraft:tadpole_bucket", - "id": 637 - }, - { - "name": "minecraft:tadpole_spawn_egg", - "id": 636 - }, - { - "name": "minecraft:tallgrass", - "id": 31 - }, - { - "name": "minecraft:target", - "id": -239 - }, - { - "name": "minecraft:tide_armor_trim_smithing_template", - "id": 692 - }, - { - "name": "minecraft:tinted_glass", - "id": -334 - }, - { - "name": "minecraft:tnt", - "id": 46 - }, - { - "name": "minecraft:tnt_minecart", - "id": 532 - }, - { - "name": "minecraft:torch", - "id": 50 - }, - { - "name": "minecraft:torchflower", - "id": -568 - }, - { - "name": "minecraft:torchflower_crop", - "id": -567 - }, - { - "name": "minecraft:torchflower_seeds", - "id": 296 - }, - { - "name": "minecraft:totem_of_undying", - "id": 575 - }, - { - "name": "minecraft:trader_llama_spawn_egg", - "id": 655 - }, - { - "name": "minecraft:trapdoor", - "id": 96 - }, - { - "name": "minecraft:trapped_chest", - "id": 146 - }, - { - "name": "minecraft:trident", - "id": 553 - }, - { - "name": "minecraft:trip_wire", - "id": 132 - }, - { - "name": "minecraft:tripwire_hook", - "id": 131 - }, - { - "name": "minecraft:tropical_fish", - "id": 266 - }, - { - "name": "minecraft:tropical_fish_bucket", - "id": 368 - }, - { - "name": "minecraft:tropical_fish_spawn_egg", - "id": 481 - }, - { - "name": "minecraft:tube_coral", - "id": -131 - }, - { - "name": "minecraft:tuff", - "id": -333 - }, - { - "name": "minecraft:turtle_egg", - "id": -159 - }, - { - "name": "minecraft:turtle_helmet", - "id": 580 - }, - { - "name": "minecraft:turtle_spawn_egg", - "id": 487 - }, - { - "name": "minecraft:twisting_vines", - "id": -287 - }, - { - "name": "minecraft:underwater_torch", - "id": 239 - }, - { - "name": "minecraft:undyed_shulker_box", - "id": 205 - }, - { - "name": "minecraft:unknown", - "id": -305 - }, - { - "name": "minecraft:unlit_redstone_torch", - "id": 75 - }, - { - "name": "minecraft:unpowered_comparator", - "id": 149 - }, - { - "name": "minecraft:unpowered_repeater", - "id": 93 - }, - { - "name": "minecraft:verdant_froglight", - "id": -470 - }, - { - "name": "minecraft:vex_armor_trim_smithing_template", - "id": 691 - }, - { - "name": "minecraft:vex_spawn_egg", - "id": 478 - }, - { - "name": "minecraft:villager_spawn_egg", - "id": 451 - }, - { - "name": "minecraft:vindicator_spawn_egg", - "id": 476 - }, - { - "name": "minecraft:vine", - "id": 106 - }, - { - "name": "minecraft:wall_banner", - "id": 177 - }, - { - "name": "minecraft:wall_sign", - "id": 68 - }, - { - "name": "minecraft:wandering_trader_spawn_egg", - "id": 494 - }, - { - "name": "minecraft:ward_armor_trim_smithing_template", - "id": 689 - }, - { - "name": "minecraft:warden_spawn_egg", - "id": 639 - }, - { - "name": "minecraft:warped_button", - "id": -261 - }, - { - "name": "minecraft:warped_door", - "id": 624 - }, - { - "name": "minecraft:warped_double_slab", - "id": -267 - }, - { - "name": "minecraft:warped_fence", - "id": -257 - }, - { - "name": "minecraft:warped_fence_gate", - "id": -259 - }, - { - "name": "minecraft:warped_fungus", - "id": -229 - }, - { - "name": "minecraft:warped_fungus_on_a_stick", - "id": 625 - }, - { - "name": "minecraft:warped_hanging_sign", - "id": -507 - }, - { - "name": "minecraft:warped_hyphae", - "id": -298 - }, - { - "name": "minecraft:warped_nylium", - "id": -233 - }, - { - "name": "minecraft:warped_planks", - "id": -243 - }, - { - "name": "minecraft:warped_pressure_plate", - "id": -263 - }, - { - "name": "minecraft:warped_roots", - "id": -224 - }, - { - "name": "minecraft:warped_sign", - "id": 622 - }, - { - "name": "minecraft:warped_slab", - "id": -265 - }, - { - "name": "minecraft:warped_stairs", - "id": -255 - }, - { - "name": "minecraft:warped_standing_sign", - "id": -251 - }, - { - "name": "minecraft:warped_stem", - "id": -226 - }, - { - "name": "minecraft:warped_trapdoor", - "id": -247 - }, - { - "name": "minecraft:warped_wall_sign", - "id": -253 - }, - { - "name": "minecraft:warped_wart_block", - "id": -227 - }, - { - "name": "minecraft:water", - "id": 9 - }, - { - "name": "minecraft:water_bucket", - "id": 364 - }, - { - "name": "minecraft:waterlily", - "id": 111 - }, - { - "name": "minecraft:waxed_copper", - "id": -344 - }, - { - "name": "minecraft:waxed_cut_copper", - "id": -351 - }, - { - "name": "minecraft:waxed_cut_copper_slab", - "id": -365 - }, - { - "name": "minecraft:waxed_cut_copper_stairs", - "id": -358 - }, - { - "name": "minecraft:waxed_double_cut_copper_slab", - "id": -372 - }, - { - "name": "minecraft:waxed_exposed_copper", - "id": -345 - }, - { - "name": "minecraft:waxed_exposed_cut_copper", - "id": -352 - }, - { - "name": "minecraft:waxed_exposed_cut_copper_slab", - "id": -366 - }, - { - "name": "minecraft:waxed_exposed_cut_copper_stairs", - "id": -359 - }, - { - "name": "minecraft:waxed_exposed_double_cut_copper_slab", - "id": -373 - }, - { - "name": "minecraft:waxed_oxidized_copper", - "id": -446 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper", - "id": -447 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper_slab", - "id": -449 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper_stairs", - "id": -448 - }, - { - "name": "minecraft:waxed_oxidized_double_cut_copper_slab", - "id": -450 - }, - { - "name": "minecraft:waxed_weathered_copper", - "id": -346 - }, - { - "name": "minecraft:waxed_weathered_cut_copper", - "id": -353 - }, - { - "name": "minecraft:waxed_weathered_cut_copper_slab", - "id": -367 - }, - { - "name": "minecraft:waxed_weathered_cut_copper_stairs", - "id": -360 - }, - { - "name": "minecraft:waxed_weathered_double_cut_copper_slab", - "id": -374 - }, - { - "name": "minecraft:wayfinder_armor_trim_smithing_template", - "id": 697 - }, - { - "name": "minecraft:weathered_copper", - "id": -342 - }, - { - "name": "minecraft:weathered_cut_copper", - "id": -349 - }, - { - "name": "minecraft:weathered_cut_copper_slab", - "id": -363 - }, - { - "name": "minecraft:weathered_cut_copper_stairs", - "id": -356 - }, - { - "name": "minecraft:weathered_double_cut_copper_slab", - "id": -370 - }, - { - "name": "minecraft:web", - "id": 30 - }, - { - "name": "minecraft:weeping_vines", - "id": -231 - }, - { - "name": "minecraft:wheat", - "id": 336 - }, - { - "name": "minecraft:wheat_seeds", - "id": 291 - }, - { - "name": "minecraft:white_candle", - "id": -413 - }, - { - "name": "minecraft:white_candle_cake", - "id": -430 - }, - { - "name": "minecraft:white_carpet", - "id": 171 - }, - { - "name": "minecraft:white_concrete", - "id": 236 - }, - { - "name": "minecraft:white_concrete_powder", - "id": 237 - }, - { - "name": "minecraft:white_dye", - "id": 412 - }, - { - "name": "minecraft:white_glazed_terracotta", - "id": 220 - }, - { - "name": "minecraft:white_shulker_box", - "id": 218 - }, - { - "name": "minecraft:white_stained_glass", - "id": 241 - }, - { - "name": "minecraft:white_stained_glass_pane", - "id": 160 - }, - { - "name": "minecraft:white_terracotta", - "id": 159 - }, - { - "name": "minecraft:white_wool", - "id": 35 - }, - { - "name": "minecraft:wild_armor_trim_smithing_template", - "id": 688 - }, - { - "name": "minecraft:witch_spawn_egg", - "id": 454 - }, - { - "name": "minecraft:wither_rose", - "id": -216 - }, - { - "name": "minecraft:wither_skeleton_spawn_egg", - "id": 466 - }, - { - "name": "minecraft:wither_spawn_egg", - "id": 509 - }, - { - "name": "minecraft:wolf_spawn_egg", - "id": 441 - }, - { - "name": "minecraft:wood", - "id": -212 - }, - { - "name": "minecraft:wooden_axe", - "id": 313 - }, - { - "name": "minecraft:wooden_button", - "id": 143 - }, - { - "name": "minecraft:wooden_door", - "id": 361 - }, - { - "name": "minecraft:wooden_hoe", - "id": 331 - }, - { - "name": "minecraft:wooden_pickaxe", - "id": 312 - }, - { - "name": "minecraft:wooden_pressure_plate", - "id": 72 - }, - { - "name": "minecraft:wooden_shovel", - "id": 311 - }, - { - "name": "minecraft:wooden_slab", - "id": 158 - }, - { - "name": "minecraft:wooden_sword", - "id": 310 - }, - { - "name": "minecraft:wool", - "id": 703 - }, - { - "name": "minecraft:writable_book", - "id": 517 - }, - { - "name": "minecraft:written_book", - "id": 518 - }, - { - "name": "minecraft:yellow_candle", - "id": -417 - }, - { - "name": "minecraft:yellow_candle_cake", - "id": -434 - }, - { - "name": "minecraft:yellow_carpet", - "id": -600 - }, - { - "name": "minecraft:yellow_concrete", - "id": -631 - }, - { - "name": "minecraft:yellow_concrete_powder", - "id": -712 - }, - { - "name": "minecraft:yellow_dye", - "id": 408 - }, - { - "name": "minecraft:yellow_flower", - "id": 37 - }, - { - "name": "minecraft:yellow_glazed_terracotta", - "id": 224 - }, - { - "name": "minecraft:yellow_shulker_box", - "id": -616 - }, - { - "name": "minecraft:yellow_stained_glass", - "id": -676 - }, - { - "name": "minecraft:yellow_stained_glass_pane", - "id": -646 - }, - { - "name": "minecraft:yellow_terracotta", - "id": -727 - }, - { - "name": "minecraft:yellow_wool", - "id": -558 - }, - { - "name": "minecraft:zoglin_spawn_egg", - "id": 500 - }, - { - "name": "minecraft:zombie_horse_spawn_egg", - "id": 470 - }, - { - "name": "minecraft:zombie_pigman_spawn_egg", - "id": 450 - }, - { - "name": "minecraft:zombie_spawn_egg", - "id": 449 - }, - { - "name": "minecraft:zombie_villager_spawn_egg", - "id": 479 - } -] \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_20_50.json b/core/src/main/resources/bedrock/runtime_item_states.1_20_50.json deleted file mode 100644 index d7535269f..000000000 --- a/core/src/main/resources/bedrock/runtime_item_states.1_20_50.json +++ /dev/null @@ -1,5846 +0,0 @@ -[ - { - "name": "minecraft:acacia_boat", - "id": 382 - }, - { - "name": "minecraft:acacia_button", - "id": -140 - }, - { - "name": "minecraft:acacia_chest_boat", - "id": 650 - }, - { - "name": "minecraft:acacia_door", - "id": 564 - }, - { - "name": "minecraft:acacia_fence", - "id": -575 - }, - { - "name": "minecraft:acacia_fence_gate", - "id": 187 - }, - { - "name": "minecraft:acacia_hanging_sign", - "id": -504 - }, - { - "name": "minecraft:acacia_log", - "id": 162 - }, - { - "name": "minecraft:acacia_planks", - "id": -742 - }, - { - "name": "minecraft:acacia_pressure_plate", - "id": -150 - }, - { - "name": "minecraft:acacia_sign", - "id": 587 - }, - { - "name": "minecraft:acacia_stairs", - "id": 163 - }, - { - "name": "minecraft:acacia_standing_sign", - "id": -190 - }, - { - "name": "minecraft:acacia_trapdoor", - "id": -145 - }, - { - "name": "minecraft:acacia_wall_sign", - "id": -191 - }, - { - "name": "minecraft:activator_rail", - "id": 126 - }, - { - "name": "minecraft:agent_spawn_egg", - "id": 490 - }, - { - "name": "minecraft:air", - "id": -158 - }, - { - "name": "minecraft:allay_spawn_egg", - "id": 639 - }, - { - "name": "minecraft:allow", - "id": 210 - }, - { - "name": "minecraft:amethyst_block", - "id": -327 - }, - { - "name": "minecraft:amethyst_cluster", - "id": -329 - }, - { - "name": "minecraft:amethyst_shard", - "id": 632 - }, - { - "name": "minecraft:ancient_debris", - "id": -271 - }, - { - "name": "minecraft:andesite", - "id": -594 - }, - { - "name": "minecraft:andesite_stairs", - "id": -171 - }, - { - "name": "minecraft:angler_pottery_sherd", - "id": 664 - }, - { - "name": "minecraft:anvil", - "id": 145 - }, - { - "name": "minecraft:apple", - "id": 257 - }, - { - "name": "minecraft:archer_pottery_sherd", - "id": 665 - }, - { - "name": "minecraft:armor_stand", - "id": 560 - }, - { - "name": "minecraft:arms_up_pottery_sherd", - "id": 666 - }, - { - "name": "minecraft:arrow", - "id": 304 - }, - { - "name": "minecraft:axolotl_bucket", - "id": 372 - }, - { - "name": "minecraft:axolotl_spawn_egg", - "id": 504 - }, - { - "name": "minecraft:azalea", - "id": -337 - }, - { - "name": "minecraft:azalea_leaves", - "id": -324 - }, - { - "name": "minecraft:azalea_leaves_flowered", - "id": -325 - }, - { - "name": "minecraft:baked_potato", - "id": 282 - }, - { - "name": "minecraft:balloon", - "id": 606 - }, - { - "name": "minecraft:bamboo", - "id": -163 - }, - { - "name": "minecraft:bamboo_block", - "id": -527 - }, - { - "name": "minecraft:bamboo_button", - "id": -511 - }, - { - "name": "minecraft:bamboo_chest_raft", - "id": 662 - }, - { - "name": "minecraft:bamboo_door", - "id": -517 - }, - { - "name": "minecraft:bamboo_double_slab", - "id": -521 - }, - { - "name": "minecraft:bamboo_fence", - "id": -515 - }, - { - "name": "minecraft:bamboo_fence_gate", - "id": -516 - }, - { - "name": "minecraft:bamboo_hanging_sign", - "id": -522 - }, - { - "name": "minecraft:bamboo_mosaic", - "id": -509 - }, - { - "name": "minecraft:bamboo_mosaic_double_slab", - "id": -525 - }, - { - "name": "minecraft:bamboo_mosaic_slab", - "id": -524 - }, - { - "name": "minecraft:bamboo_mosaic_stairs", - "id": -523 - }, - { - "name": "minecraft:bamboo_planks", - "id": -510 - }, - { - "name": "minecraft:bamboo_pressure_plate", - "id": -514 - }, - { - "name": "minecraft:bamboo_raft", - "id": 661 - }, - { - "name": "minecraft:bamboo_sapling", - "id": -164 - }, - { - "name": "minecraft:bamboo_sign", - "id": 660 - }, - { - "name": "minecraft:bamboo_slab", - "id": -513 - }, - { - "name": "minecraft:bamboo_stairs", - "id": -512 - }, - { - "name": "minecraft:bamboo_standing_sign", - "id": -518 - }, - { - "name": "minecraft:bamboo_trapdoor", - "id": -520 - }, - { - "name": "minecraft:bamboo_wall_sign", - "id": -519 - }, - { - "name": "minecraft:banner", - "id": 575 - }, - { - "name": "minecraft:banner_pattern", - "id": 718 - }, - { - "name": "minecraft:barrel", - "id": -203 - }, - { - "name": "minecraft:barrier", - "id": -161 - }, - { - "name": "minecraft:basalt", - "id": -234 - }, - { - "name": "minecraft:bat_spawn_egg", - "id": 456 - }, - { - "name": "minecraft:beacon", - "id": 138 - }, - { - "name": "minecraft:bed", - "id": 421 - }, - { - "name": "minecraft:bedrock", - "id": 7 - }, - { - "name": "minecraft:bee_nest", - "id": -218 - }, - { - "name": "minecraft:bee_spawn_egg", - "id": 497 - }, - { - "name": "minecraft:beef", - "id": 274 - }, - { - "name": "minecraft:beehive", - "id": -219 - }, - { - "name": "minecraft:beetroot", - "id": 286 - }, - { - "name": "minecraft:beetroot_seeds", - "id": 296 - }, - { - "name": "minecraft:beetroot_soup", - "id": 287 - }, - { - "name": "minecraft:bell", - "id": -206 - }, - { - "name": "minecraft:big_dripleaf", - "id": -323 - }, - { - "name": "minecraft:birch_boat", - "id": 379 - }, - { - "name": "minecraft:birch_button", - "id": -141 - }, - { - "name": "minecraft:birch_chest_boat", - "id": 647 - }, - { - "name": "minecraft:birch_door", - "id": 562 - }, - { - "name": "minecraft:birch_fence", - "id": -576 - }, - { - "name": "minecraft:birch_fence_gate", - "id": 184 - }, - { - "name": "minecraft:birch_hanging_sign", - "id": -502 - }, - { - "name": "minecraft:birch_log", - "id": -570 - }, - { - "name": "minecraft:birch_planks", - "id": -740 - }, - { - "name": "minecraft:birch_pressure_plate", - "id": -151 - }, - { - "name": "minecraft:birch_sign", - "id": 585 - }, - { - "name": "minecraft:birch_stairs", - "id": 135 - }, - { - "name": "minecraft:birch_standing_sign", - "id": -186 - }, - { - "name": "minecraft:birch_trapdoor", - "id": -146 - }, - { - "name": "minecraft:birch_wall_sign", - "id": -187 - }, - { - "name": "minecraft:black_candle", - "id": -428 - }, - { - "name": "minecraft:black_candle_cake", - "id": -445 - }, - { - "name": "minecraft:black_carpet", - "id": -611 - }, - { - "name": "minecraft:black_concrete", - "id": -642 - }, - { - "name": "minecraft:black_concrete_powder", - "id": -723 - }, - { - "name": "minecraft:black_dye", - "id": 398 - }, - { - "name": "minecraft:black_glazed_terracotta", - "id": 235 - }, - { - "name": "minecraft:black_shulker_box", - "id": -627 - }, - { - "name": "minecraft:black_stained_glass", - "id": -687 - }, - { - "name": "minecraft:black_stained_glass_pane", - "id": -657 - }, - { - "name": "minecraft:black_terracotta", - "id": -738 - }, - { - "name": "minecraft:black_wool", - "id": -554 - }, - { - "name": "minecraft:blackstone", - "id": -273 - }, - { - "name": "minecraft:blackstone_double_slab", - "id": -283 - }, - { - "name": "minecraft:blackstone_slab", - "id": -282 - }, - { - "name": "minecraft:blackstone_stairs", - "id": -276 - }, - { - "name": "minecraft:blackstone_wall", - "id": -277 - }, - { - "name": "minecraft:blade_pottery_sherd", - "id": 667 - }, - { - "name": "minecraft:blast_furnace", - "id": -196 - }, - { - "name": "minecraft:blaze_powder", - "id": 432 - }, - { - "name": "minecraft:blaze_rod", - "id": 426 - }, - { - "name": "minecraft:blaze_spawn_egg", - "id": 459 - }, - { - "name": "minecraft:bleach", - "id": 604 - }, - { - "name": "minecraft:blue_candle", - "id": -424 - }, - { - "name": "minecraft:blue_candle_cake", - "id": -441 - }, - { - "name": "minecraft:blue_carpet", - "id": -607 - }, - { - "name": "minecraft:blue_concrete", - "id": -638 - }, - { - "name": "minecraft:blue_concrete_powder", - "id": -719 - }, - { - "name": "minecraft:blue_dye", - "id": 402 - }, - { - "name": "minecraft:blue_glazed_terracotta", - "id": 231 - }, - { - "name": "minecraft:blue_ice", - "id": -11 - }, - { - "name": "minecraft:blue_shulker_box", - "id": -623 - }, - { - "name": "minecraft:blue_stained_glass", - "id": -683 - }, - { - "name": "minecraft:blue_stained_glass_pane", - "id": -653 - }, - { - "name": "minecraft:blue_terracotta", - "id": -734 - }, - { - "name": "minecraft:blue_wool", - "id": -563 - }, - { - "name": "minecraft:boat", - "id": 716 - }, - { - "name": "minecraft:bone", - "id": 418 - }, - { - "name": "minecraft:bone_block", - "id": 216 - }, - { - "name": "minecraft:bone_meal", - "id": 414 - }, - { - "name": "minecraft:book", - "id": 390 - }, - { - "name": "minecraft:bookshelf", - "id": 47 - }, - { - "name": "minecraft:border_block", - "id": 212 - }, - { - "name": "minecraft:bordure_indented_banner_pattern", - "id": 594 - }, - { - "name": "minecraft:bow", - "id": 303 - }, - { - "name": "minecraft:bowl", - "id": 324 - }, - { - "name": "minecraft:brain_coral", - "id": -581 - }, - { - "name": "minecraft:bread", - "id": 262 - }, - { - "name": "minecraft:brewer_pottery_sherd", - "id": 668 - }, - { - "name": "minecraft:brewing_stand", - "id": 434 - }, - { - "name": "minecraft:brick", - "id": 386 - }, - { - "name": "minecraft:brick_block", - "id": 45 - }, - { - "name": "minecraft:brick_stairs", - "id": 108 - }, - { - "name": "minecraft:brown_candle", - "id": -425 - }, - { - "name": "minecraft:brown_candle_cake", - "id": -442 - }, - { - "name": "minecraft:brown_carpet", - "id": -608 - }, - { - "name": "minecraft:brown_concrete", - "id": -639 - }, - { - "name": "minecraft:brown_concrete_powder", - "id": -720 - }, - { - "name": "minecraft:brown_dye", - "id": 401 - }, - { - "name": "minecraft:brown_glazed_terracotta", - "id": 232 - }, - { - "name": "minecraft:brown_mushroom", - "id": 39 - }, - { - "name": "minecraft:brown_mushroom_block", - "id": 99 - }, - { - "name": "minecraft:brown_shulker_box", - "id": -624 - }, - { - "name": "minecraft:brown_stained_glass", - "id": -684 - }, - { - "name": "minecraft:brown_stained_glass_pane", - "id": -654 - }, - { - "name": "minecraft:brown_terracotta", - "id": -735 - }, - { - "name": "minecraft:brown_wool", - "id": -555 - }, - { - "name": "minecraft:brush", - "id": 684 - }, - { - "name": "minecraft:bubble_column", - "id": -160 - }, - { - "name": "minecraft:bubble_coral", - "id": -582 - }, - { - "name": "minecraft:bucket", - "id": 363 - }, - { - "name": "minecraft:budding_amethyst", - "id": -328 - }, - { - "name": "minecraft:burn_pottery_sherd", - "id": 669 - }, - { - "name": "minecraft:cactus", - "id": 81 - }, - { - "name": "minecraft:cake", - "id": 420 - }, - { - "name": "minecraft:calcite", - "id": -326 - }, - { - "name": "minecraft:calibrated_sculk_sensor", - "id": -580 - }, - { - "name": "minecraft:camel_spawn_egg", - "id": 663 - }, - { - "name": "minecraft:camera", - "id": 601 - }, - { - "name": "minecraft:campfire", - "id": 597 - }, - { - "name": "minecraft:candle", - "id": -412 - }, - { - "name": "minecraft:candle_cake", - "id": -429 - }, - { - "name": "minecraft:carpet", - "id": 705 - }, - { - "name": "minecraft:carrot", - "id": 280 - }, - { - "name": "minecraft:carrot_on_a_stick", - "id": 525 - }, - { - "name": "minecraft:carrots", - "id": 141 - }, - { - "name": "minecraft:cartography_table", - "id": -200 - }, - { - "name": "minecraft:carved_pumpkin", - "id": -155 - }, - { - "name": "minecraft:cat_spawn_egg", - "id": 491 - }, - { - "name": "minecraft:cauldron", - "id": 435 - }, - { - "name": "minecraft:cave_spider_spawn_egg", - "id": 460 - }, - { - "name": "minecraft:cave_vines", - "id": -322 - }, - { - "name": "minecraft:cave_vines_body_with_berries", - "id": -375 - }, - { - "name": "minecraft:cave_vines_head_with_berries", - "id": -376 - }, - { - "name": "minecraft:chain", - "id": 627 - }, - { - "name": "minecraft:chain_command_block", - "id": 189 - }, - { - "name": "minecraft:chainmail_boots", - "id": 345 - }, - { - "name": "minecraft:chainmail_chestplate", - "id": 343 - }, - { - "name": "minecraft:chainmail_helmet", - "id": 342 - }, - { - "name": "minecraft:chainmail_leggings", - "id": 344 - }, - { - "name": "minecraft:charcoal", - "id": 306 - }, - { - "name": "minecraft:chemical_heat", - "id": 192 - }, - { - "name": "minecraft:chemistry_table", - "id": 238 - }, - { - "name": "minecraft:cherry_boat", - "id": 657 - }, - { - "name": "minecraft:cherry_button", - "id": -530 - }, - { - "name": "minecraft:cherry_chest_boat", - "id": 658 - }, - { - "name": "minecraft:cherry_door", - "id": -531 - }, - { - "name": "minecraft:cherry_double_slab", - "id": -540 - }, - { - "name": "minecraft:cherry_fence", - "id": -532 - }, - { - "name": "minecraft:cherry_fence_gate", - "id": -533 - }, - { - "name": "minecraft:cherry_hanging_sign", - "id": -534 - }, - { - "name": "minecraft:cherry_leaves", - "id": -548 - }, - { - "name": "minecraft:cherry_log", - "id": -536 - }, - { - "name": "minecraft:cherry_planks", - "id": -537 - }, - { - "name": "minecraft:cherry_pressure_plate", - "id": -538 - }, - { - "name": "minecraft:cherry_sapling", - "id": -547 - }, - { - "name": "minecraft:cherry_sign", - "id": 659 - }, - { - "name": "minecraft:cherry_slab", - "id": -539 - }, - { - "name": "minecraft:cherry_stairs", - "id": -541 - }, - { - "name": "minecraft:cherry_standing_sign", - "id": -542 - }, - { - "name": "minecraft:cherry_trapdoor", - "id": -543 - }, - { - "name": "minecraft:cherry_wall_sign", - "id": -544 - }, - { - "name": "minecraft:cherry_wood", - "id": -546 - }, - { - "name": "minecraft:chest", - "id": 54 - }, - { - "name": "minecraft:chest_boat", - "id": 653 - }, - { - "name": "minecraft:chest_minecart", - "id": 392 - }, - { - "name": "minecraft:chicken", - "id": 276 - }, - { - "name": "minecraft:chicken_spawn_egg", - "id": 438 - }, - { - "name": "minecraft:chiseled_bookshelf", - "id": -526 - }, - { - "name": "minecraft:chiseled_copper", - "id": -760 - }, - { - "name": "minecraft:chiseled_deepslate", - "id": -395 - }, - { - "name": "minecraft:chiseled_nether_bricks", - "id": -302 - }, - { - "name": "minecraft:chiseled_polished_blackstone", - "id": -279 - }, - { - "name": "minecraft:chiseled_tuff", - "id": -753 - }, - { - "name": "minecraft:chiseled_tuff_bricks", - "id": -759 - }, - { - "name": "minecraft:chorus_flower", - "id": 200 - }, - { - "name": "minecraft:chorus_fruit", - "id": 566 - }, - { - "name": "minecraft:chorus_plant", - "id": 240 - }, - { - "name": "minecraft:clay", - "id": 82 - }, - { - "name": "minecraft:clay_ball", - "id": 387 - }, - { - "name": "minecraft:client_request_placeholder_block", - "id": -465 - }, - { - "name": "minecraft:clock", - "id": 396 - }, - { - "name": "minecraft:coal", - "id": 305 - }, - { - "name": "minecraft:coal_block", - "id": 173 - }, - { - "name": "minecraft:coal_ore", - "id": 16 - }, - { - "name": "minecraft:coast_armor_trim_smithing_template", - "id": 688 - }, - { - "name": "minecraft:cobbled_deepslate", - "id": -379 - }, - { - "name": "minecraft:cobbled_deepslate_double_slab", - "id": -396 - }, - { - "name": "minecraft:cobbled_deepslate_slab", - "id": -380 - }, - { - "name": "minecraft:cobbled_deepslate_stairs", - "id": -381 - }, - { - "name": "minecraft:cobbled_deepslate_wall", - "id": -382 - }, - { - "name": "minecraft:cobblestone", - "id": 4 - }, - { - "name": "minecraft:cobblestone_wall", - "id": 139 - }, - { - "name": "minecraft:cocoa", - "id": 127 - }, - { - "name": "minecraft:cocoa_beans", - "id": 415 - }, - { - "name": "minecraft:cod", - "id": 265 - }, - { - "name": "minecraft:cod_bucket", - "id": 367 - }, - { - "name": "minecraft:cod_spawn_egg", - "id": 483 - }, - { - "name": "minecraft:colored_torch_bp", - "id": 204 - }, - { - "name": "minecraft:colored_torch_rg", - "id": 202 - }, - { - "name": "minecraft:command_block", - "id": 137 - }, - { - "name": "minecraft:command_block_minecart", - "id": 571 - }, - { - "name": "minecraft:comparator", - "id": 530 - }, - { - "name": "minecraft:compass", - "id": 394 - }, - { - "name": "minecraft:composter", - "id": -213 - }, - { - "name": "minecraft:compound", - "id": 602 - }, - { - "name": "minecraft:concrete", - "id": 711 - }, - { - "name": "minecraft:concrete_powder", - "id": 712 - }, - { - "name": "minecraft:conduit", - "id": -157 - }, - { - "name": "minecraft:cooked_beef", - "id": 275 - }, - { - "name": "minecraft:cooked_chicken", - "id": 277 - }, - { - "name": "minecraft:cooked_cod", - "id": 269 - }, - { - "name": "minecraft:cooked_mutton", - "id": 559 - }, - { - "name": "minecraft:cooked_porkchop", - "id": 264 - }, - { - "name": "minecraft:cooked_rabbit", - "id": 290 - }, - { - "name": "minecraft:cooked_salmon", - "id": 270 - }, - { - "name": "minecraft:cookie", - "id": 272 - }, - { - "name": "minecraft:copper_block", - "id": -340 - }, - { - "name": "minecraft:copper_bulb", - "id": -776 - }, - { - "name": "minecraft:copper_door", - "id": -784 - }, - { - "name": "minecraft:copper_grate", - "id": -768 - }, - { - "name": "minecraft:copper_ingot", - "id": 512 - }, - { - "name": "minecraft:copper_ore", - "id": -311 - }, - { - "name": "minecraft:copper_trapdoor", - "id": -792 - }, - { - "name": "minecraft:coral", - "id": 709 - }, - { - "name": "minecraft:coral_block", - "id": -132 - }, - { - "name": "minecraft:coral_fan", - "id": -133 - }, - { - "name": "minecraft:coral_fan_dead", - "id": -134 - }, - { - "name": "minecraft:coral_fan_hang", - "id": -135 - }, - { - "name": "minecraft:coral_fan_hang2", - "id": -136 - }, - { - "name": "minecraft:coral_fan_hang3", - "id": -137 - }, - { - "name": "minecraft:cow_spawn_egg", - "id": 439 - }, - { - "name": "minecraft:cracked_deepslate_bricks", - "id": -410 - }, - { - "name": "minecraft:cracked_deepslate_tiles", - "id": -409 - }, - { - "name": "minecraft:cracked_nether_bricks", - "id": -303 - }, - { - "name": "minecraft:cracked_polished_blackstone_bricks", - "id": -280 - }, - { - "name": "minecraft:crafter", - "id": -313 - }, - { - "name": "minecraft:crafting_table", - "id": 58 - }, - { - "name": "minecraft:creeper_banner_pattern", - "id": 590 - }, - { - "name": "minecraft:creeper_spawn_egg", - "id": 444 - }, - { - "name": "minecraft:crimson_button", - "id": -260 - }, - { - "name": "minecraft:crimson_door", - "id": 624 - }, - { - "name": "minecraft:crimson_double_slab", - "id": -266 - }, - { - "name": "minecraft:crimson_fence", - "id": -256 - }, - { - "name": "minecraft:crimson_fence_gate", - "id": -258 - }, - { - "name": "minecraft:crimson_fungus", - "id": -228 - }, - { - "name": "minecraft:crimson_hanging_sign", - "id": -506 - }, - { - "name": "minecraft:crimson_hyphae", - "id": -299 - }, - { - "name": "minecraft:crimson_nylium", - "id": -232 - }, - { - "name": "minecraft:crimson_planks", - "id": -242 - }, - { - "name": "minecraft:crimson_pressure_plate", - "id": -262 - }, - { - "name": "minecraft:crimson_roots", - "id": -223 - }, - { - "name": "minecraft:crimson_sign", - "id": 622 - }, - { - "name": "minecraft:crimson_slab", - "id": -264 - }, - { - "name": "minecraft:crimson_stairs", - "id": -254 - }, - { - "name": "minecraft:crimson_standing_sign", - "id": -250 - }, - { - "name": "minecraft:crimson_stem", - "id": -225 - }, - { - "name": "minecraft:crimson_trapdoor", - "id": -246 - }, - { - "name": "minecraft:crimson_wall_sign", - "id": -252 - }, - { - "name": "minecraft:crossbow", - "id": 583 - }, - { - "name": "minecraft:crying_obsidian", - "id": -289 - }, - { - "name": "minecraft:cut_copper", - "id": -347 - }, - { - "name": "minecraft:cut_copper_slab", - "id": -361 - }, - { - "name": "minecraft:cut_copper_stairs", - "id": -354 - }, - { - "name": "minecraft:cyan_candle", - "id": -422 - }, - { - "name": "minecraft:cyan_candle_cake", - "id": -439 - }, - { - "name": "minecraft:cyan_carpet", - "id": -605 - }, - { - "name": "minecraft:cyan_concrete", - "id": -636 - }, - { - "name": "minecraft:cyan_concrete_powder", - "id": -717 - }, - { - "name": "minecraft:cyan_dye", - "id": 404 - }, - { - "name": "minecraft:cyan_glazed_terracotta", - "id": 229 - }, - { - "name": "minecraft:cyan_shulker_box", - "id": -621 - }, - { - "name": "minecraft:cyan_stained_glass", - "id": -681 - }, - { - "name": "minecraft:cyan_stained_glass_pane", - "id": -651 - }, - { - "name": "minecraft:cyan_terracotta", - "id": -732 - }, - { - "name": "minecraft:cyan_wool", - "id": -561 - }, - { - "name": "minecraft:danger_pottery_sherd", - "id": 670 - }, - { - "name": "minecraft:dark_oak_boat", - "id": 383 - }, - { - "name": "minecraft:dark_oak_button", - "id": -142 - }, - { - "name": "minecraft:dark_oak_chest_boat", - "id": 651 - }, - { - "name": "minecraft:dark_oak_door", - "id": 565 - }, - { - "name": "minecraft:dark_oak_fence", - "id": -577 - }, - { - "name": "minecraft:dark_oak_fence_gate", - "id": 186 - }, - { - "name": "minecraft:dark_oak_hanging_sign", - "id": -505 - }, - { - "name": "minecraft:dark_oak_log", - "id": -572 - }, - { - "name": "minecraft:dark_oak_planks", - "id": -743 - }, - { - "name": "minecraft:dark_oak_pressure_plate", - "id": -152 - }, - { - "name": "minecraft:dark_oak_sign", - "id": 588 - }, - { - "name": "minecraft:dark_oak_stairs", - "id": 164 - }, - { - "name": "minecraft:dark_oak_trapdoor", - "id": -147 - }, - { - "name": "minecraft:dark_prismarine_stairs", - "id": -3 - }, - { - "name": "minecraft:darkoak_standing_sign", - "id": -192 - }, - { - "name": "minecraft:darkoak_wall_sign", - "id": -193 - }, - { - "name": "minecraft:daylight_detector", - "id": 151 - }, - { - "name": "minecraft:daylight_detector_inverted", - "id": 178 - }, - { - "name": "minecraft:dead_brain_coral", - "id": -586 - }, - { - "name": "minecraft:dead_bubble_coral", - "id": -587 - }, - { - "name": "minecraft:dead_fire_coral", - "id": -588 - }, - { - "name": "minecraft:dead_horn_coral", - "id": -589 - }, - { - "name": "minecraft:dead_tube_coral", - "id": -585 - }, - { - "name": "minecraft:deadbush", - "id": 32 - }, - { - "name": "minecraft:decorated_pot", - "id": -551 - }, - { - "name": "minecraft:deepslate", - "id": -378 - }, - { - "name": "minecraft:deepslate_brick_double_slab", - "id": -399 - }, - { - "name": "minecraft:deepslate_brick_slab", - "id": -392 - }, - { - "name": "minecraft:deepslate_brick_stairs", - "id": -393 - }, - { - "name": "minecraft:deepslate_brick_wall", - "id": -394 - }, - { - "name": "minecraft:deepslate_bricks", - "id": -391 - }, - { - "name": "minecraft:deepslate_coal_ore", - "id": -406 - }, - { - "name": "minecraft:deepslate_copper_ore", - "id": -408 - }, - { - "name": "minecraft:deepslate_diamond_ore", - "id": -405 - }, - { - "name": "minecraft:deepslate_emerald_ore", - "id": -407 - }, - { - "name": "minecraft:deepslate_gold_ore", - "id": -402 - }, - { - "name": "minecraft:deepslate_iron_ore", - "id": -401 - }, - { - "name": "minecraft:deepslate_lapis_ore", - "id": -400 - }, - { - "name": "minecraft:deepslate_redstone_ore", - "id": -403 - }, - { - "name": "minecraft:deepslate_tile_double_slab", - "id": -398 - }, - { - "name": "minecraft:deepslate_tile_slab", - "id": -388 - }, - { - "name": "minecraft:deepslate_tile_stairs", - "id": -389 - }, - { - "name": "minecraft:deepslate_tile_wall", - "id": -390 - }, - { - "name": "minecraft:deepslate_tiles", - "id": -387 - }, - { - "name": "minecraft:deny", - "id": 211 - }, - { - "name": "minecraft:detector_rail", - "id": 28 - }, - { - "name": "minecraft:diamond", - "id": 307 - }, - { - "name": "minecraft:diamond_axe", - "id": 322 - }, - { - "name": "minecraft:diamond_block", - "id": 57 - }, - { - "name": "minecraft:diamond_boots", - "id": 353 - }, - { - "name": "minecraft:diamond_chestplate", - "id": 351 - }, - { - "name": "minecraft:diamond_helmet", - "id": 350 - }, - { - "name": "minecraft:diamond_hoe", - "id": 335 - }, - { - "name": "minecraft:diamond_horse_armor", - "id": 541 - }, - { - "name": "minecraft:diamond_leggings", - "id": 352 - }, - { - "name": "minecraft:diamond_ore", - "id": 56 - }, - { - "name": "minecraft:diamond_pickaxe", - "id": 321 - }, - { - "name": "minecraft:diamond_shovel", - "id": 320 - }, - { - "name": "minecraft:diamond_sword", - "id": 319 - }, - { - "name": "minecraft:diorite", - "id": -592 - }, - { - "name": "minecraft:diorite_stairs", - "id": -170 - }, - { - "name": "minecraft:dirt", - "id": 3 - }, - { - "name": "minecraft:dirt_with_roots", - "id": -318 - }, - { - "name": "minecraft:disc_fragment_5", - "id": 645 - }, - { - "name": "minecraft:dispenser", - "id": 23 - }, - { - "name": "minecraft:dolphin_spawn_egg", - "id": 487 - }, - { - "name": "minecraft:donkey_spawn_egg", - "id": 468 - }, - { - "name": "minecraft:double_cut_copper_slab", - "id": -368 - }, - { - "name": "minecraft:double_plant", - "id": 175 - }, - { - "name": "minecraft:double_stone_block_slab", - "id": 43 - }, - { - "name": "minecraft:double_stone_block_slab2", - "id": 181 - }, - { - "name": "minecraft:double_stone_block_slab3", - "id": -167 - }, - { - "name": "minecraft:double_stone_block_slab4", - "id": -168 - }, - { - "name": "minecraft:double_wooden_slab", - "id": 157 - }, - { - "name": "minecraft:dragon_breath", - "id": 568 - }, - { - "name": "minecraft:dragon_egg", - "id": 122 - }, - { - "name": "minecraft:dried_kelp", - "id": 271 - }, - { - "name": "minecraft:dried_kelp_block", - "id": -139 - }, - { - "name": "minecraft:dripstone_block", - "id": -317 - }, - { - "name": "minecraft:dropper", - "id": 125 - }, - { - "name": "minecraft:drowned_spawn_egg", - "id": 486 - }, - { - "name": "minecraft:dune_armor_trim_smithing_template", - "id": 687 - }, - { - "name": "minecraft:dye", - "id": 717 - }, - { - "name": "minecraft:echo_shard", - "id": 655 - }, - { - "name": "minecraft:egg", - "id": 393 - }, - { - "name": "minecraft:elder_guardian_spawn_egg", - "id": 474 - }, - { - "name": "minecraft:element_0", - "id": 36 - }, - { - "name": "minecraft:element_1", - "id": -12 - }, - { - "name": "minecraft:element_10", - "id": -21 - }, - { - "name": "minecraft:element_100", - "id": -111 - }, - { - "name": "minecraft:element_101", - "id": -112 - }, - { - "name": "minecraft:element_102", - "id": -113 - }, - { - "name": "minecraft:element_103", - "id": -114 - }, - { - "name": "minecraft:element_104", - "id": -115 - }, - { - "name": "minecraft:element_105", - "id": -116 - }, - { - "name": "minecraft:element_106", - "id": -117 - }, - { - "name": "minecraft:element_107", - "id": -118 - }, - { - "name": "minecraft:element_108", - "id": -119 - }, - { - "name": "minecraft:element_109", - "id": -120 - }, - { - "name": "minecraft:element_11", - "id": -22 - }, - { - "name": "minecraft:element_110", - "id": -121 - }, - { - "name": "minecraft:element_111", - "id": -122 - }, - { - "name": "minecraft:element_112", - "id": -123 - }, - { - "name": "minecraft:element_113", - "id": -124 - }, - { - "name": "minecraft:element_114", - "id": -125 - }, - { - "name": "minecraft:element_115", - "id": -126 - }, - { - "name": "minecraft:element_116", - "id": -127 - }, - { - "name": "minecraft:element_117", - "id": -128 - }, - { - "name": "minecraft:element_118", - "id": -129 - }, - { - "name": "minecraft:element_12", - "id": -23 - }, - { - "name": "minecraft:element_13", - "id": -24 - }, - { - "name": "minecraft:element_14", - "id": -25 - }, - { - "name": "minecraft:element_15", - "id": -26 - }, - { - "name": "minecraft:element_16", - "id": -27 - }, - { - "name": "minecraft:element_17", - "id": -28 - }, - { - "name": "minecraft:element_18", - "id": -29 - }, - { - "name": "minecraft:element_19", - "id": -30 - }, - { - "name": "minecraft:element_2", - "id": -13 - }, - { - "name": "minecraft:element_20", - "id": -31 - }, - { - "name": "minecraft:element_21", - "id": -32 - }, - { - "name": "minecraft:element_22", - "id": -33 - }, - { - "name": "minecraft:element_23", - "id": -34 - }, - { - "name": "minecraft:element_24", - "id": -35 - }, - { - "name": "minecraft:element_25", - "id": -36 - }, - { - "name": "minecraft:element_26", - "id": -37 - }, - { - "name": "minecraft:element_27", - "id": -38 - }, - { - "name": "minecraft:element_28", - "id": -39 - }, - { - "name": "minecraft:element_29", - "id": -40 - }, - { - "name": "minecraft:element_3", - "id": -14 - }, - { - "name": "minecraft:element_30", - "id": -41 - }, - { - "name": "minecraft:element_31", - "id": -42 - }, - { - "name": "minecraft:element_32", - "id": -43 - }, - { - "name": "minecraft:element_33", - "id": -44 - }, - { - "name": "minecraft:element_34", - "id": -45 - }, - { - "name": "minecraft:element_35", - "id": -46 - }, - { - "name": "minecraft:element_36", - "id": -47 - }, - { - "name": "minecraft:element_37", - "id": -48 - }, - { - "name": "minecraft:element_38", - "id": -49 - }, - { - "name": "minecraft:element_39", - "id": -50 - }, - { - "name": "minecraft:element_4", - "id": -15 - }, - { - "name": "minecraft:element_40", - "id": -51 - }, - { - "name": "minecraft:element_41", - "id": -52 - }, - { - "name": "minecraft:element_42", - "id": -53 - }, - { - "name": "minecraft:element_43", - "id": -54 - }, - { - "name": "minecraft:element_44", - "id": -55 - }, - { - "name": "minecraft:element_45", - "id": -56 - }, - { - "name": "minecraft:element_46", - "id": -57 - }, - { - "name": "minecraft:element_47", - "id": -58 - }, - { - "name": "minecraft:element_48", - "id": -59 - }, - { - "name": "minecraft:element_49", - "id": -60 - }, - { - "name": "minecraft:element_5", - "id": -16 - }, - { - "name": "minecraft:element_50", - "id": -61 - }, - { - "name": "minecraft:element_51", - "id": -62 - }, - { - "name": "minecraft:element_52", - "id": -63 - }, - { - "name": "minecraft:element_53", - "id": -64 - }, - { - "name": "minecraft:element_54", - "id": -65 - }, - { - "name": "minecraft:element_55", - "id": -66 - }, - { - "name": "minecraft:element_56", - "id": -67 - }, - { - "name": "minecraft:element_57", - "id": -68 - }, - { - "name": "minecraft:element_58", - "id": -69 - }, - { - "name": "minecraft:element_59", - "id": -70 - }, - { - "name": "minecraft:element_6", - "id": -17 - }, - { - "name": "minecraft:element_60", - "id": -71 - }, - { - "name": "minecraft:element_61", - "id": -72 - }, - { - "name": "minecraft:element_62", - "id": -73 - }, - { - "name": "minecraft:element_63", - "id": -74 - }, - { - "name": "minecraft:element_64", - "id": -75 - }, - { - "name": "minecraft:element_65", - "id": -76 - }, - { - "name": "minecraft:element_66", - "id": -77 - }, - { - "name": "minecraft:element_67", - "id": -78 - }, - { - "name": "minecraft:element_68", - "id": -79 - }, - { - "name": "minecraft:element_69", - "id": -80 - }, - { - "name": "minecraft:element_7", - "id": -18 - }, - { - "name": "minecraft:element_70", - "id": -81 - }, - { - "name": "minecraft:element_71", - "id": -82 - }, - { - "name": "minecraft:element_72", - "id": -83 - }, - { - "name": "minecraft:element_73", - "id": -84 - }, - { - "name": "minecraft:element_74", - "id": -85 - }, - { - "name": "minecraft:element_75", - "id": -86 - }, - { - "name": "minecraft:element_76", - "id": -87 - }, - { - "name": "minecraft:element_77", - "id": -88 - }, - { - "name": "minecraft:element_78", - "id": -89 - }, - { - "name": "minecraft:element_79", - "id": -90 - }, - { - "name": "minecraft:element_8", - "id": -19 - }, - { - "name": "minecraft:element_80", - "id": -91 - }, - { - "name": "minecraft:element_81", - "id": -92 - }, - { - "name": "minecraft:element_82", - "id": -93 - }, - { - "name": "minecraft:element_83", - "id": -94 - }, - { - "name": "minecraft:element_84", - "id": -95 - }, - { - "name": "minecraft:element_85", - "id": -96 - }, - { - "name": "minecraft:element_86", - "id": -97 - }, - { - "name": "minecraft:element_87", - "id": -98 - }, - { - "name": "minecraft:element_88", - "id": -99 - }, - { - "name": "minecraft:element_89", - "id": -100 - }, - { - "name": "minecraft:element_9", - "id": -20 - }, - { - "name": "minecraft:element_90", - "id": -101 - }, - { - "name": "minecraft:element_91", - "id": -102 - }, - { - "name": "minecraft:element_92", - "id": -103 - }, - { - "name": "minecraft:element_93", - "id": -104 - }, - { - "name": "minecraft:element_94", - "id": -105 - }, - { - "name": "minecraft:element_95", - "id": -106 - }, - { - "name": "minecraft:element_96", - "id": -107 - }, - { - "name": "minecraft:element_97", - "id": -108 - }, - { - "name": "minecraft:element_98", - "id": -109 - }, - { - "name": "minecraft:element_99", - "id": -110 - }, - { - "name": "minecraft:elytra", - "id": 572 - }, - { - "name": "minecraft:emerald", - "id": 520 - }, - { - "name": "minecraft:emerald_block", - "id": 133 - }, - { - "name": "minecraft:emerald_ore", - "id": 129 - }, - { - "name": "minecraft:empty_map", - "id": 523 - }, - { - "name": "minecraft:enchanted_book", - "id": 529 - }, - { - "name": "minecraft:enchanted_golden_apple", - "id": 260 - }, - { - "name": "minecraft:enchanting_table", - "id": 116 - }, - { - "name": "minecraft:end_brick_stairs", - "id": -178 - }, - { - "name": "minecraft:end_bricks", - "id": 206 - }, - { - "name": "minecraft:end_crystal", - "id": 720 - }, - { - "name": "minecraft:end_gateway", - "id": 209 - }, - { - "name": "minecraft:end_portal", - "id": 119 - }, - { - "name": "minecraft:end_portal_frame", - "id": 120 - }, - { - "name": "minecraft:end_rod", - "id": 208 - }, - { - "name": "minecraft:end_stone", - "id": 121 - }, - { - "name": "minecraft:ender_chest", - "id": 130 - }, - { - "name": "minecraft:ender_dragon_spawn_egg", - "id": 509 - }, - { - "name": "minecraft:ender_eye", - "id": 436 - }, - { - "name": "minecraft:ender_pearl", - "id": 425 - }, - { - "name": "minecraft:enderman_spawn_egg", - "id": 445 - }, - { - "name": "minecraft:endermite_spawn_egg", - "id": 463 - }, - { - "name": "minecraft:evoker_spawn_egg", - "id": 478 - }, - { - "name": "minecraft:experience_bottle", - "id": 516 - }, - { - "name": "minecraft:explorer_pottery_sherd", - "id": 671 - }, - { - "name": "minecraft:exposed_chiseled_copper", - "id": -761 - }, - { - "name": "minecraft:exposed_copper", - "id": -341 - }, - { - "name": "minecraft:exposed_copper_bulb", - "id": -777 - }, - { - "name": "minecraft:exposed_copper_door", - "id": -785 - }, - { - "name": "minecraft:exposed_copper_grate", - "id": -769 - }, - { - "name": "minecraft:exposed_copper_trapdoor", - "id": -793 - }, - { - "name": "minecraft:exposed_cut_copper", - "id": -348 - }, - { - "name": "minecraft:exposed_cut_copper_slab", - "id": -362 - }, - { - "name": "minecraft:exposed_cut_copper_stairs", - "id": -355 - }, - { - "name": "minecraft:exposed_double_cut_copper_slab", - "id": -369 - }, - { - "name": "minecraft:eye_armor_trim_smithing_template", - "id": 691 - }, - { - "name": "minecraft:farmland", - "id": 60 - }, - { - "name": "minecraft:feather", - "id": 330 - }, - { - "name": "minecraft:fence", - "id": 707 - }, - { - "name": "minecraft:fence_gate", - "id": 107 - }, - { - "name": "minecraft:fermented_spider_eye", - "id": 431 - }, - { - "name": "minecraft:field_masoned_banner_pattern", - "id": 593 - }, - { - "name": "minecraft:filled_map", - "id": 423 - }, - { - "name": "minecraft:fire", - "id": 51 - }, - { - "name": "minecraft:fire_charge", - "id": 517 - }, - { - "name": "minecraft:fire_coral", - "id": -583 - }, - { - "name": "minecraft:firework_rocket", - "id": 527 - }, - { - "name": "minecraft:firework_star", - "id": 528 - }, - { - "name": "minecraft:fishing_rod", - "id": 395 - }, - { - "name": "minecraft:fletching_table", - "id": -201 - }, - { - "name": "minecraft:flint", - "id": 359 - }, - { - "name": "minecraft:flint_and_steel", - "id": 302 - }, - { - "name": "minecraft:flower_banner_pattern", - "id": 589 - }, - { - "name": "minecraft:flower_pot", - "id": 522 - }, - { - "name": "minecraft:flowering_azalea", - "id": -338 - }, - { - "name": "minecraft:flowing_lava", - "id": 10 - }, - { - "name": "minecraft:flowing_water", - "id": 8 - }, - { - "name": "minecraft:fox_spawn_egg", - "id": 493 - }, - { - "name": "minecraft:frame", - "id": 521 - }, - { - "name": "minecraft:friend_pottery_sherd", - "id": 672 - }, - { - "name": "minecraft:frog_spawn", - "id": -468 - }, - { - "name": "minecraft:frog_spawn_egg", - "id": 636 - }, - { - "name": "minecraft:frosted_ice", - "id": 207 - }, - { - "name": "minecraft:furnace", - "id": 61 - }, - { - "name": "minecraft:ghast_spawn_egg", - "id": 457 - }, - { - "name": "minecraft:ghast_tear", - "id": 427 - }, - { - "name": "minecraft:gilded_blackstone", - "id": -281 - }, - { - "name": "minecraft:glass", - "id": 20 - }, - { - "name": "minecraft:glass_bottle", - "id": 430 - }, - { - "name": "minecraft:glass_pane", - "id": 102 - }, - { - "name": "minecraft:glistering_melon_slice", - "id": 437 - }, - { - "name": "minecraft:globe_banner_pattern", - "id": 596 - }, - { - "name": "minecraft:glow_berries", - "id": 721 - }, - { - "name": "minecraft:glow_frame", - "id": 631 - }, - { - "name": "minecraft:glow_ink_sac", - "id": 511 - }, - { - "name": "minecraft:glow_lichen", - "id": -411 - }, - { - "name": "minecraft:glow_squid_spawn_egg", - "id": 506 - }, - { - "name": "minecraft:glow_stick", - "id": 609 - }, - { - "name": "minecraft:glowingobsidian", - "id": 246 - }, - { - "name": "minecraft:glowstone", - "id": 89 - }, - { - "name": "minecraft:glowstone_dust", - "id": 397 - }, - { - "name": "minecraft:goat_horn", - "id": 635 - }, - { - "name": "minecraft:goat_spawn_egg", - "id": 505 - }, - { - "name": "minecraft:gold_block", - "id": 41 - }, - { - "name": "minecraft:gold_ingot", - "id": 309 - }, - { - "name": "minecraft:gold_nugget", - "id": 428 - }, - { - "name": "minecraft:gold_ore", - "id": 14 - }, - { - "name": "minecraft:golden_apple", - "id": 259 - }, - { - "name": "minecraft:golden_axe", - "id": 328 - }, - { - "name": "minecraft:golden_boots", - "id": 357 - }, - { - "name": "minecraft:golden_carrot", - "id": 284 - }, - { - "name": "minecraft:golden_chestplate", - "id": 355 - }, - { - "name": "minecraft:golden_helmet", - "id": 354 - }, - { - "name": "minecraft:golden_hoe", - "id": 336 - }, - { - "name": "minecraft:golden_horse_armor", - "id": 540 - }, - { - "name": "minecraft:golden_leggings", - "id": 356 - }, - { - "name": "minecraft:golden_pickaxe", - "id": 327 - }, - { - "name": "minecraft:golden_rail", - "id": 27 - }, - { - "name": "minecraft:golden_shovel", - "id": 326 - }, - { - "name": "minecraft:golden_sword", - "id": 325 - }, - { - "name": "minecraft:granite", - "id": -590 - }, - { - "name": "minecraft:granite_stairs", - "id": -169 - }, - { - "name": "minecraft:grass", - "id": 2 - }, - { - "name": "minecraft:grass_path", - "id": 198 - }, - { - "name": "minecraft:gravel", - "id": 13 - }, - { - "name": "minecraft:gray_candle", - "id": -420 - }, - { - "name": "minecraft:gray_candle_cake", - "id": -437 - }, - { - "name": "minecraft:gray_carpet", - "id": -603 - }, - { - "name": "minecraft:gray_concrete", - "id": -634 - }, - { - "name": "minecraft:gray_concrete_powder", - "id": -715 - }, - { - "name": "minecraft:gray_dye", - "id": 406 - }, - { - "name": "minecraft:gray_glazed_terracotta", - "id": 227 - }, - { - "name": "minecraft:gray_shulker_box", - "id": -619 - }, - { - "name": "minecraft:gray_stained_glass", - "id": -679 - }, - { - "name": "minecraft:gray_stained_glass_pane", - "id": -649 - }, - { - "name": "minecraft:gray_terracotta", - "id": -730 - }, - { - "name": "minecraft:gray_wool", - "id": -553 - }, - { - "name": "minecraft:green_candle", - "id": -426 - }, - { - "name": "minecraft:green_candle_cake", - "id": -443 - }, - { - "name": "minecraft:green_carpet", - "id": -609 - }, - { - "name": "minecraft:green_concrete", - "id": -640 - }, - { - "name": "minecraft:green_concrete_powder", - "id": -721 - }, - { - "name": "minecraft:green_dye", - "id": 400 - }, - { - "name": "minecraft:green_glazed_terracotta", - "id": 233 - }, - { - "name": "minecraft:green_shulker_box", - "id": -625 - }, - { - "name": "minecraft:green_stained_glass", - "id": -685 - }, - { - "name": "minecraft:green_stained_glass_pane", - "id": -655 - }, - { - "name": "minecraft:green_terracotta", - "id": -736 - }, - { - "name": "minecraft:green_wool", - "id": -560 - }, - { - "name": "minecraft:grindstone", - "id": -195 - }, - { - "name": "minecraft:guardian_spawn_egg", - "id": 464 - }, - { - "name": "minecraft:gunpowder", - "id": 331 - }, - { - "name": "minecraft:hanging_roots", - "id": -319 - }, - { - "name": "minecraft:hard_glass", - "id": 253 - }, - { - "name": "minecraft:hard_glass_pane", - "id": 190 - }, - { - "name": "minecraft:hard_stained_glass", - "id": 254 - }, - { - "name": "minecraft:hard_stained_glass_pane", - "id": 191 - }, - { - "name": "minecraft:hardened_clay", - "id": 172 - }, - { - "name": "minecraft:hay_block", - "id": 170 - }, - { - "name": "minecraft:heart_of_the_sea", - "id": 579 - }, - { - "name": "minecraft:heart_pottery_sherd", - "id": 673 - }, - { - "name": "minecraft:heartbreak_pottery_sherd", - "id": 674 - }, - { - "name": "minecraft:heavy_weighted_pressure_plate", - "id": 148 - }, - { - "name": "minecraft:hoglin_spawn_egg", - "id": 499 - }, - { - "name": "minecraft:honey_block", - "id": -220 - }, - { - "name": "minecraft:honey_bottle", - "id": 600 - }, - { - "name": "minecraft:honeycomb", - "id": 599 - }, - { - "name": "minecraft:honeycomb_block", - "id": -221 - }, - { - "name": "minecraft:hopper", - "id": 535 - }, - { - "name": "minecraft:hopper_minecart", - "id": 534 - }, - { - "name": "minecraft:horn_coral", - "id": -584 - }, - { - "name": "minecraft:horse_spawn_egg", - "id": 461 - }, - { - "name": "minecraft:host_armor_trim_smithing_template", - "id": 701 - }, - { - "name": "minecraft:howl_pottery_sherd", - "id": 675 - }, - { - "name": "minecraft:husk_spawn_egg", - "id": 466 - }, - { - "name": "minecraft:ice", - "id": 79 - }, - { - "name": "minecraft:ice_bomb", - "id": 603 - }, - { - "name": "minecraft:infested_deepslate", - "id": -454 - }, - { - "name": "minecraft:info_update", - "id": 248 - }, - { - "name": "minecraft:info_update2", - "id": 249 - }, - { - "name": "minecraft:ink_sac", - "id": 416 - }, - { - "name": "minecraft:invisible_bedrock", - "id": 95 - }, - { - "name": "minecraft:iron_axe", - "id": 301 - }, - { - "name": "minecraft:iron_bars", - "id": 101 - }, - { - "name": "minecraft:iron_block", - "id": 42 - }, - { - "name": "minecraft:iron_boots", - "id": 349 - }, - { - "name": "minecraft:iron_chestplate", - "id": 347 - }, - { - "name": "minecraft:iron_door", - "id": 375 - }, - { - "name": "minecraft:iron_golem_spawn_egg", - "id": 507 - }, - { - "name": "minecraft:iron_helmet", - "id": 346 - }, - { - "name": "minecraft:iron_hoe", - "id": 334 - }, - { - "name": "minecraft:iron_horse_armor", - "id": 539 - }, - { - "name": "minecraft:iron_ingot", - "id": 308 - }, - { - "name": "minecraft:iron_leggings", - "id": 348 - }, - { - "name": "minecraft:iron_nugget", - "id": 577 - }, - { - "name": "minecraft:iron_ore", - "id": 15 - }, - { - "name": "minecraft:iron_pickaxe", - "id": 300 - }, - { - "name": "minecraft:iron_shovel", - "id": 299 - }, - { - "name": "minecraft:iron_sword", - "id": 310 - }, - { - "name": "minecraft:iron_trapdoor", - "id": 167 - }, - { - "name": "minecraft:item.acacia_door", - "id": 196 - }, - { - "name": "minecraft:item.bed", - "id": 26 - }, - { - "name": "minecraft:item.beetroot", - "id": 244 - }, - { - "name": "minecraft:item.birch_door", - "id": 194 - }, - { - "name": "minecraft:item.brewing_stand", - "id": 117 - }, - { - "name": "minecraft:item.cake", - "id": 92 - }, - { - "name": "minecraft:item.camera", - "id": 242 - }, - { - "name": "minecraft:item.campfire", - "id": -209 - }, - { - "name": "minecraft:item.cauldron", - "id": 118 - }, - { - "name": "minecraft:item.chain", - "id": -286 - }, - { - "name": "minecraft:item.crimson_door", - "id": -244 - }, - { - "name": "minecraft:item.dark_oak_door", - "id": 197 - }, - { - "name": "minecraft:item.flower_pot", - "id": 140 - }, - { - "name": "minecraft:item.frame", - "id": 199 - }, - { - "name": "minecraft:item.glow_frame", - "id": -339 - }, - { - "name": "minecraft:item.hopper", - "id": 154 - }, - { - "name": "minecraft:item.iron_door", - "id": 71 - }, - { - "name": "minecraft:item.jungle_door", - "id": 195 - }, - { - "name": "minecraft:item.kelp", - "id": -138 - }, - { - "name": "minecraft:item.mangrove_door", - "id": -493 - }, - { - "name": "minecraft:item.nether_sprouts", - "id": -238 - }, - { - "name": "minecraft:item.nether_wart", - "id": 115 - }, - { - "name": "minecraft:item.reeds", - "id": 83 - }, - { - "name": "minecraft:item.skull", - "id": 144 - }, - { - "name": "minecraft:item.soul_campfire", - "id": -290 - }, - { - "name": "minecraft:item.spruce_door", - "id": 193 - }, - { - "name": "minecraft:item.warped_door", - "id": -245 - }, - { - "name": "minecraft:item.wheat", - "id": 59 - }, - { - "name": "minecraft:item.wooden_door", - "id": 64 - }, - { - "name": "minecraft:jigsaw", - "id": -211 - }, - { - "name": "minecraft:jukebox", - "id": 84 - }, - { - "name": "minecraft:jungle_boat", - "id": 380 - }, - { - "name": "minecraft:jungle_button", - "id": -143 - }, - { - "name": "minecraft:jungle_chest_boat", - "id": 648 - }, - { - "name": "minecraft:jungle_door", - "id": 563 - }, - { - "name": "minecraft:jungle_fence", - "id": -578 - }, - { - "name": "minecraft:jungle_fence_gate", - "id": 185 - }, - { - "name": "minecraft:jungle_hanging_sign", - "id": -503 - }, - { - "name": "minecraft:jungle_log", - "id": -571 - }, - { - "name": "minecraft:jungle_planks", - "id": -741 - }, - { - "name": "minecraft:jungle_pressure_plate", - "id": -153 - }, - { - "name": "minecraft:jungle_sign", - "id": 586 - }, - { - "name": "minecraft:jungle_stairs", - "id": 136 - }, - { - "name": "minecraft:jungle_standing_sign", - "id": -188 - }, - { - "name": "minecraft:jungle_trapdoor", - "id": -148 - }, - { - "name": "minecraft:jungle_wall_sign", - "id": -189 - }, - { - "name": "minecraft:kelp", - "id": 385 - }, - { - "name": "minecraft:ladder", - "id": 65 - }, - { - "name": "minecraft:lantern", - "id": -208 - }, - { - "name": "minecraft:lapis_block", - "id": 22 - }, - { - "name": "minecraft:lapis_lazuli", - "id": 417 - }, - { - "name": "minecraft:lapis_ore", - "id": 21 - }, - { - "name": "minecraft:large_amethyst_bud", - "id": -330 - }, - { - "name": "minecraft:lava", - "id": 11 - }, - { - "name": "minecraft:lava_bucket", - "id": 366 - }, - { - "name": "minecraft:lead", - "id": 555 - }, - { - "name": "minecraft:leather", - "id": 384 - }, - { - "name": "minecraft:leather_boots", - "id": 341 - }, - { - "name": "minecraft:leather_chestplate", - "id": 339 - }, - { - "name": "minecraft:leather_helmet", - "id": 338 - }, - { - "name": "minecraft:leather_horse_armor", - "id": 538 - }, - { - "name": "minecraft:leather_leggings", - "id": 340 - }, - { - "name": "minecraft:leaves", - "id": 18 - }, - { - "name": "minecraft:leaves2", - "id": 161 - }, - { - "name": "minecraft:lectern", - "id": -194 - }, - { - "name": "minecraft:lever", - "id": 69 - }, - { - "name": "minecraft:light_block", - "id": -215 - }, - { - "name": "minecraft:light_blue_candle", - "id": -416 - }, - { - "name": "minecraft:light_blue_candle_cake", - "id": -433 - }, - { - "name": "minecraft:light_blue_carpet", - "id": -599 - }, - { - "name": "minecraft:light_blue_concrete", - "id": -630 - }, - { - "name": "minecraft:light_blue_concrete_powder", - "id": -711 - }, - { - "name": "minecraft:light_blue_dye", - "id": 410 - }, - { - "name": "minecraft:light_blue_glazed_terracotta", - "id": 223 - }, - { - "name": "minecraft:light_blue_shulker_box", - "id": -615 - }, - { - "name": "minecraft:light_blue_stained_glass", - "id": -675 - }, - { - "name": "minecraft:light_blue_stained_glass_pane", - "id": -645 - }, - { - "name": "minecraft:light_blue_terracotta", - "id": -726 - }, - { - "name": "minecraft:light_blue_wool", - "id": -562 - }, - { - "name": "minecraft:light_gray_candle", - "id": -421 - }, - { - "name": "minecraft:light_gray_candle_cake", - "id": -438 - }, - { - "name": "minecraft:light_gray_carpet", - "id": -604 - }, - { - "name": "minecraft:light_gray_concrete", - "id": -635 - }, - { - "name": "minecraft:light_gray_concrete_powder", - "id": -716 - }, - { - "name": "minecraft:light_gray_dye", - "id": 405 - }, - { - "name": "minecraft:light_gray_shulker_box", - "id": -620 - }, - { - "name": "minecraft:light_gray_stained_glass", - "id": -680 - }, - { - "name": "minecraft:light_gray_stained_glass_pane", - "id": -650 - }, - { - "name": "minecraft:light_gray_terracotta", - "id": -731 - }, - { - "name": "minecraft:light_gray_wool", - "id": -552 - }, - { - "name": "minecraft:light_weighted_pressure_plate", - "id": 147 - }, - { - "name": "minecraft:lightning_rod", - "id": -312 - }, - { - "name": "minecraft:lime_candle", - "id": -418 - }, - { - "name": "minecraft:lime_candle_cake", - "id": -435 - }, - { - "name": "minecraft:lime_carpet", - "id": -601 - }, - { - "name": "minecraft:lime_concrete", - "id": -632 - }, - { - "name": "minecraft:lime_concrete_powder", - "id": -713 - }, - { - "name": "minecraft:lime_dye", - "id": 408 - }, - { - "name": "minecraft:lime_glazed_terracotta", - "id": 225 - }, - { - "name": "minecraft:lime_shulker_box", - "id": -617 - }, - { - "name": "minecraft:lime_stained_glass", - "id": -677 - }, - { - "name": "minecraft:lime_stained_glass_pane", - "id": -647 - }, - { - "name": "minecraft:lime_terracotta", - "id": -728 - }, - { - "name": "minecraft:lime_wool", - "id": -559 - }, - { - "name": "minecraft:lingering_potion", - "id": 570 - }, - { - "name": "minecraft:lit_blast_furnace", - "id": -214 - }, - { - "name": "minecraft:lit_deepslate_redstone_ore", - "id": -404 - }, - { - "name": "minecraft:lit_furnace", - "id": 62 - }, - { - "name": "minecraft:lit_pumpkin", - "id": 91 - }, - { - "name": "minecraft:lit_redstone_lamp", - "id": 124 - }, - { - "name": "minecraft:lit_redstone_ore", - "id": 74 - }, - { - "name": "minecraft:lit_smoker", - "id": -199 - }, - { - "name": "minecraft:llama_spawn_egg", - "id": 476 - }, - { - "name": "minecraft:lodestone", - "id": -222 - }, - { - "name": "minecraft:lodestone_compass", - "id": 610 - }, - { - "name": "minecraft:log", - "id": 706 - }, - { - "name": "minecraft:log2", - "id": 710 - }, - { - "name": "minecraft:loom", - "id": -204 - }, - { - "name": "minecraft:magenta_candle", - "id": -415 - }, - { - "name": "minecraft:magenta_candle_cake", - "id": -432 - }, - { - "name": "minecraft:magenta_carpet", - "id": -598 - }, - { - "name": "minecraft:magenta_concrete", - "id": -629 - }, - { - "name": "minecraft:magenta_concrete_powder", - "id": -710 - }, - { - "name": "minecraft:magenta_dye", - "id": 411 - }, - { - "name": "minecraft:magenta_glazed_terracotta", - "id": 222 - }, - { - "name": "minecraft:magenta_shulker_box", - "id": -614 - }, - { - "name": "minecraft:magenta_stained_glass", - "id": -674 - }, - { - "name": "minecraft:magenta_stained_glass_pane", - "id": -644 - }, - { - "name": "minecraft:magenta_terracotta", - "id": -725 - }, - { - "name": "minecraft:magenta_wool", - "id": -565 - }, - { - "name": "minecraft:magma", - "id": 213 - }, - { - "name": "minecraft:magma_cream", - "id": 433 - }, - { - "name": "minecraft:magma_cube_spawn_egg", - "id": 458 - }, - { - "name": "minecraft:mangrove_boat", - "id": 643 - }, - { - "name": "minecraft:mangrove_button", - "id": -487 - }, - { - "name": "minecraft:mangrove_chest_boat", - "id": 652 - }, - { - "name": "minecraft:mangrove_door", - "id": 641 - }, - { - "name": "minecraft:mangrove_double_slab", - "id": -499 - }, - { - "name": "minecraft:mangrove_fence", - "id": -491 - }, - { - "name": "minecraft:mangrove_fence_gate", - "id": -492 - }, - { - "name": "minecraft:mangrove_hanging_sign", - "id": -508 - }, - { - "name": "minecraft:mangrove_leaves", - "id": -472 - }, - { - "name": "minecraft:mangrove_log", - "id": -484 - }, - { - "name": "minecraft:mangrove_planks", - "id": -486 - }, - { - "name": "minecraft:mangrove_pressure_plate", - "id": -490 - }, - { - "name": "minecraft:mangrove_propagule", - "id": -474 - }, - { - "name": "minecraft:mangrove_roots", - "id": -482 - }, - { - "name": "minecraft:mangrove_sign", - "id": 642 - }, - { - "name": "minecraft:mangrove_slab", - "id": -489 - }, - { - "name": "minecraft:mangrove_stairs", - "id": -488 - }, - { - "name": "minecraft:mangrove_standing_sign", - "id": -494 - }, - { - "name": "minecraft:mangrove_trapdoor", - "id": -496 - }, - { - "name": "minecraft:mangrove_wall_sign", - "id": -495 - }, - { - "name": "minecraft:mangrove_wood", - "id": -497 - }, - { - "name": "minecraft:medicine", - "id": 607 - }, - { - "name": "minecraft:medium_amethyst_bud", - "id": -331 - }, - { - "name": "minecraft:melon_block", - "id": 103 - }, - { - "name": "minecraft:melon_seeds", - "id": 294 - }, - { - "name": "minecraft:melon_slice", - "id": 273 - }, - { - "name": "minecraft:melon_stem", - "id": 105 - }, - { - "name": "minecraft:milk_bucket", - "id": 364 - }, - { - "name": "minecraft:minecart", - "id": 373 - }, - { - "name": "minecraft:miner_pottery_sherd", - "id": 676 - }, - { - "name": "minecraft:mob_spawner", - "id": 52 - }, - { - "name": "minecraft:mojang_banner_pattern", - "id": 592 - }, - { - "name": "minecraft:monster_egg", - "id": 97 - }, - { - "name": "minecraft:mooshroom_spawn_egg", - "id": 443 - }, - { - "name": "minecraft:moss_block", - "id": -320 - }, - { - "name": "minecraft:moss_carpet", - "id": -335 - }, - { - "name": "minecraft:mossy_cobblestone", - "id": 48 - }, - { - "name": "minecraft:mossy_cobblestone_stairs", - "id": -179 - }, - { - "name": "minecraft:mossy_stone_brick_stairs", - "id": -175 - }, - { - "name": "minecraft:mourner_pottery_sherd", - "id": 677 - }, - { - "name": "minecraft:moving_block", - "id": 250 - }, - { - "name": "minecraft:mud", - "id": -473 - }, - { - "name": "minecraft:mud_brick_double_slab", - "id": -479 - }, - { - "name": "minecraft:mud_brick_slab", - "id": -478 - }, - { - "name": "minecraft:mud_brick_stairs", - "id": -480 - }, - { - "name": "minecraft:mud_brick_wall", - "id": -481 - }, - { - "name": "minecraft:mud_bricks", - "id": -475 - }, - { - "name": "minecraft:muddy_mangrove_roots", - "id": -483 - }, - { - "name": "minecraft:mule_spawn_egg", - "id": 469 - }, - { - "name": "minecraft:mushroom_stew", - "id": 261 - }, - { - "name": "minecraft:music_disc_11", - "id": 552 - }, - { - "name": "minecraft:music_disc_13", - "id": 542 - }, - { - "name": "minecraft:music_disc_5", - "id": 644 - }, - { - "name": "minecraft:music_disc_blocks", - "id": 544 - }, - { - "name": "minecraft:music_disc_cat", - "id": 543 - }, - { - "name": "minecraft:music_disc_chirp", - "id": 545 - }, - { - "name": "minecraft:music_disc_far", - "id": 546 - }, - { - "name": "minecraft:music_disc_mall", - "id": 547 - }, - { - "name": "minecraft:music_disc_mellohi", - "id": 548 - }, - { - "name": "minecraft:music_disc_otherside", - "id": 634 - }, - { - "name": "minecraft:music_disc_pigstep", - "id": 628 - }, - { - "name": "minecraft:music_disc_relic", - "id": 702 - }, - { - "name": "minecraft:music_disc_stal", - "id": 549 - }, - { - "name": "minecraft:music_disc_strad", - "id": 550 - }, - { - "name": "minecraft:music_disc_wait", - "id": 553 - }, - { - "name": "minecraft:music_disc_ward", - "id": 551 - }, - { - "name": "minecraft:mutton", - "id": 558 - }, - { - "name": "minecraft:mycelium", - "id": 110 - }, - { - "name": "minecraft:name_tag", - "id": 556 - }, - { - "name": "minecraft:nautilus_shell", - "id": 578 - }, - { - "name": "minecraft:nether_brick", - "id": 112 - }, - { - "name": "minecraft:nether_brick_fence", - "id": 113 - }, - { - "name": "minecraft:nether_brick_stairs", - "id": 114 - }, - { - "name": "minecraft:nether_gold_ore", - "id": -288 - }, - { - "name": "minecraft:nether_sprouts", - "id": 629 - }, - { - "name": "minecraft:nether_star", - "id": 526 - }, - { - "name": "minecraft:nether_wart", - "id": 295 - }, - { - "name": "minecraft:nether_wart_block", - "id": 214 - }, - { - "name": "minecraft:netherbrick", - "id": 531 - }, - { - "name": "minecraft:netherite_axe", - "id": 614 - }, - { - "name": "minecraft:netherite_block", - "id": -270 - }, - { - "name": "minecraft:netherite_boots", - "id": 620 - }, - { - "name": "minecraft:netherite_chestplate", - "id": 618 - }, - { - "name": "minecraft:netherite_helmet", - "id": 617 - }, - { - "name": "minecraft:netherite_hoe", - "id": 615 - }, - { - "name": "minecraft:netherite_ingot", - "id": 616 - }, - { - "name": "minecraft:netherite_leggings", - "id": 619 - }, - { - "name": "minecraft:netherite_pickaxe", - "id": 613 - }, - { - "name": "minecraft:netherite_scrap", - "id": 621 - }, - { - "name": "minecraft:netherite_shovel", - "id": 612 - }, - { - "name": "minecraft:netherite_sword", - "id": 611 - }, - { - "name": "minecraft:netherite_upgrade_smithing_template", - "id": 685 - }, - { - "name": "minecraft:netherrack", - "id": 87 - }, - { - "name": "minecraft:netherreactor", - "id": 247 - }, - { - "name": "minecraft:normal_stone_stairs", - "id": -180 - }, - { - "name": "minecraft:noteblock", - "id": 25 - }, - { - "name": "minecraft:npc_spawn_egg", - "id": 473 - }, - { - "name": "minecraft:oak_boat", - "id": 378 - }, - { - "name": "minecraft:oak_chest_boat", - "id": 646 - }, - { - "name": "minecraft:oak_fence", - "id": 85 - }, - { - "name": "minecraft:oak_hanging_sign", - "id": -500 - }, - { - "name": "minecraft:oak_log", - "id": 17 - }, - { - "name": "minecraft:oak_planks", - "id": 5 - }, - { - "name": "minecraft:oak_sign", - "id": 361 - }, - { - "name": "minecraft:oak_stairs", - "id": 53 - }, - { - "name": "minecraft:observer", - "id": 251 - }, - { - "name": "minecraft:obsidian", - "id": 49 - }, - { - "name": "minecraft:ocelot_spawn_egg", - "id": 454 - }, - { - "name": "minecraft:ochre_froglight", - "id": -471 - }, - { - "name": "minecraft:orange_candle", - "id": -414 - }, - { - "name": "minecraft:orange_candle_cake", - "id": -431 - }, - { - "name": "minecraft:orange_carpet", - "id": -597 - }, - { - "name": "minecraft:orange_concrete", - "id": -628 - }, - { - "name": "minecraft:orange_concrete_powder", - "id": -709 - }, - { - "name": "minecraft:orange_dye", - "id": 412 - }, - { - "name": "minecraft:orange_glazed_terracotta", - "id": 221 - }, - { - "name": "minecraft:orange_shulker_box", - "id": -613 - }, - { - "name": "minecraft:orange_stained_glass", - "id": -673 - }, - { - "name": "minecraft:orange_stained_glass_pane", - "id": -643 - }, - { - "name": "minecraft:orange_terracotta", - "id": -724 - }, - { - "name": "minecraft:orange_wool", - "id": -557 - }, - { - "name": "minecraft:oxidized_chiseled_copper", - "id": -763 - }, - { - "name": "minecraft:oxidized_copper", - "id": -343 - }, - { - "name": "minecraft:oxidized_copper_bulb", - "id": -779 - }, - { - "name": "minecraft:oxidized_copper_door", - "id": -787 - }, - { - "name": "minecraft:oxidized_copper_grate", - "id": -771 - }, - { - "name": "minecraft:oxidized_copper_trapdoor", - "id": -795 - }, - { - "name": "minecraft:oxidized_cut_copper", - "id": -350 - }, - { - "name": "minecraft:oxidized_cut_copper_slab", - "id": -364 - }, - { - "name": "minecraft:oxidized_cut_copper_stairs", - "id": -357 - }, - { - "name": "minecraft:oxidized_double_cut_copper_slab", - "id": -371 - }, - { - "name": "minecraft:packed_ice", - "id": 174 - }, - { - "name": "minecraft:packed_mud", - "id": -477 - }, - { - "name": "minecraft:painting", - "id": 360 - }, - { - "name": "minecraft:panda_spawn_egg", - "id": 492 - }, - { - "name": "minecraft:paper", - "id": 389 - }, - { - "name": "minecraft:parrot_spawn_egg", - "id": 481 - }, - { - "name": "minecraft:pearlescent_froglight", - "id": -469 - }, - { - "name": "minecraft:phantom_membrane", - "id": 582 - }, - { - "name": "minecraft:phantom_spawn_egg", - "id": 489 - }, - { - "name": "minecraft:pig_spawn_egg", - "id": 440 - }, - { - "name": "minecraft:piglin_banner_pattern", - "id": 595 - }, - { - "name": "minecraft:piglin_brute_spawn_egg", - "id": 502 - }, - { - "name": "minecraft:piglin_spawn_egg", - "id": 500 - }, - { - "name": "minecraft:pillager_spawn_egg", - "id": 494 - }, - { - "name": "minecraft:pink_candle", - "id": -419 - }, - { - "name": "minecraft:pink_candle_cake", - "id": -436 - }, - { - "name": "minecraft:pink_carpet", - "id": -602 - }, - { - "name": "minecraft:pink_concrete", - "id": -633 - }, - { - "name": "minecraft:pink_concrete_powder", - "id": -714 - }, - { - "name": "minecraft:pink_dye", - "id": 407 - }, - { - "name": "minecraft:pink_glazed_terracotta", - "id": 226 - }, - { - "name": "minecraft:pink_petals", - "id": -549 - }, - { - "name": "minecraft:pink_shulker_box", - "id": -618 - }, - { - "name": "minecraft:pink_stained_glass", - "id": -678 - }, - { - "name": "minecraft:pink_stained_glass_pane", - "id": -648 - }, - { - "name": "minecraft:pink_terracotta", - "id": -729 - }, - { - "name": "minecraft:pink_wool", - "id": -566 - }, - { - "name": "minecraft:piston", - "id": 33 - }, - { - "name": "minecraft:piston_arm_collision", - "id": 34 - }, - { - "name": "minecraft:pitcher_crop", - "id": -574 - }, - { - "name": "minecraft:pitcher_plant", - "id": -612 - }, - { - "name": "minecraft:pitcher_pod", - "id": 298 - }, - { - "name": "minecraft:planks", - "id": 708 - }, - { - "name": "minecraft:plenty_pottery_sherd", - "id": 678 - }, - { - "name": "minecraft:podzol", - "id": 243 - }, - { - "name": "minecraft:pointed_dripstone", - "id": -308 - }, - { - "name": "minecraft:poisonous_potato", - "id": 283 - }, - { - "name": "minecraft:polar_bear_spawn_egg", - "id": 475 - }, - { - "name": "minecraft:polished_andesite", - "id": -595 - }, - { - "name": "minecraft:polished_andesite_stairs", - "id": -174 - }, - { - "name": "minecraft:polished_basalt", - "id": -235 - }, - { - "name": "minecraft:polished_blackstone", - "id": -291 - }, - { - "name": "minecraft:polished_blackstone_brick_double_slab", - "id": -285 - }, - { - "name": "minecraft:polished_blackstone_brick_slab", - "id": -284 - }, - { - "name": "minecraft:polished_blackstone_brick_stairs", - "id": -275 - }, - { - "name": "minecraft:polished_blackstone_brick_wall", - "id": -278 - }, - { - "name": "minecraft:polished_blackstone_bricks", - "id": -274 - }, - { - "name": "minecraft:polished_blackstone_button", - "id": -296 - }, - { - "name": "minecraft:polished_blackstone_double_slab", - "id": -294 - }, - { - "name": "minecraft:polished_blackstone_pressure_plate", - "id": -295 - }, - { - "name": "minecraft:polished_blackstone_slab", - "id": -293 - }, - { - "name": "minecraft:polished_blackstone_stairs", - "id": -292 - }, - { - "name": "minecraft:polished_blackstone_wall", - "id": -297 - }, - { - "name": "minecraft:polished_deepslate", - "id": -383 - }, - { - "name": "minecraft:polished_deepslate_double_slab", - "id": -397 - }, - { - "name": "minecraft:polished_deepslate_slab", - "id": -384 - }, - { - "name": "minecraft:polished_deepslate_stairs", - "id": -385 - }, - { - "name": "minecraft:polished_deepslate_wall", - "id": -386 - }, - { - "name": "minecraft:polished_diorite", - "id": -593 - }, - { - "name": "minecraft:polished_diorite_stairs", - "id": -173 - }, - { - "name": "minecraft:polished_granite", - "id": -591 - }, - { - "name": "minecraft:polished_granite_stairs", - "id": -172 - }, - { - "name": "minecraft:polished_tuff", - "id": -748 - }, - { - "name": "minecraft:polished_tuff_double_slab", - "id": -750 - }, - { - "name": "minecraft:polished_tuff_slab", - "id": -749 - }, - { - "name": "minecraft:polished_tuff_stairs", - "id": -751 - }, - { - "name": "minecraft:polished_tuff_wall", - "id": -752 - }, - { - "name": "minecraft:popped_chorus_fruit", - "id": 567 - }, - { - "name": "minecraft:porkchop", - "id": 263 - }, - { - "name": "minecraft:portal", - "id": 90 - }, - { - "name": "minecraft:potato", - "id": 281 - }, - { - "name": "minecraft:potatoes", - "id": 142 - }, - { - "name": "minecraft:potion", - "id": 429 - }, - { - "name": "minecraft:powder_snow", - "id": -306 - }, - { - "name": "minecraft:powder_snow_bucket", - "id": 371 - }, - { - "name": "minecraft:powered_comparator", - "id": 150 - }, - { - "name": "minecraft:powered_repeater", - "id": 94 - }, - { - "name": "minecraft:prismarine", - "id": 168 - }, - { - "name": "minecraft:prismarine_bricks_stairs", - "id": -4 - }, - { - "name": "minecraft:prismarine_crystals", - "id": 557 - }, - { - "name": "minecraft:prismarine_shard", - "id": 573 - }, - { - "name": "minecraft:prismarine_stairs", - "id": -2 - }, - { - "name": "minecraft:prize_pottery_sherd", - "id": 679 - }, - { - "name": "minecraft:pufferfish", - "id": 268 - }, - { - "name": "minecraft:pufferfish_bucket", - "id": 370 - }, - { - "name": "minecraft:pufferfish_spawn_egg", - "id": 484 - }, - { - "name": "minecraft:pumpkin", - "id": 86 - }, - { - "name": "minecraft:pumpkin_pie", - "id": 285 - }, - { - "name": "minecraft:pumpkin_seeds", - "id": 293 - }, - { - "name": "minecraft:pumpkin_stem", - "id": 104 - }, - { - "name": "minecraft:purple_candle", - "id": -423 - }, - { - "name": "minecraft:purple_candle_cake", - "id": -440 - }, - { - "name": "minecraft:purple_carpet", - "id": -606 - }, - { - "name": "minecraft:purple_concrete", - "id": -637 - }, - { - "name": "minecraft:purple_concrete_powder", - "id": -718 - }, - { - "name": "minecraft:purple_dye", - "id": 403 - }, - { - "name": "minecraft:purple_glazed_terracotta", - "id": 219 - }, - { - "name": "minecraft:purple_shulker_box", - "id": -622 - }, - { - "name": "minecraft:purple_stained_glass", - "id": -682 - }, - { - "name": "minecraft:purple_stained_glass_pane", - "id": -652 - }, - { - "name": "minecraft:purple_terracotta", - "id": -733 - }, - { - "name": "minecraft:purple_wool", - "id": -564 - }, - { - "name": "minecraft:purpur_block", - "id": 201 - }, - { - "name": "minecraft:purpur_stairs", - "id": 203 - }, - { - "name": "minecraft:quartz", - "id": 532 - }, - { - "name": "minecraft:quartz_block", - "id": 155 - }, - { - "name": "minecraft:quartz_bricks", - "id": -304 - }, - { - "name": "minecraft:quartz_ore", - "id": 153 - }, - { - "name": "minecraft:quartz_stairs", - "id": 156 - }, - { - "name": "minecraft:rabbit", - "id": 289 - }, - { - "name": "minecraft:rabbit_foot", - "id": 536 - }, - { - "name": "minecraft:rabbit_hide", - "id": 537 - }, - { - "name": "minecraft:rabbit_spawn_egg", - "id": 462 - }, - { - "name": "minecraft:rabbit_stew", - "id": 291 - }, - { - "name": "minecraft:rail", - "id": 66 - }, - { - "name": "minecraft:raiser_armor_trim_smithing_template", - "id": 699 - }, - { - "name": "minecraft:rapid_fertilizer", - "id": 605 - }, - { - "name": "minecraft:ravager_spawn_egg", - "id": 496 - }, - { - "name": "minecraft:raw_copper", - "id": 515 - }, - { - "name": "minecraft:raw_copper_block", - "id": -452 - }, - { - "name": "minecraft:raw_gold", - "id": 514 - }, - { - "name": "minecraft:raw_gold_block", - "id": -453 - }, - { - "name": "minecraft:raw_iron", - "id": 513 - }, - { - "name": "minecraft:raw_iron_block", - "id": -451 - }, - { - "name": "minecraft:recovery_compass", - "id": 654 - }, - { - "name": "minecraft:red_candle", - "id": -427 - }, - { - "name": "minecraft:red_candle_cake", - "id": -444 - }, - { - "name": "minecraft:red_carpet", - "id": -610 - }, - { - "name": "minecraft:red_concrete", - "id": -641 - }, - { - "name": "minecraft:red_concrete_powder", - "id": -722 - }, - { - "name": "minecraft:red_dye", - "id": 399 - }, - { - "name": "minecraft:red_flower", - "id": 38 - }, - { - "name": "minecraft:red_glazed_terracotta", - "id": 234 - }, - { - "name": "minecraft:red_mushroom", - "id": 40 - }, - { - "name": "minecraft:red_mushroom_block", - "id": 100 - }, - { - "name": "minecraft:red_nether_brick", - "id": 215 - }, - { - "name": "minecraft:red_nether_brick_stairs", - "id": -184 - }, - { - "name": "minecraft:red_sandstone", - "id": 179 - }, - { - "name": "minecraft:red_sandstone_stairs", - "id": 180 - }, - { - "name": "minecraft:red_shulker_box", - "id": -626 - }, - { - "name": "minecraft:red_stained_glass", - "id": -686 - }, - { - "name": "minecraft:red_stained_glass_pane", - "id": -656 - }, - { - "name": "minecraft:red_terracotta", - "id": -737 - }, - { - "name": "minecraft:red_wool", - "id": -556 - }, - { - "name": "minecraft:redstone", - "id": 376 - }, - { - "name": "minecraft:redstone_block", - "id": 152 - }, - { - "name": "minecraft:redstone_lamp", - "id": 123 - }, - { - "name": "minecraft:redstone_ore", - "id": 73 - }, - { - "name": "minecraft:redstone_torch", - "id": 76 - }, - { - "name": "minecraft:redstone_wire", - "id": 55 - }, - { - "name": "minecraft:reinforced_deepslate", - "id": -466 - }, - { - "name": "minecraft:repeater", - "id": 422 - }, - { - "name": "minecraft:repeating_command_block", - "id": 188 - }, - { - "name": "minecraft:reserved6", - "id": 255 - }, - { - "name": "minecraft:respawn_anchor", - "id": -272 - }, - { - "name": "minecraft:rib_armor_trim_smithing_template", - "id": 695 - }, - { - "name": "minecraft:rotten_flesh", - "id": 278 - }, - { - "name": "minecraft:saddle", - "id": 374 - }, - { - "name": "minecraft:salmon", - "id": 266 - }, - { - "name": "minecraft:salmon_bucket", - "id": 368 - }, - { - "name": "minecraft:salmon_spawn_egg", - "id": 485 - }, - { - "name": "minecraft:sand", - "id": 12 - }, - { - "name": "minecraft:sandstone", - "id": 24 - }, - { - "name": "minecraft:sandstone_stairs", - "id": 128 - }, - { - "name": "minecraft:sapling", - "id": 6 - }, - { - "name": "minecraft:scaffolding", - "id": -165 - }, - { - "name": "minecraft:sculk", - "id": -458 - }, - { - "name": "minecraft:sculk_catalyst", - "id": -460 - }, - { - "name": "minecraft:sculk_sensor", - "id": -307 - }, - { - "name": "minecraft:sculk_shrieker", - "id": -461 - }, - { - "name": "minecraft:sculk_vein", - "id": -459 - }, - { - "name": "minecraft:scute", - "id": 580 - }, - { - "name": "minecraft:sea_lantern", - "id": 169 - }, - { - "name": "minecraft:sea_pickle", - "id": -156 - }, - { - "name": "minecraft:seagrass", - "id": -130 - }, - { - "name": "minecraft:sentry_armor_trim_smithing_template", - "id": 686 - }, - { - "name": "minecraft:shaper_armor_trim_smithing_template", - "id": 700 - }, - { - "name": "minecraft:sheaf_pottery_sherd", - "id": 680 - }, - { - "name": "minecraft:shears", - "id": 424 - }, - { - "name": "minecraft:sheep_spawn_egg", - "id": 441 - }, - { - "name": "minecraft:shelter_pottery_sherd", - "id": 681 - }, - { - "name": "minecraft:shield", - "id": 358 - }, - { - "name": "minecraft:shroomlight", - "id": -230 - }, - { - "name": "minecraft:shulker_box", - "id": 715 - }, - { - "name": "minecraft:shulker_shell", - "id": 574 - }, - { - "name": "minecraft:shulker_spawn_egg", - "id": 472 - }, - { - "name": "minecraft:silence_armor_trim_smithing_template", - "id": 697 - }, - { - "name": "minecraft:silver_glazed_terracotta", - "id": 228 - }, - { - "name": "minecraft:silverfish_spawn_egg", - "id": 446 - }, - { - "name": "minecraft:skeleton_horse_spawn_egg", - "id": 470 - }, - { - "name": "minecraft:skeleton_spawn_egg", - "id": 447 - }, - { - "name": "minecraft:skull", - "id": 524 - }, - { - "name": "minecraft:skull_banner_pattern", - "id": 591 - }, - { - "name": "minecraft:skull_pottery_sherd", - "id": 682 - }, - { - "name": "minecraft:slime", - "id": 165 - }, - { - "name": "minecraft:slime_ball", - "id": 391 - }, - { - "name": "minecraft:slime_spawn_egg", - "id": 448 - }, - { - "name": "minecraft:small_amethyst_bud", - "id": -332 - }, - { - "name": "minecraft:small_dripleaf_block", - "id": -336 - }, - { - "name": "minecraft:smithing_table", - "id": -202 - }, - { - "name": "minecraft:smoker", - "id": -198 - }, - { - "name": "minecraft:smooth_basalt", - "id": -377 - }, - { - "name": "minecraft:smooth_quartz_stairs", - "id": -185 - }, - { - "name": "minecraft:smooth_red_sandstone_stairs", - "id": -176 - }, - { - "name": "minecraft:smooth_sandstone_stairs", - "id": -177 - }, - { - "name": "minecraft:smooth_stone", - "id": -183 - }, - { - "name": "minecraft:sniffer_egg", - "id": -596 - }, - { - "name": "minecraft:sniffer_spawn_egg", - "id": 503 - }, - { - "name": "minecraft:snort_pottery_sherd", - "id": 683 - }, - { - "name": "minecraft:snout_armor_trim_smithing_template", - "id": 694 - }, - { - "name": "minecraft:snow", - "id": 80 - }, - { - "name": "minecraft:snow_golem_spawn_egg", - "id": 508 - }, - { - "name": "minecraft:snow_layer", - "id": 78 - }, - { - "name": "minecraft:snowball", - "id": 377 - }, - { - "name": "minecraft:soul_campfire", - "id": 630 - }, - { - "name": "minecraft:soul_fire", - "id": -237 - }, - { - "name": "minecraft:soul_lantern", - "id": -269 - }, - { - "name": "minecraft:soul_sand", - "id": 88 - }, - { - "name": "minecraft:soul_soil", - "id": -236 - }, - { - "name": "minecraft:soul_torch", - "id": -268 - }, - { - "name": "minecraft:sparkler", - "id": 608 - }, - { - "name": "minecraft:spawn_egg", - "id": 719 - }, - { - "name": "minecraft:spider_eye", - "id": 279 - }, - { - "name": "minecraft:spider_spawn_egg", - "id": 449 - }, - { - "name": "minecraft:spire_armor_trim_smithing_template", - "id": 696 - }, - { - "name": "minecraft:splash_potion", - "id": 569 - }, - { - "name": "minecraft:sponge", - "id": 19 - }, - { - "name": "minecraft:spore_blossom", - "id": -321 - }, - { - "name": "minecraft:spruce_boat", - "id": 381 - }, - { - "name": "minecraft:spruce_button", - "id": -144 - }, - { - "name": "minecraft:spruce_chest_boat", - "id": 649 - }, - { - "name": "minecraft:spruce_door", - "id": 561 - }, - { - "name": "minecraft:spruce_fence", - "id": -579 - }, - { - "name": "minecraft:spruce_fence_gate", - "id": 183 - }, - { - "name": "minecraft:spruce_hanging_sign", - "id": -501 - }, - { - "name": "minecraft:spruce_log", - "id": -569 - }, - { - "name": "minecraft:spruce_planks", - "id": -739 - }, - { - "name": "minecraft:spruce_pressure_plate", - "id": -154 - }, - { - "name": "minecraft:spruce_sign", - "id": 584 - }, - { - "name": "minecraft:spruce_stairs", - "id": 134 - }, - { - "name": "minecraft:spruce_standing_sign", - "id": -181 - }, - { - "name": "minecraft:spruce_trapdoor", - "id": -149 - }, - { - "name": "minecraft:spruce_wall_sign", - "id": -182 - }, - { - "name": "minecraft:spyglass", - "id": 633 - }, - { - "name": "minecraft:squid_spawn_egg", - "id": 453 - }, - { - "name": "minecraft:stained_glass", - "id": 713 - }, - { - "name": "minecraft:stained_glass_pane", - "id": 714 - }, - { - "name": "minecraft:stained_hardened_clay", - "id": 703 - }, - { - "name": "minecraft:standing_banner", - "id": 176 - }, - { - "name": "minecraft:standing_sign", - "id": 63 - }, - { - "name": "minecraft:stick", - "id": 323 - }, - { - "name": "minecraft:sticky_piston", - "id": 29 - }, - { - "name": "minecraft:sticky_piston_arm_collision", - "id": -217 - }, - { - "name": "minecraft:stone", - "id": 1 - }, - { - "name": "minecraft:stone_axe", - "id": 318 - }, - { - "name": "minecraft:stone_block_slab", - "id": 44 - }, - { - "name": "minecraft:stone_block_slab2", - "id": 182 - }, - { - "name": "minecraft:stone_block_slab3", - "id": -162 - }, - { - "name": "minecraft:stone_block_slab4", - "id": -166 - }, - { - "name": "minecraft:stone_brick_stairs", - "id": 109 - }, - { - "name": "minecraft:stone_button", - "id": 77 - }, - { - "name": "minecraft:stone_hoe", - "id": 333 - }, - { - "name": "minecraft:stone_pickaxe", - "id": 317 - }, - { - "name": "minecraft:stone_pressure_plate", - "id": 70 - }, - { - "name": "minecraft:stone_shovel", - "id": 316 - }, - { - "name": "minecraft:stone_stairs", - "id": 67 - }, - { - "name": "minecraft:stone_sword", - "id": 315 - }, - { - "name": "minecraft:stonebrick", - "id": 98 - }, - { - "name": "minecraft:stonecutter", - "id": 245 - }, - { - "name": "minecraft:stonecutter_block", - "id": -197 - }, - { - "name": "minecraft:stray_spawn_egg", - "id": 465 - }, - { - "name": "minecraft:strider_spawn_egg", - "id": 498 - }, - { - "name": "minecraft:string", - "id": 329 - }, - { - "name": "minecraft:stripped_acacia_log", - "id": -8 - }, - { - "name": "minecraft:stripped_bamboo_block", - "id": -528 - }, - { - "name": "minecraft:stripped_birch_log", - "id": -6 - }, - { - "name": "minecraft:stripped_cherry_log", - "id": -535 - }, - { - "name": "minecraft:stripped_cherry_wood", - "id": -545 - }, - { - "name": "minecraft:stripped_crimson_hyphae", - "id": -300 - }, - { - "name": "minecraft:stripped_crimson_stem", - "id": -240 - }, - { - "name": "minecraft:stripped_dark_oak_log", - "id": -9 - }, - { - "name": "minecraft:stripped_jungle_log", - "id": -7 - }, - { - "name": "minecraft:stripped_mangrove_log", - "id": -485 - }, - { - "name": "minecraft:stripped_mangrove_wood", - "id": -498 - }, - { - "name": "minecraft:stripped_oak_log", - "id": -10 - }, - { - "name": "minecraft:stripped_spruce_log", - "id": -5 - }, - { - "name": "minecraft:stripped_warped_hyphae", - "id": -301 - }, - { - "name": "minecraft:stripped_warped_stem", - "id": -241 - }, - { - "name": "minecraft:structure_block", - "id": 252 - }, - { - "name": "minecraft:structure_void", - "id": 217 - }, - { - "name": "minecraft:sugar", - "id": 419 - }, - { - "name": "minecraft:sugar_cane", - "id": 388 - }, - { - "name": "minecraft:suspicious_gravel", - "id": -573 - }, - { - "name": "minecraft:suspicious_sand", - "id": -529 - }, - { - "name": "minecraft:suspicious_stew", - "id": 598 - }, - { - "name": "minecraft:sweet_berries", - "id": 288 - }, - { - "name": "minecraft:sweet_berry_bush", - "id": -207 - }, - { - "name": "minecraft:tadpole_bucket", - "id": 638 - }, - { - "name": "minecraft:tadpole_spawn_egg", - "id": 637 - }, - { - "name": "minecraft:tallgrass", - "id": 31 - }, - { - "name": "minecraft:target", - "id": -239 - }, - { - "name": "minecraft:tide_armor_trim_smithing_template", - "id": 693 - }, - { - "name": "minecraft:tinted_glass", - "id": -334 - }, - { - "name": "minecraft:tnt", - "id": 46 - }, - { - "name": "minecraft:tnt_minecart", - "id": 533 - }, - { - "name": "minecraft:torch", - "id": 50 - }, - { - "name": "minecraft:torchflower", - "id": -568 - }, - { - "name": "minecraft:torchflower_crop", - "id": -567 - }, - { - "name": "minecraft:torchflower_seeds", - "id": 297 - }, - { - "name": "minecraft:totem_of_undying", - "id": 576 - }, - { - "name": "minecraft:trader_llama_spawn_egg", - "id": 656 - }, - { - "name": "minecraft:trapdoor", - "id": 96 - }, - { - "name": "minecraft:trapped_chest", - "id": 146 - }, - { - "name": "minecraft:trident", - "id": 554 - }, - { - "name": "minecraft:trip_wire", - "id": 132 - }, - { - "name": "minecraft:tripwire_hook", - "id": 131 - }, - { - "name": "minecraft:tropical_fish", - "id": 267 - }, - { - "name": "minecraft:tropical_fish_bucket", - "id": 369 - }, - { - "name": "minecraft:tropical_fish_spawn_egg", - "id": 482 - }, - { - "name": "minecraft:tube_coral", - "id": -131 - }, - { - "name": "minecraft:tuff", - "id": -333 - }, - { - "name": "minecraft:tuff_brick_double_slab", - "id": -756 - }, - { - "name": "minecraft:tuff_brick_slab", - "id": -755 - }, - { - "name": "minecraft:tuff_brick_stairs", - "id": -757 - }, - { - "name": "minecraft:tuff_brick_wall", - "id": -758 - }, - { - "name": "minecraft:tuff_bricks", - "id": -754 - }, - { - "name": "minecraft:tuff_double_slab", - "id": -745 - }, - { - "name": "minecraft:tuff_slab", - "id": -744 - }, - { - "name": "minecraft:tuff_stairs", - "id": -746 - }, - { - "name": "minecraft:tuff_wall", - "id": -747 - }, - { - "name": "minecraft:turtle_egg", - "id": -159 - }, - { - "name": "minecraft:turtle_helmet", - "id": 581 - }, - { - "name": "minecraft:turtle_spawn_egg", - "id": 488 - }, - { - "name": "minecraft:twisting_vines", - "id": -287 - }, - { - "name": "minecraft:underwater_torch", - "id": 239 - }, - { - "name": "minecraft:undyed_shulker_box", - "id": 205 - }, - { - "name": "minecraft:unknown", - "id": -305 - }, - { - "name": "minecraft:unlit_redstone_torch", - "id": 75 - }, - { - "name": "minecraft:unpowered_comparator", - "id": 149 - }, - { - "name": "minecraft:unpowered_repeater", - "id": 93 - }, - { - "name": "minecraft:verdant_froglight", - "id": -470 - }, - { - "name": "minecraft:vex_armor_trim_smithing_template", - "id": 692 - }, - { - "name": "minecraft:vex_spawn_egg", - "id": 479 - }, - { - "name": "minecraft:villager_spawn_egg", - "id": 452 - }, - { - "name": "minecraft:vindicator_spawn_egg", - "id": 477 - }, - { - "name": "minecraft:vine", - "id": 106 - }, - { - "name": "minecraft:wall_banner", - "id": 177 - }, - { - "name": "minecraft:wall_sign", - "id": 68 - }, - { - "name": "minecraft:wandering_trader_spawn_egg", - "id": 495 - }, - { - "name": "minecraft:ward_armor_trim_smithing_template", - "id": 690 - }, - { - "name": "minecraft:warden_spawn_egg", - "id": 640 - }, - { - "name": "minecraft:warped_button", - "id": -261 - }, - { - "name": "minecraft:warped_door", - "id": 625 - }, - { - "name": "minecraft:warped_double_slab", - "id": -267 - }, - { - "name": "minecraft:warped_fence", - "id": -257 - }, - { - "name": "minecraft:warped_fence_gate", - "id": -259 - }, - { - "name": "minecraft:warped_fungus", - "id": -229 - }, - { - "name": "minecraft:warped_fungus_on_a_stick", - "id": 626 - }, - { - "name": "minecraft:warped_hanging_sign", - "id": -507 - }, - { - "name": "minecraft:warped_hyphae", - "id": -298 - }, - { - "name": "minecraft:warped_nylium", - "id": -233 - }, - { - "name": "minecraft:warped_planks", - "id": -243 - }, - { - "name": "minecraft:warped_pressure_plate", - "id": -263 - }, - { - "name": "minecraft:warped_roots", - "id": -224 - }, - { - "name": "minecraft:warped_sign", - "id": 623 - }, - { - "name": "minecraft:warped_slab", - "id": -265 - }, - { - "name": "minecraft:warped_stairs", - "id": -255 - }, - { - "name": "minecraft:warped_standing_sign", - "id": -251 - }, - { - "name": "minecraft:warped_stem", - "id": -226 - }, - { - "name": "minecraft:warped_trapdoor", - "id": -247 - }, - { - "name": "minecraft:warped_wall_sign", - "id": -253 - }, - { - "name": "minecraft:warped_wart_block", - "id": -227 - }, - { - "name": "minecraft:water", - "id": 9 - }, - { - "name": "minecraft:water_bucket", - "id": 365 - }, - { - "name": "minecraft:waterlily", - "id": 111 - }, - { - "name": "minecraft:waxed_chiseled_copper", - "id": -764 - }, - { - "name": "minecraft:waxed_copper", - "id": -344 - }, - { - "name": "minecraft:waxed_copper_bulb", - "id": -780 - }, - { - "name": "minecraft:waxed_copper_door", - "id": -788 - }, - { - "name": "minecraft:waxed_copper_grate", - "id": -772 - }, - { - "name": "minecraft:waxed_copper_trapdoor", - "id": -796 - }, - { - "name": "minecraft:waxed_cut_copper", - "id": -351 - }, - { - "name": "minecraft:waxed_cut_copper_slab", - "id": -365 - }, - { - "name": "minecraft:waxed_cut_copper_stairs", - "id": -358 - }, - { - "name": "minecraft:waxed_double_cut_copper_slab", - "id": -372 - }, - { - "name": "minecraft:waxed_exposed_chiseled_copper", - "id": -765 - }, - { - "name": "minecraft:waxed_exposed_copper", - "id": -345 - }, - { - "name": "minecraft:waxed_exposed_copper_bulb", - "id": -781 - }, - { - "name": "minecraft:waxed_exposed_copper_door", - "id": -789 - }, - { - "name": "minecraft:waxed_exposed_copper_grate", - "id": -773 - }, - { - "name": "minecraft:waxed_exposed_copper_trapdoor", - "id": -797 - }, - { - "name": "minecraft:waxed_exposed_cut_copper", - "id": -352 - }, - { - "name": "minecraft:waxed_exposed_cut_copper_slab", - "id": -366 - }, - { - "name": "minecraft:waxed_exposed_cut_copper_stairs", - "id": -359 - }, - { - "name": "minecraft:waxed_exposed_double_cut_copper_slab", - "id": -373 - }, - { - "name": "minecraft:waxed_oxidized_chiseled_copper", - "id": -766 - }, - { - "name": "minecraft:waxed_oxidized_copper", - "id": -446 - }, - { - "name": "minecraft:waxed_oxidized_copper_bulb", - "id": -783 - }, - { - "name": "minecraft:waxed_oxidized_copper_door", - "id": -791 - }, - { - "name": "minecraft:waxed_oxidized_copper_grate", - "id": -775 - }, - { - "name": "minecraft:waxed_oxidized_copper_trapdoor", - "id": -799 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper", - "id": -447 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper_slab", - "id": -449 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper_stairs", - "id": -448 - }, - { - "name": "minecraft:waxed_oxidized_double_cut_copper_slab", - "id": -450 - }, - { - "name": "minecraft:waxed_weathered_chiseled_copper", - "id": -767 - }, - { - "name": "minecraft:waxed_weathered_copper", - "id": -346 - }, - { - "name": "minecraft:waxed_weathered_copper_bulb", - "id": -782 - }, - { - "name": "minecraft:waxed_weathered_copper_door", - "id": -790 - }, - { - "name": "minecraft:waxed_weathered_copper_grate", - "id": -774 - }, - { - "name": "minecraft:waxed_weathered_copper_trapdoor", - "id": -798 - }, - { - "name": "minecraft:waxed_weathered_cut_copper", - "id": -353 - }, - { - "name": "minecraft:waxed_weathered_cut_copper_slab", - "id": -367 - }, - { - "name": "minecraft:waxed_weathered_cut_copper_stairs", - "id": -360 - }, - { - "name": "minecraft:waxed_weathered_double_cut_copper_slab", - "id": -374 - }, - { - "name": "minecraft:wayfinder_armor_trim_smithing_template", - "id": 698 - }, - { - "name": "minecraft:weathered_chiseled_copper", - "id": -762 - }, - { - "name": "minecraft:weathered_copper", - "id": -342 - }, - { - "name": "minecraft:weathered_copper_bulb", - "id": -778 - }, - { - "name": "minecraft:weathered_copper_door", - "id": -786 - }, - { - "name": "minecraft:weathered_copper_grate", - "id": -770 - }, - { - "name": "minecraft:weathered_copper_trapdoor", - "id": -794 - }, - { - "name": "minecraft:weathered_cut_copper", - "id": -349 - }, - { - "name": "minecraft:weathered_cut_copper_slab", - "id": -363 - }, - { - "name": "minecraft:weathered_cut_copper_stairs", - "id": -356 - }, - { - "name": "minecraft:weathered_double_cut_copper_slab", - "id": -370 - }, - { - "name": "minecraft:web", - "id": 30 - }, - { - "name": "minecraft:weeping_vines", - "id": -231 - }, - { - "name": "minecraft:wheat", - "id": 337 - }, - { - "name": "minecraft:wheat_seeds", - "id": 292 - }, - { - "name": "minecraft:white_candle", - "id": -413 - }, - { - "name": "minecraft:white_candle_cake", - "id": -430 - }, - { - "name": "minecraft:white_carpet", - "id": 171 - }, - { - "name": "minecraft:white_concrete", - "id": 236 - }, - { - "name": "minecraft:white_concrete_powder", - "id": 237 - }, - { - "name": "minecraft:white_dye", - "id": 413 - }, - { - "name": "minecraft:white_glazed_terracotta", - "id": 220 - }, - { - "name": "minecraft:white_shulker_box", - "id": 218 - }, - { - "name": "minecraft:white_stained_glass", - "id": 241 - }, - { - "name": "minecraft:white_stained_glass_pane", - "id": 160 - }, - { - "name": "minecraft:white_terracotta", - "id": 159 - }, - { - "name": "minecraft:white_wool", - "id": 35 - }, - { - "name": "minecraft:wild_armor_trim_smithing_template", - "id": 689 - }, - { - "name": "minecraft:witch_spawn_egg", - "id": 455 - }, - { - "name": "minecraft:wither_rose", - "id": -216 - }, - { - "name": "minecraft:wither_skeleton_spawn_egg", - "id": 467 - }, - { - "name": "minecraft:wither_spawn_egg", - "id": 510 - }, - { - "name": "minecraft:wolf_spawn_egg", - "id": 442 - }, - { - "name": "minecraft:wood", - "id": -212 - }, - { - "name": "minecraft:wooden_axe", - "id": 314 - }, - { - "name": "minecraft:wooden_button", - "id": 143 - }, - { - "name": "minecraft:wooden_door", - "id": 362 - }, - { - "name": "minecraft:wooden_hoe", - "id": 332 - }, - { - "name": "minecraft:wooden_pickaxe", - "id": 313 - }, - { - "name": "minecraft:wooden_pressure_plate", - "id": 72 - }, - { - "name": "minecraft:wooden_shovel", - "id": 312 - }, - { - "name": "minecraft:wooden_slab", - "id": 158 - }, - { - "name": "minecraft:wooden_sword", - "id": 311 - }, - { - "name": "minecraft:wool", - "id": 704 - }, - { - "name": "minecraft:writable_book", - "id": 518 - }, - { - "name": "minecraft:written_book", - "id": 519 - }, - { - "name": "minecraft:yellow_candle", - "id": -417 - }, - { - "name": "minecraft:yellow_candle_cake", - "id": -434 - }, - { - "name": "minecraft:yellow_carpet", - "id": -600 - }, - { - "name": "minecraft:yellow_concrete", - "id": -631 - }, - { - "name": "minecraft:yellow_concrete_powder", - "id": -712 - }, - { - "name": "minecraft:yellow_dye", - "id": 409 - }, - { - "name": "minecraft:yellow_flower", - "id": 37 - }, - { - "name": "minecraft:yellow_glazed_terracotta", - "id": 224 - }, - { - "name": "minecraft:yellow_shulker_box", - "id": -616 - }, - { - "name": "minecraft:yellow_stained_glass", - "id": -676 - }, - { - "name": "minecraft:yellow_stained_glass_pane", - "id": -646 - }, - { - "name": "minecraft:yellow_terracotta", - "id": -727 - }, - { - "name": "minecraft:yellow_wool", - "id": -558 - }, - { - "name": "minecraft:zoglin_spawn_egg", - "id": 501 - }, - { - "name": "minecraft:zombie_horse_spawn_egg", - "id": 471 - }, - { - "name": "minecraft:zombie_pigman_spawn_egg", - "id": 451 - }, - { - "name": "minecraft:zombie_spawn_egg", - "id": 450 - }, - { - "name": "minecraft:zombie_villager_spawn_egg", - "id": 480 - } -] \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_20_60.json b/core/src/main/resources/bedrock/runtime_item_states.1_20_60.json deleted file mode 100644 index f8b3199e3..000000000 --- a/core/src/main/resources/bedrock/runtime_item_states.1_20_60.json +++ /dev/null @@ -1,5998 +0,0 @@ -[ - { - "name": "minecraft:acacia_boat", - "id": 382 - }, - { - "name": "minecraft:acacia_button", - "id": -140 - }, - { - "name": "minecraft:acacia_chest_boat", - "id": 651 - }, - { - "name": "minecraft:acacia_door", - "id": 565 - }, - { - "name": "minecraft:acacia_fence", - "id": -575 - }, - { - "name": "minecraft:acacia_fence_gate", - "id": 187 - }, - { - "name": "minecraft:acacia_hanging_sign", - "id": -504 - }, - { - "name": "minecraft:acacia_log", - "id": 162 - }, - { - "name": "minecraft:acacia_planks", - "id": -742 - }, - { - "name": "minecraft:acacia_pressure_plate", - "id": -150 - }, - { - "name": "minecraft:acacia_sign", - "id": 588 - }, - { - "name": "minecraft:acacia_stairs", - "id": 163 - }, - { - "name": "minecraft:acacia_standing_sign", - "id": -190 - }, - { - "name": "minecraft:acacia_trapdoor", - "id": -145 - }, - { - "name": "minecraft:acacia_wall_sign", - "id": -191 - }, - { - "name": "minecraft:activator_rail", - "id": 126 - }, - { - "name": "minecraft:agent_spawn_egg", - "id": 490 - }, - { - "name": "minecraft:air", - "id": -158 - }, - { - "name": "minecraft:allay_spawn_egg", - "id": 640 - }, - { - "name": "minecraft:allow", - "id": 210 - }, - { - "name": "minecraft:amethyst_block", - "id": -327 - }, - { - "name": "minecraft:amethyst_cluster", - "id": -329 - }, - { - "name": "minecraft:amethyst_shard", - "id": 633 - }, - { - "name": "minecraft:ancient_debris", - "id": -271 - }, - { - "name": "minecraft:andesite", - "id": -594 - }, - { - "name": "minecraft:andesite_stairs", - "id": -171 - }, - { - "name": "minecraft:angler_pottery_sherd", - "id": 665 - }, - { - "name": "minecraft:anvil", - "id": 145 - }, - { - "name": "minecraft:apple", - "id": 257 - }, - { - "name": "minecraft:archer_pottery_sherd", - "id": 666 - }, - { - "name": "minecraft:armadillo_scute", - "id": 707 - }, - { - "name": "minecraft:armadillo_spawn_egg", - "id": 706 - }, - { - "name": "minecraft:armor_stand", - "id": 561 - }, - { - "name": "minecraft:arms_up_pottery_sherd", - "id": 667 - }, - { - "name": "minecraft:arrow", - "id": 304 - }, - { - "name": "minecraft:axolotl_bucket", - "id": 372 - }, - { - "name": "minecraft:axolotl_spawn_egg", - "id": 505 - }, - { - "name": "minecraft:azalea", - "id": -337 - }, - { - "name": "minecraft:azalea_leaves", - "id": -324 - }, - { - "name": "minecraft:azalea_leaves_flowered", - "id": -325 - }, - { - "name": "minecraft:baked_potato", - "id": 282 - }, - { - "name": "minecraft:balloon", - "id": 607 - }, - { - "name": "minecraft:bamboo", - "id": -163 - }, - { - "name": "minecraft:bamboo_block", - "id": -527 - }, - { - "name": "minecraft:bamboo_button", - "id": -511 - }, - { - "name": "minecraft:bamboo_chest_raft", - "id": 663 - }, - { - "name": "minecraft:bamboo_door", - "id": -517 - }, - { - "name": "minecraft:bamboo_double_slab", - "id": -521 - }, - { - "name": "minecraft:bamboo_fence", - "id": -515 - }, - { - "name": "minecraft:bamboo_fence_gate", - "id": -516 - }, - { - "name": "minecraft:bamboo_hanging_sign", - "id": -522 - }, - { - "name": "minecraft:bamboo_mosaic", - "id": -509 - }, - { - "name": "minecraft:bamboo_mosaic_double_slab", - "id": -525 - }, - { - "name": "minecraft:bamboo_mosaic_slab", - "id": -524 - }, - { - "name": "minecraft:bamboo_mosaic_stairs", - "id": -523 - }, - { - "name": "minecraft:bamboo_planks", - "id": -510 - }, - { - "name": "minecraft:bamboo_pressure_plate", - "id": -514 - }, - { - "name": "minecraft:bamboo_raft", - "id": 662 - }, - { - "name": "minecraft:bamboo_sapling", - "id": -164 - }, - { - "name": "minecraft:bamboo_sign", - "id": 661 - }, - { - "name": "minecraft:bamboo_slab", - "id": -513 - }, - { - "name": "minecraft:bamboo_stairs", - "id": -512 - }, - { - "name": "minecraft:bamboo_standing_sign", - "id": -518 - }, - { - "name": "minecraft:bamboo_trapdoor", - "id": -520 - }, - { - "name": "minecraft:bamboo_wall_sign", - "id": -519 - }, - { - "name": "minecraft:banner", - "id": 576 - }, - { - "name": "minecraft:banner_pattern", - "id": 725 - }, - { - "name": "minecraft:barrel", - "id": -203 - }, - { - "name": "minecraft:barrier", - "id": -161 - }, - { - "name": "minecraft:basalt", - "id": -234 - }, - { - "name": "minecraft:bat_spawn_egg", - "id": 456 - }, - { - "name": "minecraft:beacon", - "id": 138 - }, - { - "name": "minecraft:bed", - "id": 421 - }, - { - "name": "minecraft:bedrock", - "id": 7 - }, - { - "name": "minecraft:bee_nest", - "id": -218 - }, - { - "name": "minecraft:bee_spawn_egg", - "id": 497 - }, - { - "name": "minecraft:beef", - "id": 274 - }, - { - "name": "minecraft:beehive", - "id": -219 - }, - { - "name": "minecraft:beetroot", - "id": 286 - }, - { - "name": "minecraft:beetroot_seeds", - "id": 296 - }, - { - "name": "minecraft:beetroot_soup", - "id": 287 - }, - { - "name": "minecraft:bell", - "id": -206 - }, - { - "name": "minecraft:big_dripleaf", - "id": -323 - }, - { - "name": "minecraft:birch_boat", - "id": 379 - }, - { - "name": "minecraft:birch_button", - "id": -141 - }, - { - "name": "minecraft:birch_chest_boat", - "id": 648 - }, - { - "name": "minecraft:birch_door", - "id": 563 - }, - { - "name": "minecraft:birch_fence", - "id": -576 - }, - { - "name": "minecraft:birch_fence_gate", - "id": 184 - }, - { - "name": "minecraft:birch_hanging_sign", - "id": -502 - }, - { - "name": "minecraft:birch_log", - "id": -570 - }, - { - "name": "minecraft:birch_planks", - "id": -740 - }, - { - "name": "minecraft:birch_pressure_plate", - "id": -151 - }, - { - "name": "minecraft:birch_sign", - "id": 586 - }, - { - "name": "minecraft:birch_stairs", - "id": 135 - }, - { - "name": "minecraft:birch_standing_sign", - "id": -186 - }, - { - "name": "minecraft:birch_trapdoor", - "id": -146 - }, - { - "name": "minecraft:birch_wall_sign", - "id": -187 - }, - { - "name": "minecraft:black_candle", - "id": -428 - }, - { - "name": "minecraft:black_candle_cake", - "id": -445 - }, - { - "name": "minecraft:black_carpet", - "id": -611 - }, - { - "name": "minecraft:black_concrete", - "id": -642 - }, - { - "name": "minecraft:black_concrete_powder", - "id": -723 - }, - { - "name": "minecraft:black_dye", - "id": 398 - }, - { - "name": "minecraft:black_glazed_terracotta", - "id": 235 - }, - { - "name": "minecraft:black_shulker_box", - "id": -627 - }, - { - "name": "minecraft:black_stained_glass", - "id": -687 - }, - { - "name": "minecraft:black_stained_glass_pane", - "id": -657 - }, - { - "name": "minecraft:black_terracotta", - "id": -738 - }, - { - "name": "minecraft:black_wool", - "id": -554 - }, - { - "name": "minecraft:blackstone", - "id": -273 - }, - { - "name": "minecraft:blackstone_double_slab", - "id": -283 - }, - { - "name": "minecraft:blackstone_slab", - "id": -282 - }, - { - "name": "minecraft:blackstone_stairs", - "id": -276 - }, - { - "name": "minecraft:blackstone_wall", - "id": -277 - }, - { - "name": "minecraft:blade_pottery_sherd", - "id": 668 - }, - { - "name": "minecraft:blast_furnace", - "id": -196 - }, - { - "name": "minecraft:blaze_powder", - "id": 432 - }, - { - "name": "minecraft:blaze_rod", - "id": 426 - }, - { - "name": "minecraft:blaze_spawn_egg", - "id": 459 - }, - { - "name": "minecraft:bleach", - "id": 605 - }, - { - "name": "minecraft:blue_candle", - "id": -424 - }, - { - "name": "minecraft:blue_candle_cake", - "id": -441 - }, - { - "name": "minecraft:blue_carpet", - "id": -607 - }, - { - "name": "minecraft:blue_concrete", - "id": -638 - }, - { - "name": "minecraft:blue_concrete_powder", - "id": -719 - }, - { - "name": "minecraft:blue_dye", - "id": 402 - }, - { - "name": "minecraft:blue_glazed_terracotta", - "id": 231 - }, - { - "name": "minecraft:blue_ice", - "id": -11 - }, - { - "name": "minecraft:blue_shulker_box", - "id": -623 - }, - { - "name": "minecraft:blue_stained_glass", - "id": -683 - }, - { - "name": "minecraft:blue_stained_glass_pane", - "id": -653 - }, - { - "name": "minecraft:blue_terracotta", - "id": -734 - }, - { - "name": "minecraft:blue_wool", - "id": -563 - }, - { - "name": "minecraft:boat", - "id": 723 - }, - { - "name": "minecraft:bone", - "id": 418 - }, - { - "name": "minecraft:bone_block", - "id": 216 - }, - { - "name": "minecraft:bone_meal", - "id": 414 - }, - { - "name": "minecraft:book", - "id": 390 - }, - { - "name": "minecraft:bookshelf", - "id": 47 - }, - { - "name": "minecraft:border_block", - "id": 212 - }, - { - "name": "minecraft:bordure_indented_banner_pattern", - "id": 595 - }, - { - "name": "minecraft:bow", - "id": 303 - }, - { - "name": "minecraft:bowl", - "id": 324 - }, - { - "name": "minecraft:brain_coral", - "id": -581 - }, - { - "name": "minecraft:bread", - "id": 262 - }, - { - "name": "minecraft:breeze_spawn_egg", - "id": 504 - }, - { - "name": "minecraft:brewer_pottery_sherd", - "id": 669 - }, - { - "name": "minecraft:brewing_stand", - "id": 434 - }, - { - "name": "minecraft:brick", - "id": 386 - }, - { - "name": "minecraft:brick_block", - "id": 45 - }, - { - "name": "minecraft:brick_stairs", - "id": 108 - }, - { - "name": "minecraft:brown_candle", - "id": -425 - }, - { - "name": "minecraft:brown_candle_cake", - "id": -442 - }, - { - "name": "minecraft:brown_carpet", - "id": -608 - }, - { - "name": "minecraft:brown_concrete", - "id": -639 - }, - { - "name": "minecraft:brown_concrete_powder", - "id": -720 - }, - { - "name": "minecraft:brown_dye", - "id": 401 - }, - { - "name": "minecraft:brown_glazed_terracotta", - "id": 232 - }, - { - "name": "minecraft:brown_mushroom", - "id": 39 - }, - { - "name": "minecraft:brown_mushroom_block", - "id": 99 - }, - { - "name": "minecraft:brown_shulker_box", - "id": -624 - }, - { - "name": "minecraft:brown_stained_glass", - "id": -684 - }, - { - "name": "minecraft:brown_stained_glass_pane", - "id": -654 - }, - { - "name": "minecraft:brown_terracotta", - "id": -735 - }, - { - "name": "minecraft:brown_wool", - "id": -555 - }, - { - "name": "minecraft:brush", - "id": 685 - }, - { - "name": "minecraft:bubble_column", - "id": -160 - }, - { - "name": "minecraft:bubble_coral", - "id": -582 - }, - { - "name": "minecraft:bucket", - "id": 363 - }, - { - "name": "minecraft:budding_amethyst", - "id": -328 - }, - { - "name": "minecraft:burn_pottery_sherd", - "id": 670 - }, - { - "name": "minecraft:cactus", - "id": 81 - }, - { - "name": "minecraft:cake", - "id": 420 - }, - { - "name": "minecraft:calcite", - "id": -326 - }, - { - "name": "minecraft:calibrated_sculk_sensor", - "id": -580 - }, - { - "name": "minecraft:camel_spawn_egg", - "id": 664 - }, - { - "name": "minecraft:camera", - "id": 602 - }, - { - "name": "minecraft:campfire", - "id": 598 - }, - { - "name": "minecraft:candle", - "id": -412 - }, - { - "name": "minecraft:candle_cake", - "id": -429 - }, - { - "name": "minecraft:carpet", - "id": 710 - }, - { - "name": "minecraft:carrot", - "id": 280 - }, - { - "name": "minecraft:carrot_on_a_stick", - "id": 526 - }, - { - "name": "minecraft:carrots", - "id": 141 - }, - { - "name": "minecraft:cartography_table", - "id": -200 - }, - { - "name": "minecraft:carved_pumpkin", - "id": -155 - }, - { - "name": "minecraft:cat_spawn_egg", - "id": 491 - }, - { - "name": "minecraft:cauldron", - "id": 435 - }, - { - "name": "minecraft:cave_spider_spawn_egg", - "id": 460 - }, - { - "name": "minecraft:cave_vines", - "id": -322 - }, - { - "name": "minecraft:cave_vines_body_with_berries", - "id": -375 - }, - { - "name": "minecraft:cave_vines_head_with_berries", - "id": -376 - }, - { - "name": "minecraft:chain", - "id": 628 - }, - { - "name": "minecraft:chain_command_block", - "id": 189 - }, - { - "name": "minecraft:chainmail_boots", - "id": 345 - }, - { - "name": "minecraft:chainmail_chestplate", - "id": 343 - }, - { - "name": "minecraft:chainmail_helmet", - "id": 342 - }, - { - "name": "minecraft:chainmail_leggings", - "id": 344 - }, - { - "name": "minecraft:charcoal", - "id": 306 - }, - { - "name": "minecraft:chemical_heat", - "id": 192 - }, - { - "name": "minecraft:chemistry_table", - "id": 238 - }, - { - "name": "minecraft:cherry_boat", - "id": 658 - }, - { - "name": "minecraft:cherry_button", - "id": -530 - }, - { - "name": "minecraft:cherry_chest_boat", - "id": 659 - }, - { - "name": "minecraft:cherry_door", - "id": -531 - }, - { - "name": "minecraft:cherry_double_slab", - "id": -540 - }, - { - "name": "minecraft:cherry_fence", - "id": -532 - }, - { - "name": "minecraft:cherry_fence_gate", - "id": -533 - }, - { - "name": "minecraft:cherry_hanging_sign", - "id": -534 - }, - { - "name": "minecraft:cherry_leaves", - "id": -548 - }, - { - "name": "minecraft:cherry_log", - "id": -536 - }, - { - "name": "minecraft:cherry_planks", - "id": -537 - }, - { - "name": "minecraft:cherry_pressure_plate", - "id": -538 - }, - { - "name": "minecraft:cherry_sapling", - "id": -547 - }, - { - "name": "minecraft:cherry_sign", - "id": 660 - }, - { - "name": "minecraft:cherry_slab", - "id": -539 - }, - { - "name": "minecraft:cherry_stairs", - "id": -541 - }, - { - "name": "minecraft:cherry_standing_sign", - "id": -542 - }, - { - "name": "minecraft:cherry_trapdoor", - "id": -543 - }, - { - "name": "minecraft:cherry_wall_sign", - "id": -544 - }, - { - "name": "minecraft:cherry_wood", - "id": -546 - }, - { - "name": "minecraft:chest", - "id": 54 - }, - { - "name": "minecraft:chest_boat", - "id": 654 - }, - { - "name": "minecraft:chest_minecart", - "id": 392 - }, - { - "name": "minecraft:chicken", - "id": 276 - }, - { - "name": "minecraft:chicken_spawn_egg", - "id": 438 - }, - { - "name": "minecraft:chiseled_bookshelf", - "id": -526 - }, - { - "name": "minecraft:chiseled_copper", - "id": -760 - }, - { - "name": "minecraft:chiseled_deepslate", - "id": -395 - }, - { - "name": "minecraft:chiseled_nether_bricks", - "id": -302 - }, - { - "name": "minecraft:chiseled_polished_blackstone", - "id": -279 - }, - { - "name": "minecraft:chiseled_tuff", - "id": -753 - }, - { - "name": "minecraft:chiseled_tuff_bricks", - "id": -759 - }, - { - "name": "minecraft:chorus_flower", - "id": 200 - }, - { - "name": "minecraft:chorus_fruit", - "id": 567 - }, - { - "name": "minecraft:chorus_plant", - "id": 240 - }, - { - "name": "minecraft:clay", - "id": 82 - }, - { - "name": "minecraft:clay_ball", - "id": 387 - }, - { - "name": "minecraft:client_request_placeholder_block", - "id": -465 - }, - { - "name": "minecraft:clock", - "id": 396 - }, - { - "name": "minecraft:coal", - "id": 305 - }, - { - "name": "minecraft:coal_block", - "id": 173 - }, - { - "name": "minecraft:coal_ore", - "id": 16 - }, - { - "name": "minecraft:coast_armor_trim_smithing_template", - "id": 689 - }, - { - "name": "minecraft:cobbled_deepslate", - "id": -379 - }, - { - "name": "minecraft:cobbled_deepslate_double_slab", - "id": -396 - }, - { - "name": "minecraft:cobbled_deepslate_slab", - "id": -380 - }, - { - "name": "minecraft:cobbled_deepslate_stairs", - "id": -381 - }, - { - "name": "minecraft:cobbled_deepslate_wall", - "id": -382 - }, - { - "name": "minecraft:cobblestone", - "id": 4 - }, - { - "name": "minecraft:cobblestone_wall", - "id": 139 - }, - { - "name": "minecraft:cocoa", - "id": 127 - }, - { - "name": "minecraft:cocoa_beans", - "id": 415 - }, - { - "name": "minecraft:cod", - "id": 265 - }, - { - "name": "minecraft:cod_bucket", - "id": 367 - }, - { - "name": "minecraft:cod_spawn_egg", - "id": 483 - }, - { - "name": "minecraft:colored_torch_bp", - "id": 204 - }, - { - "name": "minecraft:colored_torch_rg", - "id": 202 - }, - { - "name": "minecraft:command_block", - "id": 137 - }, - { - "name": "minecraft:command_block_minecart", - "id": 572 - }, - { - "name": "minecraft:comparator", - "id": 531 - }, - { - "name": "minecraft:compass", - "id": 394 - }, - { - "name": "minecraft:composter", - "id": -213 - }, - { - "name": "minecraft:compound", - "id": 603 - }, - { - "name": "minecraft:concrete", - "id": 716 - }, - { - "name": "minecraft:concrete_powder", - "id": 717 - }, - { - "name": "minecraft:conduit", - "id": -157 - }, - { - "name": "minecraft:cooked_beef", - "id": 275 - }, - { - "name": "minecraft:cooked_chicken", - "id": 277 - }, - { - "name": "minecraft:cooked_cod", - "id": 269 - }, - { - "name": "minecraft:cooked_mutton", - "id": 560 - }, - { - "name": "minecraft:cooked_porkchop", - "id": 264 - }, - { - "name": "minecraft:cooked_rabbit", - "id": 290 - }, - { - "name": "minecraft:cooked_salmon", - "id": 270 - }, - { - "name": "minecraft:cookie", - "id": 272 - }, - { - "name": "minecraft:copper_block", - "id": -340 - }, - { - "name": "minecraft:copper_bulb", - "id": -776 - }, - { - "name": "minecraft:copper_door", - "id": -784 - }, - { - "name": "minecraft:copper_grate", - "id": -768 - }, - { - "name": "minecraft:copper_ingot", - "id": 513 - }, - { - "name": "minecraft:copper_ore", - "id": -311 - }, - { - "name": "minecraft:copper_trapdoor", - "id": -792 - }, - { - "name": "minecraft:coral", - "id": 714 - }, - { - "name": "minecraft:coral_block", - "id": -132 - }, - { - "name": "minecraft:coral_fan", - "id": -133 - }, - { - "name": "minecraft:coral_fan_dead", - "id": -134 - }, - { - "name": "minecraft:coral_fan_hang", - "id": -135 - }, - { - "name": "minecraft:coral_fan_hang2", - "id": -136 - }, - { - "name": "minecraft:coral_fan_hang3", - "id": -137 - }, - { - "name": "minecraft:cow_spawn_egg", - "id": 439 - }, - { - "name": "minecraft:cracked_deepslate_bricks", - "id": -410 - }, - { - "name": "minecraft:cracked_deepslate_tiles", - "id": -409 - }, - { - "name": "minecraft:cracked_nether_bricks", - "id": -303 - }, - { - "name": "minecraft:cracked_polished_blackstone_bricks", - "id": -280 - }, - { - "name": "minecraft:crafter", - "id": -313 - }, - { - "name": "minecraft:crafting_table", - "id": 58 - }, - { - "name": "minecraft:creeper_banner_pattern", - "id": 591 - }, - { - "name": "minecraft:creeper_spawn_egg", - "id": 444 - }, - { - "name": "minecraft:crimson_button", - "id": -260 - }, - { - "name": "minecraft:crimson_door", - "id": 625 - }, - { - "name": "minecraft:crimson_double_slab", - "id": -266 - }, - { - "name": "minecraft:crimson_fence", - "id": -256 - }, - { - "name": "minecraft:crimson_fence_gate", - "id": -258 - }, - { - "name": "minecraft:crimson_fungus", - "id": -228 - }, - { - "name": "minecraft:crimson_hanging_sign", - "id": -506 - }, - { - "name": "minecraft:crimson_hyphae", - "id": -299 - }, - { - "name": "minecraft:crimson_nylium", - "id": -232 - }, - { - "name": "minecraft:crimson_planks", - "id": -242 - }, - { - "name": "minecraft:crimson_pressure_plate", - "id": -262 - }, - { - "name": "minecraft:crimson_roots", - "id": -223 - }, - { - "name": "minecraft:crimson_sign", - "id": 623 - }, - { - "name": "minecraft:crimson_slab", - "id": -264 - }, - { - "name": "minecraft:crimson_stairs", - "id": -254 - }, - { - "name": "minecraft:crimson_standing_sign", - "id": -250 - }, - { - "name": "minecraft:crimson_stem", - "id": -225 - }, - { - "name": "minecraft:crimson_trapdoor", - "id": -246 - }, - { - "name": "minecraft:crimson_wall_sign", - "id": -252 - }, - { - "name": "minecraft:crossbow", - "id": 584 - }, - { - "name": "minecraft:crying_obsidian", - "id": -289 - }, - { - "name": "minecraft:cut_copper", - "id": -347 - }, - { - "name": "minecraft:cut_copper_slab", - "id": -361 - }, - { - "name": "minecraft:cut_copper_stairs", - "id": -354 - }, - { - "name": "minecraft:cyan_candle", - "id": -422 - }, - { - "name": "minecraft:cyan_candle_cake", - "id": -439 - }, - { - "name": "minecraft:cyan_carpet", - "id": -605 - }, - { - "name": "minecraft:cyan_concrete", - "id": -636 - }, - { - "name": "minecraft:cyan_concrete_powder", - "id": -717 - }, - { - "name": "minecraft:cyan_dye", - "id": 404 - }, - { - "name": "minecraft:cyan_glazed_terracotta", - "id": 229 - }, - { - "name": "minecraft:cyan_shulker_box", - "id": -621 - }, - { - "name": "minecraft:cyan_stained_glass", - "id": -681 - }, - { - "name": "minecraft:cyan_stained_glass_pane", - "id": -651 - }, - { - "name": "minecraft:cyan_terracotta", - "id": -732 - }, - { - "name": "minecraft:cyan_wool", - "id": -561 - }, - { - "name": "minecraft:danger_pottery_sherd", - "id": 671 - }, - { - "name": "minecraft:dark_oak_boat", - "id": 383 - }, - { - "name": "minecraft:dark_oak_button", - "id": -142 - }, - { - "name": "minecraft:dark_oak_chest_boat", - "id": 652 - }, - { - "name": "minecraft:dark_oak_door", - "id": 566 - }, - { - "name": "minecraft:dark_oak_fence", - "id": -577 - }, - { - "name": "minecraft:dark_oak_fence_gate", - "id": 186 - }, - { - "name": "minecraft:dark_oak_hanging_sign", - "id": -505 - }, - { - "name": "minecraft:dark_oak_log", - "id": -572 - }, - { - "name": "minecraft:dark_oak_planks", - "id": -743 - }, - { - "name": "minecraft:dark_oak_pressure_plate", - "id": -152 - }, - { - "name": "minecraft:dark_oak_sign", - "id": 589 - }, - { - "name": "minecraft:dark_oak_stairs", - "id": 164 - }, - { - "name": "minecraft:dark_oak_trapdoor", - "id": -147 - }, - { - "name": "minecraft:dark_prismarine_stairs", - "id": -3 - }, - { - "name": "minecraft:darkoak_standing_sign", - "id": -192 - }, - { - "name": "minecraft:darkoak_wall_sign", - "id": -193 - }, - { - "name": "minecraft:daylight_detector", - "id": 151 - }, - { - "name": "minecraft:daylight_detector_inverted", - "id": 178 - }, - { - "name": "minecraft:dead_brain_coral", - "id": -586 - }, - { - "name": "minecraft:dead_bubble_coral", - "id": -587 - }, - { - "name": "minecraft:dead_fire_coral", - "id": -588 - }, - { - "name": "minecraft:dead_horn_coral", - "id": -589 - }, - { - "name": "minecraft:dead_tube_coral", - "id": -585 - }, - { - "name": "minecraft:deadbush", - "id": 32 - }, - { - "name": "minecraft:decorated_pot", - "id": -551 - }, - { - "name": "minecraft:deepslate", - "id": -378 - }, - { - "name": "minecraft:deepslate_brick_double_slab", - "id": -399 - }, - { - "name": "minecraft:deepslate_brick_slab", - "id": -392 - }, - { - "name": "minecraft:deepslate_brick_stairs", - "id": -393 - }, - { - "name": "minecraft:deepslate_brick_wall", - "id": -394 - }, - { - "name": "minecraft:deepslate_bricks", - "id": -391 - }, - { - "name": "minecraft:deepslate_coal_ore", - "id": -406 - }, - { - "name": "minecraft:deepslate_copper_ore", - "id": -408 - }, - { - "name": "minecraft:deepslate_diamond_ore", - "id": -405 - }, - { - "name": "minecraft:deepslate_emerald_ore", - "id": -407 - }, - { - "name": "minecraft:deepslate_gold_ore", - "id": -402 - }, - { - "name": "minecraft:deepslate_iron_ore", - "id": -401 - }, - { - "name": "minecraft:deepslate_lapis_ore", - "id": -400 - }, - { - "name": "minecraft:deepslate_redstone_ore", - "id": -403 - }, - { - "name": "minecraft:deepslate_tile_double_slab", - "id": -398 - }, - { - "name": "minecraft:deepslate_tile_slab", - "id": -388 - }, - { - "name": "minecraft:deepslate_tile_stairs", - "id": -389 - }, - { - "name": "minecraft:deepslate_tile_wall", - "id": -390 - }, - { - "name": "minecraft:deepslate_tiles", - "id": -387 - }, - { - "name": "minecraft:deny", - "id": 211 - }, - { - "name": "minecraft:detector_rail", - "id": 28 - }, - { - "name": "minecraft:diamond", - "id": 307 - }, - { - "name": "minecraft:diamond_axe", - "id": 322 - }, - { - "name": "minecraft:diamond_block", - "id": 57 - }, - { - "name": "minecraft:diamond_boots", - "id": 353 - }, - { - "name": "minecraft:diamond_chestplate", - "id": 351 - }, - { - "name": "minecraft:diamond_helmet", - "id": 350 - }, - { - "name": "minecraft:diamond_hoe", - "id": 335 - }, - { - "name": "minecraft:diamond_horse_armor", - "id": 542 - }, - { - "name": "minecraft:diamond_leggings", - "id": 352 - }, - { - "name": "minecraft:diamond_ore", - "id": 56 - }, - { - "name": "minecraft:diamond_pickaxe", - "id": 321 - }, - { - "name": "minecraft:diamond_shovel", - "id": 320 - }, - { - "name": "minecraft:diamond_sword", - "id": 319 - }, - { - "name": "minecraft:diorite", - "id": -592 - }, - { - "name": "minecraft:diorite_stairs", - "id": -170 - }, - { - "name": "minecraft:dirt", - "id": 3 - }, - { - "name": "minecraft:dirt_with_roots", - "id": -318 - }, - { - "name": "minecraft:disc_fragment_5", - "id": 646 - }, - { - "name": "minecraft:dispenser", - "id": 23 - }, - { - "name": "minecraft:dolphin_spawn_egg", - "id": 487 - }, - { - "name": "minecraft:donkey_spawn_egg", - "id": 468 - }, - { - "name": "minecraft:double_cut_copper_slab", - "id": -368 - }, - { - "name": "minecraft:double_plant", - "id": 175 - }, - { - "name": "minecraft:double_stone_block_slab", - "id": 43 - }, - { - "name": "minecraft:double_stone_block_slab2", - "id": 181 - }, - { - "name": "minecraft:double_stone_block_slab3", - "id": -167 - }, - { - "name": "minecraft:double_stone_block_slab4", - "id": -168 - }, - { - "name": "minecraft:double_wooden_slab", - "id": 157 - }, - { - "name": "minecraft:dragon_breath", - "id": 569 - }, - { - "name": "minecraft:dragon_egg", - "id": 122 - }, - { - "name": "minecraft:dried_kelp", - "id": 271 - }, - { - "name": "minecraft:dried_kelp_block", - "id": -139 - }, - { - "name": "minecraft:dripstone_block", - "id": -317 - }, - { - "name": "minecraft:dropper", - "id": 125 - }, - { - "name": "minecraft:drowned_spawn_egg", - "id": 486 - }, - { - "name": "minecraft:dune_armor_trim_smithing_template", - "id": 688 - }, - { - "name": "minecraft:dye", - "id": 724 - }, - { - "name": "minecraft:echo_shard", - "id": 656 - }, - { - "name": "minecraft:egg", - "id": 393 - }, - { - "name": "minecraft:elder_guardian_spawn_egg", - "id": 474 - }, - { - "name": "minecraft:element_0", - "id": 36 - }, - { - "name": "minecraft:element_1", - "id": -12 - }, - { - "name": "minecraft:element_10", - "id": -21 - }, - { - "name": "minecraft:element_100", - "id": -111 - }, - { - "name": "minecraft:element_101", - "id": -112 - }, - { - "name": "minecraft:element_102", - "id": -113 - }, - { - "name": "minecraft:element_103", - "id": -114 - }, - { - "name": "minecraft:element_104", - "id": -115 - }, - { - "name": "minecraft:element_105", - "id": -116 - }, - { - "name": "minecraft:element_106", - "id": -117 - }, - { - "name": "minecraft:element_107", - "id": -118 - }, - { - "name": "minecraft:element_108", - "id": -119 - }, - { - "name": "minecraft:element_109", - "id": -120 - }, - { - "name": "minecraft:element_11", - "id": -22 - }, - { - "name": "minecraft:element_110", - "id": -121 - }, - { - "name": "minecraft:element_111", - "id": -122 - }, - { - "name": "minecraft:element_112", - "id": -123 - }, - { - "name": "minecraft:element_113", - "id": -124 - }, - { - "name": "minecraft:element_114", - "id": -125 - }, - { - "name": "minecraft:element_115", - "id": -126 - }, - { - "name": "minecraft:element_116", - "id": -127 - }, - { - "name": "minecraft:element_117", - "id": -128 - }, - { - "name": "minecraft:element_118", - "id": -129 - }, - { - "name": "minecraft:element_12", - "id": -23 - }, - { - "name": "minecraft:element_13", - "id": -24 - }, - { - "name": "minecraft:element_14", - "id": -25 - }, - { - "name": "minecraft:element_15", - "id": -26 - }, - { - "name": "minecraft:element_16", - "id": -27 - }, - { - "name": "minecraft:element_17", - "id": -28 - }, - { - "name": "minecraft:element_18", - "id": -29 - }, - { - "name": "minecraft:element_19", - "id": -30 - }, - { - "name": "minecraft:element_2", - "id": -13 - }, - { - "name": "minecraft:element_20", - "id": -31 - }, - { - "name": "minecraft:element_21", - "id": -32 - }, - { - "name": "minecraft:element_22", - "id": -33 - }, - { - "name": "minecraft:element_23", - "id": -34 - }, - { - "name": "minecraft:element_24", - "id": -35 - }, - { - "name": "minecraft:element_25", - "id": -36 - }, - { - "name": "minecraft:element_26", - "id": -37 - }, - { - "name": "minecraft:element_27", - "id": -38 - }, - { - "name": "minecraft:element_28", - "id": -39 - }, - { - "name": "minecraft:element_29", - "id": -40 - }, - { - "name": "minecraft:element_3", - "id": -14 - }, - { - "name": "minecraft:element_30", - "id": -41 - }, - { - "name": "minecraft:element_31", - "id": -42 - }, - { - "name": "minecraft:element_32", - "id": -43 - }, - { - "name": "minecraft:element_33", - "id": -44 - }, - { - "name": "minecraft:element_34", - "id": -45 - }, - { - "name": "minecraft:element_35", - "id": -46 - }, - { - "name": "minecraft:element_36", - "id": -47 - }, - { - "name": "minecraft:element_37", - "id": -48 - }, - { - "name": "minecraft:element_38", - "id": -49 - }, - { - "name": "minecraft:element_39", - "id": -50 - }, - { - "name": "minecraft:element_4", - "id": -15 - }, - { - "name": "minecraft:element_40", - "id": -51 - }, - { - "name": "minecraft:element_41", - "id": -52 - }, - { - "name": "minecraft:element_42", - "id": -53 - }, - { - "name": "minecraft:element_43", - "id": -54 - }, - { - "name": "minecraft:element_44", - "id": -55 - }, - { - "name": "minecraft:element_45", - "id": -56 - }, - { - "name": "minecraft:element_46", - "id": -57 - }, - { - "name": "minecraft:element_47", - "id": -58 - }, - { - "name": "minecraft:element_48", - "id": -59 - }, - { - "name": "minecraft:element_49", - "id": -60 - }, - { - "name": "minecraft:element_5", - "id": -16 - }, - { - "name": "minecraft:element_50", - "id": -61 - }, - { - "name": "minecraft:element_51", - "id": -62 - }, - { - "name": "minecraft:element_52", - "id": -63 - }, - { - "name": "minecraft:element_53", - "id": -64 - }, - { - "name": "minecraft:element_54", - "id": -65 - }, - { - "name": "minecraft:element_55", - "id": -66 - }, - { - "name": "minecraft:element_56", - "id": -67 - }, - { - "name": "minecraft:element_57", - "id": -68 - }, - { - "name": "minecraft:element_58", - "id": -69 - }, - { - "name": "minecraft:element_59", - "id": -70 - }, - { - "name": "minecraft:element_6", - "id": -17 - }, - { - "name": "minecraft:element_60", - "id": -71 - }, - { - "name": "minecraft:element_61", - "id": -72 - }, - { - "name": "minecraft:element_62", - "id": -73 - }, - { - "name": "minecraft:element_63", - "id": -74 - }, - { - "name": "minecraft:element_64", - "id": -75 - }, - { - "name": "minecraft:element_65", - "id": -76 - }, - { - "name": "minecraft:element_66", - "id": -77 - }, - { - "name": "minecraft:element_67", - "id": -78 - }, - { - "name": "minecraft:element_68", - "id": -79 - }, - { - "name": "minecraft:element_69", - "id": -80 - }, - { - "name": "minecraft:element_7", - "id": -18 - }, - { - "name": "minecraft:element_70", - "id": -81 - }, - { - "name": "minecraft:element_71", - "id": -82 - }, - { - "name": "minecraft:element_72", - "id": -83 - }, - { - "name": "minecraft:element_73", - "id": -84 - }, - { - "name": "minecraft:element_74", - "id": -85 - }, - { - "name": "minecraft:element_75", - "id": -86 - }, - { - "name": "minecraft:element_76", - "id": -87 - }, - { - "name": "minecraft:element_77", - "id": -88 - }, - { - "name": "minecraft:element_78", - "id": -89 - }, - { - "name": "minecraft:element_79", - "id": -90 - }, - { - "name": "minecraft:element_8", - "id": -19 - }, - { - "name": "minecraft:element_80", - "id": -91 - }, - { - "name": "minecraft:element_81", - "id": -92 - }, - { - "name": "minecraft:element_82", - "id": -93 - }, - { - "name": "minecraft:element_83", - "id": -94 - }, - { - "name": "minecraft:element_84", - "id": -95 - }, - { - "name": "minecraft:element_85", - "id": -96 - }, - { - "name": "minecraft:element_86", - "id": -97 - }, - { - "name": "minecraft:element_87", - "id": -98 - }, - { - "name": "minecraft:element_88", - "id": -99 - }, - { - "name": "minecraft:element_89", - "id": -100 - }, - { - "name": "minecraft:element_9", - "id": -20 - }, - { - "name": "minecraft:element_90", - "id": -101 - }, - { - "name": "minecraft:element_91", - "id": -102 - }, - { - "name": "minecraft:element_92", - "id": -103 - }, - { - "name": "minecraft:element_93", - "id": -104 - }, - { - "name": "minecraft:element_94", - "id": -105 - }, - { - "name": "minecraft:element_95", - "id": -106 - }, - { - "name": "minecraft:element_96", - "id": -107 - }, - { - "name": "minecraft:element_97", - "id": -108 - }, - { - "name": "minecraft:element_98", - "id": -109 - }, - { - "name": "minecraft:element_99", - "id": -110 - }, - { - "name": "minecraft:elytra", - "id": 573 - }, - { - "name": "minecraft:emerald", - "id": 521 - }, - { - "name": "minecraft:emerald_block", - "id": 133 - }, - { - "name": "minecraft:emerald_ore", - "id": 129 - }, - { - "name": "minecraft:empty_map", - "id": 524 - }, - { - "name": "minecraft:enchanted_book", - "id": 530 - }, - { - "name": "minecraft:enchanted_golden_apple", - "id": 260 - }, - { - "name": "minecraft:enchanting_table", - "id": 116 - }, - { - "name": "minecraft:end_brick_stairs", - "id": -178 - }, - { - "name": "minecraft:end_bricks", - "id": 206 - }, - { - "name": "minecraft:end_crystal", - "id": 727 - }, - { - "name": "minecraft:end_gateway", - "id": 209 - }, - { - "name": "minecraft:end_portal", - "id": 119 - }, - { - "name": "minecraft:end_portal_frame", - "id": 120 - }, - { - "name": "minecraft:end_rod", - "id": 208 - }, - { - "name": "minecraft:end_stone", - "id": 121 - }, - { - "name": "minecraft:ender_chest", - "id": 130 - }, - { - "name": "minecraft:ender_dragon_spawn_egg", - "id": 510 - }, - { - "name": "minecraft:ender_eye", - "id": 436 - }, - { - "name": "minecraft:ender_pearl", - "id": 425 - }, - { - "name": "minecraft:enderman_spawn_egg", - "id": 445 - }, - { - "name": "minecraft:endermite_spawn_egg", - "id": 463 - }, - { - "name": "minecraft:evoker_spawn_egg", - "id": 478 - }, - { - "name": "minecraft:experience_bottle", - "id": 517 - }, - { - "name": "minecraft:explorer_pottery_sherd", - "id": 672 - }, - { - "name": "minecraft:exposed_chiseled_copper", - "id": -761 - }, - { - "name": "minecraft:exposed_copper", - "id": -341 - }, - { - "name": "minecraft:exposed_copper_bulb", - "id": -777 - }, - { - "name": "minecraft:exposed_copper_door", - "id": -785 - }, - { - "name": "minecraft:exposed_copper_grate", - "id": -769 - }, - { - "name": "minecraft:exposed_copper_trapdoor", - "id": -793 - }, - { - "name": "minecraft:exposed_cut_copper", - "id": -348 - }, - { - "name": "minecraft:exposed_cut_copper_slab", - "id": -362 - }, - { - "name": "minecraft:exposed_cut_copper_stairs", - "id": -355 - }, - { - "name": "minecraft:exposed_double_cut_copper_slab", - "id": -369 - }, - { - "name": "minecraft:eye_armor_trim_smithing_template", - "id": 692 - }, - { - "name": "minecraft:farmland", - "id": 60 - }, - { - "name": "minecraft:feather", - "id": 330 - }, - { - "name": "minecraft:fence", - "id": 712 - }, - { - "name": "minecraft:fence_gate", - "id": 107 - }, - { - "name": "minecraft:fermented_spider_eye", - "id": 431 - }, - { - "name": "minecraft:field_masoned_banner_pattern", - "id": 594 - }, - { - "name": "minecraft:filled_map", - "id": 423 - }, - { - "name": "minecraft:fire", - "id": 51 - }, - { - "name": "minecraft:fire_charge", - "id": 518 - }, - { - "name": "minecraft:fire_coral", - "id": -583 - }, - { - "name": "minecraft:firework_rocket", - "id": 528 - }, - { - "name": "minecraft:firework_star", - "id": 529 - }, - { - "name": "minecraft:fishing_rod", - "id": 395 - }, - { - "name": "minecraft:fletching_table", - "id": -201 - }, - { - "name": "minecraft:flint", - "id": 359 - }, - { - "name": "minecraft:flint_and_steel", - "id": 302 - }, - { - "name": "minecraft:flower_banner_pattern", - "id": 590 - }, - { - "name": "minecraft:flower_pot", - "id": 523 - }, - { - "name": "minecraft:flowering_azalea", - "id": -338 - }, - { - "name": "minecraft:flowing_lava", - "id": 10 - }, - { - "name": "minecraft:flowing_water", - "id": 8 - }, - { - "name": "minecraft:fox_spawn_egg", - "id": 493 - }, - { - "name": "minecraft:frame", - "id": 522 - }, - { - "name": "minecraft:friend_pottery_sherd", - "id": 673 - }, - { - "name": "minecraft:frog_spawn", - "id": -468 - }, - { - "name": "minecraft:frog_spawn_egg", - "id": 637 - }, - { - "name": "minecraft:frosted_ice", - "id": 207 - }, - { - "name": "minecraft:furnace", - "id": 61 - }, - { - "name": "minecraft:ghast_spawn_egg", - "id": 457 - }, - { - "name": "minecraft:ghast_tear", - "id": 427 - }, - { - "name": "minecraft:gilded_blackstone", - "id": -281 - }, - { - "name": "minecraft:glass", - "id": 20 - }, - { - "name": "minecraft:glass_bottle", - "id": 430 - }, - { - "name": "minecraft:glass_pane", - "id": 102 - }, - { - "name": "minecraft:glistering_melon_slice", - "id": 437 - }, - { - "name": "minecraft:globe_banner_pattern", - "id": 597 - }, - { - "name": "minecraft:glow_berries", - "id": 728 - }, - { - "name": "minecraft:glow_frame", - "id": 632 - }, - { - "name": "minecraft:glow_ink_sac", - "id": 512 - }, - { - "name": "minecraft:glow_lichen", - "id": -411 - }, - { - "name": "minecraft:glow_squid_spawn_egg", - "id": 507 - }, - { - "name": "minecraft:glow_stick", - "id": 610 - }, - { - "name": "minecraft:glowingobsidian", - "id": 246 - }, - { - "name": "minecraft:glowstone", - "id": 89 - }, - { - "name": "minecraft:glowstone_dust", - "id": 397 - }, - { - "name": "minecraft:goat_horn", - "id": 636 - }, - { - "name": "minecraft:goat_spawn_egg", - "id": 506 - }, - { - "name": "minecraft:gold_block", - "id": 41 - }, - { - "name": "minecraft:gold_ingot", - "id": 309 - }, - { - "name": "minecraft:gold_nugget", - "id": 428 - }, - { - "name": "minecraft:gold_ore", - "id": 14 - }, - { - "name": "minecraft:golden_apple", - "id": 259 - }, - { - "name": "minecraft:golden_axe", - "id": 328 - }, - { - "name": "minecraft:golden_boots", - "id": 357 - }, - { - "name": "minecraft:golden_carrot", - "id": 284 - }, - { - "name": "minecraft:golden_chestplate", - "id": 355 - }, - { - "name": "minecraft:golden_helmet", - "id": 354 - }, - { - "name": "minecraft:golden_hoe", - "id": 336 - }, - { - "name": "minecraft:golden_horse_armor", - "id": 541 - }, - { - "name": "minecraft:golden_leggings", - "id": 356 - }, - { - "name": "minecraft:golden_pickaxe", - "id": 327 - }, - { - "name": "minecraft:golden_rail", - "id": 27 - }, - { - "name": "minecraft:golden_shovel", - "id": 326 - }, - { - "name": "minecraft:golden_sword", - "id": 325 - }, - { - "name": "minecraft:granite", - "id": -590 - }, - { - "name": "minecraft:granite_stairs", - "id": -169 - }, - { - "name": "minecraft:grass", - "id": 2 - }, - { - "name": "minecraft:grass_path", - "id": 198 - }, - { - "name": "minecraft:gravel", - "id": 13 - }, - { - "name": "minecraft:gray_candle", - "id": -420 - }, - { - "name": "minecraft:gray_candle_cake", - "id": -437 - }, - { - "name": "minecraft:gray_carpet", - "id": -603 - }, - { - "name": "minecraft:gray_concrete", - "id": -634 - }, - { - "name": "minecraft:gray_concrete_powder", - "id": -715 - }, - { - "name": "minecraft:gray_dye", - "id": 406 - }, - { - "name": "minecraft:gray_glazed_terracotta", - "id": 227 - }, - { - "name": "minecraft:gray_shulker_box", - "id": -619 - }, - { - "name": "minecraft:gray_stained_glass", - "id": -679 - }, - { - "name": "minecraft:gray_stained_glass_pane", - "id": -649 - }, - { - "name": "minecraft:gray_terracotta", - "id": -730 - }, - { - "name": "minecraft:gray_wool", - "id": -553 - }, - { - "name": "minecraft:green_candle", - "id": -426 - }, - { - "name": "minecraft:green_candle_cake", - "id": -443 - }, - { - "name": "minecraft:green_carpet", - "id": -609 - }, - { - "name": "minecraft:green_concrete", - "id": -640 - }, - { - "name": "minecraft:green_concrete_powder", - "id": -721 - }, - { - "name": "minecraft:green_dye", - "id": 400 - }, - { - "name": "minecraft:green_glazed_terracotta", - "id": 233 - }, - { - "name": "minecraft:green_shulker_box", - "id": -625 - }, - { - "name": "minecraft:green_stained_glass", - "id": -685 - }, - { - "name": "minecraft:green_stained_glass_pane", - "id": -655 - }, - { - "name": "minecraft:green_terracotta", - "id": -736 - }, - { - "name": "minecraft:green_wool", - "id": -560 - }, - { - "name": "minecraft:grindstone", - "id": -195 - }, - { - "name": "minecraft:guardian_spawn_egg", - "id": 464 - }, - { - "name": "minecraft:gunpowder", - "id": 331 - }, - { - "name": "minecraft:hanging_roots", - "id": -319 - }, - { - "name": "minecraft:hard_black_stained_glass", - "id": -702 - }, - { - "name": "minecraft:hard_black_stained_glass_pane", - "id": -672 - }, - { - "name": "minecraft:hard_blue_stained_glass", - "id": -698 - }, - { - "name": "minecraft:hard_blue_stained_glass_pane", - "id": -668 - }, - { - "name": "minecraft:hard_brown_stained_glass", - "id": -699 - }, - { - "name": "minecraft:hard_brown_stained_glass_pane", - "id": -669 - }, - { - "name": "minecraft:hard_cyan_stained_glass", - "id": -696 - }, - { - "name": "minecraft:hard_cyan_stained_glass_pane", - "id": -666 - }, - { - "name": "minecraft:hard_glass", - "id": 253 - }, - { - "name": "minecraft:hard_glass_pane", - "id": 190 - }, - { - "name": "minecraft:hard_gray_stained_glass", - "id": -694 - }, - { - "name": "minecraft:hard_gray_stained_glass_pane", - "id": -664 - }, - { - "name": "minecraft:hard_green_stained_glass", - "id": -700 - }, - { - "name": "minecraft:hard_green_stained_glass_pane", - "id": -670 - }, - { - "name": "minecraft:hard_light_blue_stained_glass", - "id": -690 - }, - { - "name": "minecraft:hard_light_blue_stained_glass_pane", - "id": -660 - }, - { - "name": "minecraft:hard_light_gray_stained_glass", - "id": -695 - }, - { - "name": "minecraft:hard_light_gray_stained_glass_pane", - "id": -665 - }, - { - "name": "minecraft:hard_lime_stained_glass", - "id": -692 - }, - { - "name": "minecraft:hard_lime_stained_glass_pane", - "id": -662 - }, - { - "name": "minecraft:hard_magenta_stained_glass", - "id": -689 - }, - { - "name": "minecraft:hard_magenta_stained_glass_pane", - "id": -659 - }, - { - "name": "minecraft:hard_orange_stained_glass", - "id": -688 - }, - { - "name": "minecraft:hard_orange_stained_glass_pane", - "id": -658 - }, - { - "name": "minecraft:hard_pink_stained_glass", - "id": -693 - }, - { - "name": "minecraft:hard_pink_stained_glass_pane", - "id": -663 - }, - { - "name": "minecraft:hard_purple_stained_glass", - "id": -697 - }, - { - "name": "minecraft:hard_purple_stained_glass_pane", - "id": -667 - }, - { - "name": "minecraft:hard_red_stained_glass", - "id": -701 - }, - { - "name": "minecraft:hard_red_stained_glass_pane", - "id": -671 - }, - { - "name": "minecraft:hard_stained_glass", - "id": 721 - }, - { - "name": "minecraft:hard_stained_glass_pane", - "id": 722 - }, - { - "name": "minecraft:hard_white_stained_glass", - "id": 254 - }, - { - "name": "minecraft:hard_white_stained_glass_pane", - "id": 191 - }, - { - "name": "minecraft:hard_yellow_stained_glass", - "id": -691 - }, - { - "name": "minecraft:hard_yellow_stained_glass_pane", - "id": -661 - }, - { - "name": "minecraft:hardened_clay", - "id": 172 - }, - { - "name": "minecraft:hay_block", - "id": 170 - }, - { - "name": "minecraft:heart_of_the_sea", - "id": 580 - }, - { - "name": "minecraft:heart_pottery_sherd", - "id": 674 - }, - { - "name": "minecraft:heartbreak_pottery_sherd", - "id": 675 - }, - { - "name": "minecraft:heavy_weighted_pressure_plate", - "id": 148 - }, - { - "name": "minecraft:hoglin_spawn_egg", - "id": 499 - }, - { - "name": "minecraft:honey_block", - "id": -220 - }, - { - "name": "minecraft:honey_bottle", - "id": 601 - }, - { - "name": "minecraft:honeycomb", - "id": 600 - }, - { - "name": "minecraft:honeycomb_block", - "id": -221 - }, - { - "name": "minecraft:hopper", - "id": 536 - }, - { - "name": "minecraft:hopper_minecart", - "id": 535 - }, - { - "name": "minecraft:horn_coral", - "id": -584 - }, - { - "name": "minecraft:horse_spawn_egg", - "id": 461 - }, - { - "name": "minecraft:host_armor_trim_smithing_template", - "id": 702 - }, - { - "name": "minecraft:howl_pottery_sherd", - "id": 676 - }, - { - "name": "minecraft:husk_spawn_egg", - "id": 466 - }, - { - "name": "minecraft:ice", - "id": 79 - }, - { - "name": "minecraft:ice_bomb", - "id": 604 - }, - { - "name": "minecraft:infested_deepslate", - "id": -454 - }, - { - "name": "minecraft:info_update", - "id": 248 - }, - { - "name": "minecraft:info_update2", - "id": 249 - }, - { - "name": "minecraft:ink_sac", - "id": 416 - }, - { - "name": "minecraft:invisible_bedrock", - "id": 95 - }, - { - "name": "minecraft:iron_axe", - "id": 301 - }, - { - "name": "minecraft:iron_bars", - "id": 101 - }, - { - "name": "minecraft:iron_block", - "id": 42 - }, - { - "name": "minecraft:iron_boots", - "id": 349 - }, - { - "name": "minecraft:iron_chestplate", - "id": 347 - }, - { - "name": "minecraft:iron_door", - "id": 375 - }, - { - "name": "minecraft:iron_golem_spawn_egg", - "id": 508 - }, - { - "name": "minecraft:iron_helmet", - "id": 346 - }, - { - "name": "minecraft:iron_hoe", - "id": 334 - }, - { - "name": "minecraft:iron_horse_armor", - "id": 540 - }, - { - "name": "minecraft:iron_ingot", - "id": 308 - }, - { - "name": "minecraft:iron_leggings", - "id": 348 - }, - { - "name": "minecraft:iron_nugget", - "id": 578 - }, - { - "name": "minecraft:iron_ore", - "id": 15 - }, - { - "name": "minecraft:iron_pickaxe", - "id": 300 - }, - { - "name": "minecraft:iron_shovel", - "id": 299 - }, - { - "name": "minecraft:iron_sword", - "id": 310 - }, - { - "name": "minecraft:iron_trapdoor", - "id": 167 - }, - { - "name": "minecraft:item.acacia_door", - "id": 196 - }, - { - "name": "minecraft:item.bed", - "id": 26 - }, - { - "name": "minecraft:item.beetroot", - "id": 244 - }, - { - "name": "minecraft:item.birch_door", - "id": 194 - }, - { - "name": "minecraft:item.brewing_stand", - "id": 117 - }, - { - "name": "minecraft:item.cake", - "id": 92 - }, - { - "name": "minecraft:item.camera", - "id": 242 - }, - { - "name": "minecraft:item.campfire", - "id": -209 - }, - { - "name": "minecraft:item.cauldron", - "id": 118 - }, - { - "name": "minecraft:item.chain", - "id": -286 - }, - { - "name": "minecraft:item.crimson_door", - "id": -244 - }, - { - "name": "minecraft:item.dark_oak_door", - "id": 197 - }, - { - "name": "minecraft:item.flower_pot", - "id": 140 - }, - { - "name": "minecraft:item.frame", - "id": 199 - }, - { - "name": "minecraft:item.glow_frame", - "id": -339 - }, - { - "name": "minecraft:item.hopper", - "id": 154 - }, - { - "name": "minecraft:item.iron_door", - "id": 71 - }, - { - "name": "minecraft:item.jungle_door", - "id": 195 - }, - { - "name": "minecraft:item.kelp", - "id": -138 - }, - { - "name": "minecraft:item.mangrove_door", - "id": -493 - }, - { - "name": "minecraft:item.nether_sprouts", - "id": -238 - }, - { - "name": "minecraft:item.nether_wart", - "id": 115 - }, - { - "name": "minecraft:item.reeds", - "id": 83 - }, - { - "name": "minecraft:item.skull", - "id": 144 - }, - { - "name": "minecraft:item.soul_campfire", - "id": -290 - }, - { - "name": "minecraft:item.spruce_door", - "id": 193 - }, - { - "name": "minecraft:item.warped_door", - "id": -245 - }, - { - "name": "minecraft:item.wheat", - "id": 59 - }, - { - "name": "minecraft:item.wooden_door", - "id": 64 - }, - { - "name": "minecraft:jigsaw", - "id": -211 - }, - { - "name": "minecraft:jukebox", - "id": 84 - }, - { - "name": "minecraft:jungle_boat", - "id": 380 - }, - { - "name": "minecraft:jungle_button", - "id": -143 - }, - { - "name": "minecraft:jungle_chest_boat", - "id": 649 - }, - { - "name": "minecraft:jungle_door", - "id": 564 - }, - { - "name": "minecraft:jungle_fence", - "id": -578 - }, - { - "name": "minecraft:jungle_fence_gate", - "id": 185 - }, - { - "name": "minecraft:jungle_hanging_sign", - "id": -503 - }, - { - "name": "minecraft:jungle_log", - "id": -571 - }, - { - "name": "minecraft:jungle_planks", - "id": -741 - }, - { - "name": "minecraft:jungle_pressure_plate", - "id": -153 - }, - { - "name": "minecraft:jungle_sign", - "id": 587 - }, - { - "name": "minecraft:jungle_stairs", - "id": 136 - }, - { - "name": "minecraft:jungle_standing_sign", - "id": -188 - }, - { - "name": "minecraft:jungle_trapdoor", - "id": -148 - }, - { - "name": "minecraft:jungle_wall_sign", - "id": -189 - }, - { - "name": "minecraft:kelp", - "id": 385 - }, - { - "name": "minecraft:ladder", - "id": 65 - }, - { - "name": "minecraft:lantern", - "id": -208 - }, - { - "name": "minecraft:lapis_block", - "id": 22 - }, - { - "name": "minecraft:lapis_lazuli", - "id": 417 - }, - { - "name": "minecraft:lapis_ore", - "id": 21 - }, - { - "name": "minecraft:large_amethyst_bud", - "id": -330 - }, - { - "name": "minecraft:lava", - "id": 11 - }, - { - "name": "minecraft:lava_bucket", - "id": 366 - }, - { - "name": "minecraft:lead", - "id": 556 - }, - { - "name": "minecraft:leather", - "id": 384 - }, - { - "name": "minecraft:leather_boots", - "id": 341 - }, - { - "name": "minecraft:leather_chestplate", - "id": 339 - }, - { - "name": "minecraft:leather_helmet", - "id": 338 - }, - { - "name": "minecraft:leather_horse_armor", - "id": 539 - }, - { - "name": "minecraft:leather_leggings", - "id": 340 - }, - { - "name": "minecraft:leaves", - "id": 18 - }, - { - "name": "minecraft:leaves2", - "id": 161 - }, - { - "name": "minecraft:lectern", - "id": -194 - }, - { - "name": "minecraft:lever", - "id": 69 - }, - { - "name": "minecraft:light_block", - "id": -215 - }, - { - "name": "minecraft:light_blue_candle", - "id": -416 - }, - { - "name": "minecraft:light_blue_candle_cake", - "id": -433 - }, - { - "name": "minecraft:light_blue_carpet", - "id": -599 - }, - { - "name": "minecraft:light_blue_concrete", - "id": -630 - }, - { - "name": "minecraft:light_blue_concrete_powder", - "id": -711 - }, - { - "name": "minecraft:light_blue_dye", - "id": 410 - }, - { - "name": "minecraft:light_blue_glazed_terracotta", - "id": 223 - }, - { - "name": "minecraft:light_blue_shulker_box", - "id": -615 - }, - { - "name": "minecraft:light_blue_stained_glass", - "id": -675 - }, - { - "name": "minecraft:light_blue_stained_glass_pane", - "id": -645 - }, - { - "name": "minecraft:light_blue_terracotta", - "id": -726 - }, - { - "name": "minecraft:light_blue_wool", - "id": -562 - }, - { - "name": "minecraft:light_gray_candle", - "id": -421 - }, - { - "name": "minecraft:light_gray_candle_cake", - "id": -438 - }, - { - "name": "minecraft:light_gray_carpet", - "id": -604 - }, - { - "name": "minecraft:light_gray_concrete", - "id": -635 - }, - { - "name": "minecraft:light_gray_concrete_powder", - "id": -716 - }, - { - "name": "minecraft:light_gray_dye", - "id": 405 - }, - { - "name": "minecraft:light_gray_shulker_box", - "id": -620 - }, - { - "name": "minecraft:light_gray_stained_glass", - "id": -680 - }, - { - "name": "minecraft:light_gray_stained_glass_pane", - "id": -650 - }, - { - "name": "minecraft:light_gray_terracotta", - "id": -731 - }, - { - "name": "minecraft:light_gray_wool", - "id": -552 - }, - { - "name": "minecraft:light_weighted_pressure_plate", - "id": 147 - }, - { - "name": "minecraft:lightning_rod", - "id": -312 - }, - { - "name": "minecraft:lime_candle", - "id": -418 - }, - { - "name": "minecraft:lime_candle_cake", - "id": -435 - }, - { - "name": "minecraft:lime_carpet", - "id": -601 - }, - { - "name": "minecraft:lime_concrete", - "id": -632 - }, - { - "name": "minecraft:lime_concrete_powder", - "id": -713 - }, - { - "name": "minecraft:lime_dye", - "id": 408 - }, - { - "name": "minecraft:lime_glazed_terracotta", - "id": 225 - }, - { - "name": "minecraft:lime_shulker_box", - "id": -617 - }, - { - "name": "minecraft:lime_stained_glass", - "id": -677 - }, - { - "name": "minecraft:lime_stained_glass_pane", - "id": -647 - }, - { - "name": "minecraft:lime_terracotta", - "id": -728 - }, - { - "name": "minecraft:lime_wool", - "id": -559 - }, - { - "name": "minecraft:lingering_potion", - "id": 571 - }, - { - "name": "minecraft:lit_blast_furnace", - "id": -214 - }, - { - "name": "minecraft:lit_deepslate_redstone_ore", - "id": -404 - }, - { - "name": "minecraft:lit_furnace", - "id": 62 - }, - { - "name": "minecraft:lit_pumpkin", - "id": 91 - }, - { - "name": "minecraft:lit_redstone_lamp", - "id": 124 - }, - { - "name": "minecraft:lit_redstone_ore", - "id": 74 - }, - { - "name": "minecraft:lit_smoker", - "id": -199 - }, - { - "name": "minecraft:llama_spawn_egg", - "id": 476 - }, - { - "name": "minecraft:lodestone", - "id": -222 - }, - { - "name": "minecraft:lodestone_compass", - "id": 611 - }, - { - "name": "minecraft:log", - "id": 711 - }, - { - "name": "minecraft:log2", - "id": 715 - }, - { - "name": "minecraft:loom", - "id": -204 - }, - { - "name": "minecraft:magenta_candle", - "id": -415 - }, - { - "name": "minecraft:magenta_candle_cake", - "id": -432 - }, - { - "name": "minecraft:magenta_carpet", - "id": -598 - }, - { - "name": "minecraft:magenta_concrete", - "id": -629 - }, - { - "name": "minecraft:magenta_concrete_powder", - "id": -710 - }, - { - "name": "minecraft:magenta_dye", - "id": 411 - }, - { - "name": "minecraft:magenta_glazed_terracotta", - "id": 222 - }, - { - "name": "minecraft:magenta_shulker_box", - "id": -614 - }, - { - "name": "minecraft:magenta_stained_glass", - "id": -674 - }, - { - "name": "minecraft:magenta_stained_glass_pane", - "id": -644 - }, - { - "name": "minecraft:magenta_terracotta", - "id": -725 - }, - { - "name": "minecraft:magenta_wool", - "id": -565 - }, - { - "name": "minecraft:magma", - "id": 213 - }, - { - "name": "minecraft:magma_cream", - "id": 433 - }, - { - "name": "minecraft:magma_cube_spawn_egg", - "id": 458 - }, - { - "name": "minecraft:mangrove_boat", - "id": 644 - }, - { - "name": "minecraft:mangrove_button", - "id": -487 - }, - { - "name": "minecraft:mangrove_chest_boat", - "id": 653 - }, - { - "name": "minecraft:mangrove_door", - "id": 642 - }, - { - "name": "minecraft:mangrove_double_slab", - "id": -499 - }, - { - "name": "minecraft:mangrove_fence", - "id": -491 - }, - { - "name": "minecraft:mangrove_fence_gate", - "id": -492 - }, - { - "name": "minecraft:mangrove_hanging_sign", - "id": -508 - }, - { - "name": "minecraft:mangrove_leaves", - "id": -472 - }, - { - "name": "minecraft:mangrove_log", - "id": -484 - }, - { - "name": "minecraft:mangrove_planks", - "id": -486 - }, - { - "name": "minecraft:mangrove_pressure_plate", - "id": -490 - }, - { - "name": "minecraft:mangrove_propagule", - "id": -474 - }, - { - "name": "minecraft:mangrove_roots", - "id": -482 - }, - { - "name": "minecraft:mangrove_sign", - "id": 643 - }, - { - "name": "minecraft:mangrove_slab", - "id": -489 - }, - { - "name": "minecraft:mangrove_stairs", - "id": -488 - }, - { - "name": "minecraft:mangrove_standing_sign", - "id": -494 - }, - { - "name": "minecraft:mangrove_trapdoor", - "id": -496 - }, - { - "name": "minecraft:mangrove_wall_sign", - "id": -495 - }, - { - "name": "minecraft:mangrove_wood", - "id": -497 - }, - { - "name": "minecraft:medicine", - "id": 608 - }, - { - "name": "minecraft:medium_amethyst_bud", - "id": -331 - }, - { - "name": "minecraft:melon_block", - "id": 103 - }, - { - "name": "minecraft:melon_seeds", - "id": 294 - }, - { - "name": "minecraft:melon_slice", - "id": 273 - }, - { - "name": "minecraft:melon_stem", - "id": 105 - }, - { - "name": "minecraft:milk_bucket", - "id": 364 - }, - { - "name": "minecraft:minecart", - "id": 373 - }, - { - "name": "minecraft:miner_pottery_sherd", - "id": 677 - }, - { - "name": "minecraft:mob_spawner", - "id": 52 - }, - { - "name": "minecraft:mojang_banner_pattern", - "id": 593 - }, - { - "name": "minecraft:monster_egg", - "id": 97 - }, - { - "name": "minecraft:mooshroom_spawn_egg", - "id": 443 - }, - { - "name": "minecraft:moss_block", - "id": -320 - }, - { - "name": "minecraft:moss_carpet", - "id": -335 - }, - { - "name": "minecraft:mossy_cobblestone", - "id": 48 - }, - { - "name": "minecraft:mossy_cobblestone_stairs", - "id": -179 - }, - { - "name": "minecraft:mossy_stone_brick_stairs", - "id": -175 - }, - { - "name": "minecraft:mourner_pottery_sherd", - "id": 678 - }, - { - "name": "minecraft:moving_block", - "id": 250 - }, - { - "name": "minecraft:mud", - "id": -473 - }, - { - "name": "minecraft:mud_brick_double_slab", - "id": -479 - }, - { - "name": "minecraft:mud_brick_slab", - "id": -478 - }, - { - "name": "minecraft:mud_brick_stairs", - "id": -480 - }, - { - "name": "minecraft:mud_brick_wall", - "id": -481 - }, - { - "name": "minecraft:mud_bricks", - "id": -475 - }, - { - "name": "minecraft:muddy_mangrove_roots", - "id": -483 - }, - { - "name": "minecraft:mule_spawn_egg", - "id": 469 - }, - { - "name": "minecraft:mushroom_stew", - "id": 261 - }, - { - "name": "minecraft:music_disc_11", - "id": 553 - }, - { - "name": "minecraft:music_disc_13", - "id": 543 - }, - { - "name": "minecraft:music_disc_5", - "id": 645 - }, - { - "name": "minecraft:music_disc_blocks", - "id": 545 - }, - { - "name": "minecraft:music_disc_cat", - "id": 544 - }, - { - "name": "minecraft:music_disc_chirp", - "id": 546 - }, - { - "name": "minecraft:music_disc_far", - "id": 547 - }, - { - "name": "minecraft:music_disc_mall", - "id": 548 - }, - { - "name": "minecraft:music_disc_mellohi", - "id": 549 - }, - { - "name": "minecraft:music_disc_otherside", - "id": 635 - }, - { - "name": "minecraft:music_disc_pigstep", - "id": 629 - }, - { - "name": "minecraft:music_disc_relic", - "id": 703 - }, - { - "name": "minecraft:music_disc_stal", - "id": 550 - }, - { - "name": "minecraft:music_disc_strad", - "id": 551 - }, - { - "name": "minecraft:music_disc_wait", - "id": 554 - }, - { - "name": "minecraft:music_disc_ward", - "id": 552 - }, - { - "name": "minecraft:mutton", - "id": 559 - }, - { - "name": "minecraft:mycelium", - "id": 110 - }, - { - "name": "minecraft:name_tag", - "id": 557 - }, - { - "name": "minecraft:nautilus_shell", - "id": 579 - }, - { - "name": "minecraft:nether_brick", - "id": 112 - }, - { - "name": "minecraft:nether_brick_fence", - "id": 113 - }, - { - "name": "minecraft:nether_brick_stairs", - "id": 114 - }, - { - "name": "minecraft:nether_gold_ore", - "id": -288 - }, - { - "name": "minecraft:nether_sprouts", - "id": 630 - }, - { - "name": "minecraft:nether_star", - "id": 527 - }, - { - "name": "minecraft:nether_wart", - "id": 295 - }, - { - "name": "minecraft:nether_wart_block", - "id": 214 - }, - { - "name": "minecraft:netherbrick", - "id": 532 - }, - { - "name": "minecraft:netherite_axe", - "id": 615 - }, - { - "name": "minecraft:netherite_block", - "id": -270 - }, - { - "name": "minecraft:netherite_boots", - "id": 621 - }, - { - "name": "minecraft:netherite_chestplate", - "id": 619 - }, - { - "name": "minecraft:netherite_helmet", - "id": 618 - }, - { - "name": "minecraft:netherite_hoe", - "id": 616 - }, - { - "name": "minecraft:netherite_ingot", - "id": 617 - }, - { - "name": "minecraft:netherite_leggings", - "id": 620 - }, - { - "name": "minecraft:netherite_pickaxe", - "id": 614 - }, - { - "name": "minecraft:netherite_scrap", - "id": 622 - }, - { - "name": "minecraft:netherite_shovel", - "id": 613 - }, - { - "name": "minecraft:netherite_sword", - "id": 612 - }, - { - "name": "minecraft:netherite_upgrade_smithing_template", - "id": 686 - }, - { - "name": "minecraft:netherrack", - "id": 87 - }, - { - "name": "minecraft:netherreactor", - "id": 247 - }, - { - "name": "minecraft:normal_stone_stairs", - "id": -180 - }, - { - "name": "minecraft:noteblock", - "id": 25 - }, - { - "name": "minecraft:npc_spawn_egg", - "id": 473 - }, - { - "name": "minecraft:oak_boat", - "id": 378 - }, - { - "name": "minecraft:oak_chest_boat", - "id": 647 - }, - { - "name": "minecraft:oak_fence", - "id": 85 - }, - { - "name": "minecraft:oak_hanging_sign", - "id": -500 - }, - { - "name": "minecraft:oak_log", - "id": 17 - }, - { - "name": "minecraft:oak_planks", - "id": 5 - }, - { - "name": "minecraft:oak_sign", - "id": 361 - }, - { - "name": "minecraft:oak_stairs", - "id": 53 - }, - { - "name": "minecraft:observer", - "id": 251 - }, - { - "name": "minecraft:obsidian", - "id": 49 - }, - { - "name": "minecraft:ocelot_spawn_egg", - "id": 454 - }, - { - "name": "minecraft:ochre_froglight", - "id": -471 - }, - { - "name": "minecraft:orange_candle", - "id": -414 - }, - { - "name": "minecraft:orange_candle_cake", - "id": -431 - }, - { - "name": "minecraft:orange_carpet", - "id": -597 - }, - { - "name": "minecraft:orange_concrete", - "id": -628 - }, - { - "name": "minecraft:orange_concrete_powder", - "id": -709 - }, - { - "name": "minecraft:orange_dye", - "id": 412 - }, - { - "name": "minecraft:orange_glazed_terracotta", - "id": 221 - }, - { - "name": "minecraft:orange_shulker_box", - "id": -613 - }, - { - "name": "minecraft:orange_stained_glass", - "id": -673 - }, - { - "name": "minecraft:orange_stained_glass_pane", - "id": -643 - }, - { - "name": "minecraft:orange_terracotta", - "id": -724 - }, - { - "name": "minecraft:orange_wool", - "id": -557 - }, - { - "name": "minecraft:oxidized_chiseled_copper", - "id": -763 - }, - { - "name": "minecraft:oxidized_copper", - "id": -343 - }, - { - "name": "minecraft:oxidized_copper_bulb", - "id": -779 - }, - { - "name": "minecraft:oxidized_copper_door", - "id": -787 - }, - { - "name": "minecraft:oxidized_copper_grate", - "id": -771 - }, - { - "name": "minecraft:oxidized_copper_trapdoor", - "id": -795 - }, - { - "name": "minecraft:oxidized_cut_copper", - "id": -350 - }, - { - "name": "minecraft:oxidized_cut_copper_slab", - "id": -364 - }, - { - "name": "minecraft:oxidized_cut_copper_stairs", - "id": -357 - }, - { - "name": "minecraft:oxidized_double_cut_copper_slab", - "id": -371 - }, - { - "name": "minecraft:packed_ice", - "id": 174 - }, - { - "name": "minecraft:packed_mud", - "id": -477 - }, - { - "name": "minecraft:painting", - "id": 360 - }, - { - "name": "minecraft:panda_spawn_egg", - "id": 492 - }, - { - "name": "minecraft:paper", - "id": 389 - }, - { - "name": "minecraft:parrot_spawn_egg", - "id": 481 - }, - { - "name": "minecraft:pearlescent_froglight", - "id": -469 - }, - { - "name": "minecraft:phantom_membrane", - "id": 583 - }, - { - "name": "minecraft:phantom_spawn_egg", - "id": 489 - }, - { - "name": "minecraft:pig_spawn_egg", - "id": 440 - }, - { - "name": "minecraft:piglin_banner_pattern", - "id": 596 - }, - { - "name": "minecraft:piglin_brute_spawn_egg", - "id": 502 - }, - { - "name": "minecraft:piglin_spawn_egg", - "id": 500 - }, - { - "name": "minecraft:pillager_spawn_egg", - "id": 494 - }, - { - "name": "minecraft:pink_candle", - "id": -419 - }, - { - "name": "minecraft:pink_candle_cake", - "id": -436 - }, - { - "name": "minecraft:pink_carpet", - "id": -602 - }, - { - "name": "minecraft:pink_concrete", - "id": -633 - }, - { - "name": "minecraft:pink_concrete_powder", - "id": -714 - }, - { - "name": "minecraft:pink_dye", - "id": 407 - }, - { - "name": "minecraft:pink_glazed_terracotta", - "id": 226 - }, - { - "name": "minecraft:pink_petals", - "id": -549 - }, - { - "name": "minecraft:pink_shulker_box", - "id": -618 - }, - { - "name": "minecraft:pink_stained_glass", - "id": -678 - }, - { - "name": "minecraft:pink_stained_glass_pane", - "id": -648 - }, - { - "name": "minecraft:pink_terracotta", - "id": -729 - }, - { - "name": "minecraft:pink_wool", - "id": -566 - }, - { - "name": "minecraft:piston", - "id": 33 - }, - { - "name": "minecraft:piston_arm_collision", - "id": 34 - }, - { - "name": "minecraft:pitcher_crop", - "id": -574 - }, - { - "name": "minecraft:pitcher_plant", - "id": -612 - }, - { - "name": "minecraft:pitcher_pod", - "id": 298 - }, - { - "name": "minecraft:planks", - "id": 713 - }, - { - "name": "minecraft:plenty_pottery_sherd", - "id": 679 - }, - { - "name": "minecraft:podzol", - "id": 243 - }, - { - "name": "minecraft:pointed_dripstone", - "id": -308 - }, - { - "name": "minecraft:poisonous_potato", - "id": 283 - }, - { - "name": "minecraft:polar_bear_spawn_egg", - "id": 475 - }, - { - "name": "minecraft:polished_andesite", - "id": -595 - }, - { - "name": "minecraft:polished_andesite_stairs", - "id": -174 - }, - { - "name": "minecraft:polished_basalt", - "id": -235 - }, - { - "name": "minecraft:polished_blackstone", - "id": -291 - }, - { - "name": "minecraft:polished_blackstone_brick_double_slab", - "id": -285 - }, - { - "name": "minecraft:polished_blackstone_brick_slab", - "id": -284 - }, - { - "name": "minecraft:polished_blackstone_brick_stairs", - "id": -275 - }, - { - "name": "minecraft:polished_blackstone_brick_wall", - "id": -278 - }, - { - "name": "minecraft:polished_blackstone_bricks", - "id": -274 - }, - { - "name": "minecraft:polished_blackstone_button", - "id": -296 - }, - { - "name": "minecraft:polished_blackstone_double_slab", - "id": -294 - }, - { - "name": "minecraft:polished_blackstone_pressure_plate", - "id": -295 - }, - { - "name": "minecraft:polished_blackstone_slab", - "id": -293 - }, - { - "name": "minecraft:polished_blackstone_stairs", - "id": -292 - }, - { - "name": "minecraft:polished_blackstone_wall", - "id": -297 - }, - { - "name": "minecraft:polished_deepslate", - "id": -383 - }, - { - "name": "minecraft:polished_deepslate_double_slab", - "id": -397 - }, - { - "name": "minecraft:polished_deepslate_slab", - "id": -384 - }, - { - "name": "minecraft:polished_deepslate_stairs", - "id": -385 - }, - { - "name": "minecraft:polished_deepslate_wall", - "id": -386 - }, - { - "name": "minecraft:polished_diorite", - "id": -593 - }, - { - "name": "minecraft:polished_diorite_stairs", - "id": -173 - }, - { - "name": "minecraft:polished_granite", - "id": -591 - }, - { - "name": "minecraft:polished_granite_stairs", - "id": -172 - }, - { - "name": "minecraft:polished_tuff", - "id": -748 - }, - { - "name": "minecraft:polished_tuff_double_slab", - "id": -750 - }, - { - "name": "minecraft:polished_tuff_slab", - "id": -749 - }, - { - "name": "minecraft:polished_tuff_stairs", - "id": -751 - }, - { - "name": "minecraft:polished_tuff_wall", - "id": -752 - }, - { - "name": "minecraft:popped_chorus_fruit", - "id": 568 - }, - { - "name": "minecraft:porkchop", - "id": 263 - }, - { - "name": "minecraft:portal", - "id": 90 - }, - { - "name": "minecraft:potato", - "id": 281 - }, - { - "name": "minecraft:potatoes", - "id": 142 - }, - { - "name": "minecraft:potion", - "id": 429 - }, - { - "name": "minecraft:powder_snow", - "id": -306 - }, - { - "name": "minecraft:powder_snow_bucket", - "id": 371 - }, - { - "name": "minecraft:powered_comparator", - "id": 150 - }, - { - "name": "minecraft:powered_repeater", - "id": 94 - }, - { - "name": "minecraft:prismarine", - "id": 168 - }, - { - "name": "minecraft:prismarine_bricks_stairs", - "id": -4 - }, - { - "name": "minecraft:prismarine_crystals", - "id": 558 - }, - { - "name": "minecraft:prismarine_shard", - "id": 574 - }, - { - "name": "minecraft:prismarine_stairs", - "id": -2 - }, - { - "name": "minecraft:prize_pottery_sherd", - "id": 680 - }, - { - "name": "minecraft:pufferfish", - "id": 268 - }, - { - "name": "minecraft:pufferfish_bucket", - "id": 370 - }, - { - "name": "minecraft:pufferfish_spawn_egg", - "id": 484 - }, - { - "name": "minecraft:pumpkin", - "id": 86 - }, - { - "name": "minecraft:pumpkin_pie", - "id": 285 - }, - { - "name": "minecraft:pumpkin_seeds", - "id": 293 - }, - { - "name": "minecraft:pumpkin_stem", - "id": 104 - }, - { - "name": "minecraft:purple_candle", - "id": -423 - }, - { - "name": "minecraft:purple_candle_cake", - "id": -440 - }, - { - "name": "minecraft:purple_carpet", - "id": -606 - }, - { - "name": "minecraft:purple_concrete", - "id": -637 - }, - { - "name": "minecraft:purple_concrete_powder", - "id": -718 - }, - { - "name": "minecraft:purple_dye", - "id": 403 - }, - { - "name": "minecraft:purple_glazed_terracotta", - "id": 219 - }, - { - "name": "minecraft:purple_shulker_box", - "id": -622 - }, - { - "name": "minecraft:purple_stained_glass", - "id": -682 - }, - { - "name": "minecraft:purple_stained_glass_pane", - "id": -652 - }, - { - "name": "minecraft:purple_terracotta", - "id": -733 - }, - { - "name": "minecraft:purple_wool", - "id": -564 - }, - { - "name": "minecraft:purpur_block", - "id": 201 - }, - { - "name": "minecraft:purpur_stairs", - "id": 203 - }, - { - "name": "minecraft:quartz", - "id": 533 - }, - { - "name": "minecraft:quartz_block", - "id": 155 - }, - { - "name": "minecraft:quartz_bricks", - "id": -304 - }, - { - "name": "minecraft:quartz_ore", - "id": 153 - }, - { - "name": "minecraft:quartz_stairs", - "id": 156 - }, - { - "name": "minecraft:rabbit", - "id": 289 - }, - { - "name": "minecraft:rabbit_foot", - "id": 537 - }, - { - "name": "minecraft:rabbit_hide", - "id": 538 - }, - { - "name": "minecraft:rabbit_spawn_egg", - "id": 462 - }, - { - "name": "minecraft:rabbit_stew", - "id": 291 - }, - { - "name": "minecraft:rail", - "id": 66 - }, - { - "name": "minecraft:raiser_armor_trim_smithing_template", - "id": 700 - }, - { - "name": "minecraft:rapid_fertilizer", - "id": 606 - }, - { - "name": "minecraft:ravager_spawn_egg", - "id": 496 - }, - { - "name": "minecraft:raw_copper", - "id": 516 - }, - { - "name": "minecraft:raw_copper_block", - "id": -452 - }, - { - "name": "minecraft:raw_gold", - "id": 515 - }, - { - "name": "minecraft:raw_gold_block", - "id": -453 - }, - { - "name": "minecraft:raw_iron", - "id": 514 - }, - { - "name": "minecraft:raw_iron_block", - "id": -451 - }, - { - "name": "minecraft:recovery_compass", - "id": 655 - }, - { - "name": "minecraft:red_candle", - "id": -427 - }, - { - "name": "minecraft:red_candle_cake", - "id": -444 - }, - { - "name": "minecraft:red_carpet", - "id": -610 - }, - { - "name": "minecraft:red_concrete", - "id": -641 - }, - { - "name": "minecraft:red_concrete_powder", - "id": -722 - }, - { - "name": "minecraft:red_dye", - "id": 399 - }, - { - "name": "minecraft:red_flower", - "id": 38 - }, - { - "name": "minecraft:red_glazed_terracotta", - "id": 234 - }, - { - "name": "minecraft:red_mushroom", - "id": 40 - }, - { - "name": "minecraft:red_mushroom_block", - "id": 100 - }, - { - "name": "minecraft:red_nether_brick", - "id": 215 - }, - { - "name": "minecraft:red_nether_brick_stairs", - "id": -184 - }, - { - "name": "minecraft:red_sandstone", - "id": 179 - }, - { - "name": "minecraft:red_sandstone_stairs", - "id": 180 - }, - { - "name": "minecraft:red_shulker_box", - "id": -626 - }, - { - "name": "minecraft:red_stained_glass", - "id": -686 - }, - { - "name": "minecraft:red_stained_glass_pane", - "id": -656 - }, - { - "name": "minecraft:red_terracotta", - "id": -737 - }, - { - "name": "minecraft:red_wool", - "id": -556 - }, - { - "name": "minecraft:redstone", - "id": 376 - }, - { - "name": "minecraft:redstone_block", - "id": 152 - }, - { - "name": "minecraft:redstone_lamp", - "id": 123 - }, - { - "name": "minecraft:redstone_ore", - "id": 73 - }, - { - "name": "minecraft:redstone_torch", - "id": 76 - }, - { - "name": "minecraft:redstone_wire", - "id": 55 - }, - { - "name": "minecraft:reinforced_deepslate", - "id": -466 - }, - { - "name": "minecraft:repeater", - "id": 422 - }, - { - "name": "minecraft:repeating_command_block", - "id": 188 - }, - { - "name": "minecraft:reserved6", - "id": 255 - }, - { - "name": "minecraft:respawn_anchor", - "id": -272 - }, - { - "name": "minecraft:rib_armor_trim_smithing_template", - "id": 696 - }, - { - "name": "minecraft:rotten_flesh", - "id": 278 - }, - { - "name": "minecraft:saddle", - "id": 374 - }, - { - "name": "minecraft:salmon", - "id": 266 - }, - { - "name": "minecraft:salmon_bucket", - "id": 368 - }, - { - "name": "minecraft:salmon_spawn_egg", - "id": 485 - }, - { - "name": "minecraft:sand", - "id": 12 - }, - { - "name": "minecraft:sandstone", - "id": 24 - }, - { - "name": "minecraft:sandstone_stairs", - "id": 128 - }, - { - "name": "minecraft:sapling", - "id": 6 - }, - { - "name": "minecraft:scaffolding", - "id": -165 - }, - { - "name": "minecraft:sculk", - "id": -458 - }, - { - "name": "minecraft:sculk_catalyst", - "id": -460 - }, - { - "name": "minecraft:sculk_sensor", - "id": -307 - }, - { - "name": "minecraft:sculk_shrieker", - "id": -461 - }, - { - "name": "minecraft:sculk_vein", - "id": -459 - }, - { - "name": "minecraft:sea_lantern", - "id": 169 - }, - { - "name": "minecraft:sea_pickle", - "id": -156 - }, - { - "name": "minecraft:seagrass", - "id": -130 - }, - { - "name": "minecraft:sentry_armor_trim_smithing_template", - "id": 687 - }, - { - "name": "minecraft:shaper_armor_trim_smithing_template", - "id": 701 - }, - { - "name": "minecraft:sheaf_pottery_sherd", - "id": 681 - }, - { - "name": "minecraft:shears", - "id": 424 - }, - { - "name": "minecraft:sheep_spawn_egg", - "id": 441 - }, - { - "name": "minecraft:shelter_pottery_sherd", - "id": 682 - }, - { - "name": "minecraft:shield", - "id": 358 - }, - { - "name": "minecraft:shroomlight", - "id": -230 - }, - { - "name": "minecraft:shulker_box", - "id": 720 - }, - { - "name": "minecraft:shulker_shell", - "id": 575 - }, - { - "name": "minecraft:shulker_spawn_egg", - "id": 472 - }, - { - "name": "minecraft:silence_armor_trim_smithing_template", - "id": 698 - }, - { - "name": "minecraft:silver_glazed_terracotta", - "id": 228 - }, - { - "name": "minecraft:silverfish_spawn_egg", - "id": 446 - }, - { - "name": "minecraft:skeleton_horse_spawn_egg", - "id": 470 - }, - { - "name": "minecraft:skeleton_spawn_egg", - "id": 447 - }, - { - "name": "minecraft:skull", - "id": 525 - }, - { - "name": "minecraft:skull_banner_pattern", - "id": 592 - }, - { - "name": "minecraft:skull_pottery_sherd", - "id": 683 - }, - { - "name": "minecraft:slime", - "id": 165 - }, - { - "name": "minecraft:slime_ball", - "id": 391 - }, - { - "name": "minecraft:slime_spawn_egg", - "id": 448 - }, - { - "name": "minecraft:small_amethyst_bud", - "id": -332 - }, - { - "name": "minecraft:small_dripleaf_block", - "id": -336 - }, - { - "name": "minecraft:smithing_table", - "id": -202 - }, - { - "name": "minecraft:smoker", - "id": -198 - }, - { - "name": "minecraft:smooth_basalt", - "id": -377 - }, - { - "name": "minecraft:smooth_quartz_stairs", - "id": -185 - }, - { - "name": "minecraft:smooth_red_sandstone_stairs", - "id": -176 - }, - { - "name": "minecraft:smooth_sandstone_stairs", - "id": -177 - }, - { - "name": "minecraft:smooth_stone", - "id": -183 - }, - { - "name": "minecraft:sniffer_egg", - "id": -596 - }, - { - "name": "minecraft:sniffer_spawn_egg", - "id": 503 - }, - { - "name": "minecraft:snort_pottery_sherd", - "id": 684 - }, - { - "name": "minecraft:snout_armor_trim_smithing_template", - "id": 695 - }, - { - "name": "minecraft:snow", - "id": 80 - }, - { - "name": "minecraft:snow_golem_spawn_egg", - "id": 509 - }, - { - "name": "minecraft:snow_layer", - "id": 78 - }, - { - "name": "minecraft:snowball", - "id": 377 - }, - { - "name": "minecraft:soul_campfire", - "id": 631 - }, - { - "name": "minecraft:soul_fire", - "id": -237 - }, - { - "name": "minecraft:soul_lantern", - "id": -269 - }, - { - "name": "minecraft:soul_sand", - "id": 88 - }, - { - "name": "minecraft:soul_soil", - "id": -236 - }, - { - "name": "minecraft:soul_torch", - "id": -268 - }, - { - "name": "minecraft:sparkler", - "id": 609 - }, - { - "name": "minecraft:spawn_egg", - "id": 726 - }, - { - "name": "minecraft:spider_eye", - "id": 279 - }, - { - "name": "minecraft:spider_spawn_egg", - "id": 449 - }, - { - "name": "minecraft:spire_armor_trim_smithing_template", - "id": 697 - }, - { - "name": "minecraft:splash_potion", - "id": 570 - }, - { - "name": "minecraft:sponge", - "id": 19 - }, - { - "name": "minecraft:spore_blossom", - "id": -321 - }, - { - "name": "minecraft:spruce_boat", - "id": 381 - }, - { - "name": "minecraft:spruce_button", - "id": -144 - }, - { - "name": "minecraft:spruce_chest_boat", - "id": 650 - }, - { - "name": "minecraft:spruce_door", - "id": 562 - }, - { - "name": "minecraft:spruce_fence", - "id": -579 - }, - { - "name": "minecraft:spruce_fence_gate", - "id": 183 - }, - { - "name": "minecraft:spruce_hanging_sign", - "id": -501 - }, - { - "name": "minecraft:spruce_log", - "id": -569 - }, - { - "name": "minecraft:spruce_planks", - "id": -739 - }, - { - "name": "minecraft:spruce_pressure_plate", - "id": -154 - }, - { - "name": "minecraft:spruce_sign", - "id": 585 - }, - { - "name": "minecraft:spruce_stairs", - "id": 134 - }, - { - "name": "minecraft:spruce_standing_sign", - "id": -181 - }, - { - "name": "minecraft:spruce_trapdoor", - "id": -149 - }, - { - "name": "minecraft:spruce_wall_sign", - "id": -182 - }, - { - "name": "minecraft:spyglass", - "id": 634 - }, - { - "name": "minecraft:squid_spawn_egg", - "id": 453 - }, - { - "name": "minecraft:stained_glass", - "id": 718 - }, - { - "name": "minecraft:stained_glass_pane", - "id": 719 - }, - { - "name": "minecraft:stained_hardened_clay", - "id": 704 - }, - { - "name": "minecraft:standing_banner", - "id": 176 - }, - { - "name": "minecraft:standing_sign", - "id": 63 - }, - { - "name": "minecraft:stick", - "id": 323 - }, - { - "name": "minecraft:sticky_piston", - "id": 29 - }, - { - "name": "minecraft:sticky_piston_arm_collision", - "id": -217 - }, - { - "name": "minecraft:stone", - "id": 1 - }, - { - "name": "minecraft:stone_axe", - "id": 318 - }, - { - "name": "minecraft:stone_block_slab", - "id": 44 - }, - { - "name": "minecraft:stone_block_slab2", - "id": 182 - }, - { - "name": "minecraft:stone_block_slab3", - "id": -162 - }, - { - "name": "minecraft:stone_block_slab4", - "id": -166 - }, - { - "name": "minecraft:stone_brick_stairs", - "id": 109 - }, - { - "name": "minecraft:stone_button", - "id": 77 - }, - { - "name": "minecraft:stone_hoe", - "id": 333 - }, - { - "name": "minecraft:stone_pickaxe", - "id": 317 - }, - { - "name": "minecraft:stone_pressure_plate", - "id": 70 - }, - { - "name": "minecraft:stone_shovel", - "id": 316 - }, - { - "name": "minecraft:stone_stairs", - "id": 67 - }, - { - "name": "minecraft:stone_sword", - "id": 315 - }, - { - "name": "minecraft:stonebrick", - "id": 98 - }, - { - "name": "minecraft:stonecutter", - "id": 245 - }, - { - "name": "minecraft:stonecutter_block", - "id": -197 - }, - { - "name": "minecraft:stray_spawn_egg", - "id": 465 - }, - { - "name": "minecraft:strider_spawn_egg", - "id": 498 - }, - { - "name": "minecraft:string", - "id": 329 - }, - { - "name": "minecraft:stripped_acacia_log", - "id": -8 - }, - { - "name": "minecraft:stripped_bamboo_block", - "id": -528 - }, - { - "name": "minecraft:stripped_birch_log", - "id": -6 - }, - { - "name": "minecraft:stripped_cherry_log", - "id": -535 - }, - { - "name": "minecraft:stripped_cherry_wood", - "id": -545 - }, - { - "name": "minecraft:stripped_crimson_hyphae", - "id": -300 - }, - { - "name": "minecraft:stripped_crimson_stem", - "id": -240 - }, - { - "name": "minecraft:stripped_dark_oak_log", - "id": -9 - }, - { - "name": "minecraft:stripped_jungle_log", - "id": -7 - }, - { - "name": "minecraft:stripped_mangrove_log", - "id": -485 - }, - { - "name": "minecraft:stripped_mangrove_wood", - "id": -498 - }, - { - "name": "minecraft:stripped_oak_log", - "id": -10 - }, - { - "name": "minecraft:stripped_spruce_log", - "id": -5 - }, - { - "name": "minecraft:stripped_warped_hyphae", - "id": -301 - }, - { - "name": "minecraft:stripped_warped_stem", - "id": -241 - }, - { - "name": "minecraft:structure_block", - "id": 252 - }, - { - "name": "minecraft:structure_void", - "id": 217 - }, - { - "name": "minecraft:sugar", - "id": 419 - }, - { - "name": "minecraft:sugar_cane", - "id": 388 - }, - { - "name": "minecraft:suspicious_gravel", - "id": -573 - }, - { - "name": "minecraft:suspicious_sand", - "id": -529 - }, - { - "name": "minecraft:suspicious_stew", - "id": 599 - }, - { - "name": "minecraft:sweet_berries", - "id": 288 - }, - { - "name": "minecraft:sweet_berry_bush", - "id": -207 - }, - { - "name": "minecraft:tadpole_bucket", - "id": 639 - }, - { - "name": "minecraft:tadpole_spawn_egg", - "id": 638 - }, - { - "name": "minecraft:tallgrass", - "id": 31 - }, - { - "name": "minecraft:target", - "id": -239 - }, - { - "name": "minecraft:tide_armor_trim_smithing_template", - "id": 694 - }, - { - "name": "minecraft:tinted_glass", - "id": -334 - }, - { - "name": "minecraft:tnt", - "id": 46 - }, - { - "name": "minecraft:tnt_minecart", - "id": 534 - }, - { - "name": "minecraft:torch", - "id": 50 - }, - { - "name": "minecraft:torchflower", - "id": -568 - }, - { - "name": "minecraft:torchflower_crop", - "id": -567 - }, - { - "name": "minecraft:torchflower_seeds", - "id": 297 - }, - { - "name": "minecraft:totem_of_undying", - "id": 577 - }, - { - "name": "minecraft:trader_llama_spawn_egg", - "id": 657 - }, - { - "name": "minecraft:trapdoor", - "id": 96 - }, - { - "name": "minecraft:trapped_chest", - "id": 146 - }, - { - "name": "minecraft:trial_key", - "id": 705 - }, - { - "name": "minecraft:trial_spawner", - "id": -315 - }, - { - "name": "minecraft:trident", - "id": 555 - }, - { - "name": "minecraft:trip_wire", - "id": 132 - }, - { - "name": "minecraft:tripwire_hook", - "id": 131 - }, - { - "name": "minecraft:tropical_fish", - "id": 267 - }, - { - "name": "minecraft:tropical_fish_bucket", - "id": 369 - }, - { - "name": "minecraft:tropical_fish_spawn_egg", - "id": 482 - }, - { - "name": "minecraft:tube_coral", - "id": -131 - }, - { - "name": "minecraft:tuff", - "id": -333 - }, - { - "name": "minecraft:tuff_brick_double_slab", - "id": -756 - }, - { - "name": "minecraft:tuff_brick_slab", - "id": -755 - }, - { - "name": "minecraft:tuff_brick_stairs", - "id": -757 - }, - { - "name": "minecraft:tuff_brick_wall", - "id": -758 - }, - { - "name": "minecraft:tuff_bricks", - "id": -754 - }, - { - "name": "minecraft:tuff_double_slab", - "id": -745 - }, - { - "name": "minecraft:tuff_slab", - "id": -744 - }, - { - "name": "minecraft:tuff_stairs", - "id": -746 - }, - { - "name": "minecraft:tuff_wall", - "id": -747 - }, - { - "name": "minecraft:turtle_egg", - "id": -159 - }, - { - "name": "minecraft:turtle_helmet", - "id": 582 - }, - { - "name": "minecraft:turtle_scute", - "id": 581 - }, - { - "name": "minecraft:turtle_spawn_egg", - "id": 488 - }, - { - "name": "minecraft:twisting_vines", - "id": -287 - }, - { - "name": "minecraft:underwater_torch", - "id": 239 - }, - { - "name": "minecraft:undyed_shulker_box", - "id": 205 - }, - { - "name": "minecraft:unknown", - "id": -305 - }, - { - "name": "minecraft:unlit_redstone_torch", - "id": 75 - }, - { - "name": "minecraft:unpowered_comparator", - "id": 149 - }, - { - "name": "minecraft:unpowered_repeater", - "id": 93 - }, - { - "name": "minecraft:verdant_froglight", - "id": -470 - }, - { - "name": "minecraft:vex_armor_trim_smithing_template", - "id": 693 - }, - { - "name": "minecraft:vex_spawn_egg", - "id": 479 - }, - { - "name": "minecraft:villager_spawn_egg", - "id": 452 - }, - { - "name": "minecraft:vindicator_spawn_egg", - "id": 477 - }, - { - "name": "minecraft:vine", - "id": 106 - }, - { - "name": "minecraft:wall_banner", - "id": 177 - }, - { - "name": "minecraft:wall_sign", - "id": 68 - }, - { - "name": "minecraft:wandering_trader_spawn_egg", - "id": 495 - }, - { - "name": "minecraft:ward_armor_trim_smithing_template", - "id": 691 - }, - { - "name": "minecraft:warden_spawn_egg", - "id": 641 - }, - { - "name": "minecraft:warped_button", - "id": -261 - }, - { - "name": "minecraft:warped_door", - "id": 626 - }, - { - "name": "minecraft:warped_double_slab", - "id": -267 - }, - { - "name": "minecraft:warped_fence", - "id": -257 - }, - { - "name": "minecraft:warped_fence_gate", - "id": -259 - }, - { - "name": "minecraft:warped_fungus", - "id": -229 - }, - { - "name": "minecraft:warped_fungus_on_a_stick", - "id": 627 - }, - { - "name": "minecraft:warped_hanging_sign", - "id": -507 - }, - { - "name": "minecraft:warped_hyphae", - "id": -298 - }, - { - "name": "minecraft:warped_nylium", - "id": -233 - }, - { - "name": "minecraft:warped_planks", - "id": -243 - }, - { - "name": "minecraft:warped_pressure_plate", - "id": -263 - }, - { - "name": "minecraft:warped_roots", - "id": -224 - }, - { - "name": "minecraft:warped_sign", - "id": 624 - }, - { - "name": "minecraft:warped_slab", - "id": -265 - }, - { - "name": "minecraft:warped_stairs", - "id": -255 - }, - { - "name": "minecraft:warped_standing_sign", - "id": -251 - }, - { - "name": "minecraft:warped_stem", - "id": -226 - }, - { - "name": "minecraft:warped_trapdoor", - "id": -247 - }, - { - "name": "minecraft:warped_wall_sign", - "id": -253 - }, - { - "name": "minecraft:warped_wart_block", - "id": -227 - }, - { - "name": "minecraft:water", - "id": 9 - }, - { - "name": "minecraft:water_bucket", - "id": 365 - }, - { - "name": "minecraft:waterlily", - "id": 111 - }, - { - "name": "minecraft:waxed_chiseled_copper", - "id": -764 - }, - { - "name": "minecraft:waxed_copper", - "id": -344 - }, - { - "name": "minecraft:waxed_copper_bulb", - "id": -780 - }, - { - "name": "minecraft:waxed_copper_door", - "id": -788 - }, - { - "name": "minecraft:waxed_copper_grate", - "id": -772 - }, - { - "name": "minecraft:waxed_copper_trapdoor", - "id": -796 - }, - { - "name": "minecraft:waxed_cut_copper", - "id": -351 - }, - { - "name": "minecraft:waxed_cut_copper_slab", - "id": -365 - }, - { - "name": "minecraft:waxed_cut_copper_stairs", - "id": -358 - }, - { - "name": "minecraft:waxed_double_cut_copper_slab", - "id": -372 - }, - { - "name": "minecraft:waxed_exposed_chiseled_copper", - "id": -765 - }, - { - "name": "minecraft:waxed_exposed_copper", - "id": -345 - }, - { - "name": "minecraft:waxed_exposed_copper_bulb", - "id": -781 - }, - { - "name": "minecraft:waxed_exposed_copper_door", - "id": -789 - }, - { - "name": "minecraft:waxed_exposed_copper_grate", - "id": -773 - }, - { - "name": "minecraft:waxed_exposed_copper_trapdoor", - "id": -797 - }, - { - "name": "minecraft:waxed_exposed_cut_copper", - "id": -352 - }, - { - "name": "minecraft:waxed_exposed_cut_copper_slab", - "id": -366 - }, - { - "name": "minecraft:waxed_exposed_cut_copper_stairs", - "id": -359 - }, - { - "name": "minecraft:waxed_exposed_double_cut_copper_slab", - "id": -373 - }, - { - "name": "minecraft:waxed_oxidized_chiseled_copper", - "id": -766 - }, - { - "name": "minecraft:waxed_oxidized_copper", - "id": -446 - }, - { - "name": "minecraft:waxed_oxidized_copper_bulb", - "id": -783 - }, - { - "name": "minecraft:waxed_oxidized_copper_door", - "id": -791 - }, - { - "name": "minecraft:waxed_oxidized_copper_grate", - "id": -775 - }, - { - "name": "minecraft:waxed_oxidized_copper_trapdoor", - "id": -799 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper", - "id": -447 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper_slab", - "id": -449 - }, - { - "name": "minecraft:waxed_oxidized_cut_copper_stairs", - "id": -448 - }, - { - "name": "minecraft:waxed_oxidized_double_cut_copper_slab", - "id": -450 - }, - { - "name": "minecraft:waxed_weathered_chiseled_copper", - "id": -767 - }, - { - "name": "minecraft:waxed_weathered_copper", - "id": -346 - }, - { - "name": "minecraft:waxed_weathered_copper_bulb", - "id": -782 - }, - { - "name": "minecraft:waxed_weathered_copper_door", - "id": -790 - }, - { - "name": "minecraft:waxed_weathered_copper_grate", - "id": -774 - }, - { - "name": "minecraft:waxed_weathered_copper_trapdoor", - "id": -798 - }, - { - "name": "minecraft:waxed_weathered_cut_copper", - "id": -353 - }, - { - "name": "minecraft:waxed_weathered_cut_copper_slab", - "id": -367 - }, - { - "name": "minecraft:waxed_weathered_cut_copper_stairs", - "id": -360 - }, - { - "name": "minecraft:waxed_weathered_double_cut_copper_slab", - "id": -374 - }, - { - "name": "minecraft:wayfinder_armor_trim_smithing_template", - "id": 699 - }, - { - "name": "minecraft:weathered_chiseled_copper", - "id": -762 - }, - { - "name": "minecraft:weathered_copper", - "id": -342 - }, - { - "name": "minecraft:weathered_copper_bulb", - "id": -778 - }, - { - "name": "minecraft:weathered_copper_door", - "id": -786 - }, - { - "name": "minecraft:weathered_copper_grate", - "id": -770 - }, - { - "name": "minecraft:weathered_copper_trapdoor", - "id": -794 - }, - { - "name": "minecraft:weathered_cut_copper", - "id": -349 - }, - { - "name": "minecraft:weathered_cut_copper_slab", - "id": -363 - }, - { - "name": "minecraft:weathered_cut_copper_stairs", - "id": -356 - }, - { - "name": "minecraft:weathered_double_cut_copper_slab", - "id": -370 - }, - { - "name": "minecraft:web", - "id": 30 - }, - { - "name": "minecraft:weeping_vines", - "id": -231 - }, - { - "name": "minecraft:wheat", - "id": 337 - }, - { - "name": "minecraft:wheat_seeds", - "id": 292 - }, - { - "name": "minecraft:white_candle", - "id": -413 - }, - { - "name": "minecraft:white_candle_cake", - "id": -430 - }, - { - "name": "minecraft:white_carpet", - "id": 171 - }, - { - "name": "minecraft:white_concrete", - "id": 236 - }, - { - "name": "minecraft:white_concrete_powder", - "id": 237 - }, - { - "name": "minecraft:white_dye", - "id": 413 - }, - { - "name": "minecraft:white_glazed_terracotta", - "id": 220 - }, - { - "name": "minecraft:white_shulker_box", - "id": 218 - }, - { - "name": "minecraft:white_stained_glass", - "id": 241 - }, - { - "name": "minecraft:white_stained_glass_pane", - "id": 160 - }, - { - "name": "minecraft:white_terracotta", - "id": 159 - }, - { - "name": "minecraft:white_wool", - "id": 35 - }, - { - "name": "minecraft:wild_armor_trim_smithing_template", - "id": 690 - }, - { - "name": "minecraft:witch_spawn_egg", - "id": 455 - }, - { - "name": "minecraft:wither_rose", - "id": -216 - }, - { - "name": "minecraft:wither_skeleton_spawn_egg", - "id": 467 - }, - { - "name": "minecraft:wither_spawn_egg", - "id": 511 - }, - { - "name": "minecraft:wolf_armor", - "id": 708 - }, - { - "name": "minecraft:wolf_spawn_egg", - "id": 442 - }, - { - "name": "minecraft:wood", - "id": -212 - }, - { - "name": "minecraft:wooden_axe", - "id": 314 - }, - { - "name": "minecraft:wooden_button", - "id": 143 - }, - { - "name": "minecraft:wooden_door", - "id": 362 - }, - { - "name": "minecraft:wooden_hoe", - "id": 332 - }, - { - "name": "minecraft:wooden_pickaxe", - "id": 313 - }, - { - "name": "minecraft:wooden_pressure_plate", - "id": 72 - }, - { - "name": "minecraft:wooden_shovel", - "id": 312 - }, - { - "name": "minecraft:wooden_slab", - "id": 158 - }, - { - "name": "minecraft:wooden_sword", - "id": 311 - }, - { - "name": "minecraft:wool", - "id": 709 - }, - { - "name": "minecraft:writable_book", - "id": 519 - }, - { - "name": "minecraft:written_book", - "id": 520 - }, - { - "name": "minecraft:yellow_candle", - "id": -417 - }, - { - "name": "minecraft:yellow_candle_cake", - "id": -434 - }, - { - "name": "minecraft:yellow_carpet", - "id": -600 - }, - { - "name": "minecraft:yellow_concrete", - "id": -631 - }, - { - "name": "minecraft:yellow_concrete_powder", - "id": -712 - }, - { - "name": "minecraft:yellow_dye", - "id": 409 - }, - { - "name": "minecraft:yellow_flower", - "id": 37 - }, - { - "name": "minecraft:yellow_glazed_terracotta", - "id": 224 - }, - { - "name": "minecraft:yellow_shulker_box", - "id": -616 - }, - { - "name": "minecraft:yellow_stained_glass", - "id": -676 - }, - { - "name": "minecraft:yellow_stained_glass_pane", - "id": -646 - }, - { - "name": "minecraft:yellow_terracotta", - "id": -727 - }, - { - "name": "minecraft:yellow_wool", - "id": -558 - }, - { - "name": "minecraft:zoglin_spawn_egg", - "id": 501 - }, - { - "name": "minecraft:zombie_horse_spawn_egg", - "id": 471 - }, - { - "name": "minecraft:zombie_pigman_spawn_egg", - "id": 451 - }, - { - "name": "minecraft:zombie_spawn_egg", - "id": 450 - }, - { - "name": "minecraft:zombie_villager_spawn_egg", - "id": 480 - } -] \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_20_70.json b/core/src/main/resources/bedrock/runtime_item_states.1_21_0.json similarity index 95% rename from core/src/main/resources/bedrock/runtime_item_states.1_20_70.json rename to core/src/main/resources/bedrock/runtime_item_states.1_21_0.json index 887b89ba1..1430a5437 100644 --- a/core/src/main/resources/bedrock/runtime_item_states.1_20_70.json +++ b/core/src/main/resources/bedrock/runtime_item_states.1_21_0.json @@ -1,7 +1,7 @@ [ { "name": "minecraft:acacia_boat", - "id": 383 + "id": 387 }, { "name": "minecraft:acacia_button", @@ -9,11 +9,11 @@ }, { "name": "minecraft:acacia_chest_boat", - "id": 653 + "id": 661 }, { "name": "minecraft:acacia_door", - "id": 567 + "id": 572 }, { "name": "minecraft:acacia_double_slab", @@ -47,9 +47,13 @@ "name": "minecraft:acacia_pressure_plate", "id": -150 }, + { + "name": "minecraft:acacia_sapling", + "id": -828 + }, { "name": "minecraft:acacia_sign", - "id": 590 + "id": 595 }, { "name": "minecraft:acacia_slab", @@ -81,7 +85,7 @@ }, { "name": "minecraft:agent_spawn_egg", - "id": 492 + "id": 497 }, { "name": "minecraft:air", @@ -89,7 +93,11 @@ }, { "name": "minecraft:allay_spawn_egg", - "id": 642 + "id": 650 + }, + { + "name": "minecraft:allium", + "id": -831 }, { "name": "minecraft:allow", @@ -105,7 +113,7 @@ }, { "name": "minecraft:amethyst_shard", - "id": 635 + "id": 643 }, { "name": "minecraft:ancient_debris", @@ -121,7 +129,7 @@ }, { "name": "minecraft:angler_pottery_sherd", - "id": 667 + "id": 675 }, { "name": "minecraft:anvil", @@ -133,35 +141,35 @@ }, { "name": "minecraft:archer_pottery_sherd", - "id": 668 + "id": 676 }, { "name": "minecraft:armadillo_scute", - "id": 709 + "id": 721 }, { "name": "minecraft:armadillo_spawn_egg", - "id": 708 + "id": 720 }, { "name": "minecraft:armor_stand", - "id": 563 + "id": 568 }, { "name": "minecraft:arms_up_pottery_sherd", - "id": 669 + "id": 677 }, { "name": "minecraft:arrow", - "id": 304 + "id": 307 }, { "name": "minecraft:axolotl_bucket", - "id": 372 + "id": 376 }, { "name": "minecraft:axolotl_spawn_egg", - "id": 507 + "id": 512 }, { "name": "minecraft:azalea", @@ -175,13 +183,17 @@ "name": "minecraft:azalea_leaves_flowered", "id": -325 }, + { + "name": "minecraft:azure_bluet", + "id": -832 + }, { "name": "minecraft:baked_potato", - "id": 282 + "id": 285 }, { "name": "minecraft:balloon", - "id": 609 + "id": 617 }, { "name": "minecraft:bamboo", @@ -197,7 +209,7 @@ }, { "name": "minecraft:bamboo_chest_raft", - "id": 665 + "id": 673 }, { "name": "minecraft:bamboo_door", @@ -245,7 +257,7 @@ }, { "name": "minecraft:bamboo_raft", - "id": 664 + "id": 672 }, { "name": "minecraft:bamboo_sapling", @@ -253,7 +265,7 @@ }, { "name": "minecraft:bamboo_sign", - "id": 663 + "id": 671 }, { "name": "minecraft:bamboo_slab", @@ -277,11 +289,11 @@ }, { "name": "minecraft:banner", - "id": 578 + "id": 583 }, { "name": "minecraft:banner_pattern", - "id": 731 + "id": 756 }, { "name": "minecraft:barrel", @@ -297,7 +309,7 @@ }, { "name": "minecraft:bat_spawn_egg", - "id": 457 + "id": 462 }, { "name": "minecraft:beacon", @@ -305,7 +317,7 @@ }, { "name": "minecraft:bed", - "id": 422 + "id": 426 }, { "name": "minecraft:bedrock", @@ -317,11 +329,11 @@ }, { "name": "minecraft:bee_spawn_egg", - "id": 499 + "id": 504 }, { "name": "minecraft:beef", - "id": 274 + "id": 277 }, { "name": "minecraft:beehive", @@ -329,15 +341,15 @@ }, { "name": "minecraft:beetroot", - "id": 286 + "id": 289 }, { "name": "minecraft:beetroot_seeds", - "id": 296 + "id": 299 }, { "name": "minecraft:beetroot_soup", - "id": 287 + "id": 290 }, { "name": "minecraft:bell", @@ -349,7 +361,7 @@ }, { "name": "minecraft:birch_boat", - "id": 380 + "id": 384 }, { "name": "minecraft:birch_button", @@ -357,11 +369,11 @@ }, { "name": "minecraft:birch_chest_boat", - "id": 650 + "id": 658 }, { "name": "minecraft:birch_door", - "id": 565 + "id": 570 }, { "name": "minecraft:birch_double_slab", @@ -395,9 +407,13 @@ "name": "minecraft:birch_pressure_plate", "id": -151 }, + { + "name": "minecraft:birch_sapling", + "id": -826 + }, { "name": "minecraft:birch_sign", - "id": 588 + "id": 593 }, { "name": "minecraft:birch_slab", @@ -445,7 +461,7 @@ }, { "name": "minecraft:black_dye", - "id": 399 + "id": 403 }, { "name": "minecraft:black_glazed_terracotta", @@ -493,7 +509,7 @@ }, { "name": "minecraft:blade_pottery_sherd", - "id": 670 + "id": 678 }, { "name": "minecraft:blast_furnace", @@ -501,19 +517,19 @@ }, { "name": "minecraft:blaze_powder", - "id": 433 + "id": 438 }, { "name": "minecraft:blaze_rod", - "id": 427 + "id": 431 }, { "name": "minecraft:blaze_spawn_egg", - "id": 460 + "id": 465 }, { "name": "minecraft:bleach", - "id": 607 + "id": 615 }, { "name": "minecraft:blue_candle", @@ -537,7 +553,7 @@ }, { "name": "minecraft:blue_dye", - "id": 403 + "id": 407 }, { "name": "minecraft:blue_glazed_terracotta", @@ -547,6 +563,10 @@ "name": "minecraft:blue_ice", "id": -11 }, + { + "name": "minecraft:blue_orchid", + "id": -830 + }, { "name": "minecraft:blue_shulker_box", "id": -623 @@ -569,15 +589,19 @@ }, { "name": "minecraft:boat", - "id": 729 + "id": 754 }, { "name": "minecraft:bogged_spawn_egg", - "id": 467 + "id": 472 + }, + { + "name": "minecraft:bolt_armor_trim_smithing_template", + "id": 717 }, { "name": "minecraft:bone", - "id": 419 + "id": 423 }, { "name": "minecraft:bone_block", @@ -585,11 +609,11 @@ }, { "name": "minecraft:bone_meal", - "id": 415 + "id": 419 }, { "name": "minecraft:book", - "id": 391 + "id": 395 }, { "name": "minecraft:bookshelf", @@ -601,44 +625,60 @@ }, { "name": "minecraft:bordure_indented_banner_pattern", - "id": 597 + "id": 602 }, { "name": "minecraft:bow", - "id": 303 + "id": 306 }, { "name": "minecraft:bowl", - "id": 324 + "id": 328 }, { "name": "minecraft:brain_coral", "id": -581 }, + { + "name": "minecraft:brain_coral_block", + "id": -849 + }, + { + "name": "minecraft:brain_coral_fan", + "id": -840 + }, { "name": "minecraft:bread", - "id": 262 + "id": 265 + }, + { + "name": "minecraft:breeze_rod", + "id": 432 }, { "name": "minecraft:breeze_spawn_egg", - "id": 506 + "id": 511 }, { "name": "minecraft:brewer_pottery_sherd", - "id": 671 + "id": 679 }, { "name": "minecraft:brewing_stand", - "id": 435 + "id": 440 }, { "name": "minecraft:brick", - "id": 387 + "id": 391 }, { "name": "minecraft:brick_block", "id": 45 }, + { + "name": "minecraft:brick_slab", + "id": -874 + }, { "name": "minecraft:brick_stairs", "id": 108 @@ -665,7 +705,7 @@ }, { "name": "minecraft:brown_dye", - "id": 402 + "id": 406 }, { "name": "minecraft:brown_glazed_terracotta", @@ -701,7 +741,7 @@ }, { "name": "minecraft:brush", - "id": 687 + "id": 698 }, { "name": "minecraft:bubble_column", @@ -711,9 +751,17 @@ "name": "minecraft:bubble_coral", "id": -582 }, + { + "name": "minecraft:bubble_coral_block", + "id": -850 + }, + { + "name": "minecraft:bubble_coral_fan", + "id": -841 + }, { "name": "minecraft:bucket", - "id": 363 + "id": 367 }, { "name": "minecraft:budding_amethyst", @@ -721,7 +769,7 @@ }, { "name": "minecraft:burn_pottery_sherd", - "id": 672 + "id": 680 }, { "name": "minecraft:cactus", @@ -729,7 +777,7 @@ }, { "name": "minecraft:cake", - "id": 421 + "id": 425 }, { "name": "minecraft:calcite", @@ -741,15 +789,15 @@ }, { "name": "minecraft:camel_spawn_egg", - "id": 666 + "id": 674 }, { "name": "minecraft:camera", - "id": 604 + "id": 612 }, { "name": "minecraft:campfire", - "id": 600 + "id": 607 }, { "name": "minecraft:candle", @@ -761,15 +809,15 @@ }, { "name": "minecraft:carpet", - "id": 712 + "id": 726 }, { "name": "minecraft:carrot", - "id": 280 + "id": 283 }, { "name": "minecraft:carrot_on_a_stick", - "id": 528 + "id": 533 }, { "name": "minecraft:carrots", @@ -785,15 +833,15 @@ }, { "name": "minecraft:cat_spawn_egg", - "id": 493 + "id": 498 }, { "name": "minecraft:cauldron", - "id": 436 + "id": 441 }, { "name": "minecraft:cave_spider_spawn_egg", - "id": 461 + "id": 466 }, { "name": "minecraft:cave_vines", @@ -809,7 +857,7 @@ }, { "name": "minecraft:chain", - "id": 630 + "id": 638 }, { "name": "minecraft:chain_command_block", @@ -817,23 +865,23 @@ }, { "name": "minecraft:chainmail_boots", - "id": 345 + "id": 349 }, { "name": "minecraft:chainmail_chestplate", - "id": 343 + "id": 347 }, { "name": "minecraft:chainmail_helmet", - "id": 342 + "id": 346 }, { "name": "minecraft:chainmail_leggings", - "id": 344 + "id": 348 }, { "name": "minecraft:charcoal", - "id": 306 + "id": 309 }, { "name": "minecraft:chemical_heat", @@ -845,7 +893,7 @@ }, { "name": "minecraft:cherry_boat", - "id": 660 + "id": 668 }, { "name": "minecraft:cherry_button", @@ -853,7 +901,7 @@ }, { "name": "minecraft:cherry_chest_boat", - "id": 661 + "id": 669 }, { "name": "minecraft:cherry_door", @@ -897,7 +945,7 @@ }, { "name": "minecraft:cherry_sign", - "id": 662 + "id": 670 }, { "name": "minecraft:cherry_slab", @@ -929,19 +977,19 @@ }, { "name": "minecraft:chest_boat", - "id": 656 + "id": 664 }, { "name": "minecraft:chest_minecart", - "id": 393 + "id": 397 }, { "name": "minecraft:chicken", - "id": 276 + "id": 279 }, { "name": "minecraft:chicken_spawn_egg", - "id": 439 + "id": 444 }, { "name": "minecraft:chiseled_bookshelf", @@ -977,7 +1025,7 @@ }, { "name": "minecraft:chorus_fruit", - "id": 569 + "id": 574 }, { "name": "minecraft:chorus_plant", @@ -989,7 +1037,7 @@ }, { "name": "minecraft:clay_ball", - "id": 388 + "id": 392 }, { "name": "minecraft:client_request_placeholder_block", @@ -997,11 +1045,11 @@ }, { "name": "minecraft:clock", - "id": 397 + "id": 401 }, { "name": "minecraft:coal", - "id": 305 + "id": 308 }, { "name": "minecraft:coal_block", @@ -1013,7 +1061,7 @@ }, { "name": "minecraft:coast_armor_trim_smithing_template", - "id": 691 + "id": 702 }, { "name": "minecraft:cobbled_deepslate", @@ -1039,6 +1087,10 @@ "name": "minecraft:cobblestone", "id": 4 }, + { + "name": "minecraft:cobblestone_slab", + "id": -873 + }, { "name": "minecraft:cobblestone_wall", "id": 139 @@ -1049,19 +1101,19 @@ }, { "name": "minecraft:cocoa_beans", - "id": 416 + "id": 420 }, { "name": "minecraft:cod", - "id": 265 + "id": 268 }, { "name": "minecraft:cod_bucket", - "id": 367 + "id": 371 }, { "name": "minecraft:cod_spawn_egg", - "id": 485 + "id": 490 }, { "name": "minecraft:colored_torch_bp", @@ -1077,15 +1129,15 @@ }, { "name": "minecraft:command_block_minecart", - "id": 574 + "id": 579 }, { "name": "minecraft:comparator", - "id": 533 + "id": 538 }, { "name": "minecraft:compass", - "id": 395 + "id": 399 }, { "name": "minecraft:composter", @@ -1093,15 +1145,15 @@ }, { "name": "minecraft:compound", - "id": 605 + "id": 613 }, { "name": "minecraft:concrete", - "id": 721 + "id": 743 }, { "name": "minecraft:concrete_powder", - "id": 722 + "id": 744 }, { "name": "minecraft:conduit", @@ -1109,35 +1161,35 @@ }, { "name": "minecraft:cooked_beef", - "id": 275 + "id": 278 }, { "name": "minecraft:cooked_chicken", - "id": 277 + "id": 280 }, { "name": "minecraft:cooked_cod", - "id": 269 + "id": 272 }, { "name": "minecraft:cooked_mutton", - "id": 562 + "id": 567 }, { "name": "minecraft:cooked_porkchop", - "id": 264 + "id": 267 }, { "name": "minecraft:cooked_rabbit", - "id": 290 + "id": 293 }, { "name": "minecraft:cooked_salmon", - "id": 270 + "id": 273 }, { "name": "minecraft:cookie", - "id": 272 + "id": 275 }, { "name": "minecraft:copper_block", @@ -1157,7 +1209,7 @@ }, { "name": "minecraft:copper_ingot", - "id": 515 + "id": 520 }, { "name": "minecraft:copper_ore", @@ -1169,19 +1221,19 @@ }, { "name": "minecraft:coral", - "id": 719 + "id": 740 }, { "name": "minecraft:coral_block", - "id": -132 + "id": 729 }, { "name": "minecraft:coral_fan", - "id": -133 + "id": 730 }, { "name": "minecraft:coral_fan_dead", - "id": -134 + "id": 731 }, { "name": "minecraft:coral_fan_hang", @@ -1195,9 +1247,13 @@ "name": "minecraft:coral_fan_hang3", "id": -137 }, + { + "name": "minecraft:cornflower", + "id": -838 + }, { "name": "minecraft:cow_spawn_egg", - "id": 440 + "id": 445 }, { "name": "minecraft:cracked_deepslate_bricks", @@ -1225,11 +1281,11 @@ }, { "name": "minecraft:creeper_banner_pattern", - "id": 593 + "id": 598 }, { "name": "minecraft:creeper_spawn_egg", - "id": 445 + "id": 450 }, { "name": "minecraft:crimson_button", @@ -1237,7 +1293,7 @@ }, { "name": "minecraft:crimson_door", - "id": 627 + "id": 635 }, { "name": "minecraft:crimson_double_slab", @@ -1281,7 +1337,7 @@ }, { "name": "minecraft:crimson_sign", - "id": 625 + "id": 633 }, { "name": "minecraft:crimson_slab", @@ -1309,7 +1365,7 @@ }, { "name": "minecraft:crossbow", - "id": 586 + "id": 591 }, { "name": "minecraft:crying_obsidian", @@ -1349,7 +1405,7 @@ }, { "name": "minecraft:cyan_dye", - "id": 405 + "id": 409 }, { "name": "minecraft:cyan_glazed_terracotta", @@ -1377,11 +1433,11 @@ }, { "name": "minecraft:danger_pottery_sherd", - "id": 673 + "id": 681 }, { "name": "minecraft:dark_oak_boat", - "id": 384 + "id": 388 }, { "name": "minecraft:dark_oak_button", @@ -1389,11 +1445,11 @@ }, { "name": "minecraft:dark_oak_chest_boat", - "id": 654 + "id": 662 }, { "name": "minecraft:dark_oak_door", - "id": 568 + "id": 573 }, { "name": "minecraft:dark_oak_double_slab", @@ -1427,9 +1483,13 @@ "name": "minecraft:dark_oak_pressure_plate", "id": -152 }, + { + "name": "minecraft:dark_oak_sapling", + "id": -829 + }, { "name": "minecraft:dark_oak_sign", - "id": 591 + "id": 596 }, { "name": "minecraft:dark_oak_slab", @@ -1471,22 +1531,62 @@ "name": "minecraft:dead_brain_coral", "id": -586 }, + { + "name": "minecraft:dead_brain_coral_block", + "id": -854 + }, + { + "name": "minecraft:dead_brain_coral_fan", + "id": -844 + }, { "name": "minecraft:dead_bubble_coral", "id": -587 }, + { + "name": "minecraft:dead_bubble_coral_block", + "id": -855 + }, + { + "name": "minecraft:dead_bubble_coral_fan", + "id": -845 + }, { "name": "minecraft:dead_fire_coral", "id": -588 }, + { + "name": "minecraft:dead_fire_coral_block", + "id": -856 + }, + { + "name": "minecraft:dead_fire_coral_fan", + "id": -846 + }, { "name": "minecraft:dead_horn_coral", "id": -589 }, + { + "name": "minecraft:dead_horn_coral_block", + "id": -857 + }, + { + "name": "minecraft:dead_horn_coral_fan", + "id": -847 + }, { "name": "minecraft:dead_tube_coral", "id": -585 }, + { + "name": "minecraft:dead_tube_coral_block", + "id": -853 + }, + { + "name": "minecraft:dead_tube_coral_fan", + "id": -134 + }, { "name": "minecraft:deadbush", "id": 32 @@ -1581,11 +1681,11 @@ }, { "name": "minecraft:diamond", - "id": 307 + "id": 310 }, { "name": "minecraft:diamond_axe", - "id": 322 + "id": 325 }, { "name": "minecraft:diamond_block", @@ -1593,27 +1693,27 @@ }, { "name": "minecraft:diamond_boots", - "id": 353 + "id": 357 }, { "name": "minecraft:diamond_chestplate", - "id": 351 + "id": 355 }, { "name": "minecraft:diamond_helmet", - "id": 350 + "id": 354 }, { "name": "minecraft:diamond_hoe", - "id": 335 + "id": 339 }, { "name": "minecraft:diamond_horse_armor", - "id": 544 + "id": 549 }, { "name": "minecraft:diamond_leggings", - "id": 352 + "id": 356 }, { "name": "minecraft:diamond_ore", @@ -1621,15 +1721,15 @@ }, { "name": "minecraft:diamond_pickaxe", - "id": 321 + "id": 324 }, { "name": "minecraft:diamond_shovel", - "id": 320 + "id": 323 }, { "name": "minecraft:diamond_sword", - "id": 319 + "id": 322 }, { "name": "minecraft:diorite", @@ -1649,7 +1749,7 @@ }, { "name": "minecraft:disc_fragment_5", - "id": 648 + "id": 656 }, { "name": "minecraft:dispenser", @@ -1657,11 +1757,11 @@ }, { "name": "minecraft:dolphin_spawn_egg", - "id": 489 + "id": 494 }, { "name": "minecraft:donkey_spawn_egg", - "id": 470 + "id": 475 }, { "name": "minecraft:double_cut_copper_slab", @@ -1669,7 +1769,7 @@ }, { "name": "minecraft:double_plant", - "id": 175 + "id": 738 }, { "name": "minecraft:double_stone_block_slab", @@ -1689,7 +1789,7 @@ }, { "name": "minecraft:dragon_breath", - "id": 571 + "id": 576 }, { "name": "minecraft:dragon_egg", @@ -1697,7 +1797,7 @@ }, { "name": "minecraft:dried_kelp", - "id": 271 + "id": 274 }, { "name": "minecraft:dried_kelp_block", @@ -1713,27 +1813,27 @@ }, { "name": "minecraft:drowned_spawn_egg", - "id": 488 + "id": 493 }, { "name": "minecraft:dune_armor_trim_smithing_template", - "id": 690 + "id": 701 }, { "name": "minecraft:dye", - "id": 730 + "id": 755 }, { "name": "minecraft:echo_shard", - "id": 658 + "id": 666 }, { "name": "minecraft:egg", - "id": 394 + "id": 398 }, { "name": "minecraft:elder_guardian_spawn_egg", - "id": 476 + "id": 481 }, { "name": "minecraft:element_0", @@ -2213,11 +2313,11 @@ }, { "name": "minecraft:elytra", - "id": 575 + "id": 580 }, { "name": "minecraft:emerald", - "id": 523 + "id": 528 }, { "name": "minecraft:emerald_block", @@ -2229,15 +2329,15 @@ }, { "name": "minecraft:empty_map", - "id": 526 + "id": 531 }, { "name": "minecraft:enchanted_book", - "id": 532 + "id": 537 }, { "name": "minecraft:enchanted_golden_apple", - "id": 260 + "id": 263 }, { "name": "minecraft:enchanting_table", @@ -2253,7 +2353,7 @@ }, { "name": "minecraft:end_crystal", - "id": 733 + "id": 758 }, { "name": "minecraft:end_gateway", @@ -2281,35 +2381,35 @@ }, { "name": "minecraft:ender_dragon_spawn_egg", - "id": 512 + "id": 517 }, { "name": "minecraft:ender_eye", - "id": 437 + "id": 442 }, { "name": "minecraft:ender_pearl", - "id": 426 + "id": 430 }, { "name": "minecraft:enderman_spawn_egg", - "id": 446 + "id": 451 }, { "name": "minecraft:endermite_spawn_egg", - "id": 464 + "id": 469 }, { "name": "minecraft:evoker_spawn_egg", - "id": 480 + "id": 485 }, { "name": "minecraft:experience_bottle", - "id": 519 + "id": 524 }, { "name": "minecraft:explorer_pottery_sherd", - "id": 674 + "id": 682 }, { "name": "minecraft:exposed_chiseled_copper", @@ -2353,7 +2453,7 @@ }, { "name": "minecraft:eye_armor_trim_smithing_template", - "id": 694 + "id": 705 }, { "name": "minecraft:farmland", @@ -2361,11 +2461,11 @@ }, { "name": "minecraft:feather", - "id": 330 + "id": 334 }, { "name": "minecraft:fence", - "id": 714 + "id": 728 }, { "name": "minecraft:fence_gate", @@ -2373,15 +2473,19 @@ }, { "name": "minecraft:fermented_spider_eye", - "id": 432 + "id": 437 + }, + { + "name": "minecraft:fern", + "id": -848 }, { "name": "minecraft:field_masoned_banner_pattern", - "id": 596 + "id": 601 }, { "name": "minecraft:filled_map", - "id": 424 + "id": 428 }, { "name": "minecraft:fire", @@ -2389,23 +2493,31 @@ }, { "name": "minecraft:fire_charge", - "id": 520 + "id": 525 }, { "name": "minecraft:fire_coral", "id": -583 }, + { + "name": "minecraft:fire_coral_block", + "id": -851 + }, + { + "name": "minecraft:fire_coral_fan", + "id": -842 + }, { "name": "minecraft:firework_rocket", - "id": 530 + "id": 535 }, { "name": "minecraft:firework_star", - "id": 531 + "id": 536 }, { "name": "minecraft:fishing_rod", - "id": 396 + "id": 400 }, { "name": "minecraft:fletching_table", @@ -2413,19 +2525,31 @@ }, { "name": "minecraft:flint", - "id": 359 + "id": 363 }, { "name": "minecraft:flint_and_steel", - "id": 302 + "id": 305 + }, + { + "name": "minecraft:flow_armor_trim_smithing_template", + "id": 716 + }, + { + "name": "minecraft:flow_banner_pattern", + "id": 605 + }, + { + "name": "minecraft:flow_pottery_sherd", + "id": 683 }, { "name": "minecraft:flower_banner_pattern", - "id": 592 + "id": 597 }, { "name": "minecraft:flower_pot", - "id": 525 + "id": 530 }, { "name": "minecraft:flowering_azalea", @@ -2441,15 +2565,15 @@ }, { "name": "minecraft:fox_spawn_egg", - "id": 495 + "id": 500 }, { "name": "minecraft:frame", - "id": 524 + "id": 529 }, { "name": "minecraft:friend_pottery_sherd", - "id": 675 + "id": 684 }, { "name": "minecraft:frog_spawn", @@ -2457,7 +2581,7 @@ }, { "name": "minecraft:frog_spawn_egg", - "id": 639 + "id": 647 }, { "name": "minecraft:frosted_ice", @@ -2469,11 +2593,11 @@ }, { "name": "minecraft:ghast_spawn_egg", - "id": 458 + "id": 463 }, { "name": "minecraft:ghast_tear", - "id": 428 + "id": 433 }, { "name": "minecraft:gilded_blackstone", @@ -2485,7 +2609,7 @@ }, { "name": "minecraft:glass_bottle", - "id": 431 + "id": 436 }, { "name": "minecraft:glass_pane", @@ -2493,23 +2617,23 @@ }, { "name": "minecraft:glistering_melon_slice", - "id": 438 + "id": 443 }, { "name": "minecraft:globe_banner_pattern", - "id": 599 + "id": 604 }, { "name": "minecraft:glow_berries", - "id": 734 + "id": 759 }, { "name": "minecraft:glow_frame", - "id": 634 + "id": 642 }, { "name": "minecraft:glow_ink_sac", - "id": 514 + "id": 519 }, { "name": "minecraft:glow_lichen", @@ -2517,11 +2641,11 @@ }, { "name": "minecraft:glow_squid_spawn_egg", - "id": 509 + "id": 514 }, { "name": "minecraft:glow_stick", - "id": 612 + "id": 620 }, { "name": "minecraft:glowingobsidian", @@ -2533,15 +2657,15 @@ }, { "name": "minecraft:glowstone_dust", - "id": 398 + "id": 402 }, { "name": "minecraft:goat_horn", - "id": 638 + "id": 646 }, { "name": "minecraft:goat_spawn_egg", - "id": 508 + "id": 513 }, { "name": "minecraft:gold_block", @@ -2549,11 +2673,11 @@ }, { "name": "minecraft:gold_ingot", - "id": 309 + "id": 312 }, { "name": "minecraft:gold_nugget", - "id": 429 + "id": 434 }, { "name": "minecraft:gold_ore", @@ -2561,43 +2685,43 @@ }, { "name": "minecraft:golden_apple", - "id": 259 + "id": 262 }, { "name": "minecraft:golden_axe", - "id": 328 + "id": 332 }, { "name": "minecraft:golden_boots", - "id": 357 + "id": 361 }, { "name": "minecraft:golden_carrot", - "id": 284 + "id": 287 }, { "name": "minecraft:golden_chestplate", - "id": 355 + "id": 359 }, { "name": "minecraft:golden_helmet", - "id": 354 + "id": 358 }, { "name": "minecraft:golden_hoe", - "id": 336 + "id": 340 }, { "name": "minecraft:golden_horse_armor", - "id": 543 + "id": 548 }, { "name": "minecraft:golden_leggings", - "id": 356 + "id": 360 }, { "name": "minecraft:golden_pickaxe", - "id": 327 + "id": 331 }, { "name": "minecraft:golden_rail", @@ -2605,11 +2729,11 @@ }, { "name": "minecraft:golden_shovel", - "id": 326 + "id": 330 }, { "name": "minecraft:golden_sword", - "id": 325 + "id": 329 }, { "name": "minecraft:granite", @@ -2653,7 +2777,7 @@ }, { "name": "minecraft:gray_dye", - "id": 407 + "id": 411 }, { "name": "minecraft:gray_glazed_terracotta", @@ -2701,7 +2825,7 @@ }, { "name": "minecraft:green_dye", - "id": 401 + "id": 405 }, { "name": "minecraft:green_glazed_terracotta", @@ -2733,11 +2857,19 @@ }, { "name": "minecraft:guardian_spawn_egg", - "id": 465 + "id": 470 }, { "name": "minecraft:gunpowder", - "id": 331 + "id": 335 + }, + { + "name": "minecraft:guster_banner_pattern", + "id": 606 + }, + { + "name": "minecraft:guster_pottery_sherd", + "id": 685 }, { "name": "minecraft:hanging_roots", @@ -2865,11 +2997,11 @@ }, { "name": "minecraft:hard_stained_glass", - "id": 727 + "id": 752 }, { "name": "minecraft:hard_stained_glass_pane", - "id": 728 + "id": 753 }, { "name": "minecraft:hard_white_stained_glass", @@ -2897,15 +3029,19 @@ }, { "name": "minecraft:heart_of_the_sea", - "id": 582 + "id": 587 }, { "name": "minecraft:heart_pottery_sherd", - "id": 676 + "id": 686 }, { "name": "minecraft:heartbreak_pottery_sherd", - "id": 677 + "id": 687 + }, + { + "name": "minecraft:heavy_core", + "id": -316 }, { "name": "minecraft:heavy_weighted_pressure_plate", @@ -2913,7 +3049,7 @@ }, { "name": "minecraft:hoglin_spawn_egg", - "id": 501 + "id": 506 }, { "name": "minecraft:honey_block", @@ -2921,11 +3057,11 @@ }, { "name": "minecraft:honey_bottle", - "id": 603 + "id": 610 }, { "name": "minecraft:honeycomb", - "id": 602 + "id": 609 }, { "name": "minecraft:honeycomb_block", @@ -2933,31 +3069,39 @@ }, { "name": "minecraft:hopper", - "id": 538 + "id": 543 }, { "name": "minecraft:hopper_minecart", - "id": 537 + "id": 542 }, { "name": "minecraft:horn_coral", "id": -584 }, + { + "name": "minecraft:horn_coral_block", + "id": -852 + }, + { + "name": "minecraft:horn_coral_fan", + "id": -843 + }, { "name": "minecraft:horse_spawn_egg", - "id": 462 + "id": 467 }, { "name": "minecraft:host_armor_trim_smithing_template", - "id": 704 + "id": 715 }, { "name": "minecraft:howl_pottery_sherd", - "id": 678 + "id": 688 }, { "name": "minecraft:husk_spawn_egg", - "id": 468 + "id": 473 }, { "name": "minecraft:ice", @@ -2965,7 +3109,7 @@ }, { "name": "minecraft:ice_bomb", - "id": 606 + "id": 614 }, { "name": "minecraft:infested_deepslate", @@ -2981,7 +3125,7 @@ }, { "name": "minecraft:ink_sac", - "id": 417 + "id": 421 }, { "name": "minecraft:invisible_bedrock", @@ -2989,7 +3133,7 @@ }, { "name": "minecraft:iron_axe", - "id": 301 + "id": 304 }, { "name": "minecraft:iron_bars", @@ -3001,43 +3145,43 @@ }, { "name": "minecraft:iron_boots", - "id": 349 + "id": 353 }, { "name": "minecraft:iron_chestplate", - "id": 347 + "id": 351 }, { "name": "minecraft:iron_door", - "id": 375 + "id": 379 }, { "name": "minecraft:iron_golem_spawn_egg", - "id": 510 + "id": 515 }, { "name": "minecraft:iron_helmet", - "id": 346 + "id": 350 }, { "name": "minecraft:iron_hoe", - "id": 334 + "id": 338 }, { "name": "minecraft:iron_horse_armor", - "id": 542 + "id": 547 }, { "name": "minecraft:iron_ingot", - "id": 308 + "id": 311 }, { "name": "minecraft:iron_leggings", - "id": 348 + "id": 352 }, { "name": "minecraft:iron_nugget", - "id": 580 + "id": 585 }, { "name": "minecraft:iron_ore", @@ -3045,15 +3189,15 @@ }, { "name": "minecraft:iron_pickaxe", - "id": 300 + "id": 303 }, { "name": "minecraft:iron_shovel", - "id": 299 + "id": 302 }, { "name": "minecraft:iron_sword", - "id": 310 + "id": 313 }, { "name": "minecraft:iron_trapdoor", @@ -3185,7 +3329,7 @@ }, { "name": "minecraft:jungle_boat", - "id": 381 + "id": 385 }, { "name": "minecraft:jungle_button", @@ -3193,11 +3337,11 @@ }, { "name": "minecraft:jungle_chest_boat", - "id": 651 + "id": 659 }, { "name": "minecraft:jungle_door", - "id": 566 + "id": 571 }, { "name": "minecraft:jungle_double_slab", @@ -3231,9 +3375,13 @@ "name": "minecraft:jungle_pressure_plate", "id": -153 }, + { + "name": "minecraft:jungle_sapling", + "id": -827 + }, { "name": "minecraft:jungle_sign", - "id": 589 + "id": 594 }, { "name": "minecraft:jungle_slab", @@ -3261,7 +3409,7 @@ }, { "name": "minecraft:kelp", - "id": 386 + "id": 390 }, { "name": "minecraft:ladder", @@ -3277,7 +3425,7 @@ }, { "name": "minecraft:lapis_lazuli", - "id": 418 + "id": 422 }, { "name": "minecraft:lapis_ore", @@ -3287,49 +3435,53 @@ "name": "minecraft:large_amethyst_bud", "id": -330 }, + { + "name": "minecraft:large_fern", + "id": -865 + }, { "name": "minecraft:lava", "id": 11 }, { "name": "minecraft:lava_bucket", - "id": 366 + "id": 370 }, { "name": "minecraft:lead", - "id": 558 + "id": 563 }, { "name": "minecraft:leather", - "id": 385 + "id": 389 }, { "name": "minecraft:leather_boots", - "id": 341 + "id": 345 }, { "name": "minecraft:leather_chestplate", - "id": 339 + "id": 343 }, { "name": "minecraft:leather_helmet", - "id": 338 + "id": 342 }, { "name": "minecraft:leather_horse_armor", - "id": 541 + "id": 546 }, { "name": "minecraft:leather_leggings", - "id": 340 + "id": 344 }, { "name": "minecraft:leaves", - "id": 715 + "id": 733 }, { "name": "minecraft:leaves2", - "id": 716 + "id": 734 }, { "name": "minecraft:lectern", @@ -3365,7 +3517,7 @@ }, { "name": "minecraft:light_blue_dye", - "id": 411 + "id": 415 }, { "name": "minecraft:light_blue_glazed_terracotta", @@ -3413,7 +3565,7 @@ }, { "name": "minecraft:light_gray_dye", - "id": 406 + "id": 410 }, { "name": "minecraft:light_gray_shulker_box", @@ -3443,6 +3595,14 @@ "name": "minecraft:lightning_rod", "id": -312 }, + { + "name": "minecraft:lilac", + "id": -863 + }, + { + "name": "minecraft:lily_of_the_valley", + "id": -839 + }, { "name": "minecraft:lime_candle", "id": -418 @@ -3465,7 +3625,7 @@ }, { "name": "minecraft:lime_dye", - "id": 409 + "id": 413 }, { "name": "minecraft:lime_glazed_terracotta", @@ -3493,7 +3653,7 @@ }, { "name": "minecraft:lingering_potion", - "id": 573 + "id": 578 }, { "name": "minecraft:lit_blast_furnace", @@ -3525,7 +3685,7 @@ }, { "name": "minecraft:llama_spawn_egg", - "id": 478 + "id": 483 }, { "name": "minecraft:lodestone", @@ -3533,20 +3693,24 @@ }, { "name": "minecraft:lodestone_compass", - "id": 613 + "id": 621 }, { "name": "minecraft:log", - "id": 713 + "id": 727 }, { "name": "minecraft:log2", - "id": 720 + "id": 742 }, { "name": "minecraft:loom", "id": -204 }, + { + "name": "minecraft:mace", + "id": 326 + }, { "name": "minecraft:magenta_candle", "id": -415 @@ -3569,7 +3733,7 @@ }, { "name": "minecraft:magenta_dye", - "id": 412 + "id": 416 }, { "name": "minecraft:magenta_glazed_terracotta", @@ -3601,15 +3765,15 @@ }, { "name": "minecraft:magma_cream", - "id": 434 + "id": 439 }, { "name": "minecraft:magma_cube_spawn_egg", - "id": 459 + "id": 464 }, { "name": "minecraft:mangrove_boat", - "id": 646 + "id": 654 }, { "name": "minecraft:mangrove_button", @@ -3617,11 +3781,11 @@ }, { "name": "minecraft:mangrove_chest_boat", - "id": 655 + "id": 663 }, { "name": "minecraft:mangrove_door", - "id": 644 + "id": 652 }, { "name": "minecraft:mangrove_double_slab", @@ -3665,7 +3829,7 @@ }, { "name": "minecraft:mangrove_sign", - "id": 645 + "id": 653 }, { "name": "minecraft:mangrove_slab", @@ -3693,7 +3857,7 @@ }, { "name": "minecraft:medicine", - "id": 610 + "id": 618 }, { "name": "minecraft:medium_amethyst_bud", @@ -3705,11 +3869,11 @@ }, { "name": "minecraft:melon_seeds", - "id": 294 + "id": 297 }, { "name": "minecraft:melon_slice", - "id": 273 + "id": 276 }, { "name": "minecraft:melon_stem", @@ -3717,15 +3881,15 @@ }, { "name": "minecraft:milk_bucket", - "id": 364 + "id": 368 }, { "name": "minecraft:minecart", - "id": 373 + "id": 377 }, { "name": "minecraft:miner_pottery_sherd", - "id": 679 + "id": 689 }, { "name": "minecraft:mob_spawner", @@ -3733,7 +3897,7 @@ }, { "name": "minecraft:mojang_banner_pattern", - "id": 595 + "id": 600 }, { "name": "minecraft:monster_egg", @@ -3741,7 +3905,7 @@ }, { "name": "minecraft:mooshroom_spawn_egg", - "id": 444 + "id": 449 }, { "name": "minecraft:moss_block", @@ -3765,7 +3929,7 @@ }, { "name": "minecraft:mourner_pottery_sherd", - "id": 680 + "id": 690 }, { "name": "minecraft:moving_block", @@ -3801,91 +3965,103 @@ }, { "name": "minecraft:mule_spawn_egg", - "id": 471 + "id": 476 }, { "name": "minecraft:mushroom_stew", - "id": 261 + "id": 264 }, { "name": "minecraft:music_disc_11", - "id": 555 + "id": 560 }, { "name": "minecraft:music_disc_13", - "id": 545 - }, - { - "name": "minecraft:music_disc_5", - "id": 647 - }, - { - "name": "minecraft:music_disc_blocks", - "id": 547 - }, - { - "name": "minecraft:music_disc_cat", - "id": 546 - }, - { - "name": "minecraft:music_disc_chirp", - "id": 548 - }, - { - "name": "minecraft:music_disc_far", - "id": 549 - }, - { - "name": "minecraft:music_disc_mall", "id": 550 }, { - "name": "minecraft:music_disc_mellohi", - "id": 551 + "name": "minecraft:music_disc_5", + "id": 655 }, { - "name": "minecraft:music_disc_otherside", - "id": 637 - }, - { - "name": "minecraft:music_disc_pigstep", - "id": 631 - }, - { - "name": "minecraft:music_disc_relic", - "id": 705 - }, - { - "name": "minecraft:music_disc_stal", + "name": "minecraft:music_disc_blocks", "id": 552 }, { - "name": "minecraft:music_disc_strad", + "name": "minecraft:music_disc_cat", + "id": 551 + }, + { + "name": "minecraft:music_disc_chirp", "id": 553 }, { - "name": "minecraft:music_disc_wait", - "id": 556 + "name": "minecraft:music_disc_creator", + "id": 749 }, { - "name": "minecraft:music_disc_ward", + "name": "minecraft:music_disc_creator_music_box", + "id": 750 + }, + { + "name": "minecraft:music_disc_far", "id": 554 }, { - "name": "minecraft:mutton", + "name": "minecraft:music_disc_mall", + "id": 555 + }, + { + "name": "minecraft:music_disc_mellohi", + "id": 556 + }, + { + "name": "minecraft:music_disc_otherside", + "id": 645 + }, + { + "name": "minecraft:music_disc_pigstep", + "id": 639 + }, + { + "name": "minecraft:music_disc_precipice", + "id": 751 + }, + { + "name": "minecraft:music_disc_relic", + "id": 718 + }, + { + "name": "minecraft:music_disc_stal", + "id": 557 + }, + { + "name": "minecraft:music_disc_strad", + "id": 558 + }, + { + "name": "minecraft:music_disc_wait", "id": 561 }, + { + "name": "minecraft:music_disc_ward", + "id": 559 + }, + { + "name": "minecraft:mutton", + "id": 566 + }, { "name": "minecraft:mycelium", "id": 110 }, { "name": "minecraft:name_tag", - "id": 559 + "id": 564 }, { "name": "minecraft:nautilus_shell", - "id": 581 + "id": 586 }, { "name": "minecraft:nether_brick", @@ -3895,6 +4071,10 @@ "name": "minecraft:nether_brick_fence", "id": 113 }, + { + "name": "minecraft:nether_brick_slab", + "id": -877 + }, { "name": "minecraft:nether_brick_stairs", "id": 114 @@ -3905,15 +4085,15 @@ }, { "name": "minecraft:nether_sprouts", - "id": 632 + "id": 640 }, { "name": "minecraft:nether_star", - "id": 529 + "id": 534 }, { "name": "minecraft:nether_wart", - "id": 295 + "id": 298 }, { "name": "minecraft:nether_wart_block", @@ -3921,11 +4101,11 @@ }, { "name": "minecraft:netherbrick", - "id": 534 + "id": 539 }, { "name": "minecraft:netherite_axe", - "id": 617 + "id": 625 }, { "name": "minecraft:netherite_block", @@ -3933,47 +4113,47 @@ }, { "name": "minecraft:netherite_boots", - "id": 623 + "id": 631 }, { "name": "minecraft:netherite_chestplate", - "id": 621 + "id": 629 }, { "name": "minecraft:netherite_helmet", - "id": 620 + "id": 628 }, { "name": "minecraft:netherite_hoe", - "id": 618 + "id": 626 }, { "name": "minecraft:netherite_ingot", - "id": 619 + "id": 627 }, { "name": "minecraft:netherite_leggings", - "id": 622 + "id": 630 }, { "name": "minecraft:netherite_pickaxe", - "id": 616 - }, - { - "name": "minecraft:netherite_scrap", "id": 624 }, + { + "name": "minecraft:netherite_scrap", + "id": 632 + }, { "name": "minecraft:netherite_shovel", - "id": 615 + "id": 623 }, { "name": "minecraft:netherite_sword", - "id": 614 + "id": 622 }, { "name": "minecraft:netherite_upgrade_smithing_template", - "id": 688 + "id": 699 }, { "name": "minecraft:netherrack", @@ -3993,15 +4173,15 @@ }, { "name": "minecraft:npc_spawn_egg", - "id": 475 + "id": 480 }, { "name": "minecraft:oak_boat", - "id": 379 + "id": 383 }, { "name": "minecraft:oak_chest_boat", - "id": 649 + "id": 657 }, { "name": "minecraft:oak_double_slab", @@ -4027,9 +4207,13 @@ "name": "minecraft:oak_planks", "id": 5 }, + { + "name": "minecraft:oak_sapling", + "id": 6 + }, { "name": "minecraft:oak_sign", - "id": 361 + "id": 365 }, { "name": "minecraft:oak_slab", @@ -4053,12 +4237,20 @@ }, { "name": "minecraft:ocelot_spawn_egg", - "id": 455 + "id": 460 }, { "name": "minecraft:ochre_froglight", "id": -471 }, + { + "name": "minecraft:ominous_bottle", + "id": 611 + }, + { + "name": "minecraft:ominous_trial_key", + "id": 258 + }, { "name": "minecraft:orange_candle", "id": -414 @@ -4081,7 +4273,7 @@ }, { "name": "minecraft:orange_dye", - "id": 413 + "id": 417 }, { "name": "minecraft:orange_glazed_terracotta", @@ -4103,10 +4295,18 @@ "name": "minecraft:orange_terracotta", "id": -724 }, + { + "name": "minecraft:orange_tulip", + "id": -834 + }, { "name": "minecraft:orange_wool", "id": -557 }, + { + "name": "minecraft:oxeye_daisy", + "id": -837 + }, { "name": "minecraft:oxidized_chiseled_copper", "id": -763 @@ -4157,51 +4357,59 @@ }, { "name": "minecraft:painting", - "id": 360 + "id": 364 }, { "name": "minecraft:panda_spawn_egg", - "id": 494 + "id": 499 }, { "name": "minecraft:paper", - "id": 390 + "id": 394 }, { "name": "minecraft:parrot_spawn_egg", - "id": 483 + "id": 488 }, { "name": "minecraft:pearlescent_froglight", "id": -469 }, + { + "name": "minecraft:peony", + "id": -867 + }, + { + "name": "minecraft:petrified_oak_slab", + "id": -902 + }, { "name": "minecraft:phantom_membrane", - "id": 585 + "id": 590 }, { "name": "minecraft:phantom_spawn_egg", - "id": 491 + "id": 496 }, { "name": "minecraft:pig_spawn_egg", - "id": 441 + "id": 446 }, { "name": "minecraft:piglin_banner_pattern", - "id": 598 + "id": 603 }, { "name": "minecraft:piglin_brute_spawn_egg", - "id": 504 + "id": 509 }, { "name": "minecraft:piglin_spawn_egg", - "id": 502 + "id": 507 }, { "name": "minecraft:pillager_spawn_egg", - "id": 496 + "id": 501 }, { "name": "minecraft:pink_candle", @@ -4225,7 +4433,7 @@ }, { "name": "minecraft:pink_dye", - "id": 408 + "id": 412 }, { "name": "minecraft:pink_glazed_terracotta", @@ -4251,6 +4459,10 @@ "name": "minecraft:pink_terracotta", "id": -729 }, + { + "name": "minecraft:pink_tulip", + "id": -836 + }, { "name": "minecraft:pink_wool", "id": -566 @@ -4273,15 +4485,15 @@ }, { "name": "minecraft:pitcher_pod", - "id": 298 + "id": 301 }, { "name": "minecraft:planks", - "id": 718 + "id": 739 }, { "name": "minecraft:plenty_pottery_sherd", - "id": 681 + "id": 691 }, { "name": "minecraft:podzol", @@ -4293,11 +4505,11 @@ }, { "name": "minecraft:poisonous_potato", - "id": 283 + "id": 286 }, { "name": "minecraft:polar_bear_spawn_egg", - "id": 477 + "id": 482 }, { "name": "minecraft:polished_andesite", @@ -4417,11 +4629,15 @@ }, { "name": "minecraft:popped_chorus_fruit", - "id": 570 + "id": 575 + }, + { + "name": "minecraft:poppy", + "id": 38 }, { "name": "minecraft:porkchop", - "id": 263 + "id": 266 }, { "name": "minecraft:portal", @@ -4429,7 +4645,7 @@ }, { "name": "minecraft:potato", - "id": 281 + "id": 284 }, { "name": "minecraft:potatoes", @@ -4437,7 +4653,7 @@ }, { "name": "minecraft:potion", - "id": 430 + "id": 435 }, { "name": "minecraft:powder_snow", @@ -4445,7 +4661,7 @@ }, { "name": "minecraft:powder_snow_bucket", - "id": 371 + "id": 375 }, { "name": "minecraft:powered_comparator", @@ -4465,11 +4681,11 @@ }, { "name": "minecraft:prismarine_crystals", - "id": 560 + "id": 565 }, { "name": "minecraft:prismarine_shard", - "id": 576 + "id": 581 }, { "name": "minecraft:prismarine_stairs", @@ -4477,19 +4693,19 @@ }, { "name": "minecraft:prize_pottery_sherd", - "id": 682 + "id": 692 }, { "name": "minecraft:pufferfish", - "id": 268 + "id": 271 }, { "name": "minecraft:pufferfish_bucket", - "id": 370 + "id": 374 }, { "name": "minecraft:pufferfish_spawn_egg", - "id": 486 + "id": 491 }, { "name": "minecraft:pumpkin", @@ -4497,11 +4713,11 @@ }, { "name": "minecraft:pumpkin_pie", - "id": 285 + "id": 288 }, { "name": "minecraft:pumpkin_seeds", - "id": 293 + "id": 296 }, { "name": "minecraft:pumpkin_stem", @@ -4529,7 +4745,7 @@ }, { "name": "minecraft:purple_dye", - "id": 404 + "id": 408 }, { "name": "minecraft:purple_glazed_terracotta", @@ -4565,7 +4781,7 @@ }, { "name": "minecraft:quartz", - "id": 535 + "id": 540 }, { "name": "minecraft:quartz_block", @@ -4579,29 +4795,33 @@ "name": "minecraft:quartz_ore", "id": 153 }, + { + "name": "minecraft:quartz_slab", + "id": -876 + }, { "name": "minecraft:quartz_stairs", "id": 156 }, { "name": "minecraft:rabbit", - "id": 289 + "id": 292 }, { "name": "minecraft:rabbit_foot", - "id": 539 + "id": 544 }, { "name": "minecraft:rabbit_hide", - "id": 540 + "id": 545 }, { "name": "minecraft:rabbit_spawn_egg", - "id": 463 + "id": 468 }, { "name": "minecraft:rabbit_stew", - "id": 291 + "id": 294 }, { "name": "minecraft:rail", @@ -4609,19 +4829,19 @@ }, { "name": "minecraft:raiser_armor_trim_smithing_template", - "id": 702 + "id": 713 }, { "name": "minecraft:rapid_fertilizer", - "id": 608 + "id": 616 }, { "name": "minecraft:ravager_spawn_egg", - "id": 498 + "id": 503 }, { "name": "minecraft:raw_copper", - "id": 518 + "id": 523 }, { "name": "minecraft:raw_copper_block", @@ -4629,7 +4849,7 @@ }, { "name": "minecraft:raw_gold", - "id": 517 + "id": 522 }, { "name": "minecraft:raw_gold_block", @@ -4637,7 +4857,7 @@ }, { "name": "minecraft:raw_iron", - "id": 516 + "id": 521 }, { "name": "minecraft:raw_iron_block", @@ -4645,7 +4865,7 @@ }, { "name": "minecraft:recovery_compass", - "id": 657 + "id": 665 }, { "name": "minecraft:red_candle", @@ -4669,11 +4889,11 @@ }, { "name": "minecraft:red_dye", - "id": 400 + "id": 404 }, { "name": "minecraft:red_flower", - "id": 38 + "id": 737 }, { "name": "minecraft:red_glazed_terracotta", @@ -4719,13 +4939,17 @@ "name": "minecraft:red_terracotta", "id": -737 }, + { + "name": "minecraft:red_tulip", + "id": -833 + }, { "name": "minecraft:red_wool", "id": -556 }, { "name": "minecraft:redstone", - "id": 376 + "id": 380 }, { "name": "minecraft:redstone_block", @@ -4753,7 +4977,7 @@ }, { "name": "minecraft:repeater", - "id": 423 + "id": 427 }, { "name": "minecraft:repeating_command_block", @@ -4769,27 +4993,31 @@ }, { "name": "minecraft:rib_armor_trim_smithing_template", - "id": 698 + "id": 709 + }, + { + "name": "minecraft:rose_bush", + "id": -866 }, { "name": "minecraft:rotten_flesh", - "id": 278 + "id": 281 }, { "name": "minecraft:saddle", - "id": 374 + "id": 378 }, { "name": "minecraft:salmon", - "id": 266 + "id": 269 }, { "name": "minecraft:salmon_bucket", - "id": 368 + "id": 372 }, { "name": "minecraft:salmon_spawn_egg", - "id": 487 + "id": 492 }, { "name": "minecraft:sand", @@ -4799,18 +5027,26 @@ "name": "minecraft:sandstone", "id": 24 }, + { + "name": "minecraft:sandstone_slab", + "id": -872 + }, { "name": "minecraft:sandstone_stairs", "id": 128 }, { "name": "minecraft:sapling", - "id": 6 + "id": 732 }, { "name": "minecraft:scaffolding", "id": -165 }, + { + "name": "minecraft:scrape_pottery_sherd", + "id": 693 + }, { "name": "minecraft:sculk", "id": -458 @@ -4845,31 +5081,35 @@ }, { "name": "minecraft:sentry_armor_trim_smithing_template", - "id": 689 + "id": 700 }, { "name": "minecraft:shaper_armor_trim_smithing_template", - "id": 703 + "id": 714 }, { "name": "minecraft:sheaf_pottery_sherd", - "id": 683 + "id": 694 }, { "name": "minecraft:shears", - "id": 425 + "id": 429 }, { "name": "minecraft:sheep_spawn_egg", - "id": 442 + "id": 447 }, { "name": "minecraft:shelter_pottery_sherd", - "id": 684 + "id": 695 }, { "name": "minecraft:shield", - "id": 358 + "id": 362 + }, + { + "name": "minecraft:short_grass", + "id": 31 }, { "name": "minecraft:shroomlight", @@ -4877,19 +5117,19 @@ }, { "name": "minecraft:shulker_box", - "id": 725 + "id": 747 }, { "name": "minecraft:shulker_shell", - "id": 577 + "id": 582 }, { "name": "minecraft:shulker_spawn_egg", - "id": 474 + "id": 479 }, { "name": "minecraft:silence_armor_trim_smithing_template", - "id": 700 + "id": 711 }, { "name": "minecraft:silver_glazed_terracotta", @@ -4897,27 +5137,27 @@ }, { "name": "minecraft:silverfish_spawn_egg", - "id": 447 + "id": 452 }, { "name": "minecraft:skeleton_horse_spawn_egg", - "id": 472 + "id": 477 }, { "name": "minecraft:skeleton_spawn_egg", - "id": 448 + "id": 453 }, { "name": "minecraft:skull", - "id": 527 + "id": 532 }, { "name": "minecraft:skull_banner_pattern", - "id": 594 + "id": 599 }, { "name": "minecraft:skull_pottery_sherd", - "id": 685 + "id": 696 }, { "name": "minecraft:slime", @@ -4925,11 +5165,11 @@ }, { "name": "minecraft:slime_ball", - "id": 392 + "id": 396 }, { "name": "minecraft:slime_spawn_egg", - "id": 449 + "id": 454 }, { "name": "minecraft:small_amethyst_bud", @@ -4967,21 +5207,25 @@ "name": "minecraft:smooth_stone", "id": -183 }, + { + "name": "minecraft:smooth_stone_slab", + "id": 44 + }, { "name": "minecraft:sniffer_egg", "id": -596 }, { "name": "minecraft:sniffer_spawn_egg", - "id": 505 + "id": 510 }, { "name": "minecraft:snort_pottery_sherd", - "id": 686 + "id": 697 }, { "name": "minecraft:snout_armor_trim_smithing_template", - "id": 697 + "id": 708 }, { "name": "minecraft:snow", @@ -4989,7 +5233,7 @@ }, { "name": "minecraft:snow_golem_spawn_egg", - "id": 511 + "id": 516 }, { "name": "minecraft:snow_layer", @@ -4997,11 +5241,11 @@ }, { "name": "minecraft:snowball", - "id": 377 + "id": 381 }, { "name": "minecraft:soul_campfire", - "id": 633 + "id": 641 }, { "name": "minecraft:soul_fire", @@ -5025,27 +5269,27 @@ }, { "name": "minecraft:sparkler", - "id": 611 + "id": 619 }, { "name": "minecraft:spawn_egg", - "id": 732 + "id": 757 }, { "name": "minecraft:spider_eye", - "id": 279 + "id": 282 }, { "name": "minecraft:spider_spawn_egg", - "id": 450 + "id": 455 }, { "name": "minecraft:spire_armor_trim_smithing_template", - "id": 699 + "id": 710 }, { "name": "minecraft:splash_potion", - "id": 572 + "id": 577 }, { "name": "minecraft:sponge", @@ -5057,7 +5301,7 @@ }, { "name": "minecraft:spruce_boat", - "id": 382 + "id": 386 }, { "name": "minecraft:spruce_button", @@ -5065,11 +5309,11 @@ }, { "name": "minecraft:spruce_chest_boat", - "id": 652 + "id": 660 }, { "name": "minecraft:spruce_door", - "id": 564 + "id": 569 }, { "name": "minecraft:spruce_double_slab", @@ -5103,9 +5347,13 @@ "name": "minecraft:spruce_pressure_plate", "id": -154 }, + { + "name": "minecraft:spruce_sapling", + "id": -825 + }, { "name": "minecraft:spruce_sign", - "id": 587 + "id": 592 }, { "name": "minecraft:spruce_slab", @@ -5133,23 +5381,23 @@ }, { "name": "minecraft:spyglass", - "id": 636 + "id": 644 }, { "name": "minecraft:squid_spawn_egg", - "id": 454 + "id": 459 }, { "name": "minecraft:stained_glass", - "id": 723 + "id": 745 }, { "name": "minecraft:stained_glass_pane", - "id": 724 + "id": 746 }, { "name": "minecraft:stained_hardened_clay", - "id": 706 + "id": 719 }, { "name": "minecraft:standing_banner", @@ -5161,7 +5409,7 @@ }, { "name": "minecraft:stick", - "id": 323 + "id": 327 }, { "name": "minecraft:sticky_piston", @@ -5177,11 +5425,11 @@ }, { "name": "minecraft:stone_axe", - "id": 318 + "id": 321 }, { "name": "minecraft:stone_block_slab", - "id": 44 + "id": 736 }, { "name": "minecraft:stone_block_slab2", @@ -5195,6 +5443,10 @@ "name": "minecraft:stone_block_slab4", "id": -166 }, + { + "name": "minecraft:stone_brick_slab", + "id": -875 + }, { "name": "minecraft:stone_brick_stairs", "id": 109 @@ -5205,11 +5457,11 @@ }, { "name": "minecraft:stone_hoe", - "id": 333 + "id": 337 }, { "name": "minecraft:stone_pickaxe", - "id": 317 + "id": 320 }, { "name": "minecraft:stone_pressure_plate", @@ -5217,7 +5469,7 @@ }, { "name": "minecraft:stone_shovel", - "id": 316 + "id": 319 }, { "name": "minecraft:stone_stairs", @@ -5225,7 +5477,7 @@ }, { "name": "minecraft:stone_sword", - "id": 315 + "id": 318 }, { "name": "minecraft:stonebrick", @@ -5241,15 +5493,15 @@ }, { "name": "minecraft:stray_spawn_egg", - "id": 466 + "id": 471 }, { "name": "minecraft:strider_spawn_egg", - "id": 500 + "id": 505 }, { "name": "minecraft:string", - "id": 329 + "id": 333 }, { "name": "minecraft:stripped_acacia_log", @@ -5345,11 +5597,15 @@ }, { "name": "minecraft:sugar", - "id": 420 + "id": 424 }, { "name": "minecraft:sugar_cane", - "id": 389 + "id": 393 + }, + { + "name": "minecraft:sunflower", + "id": 175 }, { "name": "minecraft:suspicious_gravel", @@ -5361,11 +5617,11 @@ }, { "name": "minecraft:suspicious_stew", - "id": 601 + "id": 608 }, { "name": "minecraft:sweet_berries", - "id": 288 + "id": 291 }, { "name": "minecraft:sweet_berry_bush", @@ -5373,15 +5629,19 @@ }, { "name": "minecraft:tadpole_bucket", - "id": 641 + "id": 649 }, { "name": "minecraft:tadpole_spawn_egg", - "id": 640 + "id": 648 + }, + { + "name": "minecraft:tall_grass", + "id": -864 }, { "name": "minecraft:tallgrass", - "id": 31 + "id": 741 }, { "name": "minecraft:target", @@ -5389,7 +5649,7 @@ }, { "name": "minecraft:tide_armor_trim_smithing_template", - "id": 696 + "id": 707 }, { "name": "minecraft:tinted_glass", @@ -5401,7 +5661,7 @@ }, { "name": "minecraft:tnt_minecart", - "id": 536 + "id": 541 }, { "name": "minecraft:torch", @@ -5417,15 +5677,15 @@ }, { "name": "minecraft:torchflower_seeds", - "id": 297 + "id": 300 }, { "name": "minecraft:totem_of_undying", - "id": 579 + "id": 584 }, { "name": "minecraft:trader_llama_spawn_egg", - "id": 659 + "id": 667 }, { "name": "minecraft:trapdoor", @@ -5437,7 +5697,7 @@ }, { "name": "minecraft:trial_key", - "id": 707 + "id": 259 }, { "name": "minecraft:trial_spawner", @@ -5445,7 +5705,7 @@ }, { "name": "minecraft:trident", - "id": 557 + "id": 562 }, { "name": "minecraft:trip_wire", @@ -5457,20 +5717,28 @@ }, { "name": "minecraft:tropical_fish", - "id": 267 + "id": 270 }, { "name": "minecraft:tropical_fish_bucket", - "id": 369 + "id": 373 }, { "name": "minecraft:tropical_fish_spawn_egg", - "id": 484 + "id": 489 }, { "name": "minecraft:tube_coral", "id": -131 }, + { + "name": "minecraft:tube_coral_block", + "id": -132 + }, + { + "name": "minecraft:tube_coral_fan", + "id": -133 + }, { "name": "minecraft:tuff", "id": -333 @@ -5517,15 +5785,15 @@ }, { "name": "minecraft:turtle_helmet", - "id": 584 + "id": 589 }, { "name": "minecraft:turtle_scute", - "id": 583 + "id": 588 }, { "name": "minecraft:turtle_spawn_egg", - "id": 490 + "id": 495 }, { "name": "minecraft:twisting_vines", @@ -5565,19 +5833,19 @@ }, { "name": "minecraft:vex_armor_trim_smithing_template", - "id": 695 + "id": 706 }, { "name": "minecraft:vex_spawn_egg", - "id": 481 + "id": 486 }, { "name": "minecraft:villager_spawn_egg", - "id": 453 + "id": 458 }, { "name": "minecraft:vindicator_spawn_egg", - "id": 479 + "id": 484 }, { "name": "minecraft:vine", @@ -5593,15 +5861,15 @@ }, { "name": "minecraft:wandering_trader_spawn_egg", - "id": 497 + "id": 502 }, { "name": "minecraft:ward_armor_trim_smithing_template", - "id": 693 + "id": 704 }, { "name": "minecraft:warden_spawn_egg", - "id": 643 + "id": 651 }, { "name": "minecraft:warped_button", @@ -5609,7 +5877,7 @@ }, { "name": "minecraft:warped_door", - "id": 628 + "id": 636 }, { "name": "minecraft:warped_double_slab", @@ -5629,7 +5897,7 @@ }, { "name": "minecraft:warped_fungus_on_a_stick", - "id": 629 + "id": 637 }, { "name": "minecraft:warped_hanging_sign", @@ -5657,7 +5925,7 @@ }, { "name": "minecraft:warped_sign", - "id": 626 + "id": 634 }, { "name": "minecraft:warped_slab", @@ -5693,7 +5961,7 @@ }, { "name": "minecraft:water_bucket", - "id": 365 + "id": 369 }, { "name": "minecraft:waterlily", @@ -5861,7 +6129,7 @@ }, { "name": "minecraft:wayfinder_armor_trim_smithing_template", - "id": 701 + "id": 712 }, { "name": "minecraft:weathered_chiseled_copper", @@ -5913,11 +6181,11 @@ }, { "name": "minecraft:wheat", - "id": 337 + "id": 341 }, { "name": "minecraft:wheat_seeds", - "id": 292 + "id": 295 }, { "name": "minecraft:white_candle", @@ -5941,7 +6209,7 @@ }, { "name": "minecraft:white_dye", - "id": 414 + "id": 418 }, { "name": "minecraft:white_glazed_terracotta", @@ -5963,21 +6231,25 @@ "name": "minecraft:white_terracotta", "id": 159 }, + { + "name": "minecraft:white_tulip", + "id": -835 + }, { "name": "minecraft:white_wool", "id": 35 }, { "name": "minecraft:wild_armor_trim_smithing_template", - "id": 692 + "id": 703 }, { "name": "minecraft:wind_charge", - "id": 378 + "id": 260 }, { "name": "minecraft:witch_spawn_egg", - "id": 456 + "id": 461 }, { "name": "minecraft:wither_rose", @@ -5985,27 +6257,27 @@ }, { "name": "minecraft:wither_skeleton_spawn_egg", - "id": 469 + "id": 474 }, { "name": "minecraft:wither_spawn_egg", - "id": 513 + "id": 518 }, { "name": "minecraft:wolf_armor", - "id": 710 + "id": 722 }, { "name": "minecraft:wolf_spawn_egg", - "id": 443 + "id": 448 }, { "name": "minecraft:wood", - "id": 726 + "id": 748 }, { "name": "minecraft:wooden_axe", - "id": 314 + "id": 317 }, { "name": "minecraft:wooden_button", @@ -6013,15 +6285,15 @@ }, { "name": "minecraft:wooden_door", - "id": 362 + "id": 366 }, { "name": "minecraft:wooden_hoe", - "id": 332 + "id": 336 }, { "name": "minecraft:wooden_pickaxe", - "id": 313 + "id": 316 }, { "name": "minecraft:wooden_pressure_plate", @@ -6029,27 +6301,27 @@ }, { "name": "minecraft:wooden_shovel", - "id": 312 + "id": 315 }, { "name": "minecraft:wooden_slab", - "id": 717 + "id": 735 }, { "name": "minecraft:wooden_sword", - "id": 311 + "id": 314 }, { "name": "minecraft:wool", - "id": 711 + "id": 725 }, { "name": "minecraft:writable_book", - "id": 521 + "id": 526 }, { "name": "minecraft:written_book", - "id": 522 + "id": 527 }, { "name": "minecraft:yellow_candle", @@ -6073,7 +6345,7 @@ }, { "name": "minecraft:yellow_dye", - "id": 410 + "id": 414 }, { "name": "minecraft:yellow_flower", @@ -6105,22 +6377,22 @@ }, { "name": "minecraft:zoglin_spawn_egg", - "id": 503 + "id": 508 }, { "name": "minecraft:zombie_horse_spawn_egg", - "id": 473 + "id": 478 }, { "name": "minecraft:zombie_pigman_spawn_egg", - "id": 452 + "id": 457 }, { "name": "minecraft:zombie_spawn_egg", - "id": 451 + "id": 456 }, { "name": "minecraft:zombie_villager_spawn_egg", - "id": 482 + "id": 487 } ] \ No newline at end of file diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 968a22bba..ec45f59c8 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 968a22bbab02d7d003c5b451a40d8bb2439b0d97 +Subproject commit ec45f59c8590945c9226921ef7e339f510983dc1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aa68a0bc0..8301029d2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,8 +10,7 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "3.0.0.Beta1-20240411.165033-129" -protocol-connection = "3.0.0.Beta1-20240411.165033-128" +protocol = "3.0.0.Beta2-20240520.153053-5" raknet = "1.0.0.CR3-20240416.144209-1" blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "e5b0bcc" @@ -117,12 +116,9 @@ viaproxy = { group = "net.raphimc", name = "ViaProxy", version.ref = "viaproxy" viaversion = { group = "com.viaversion", name = "viaversion", version.ref = "viaversion" } websocket = { group = "org.java-websocket", name = "Java-WebSocket", version.ref = "websocket" } -#protocol-common = { group = "org.cloudburstmc.protocol", name = "common", version.ref = "protocol-connection" } -#protocol-codec = { group = "org.cloudburstmc.protocol", name = "bedrock-codec", version.ref = "protocol" } -#protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-connection", version.ref = "protocol-connection" } -protocol-common = { group = "com.github.GeyserMC.Protocol", name = "common", version = "ade21be" } -protocol-codec = { group = "com.github.GeyserMC.Protocol", name = "bedrock-codec", version = "ade21be" } -protocol-connection = { group = "com.github.GeyserMC.Protocol", name = "bedrock-connection", version = "ade21be" } +protocol-common = { group = "org.cloudburstmc.protocol", name = "common", version.ref = "protocol" } +protocol-codec = { group = "org.cloudburstmc.protocol", name = "bedrock-codec", version.ref = "protocol" } +protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-connection", version.ref = "protocol" } math = { group = "org.cloudburstmc.math", name = "immutable", version = "2.0" } From cb0488a271c6db3637476477902234725461aa7f Mon Sep 17 00:00:00 2001 From: Valaphee The Meerkat <32491319+valaphee@users.noreply.github.com> Date: Mon, 27 May 2024 14:08:04 +0200 Subject: [PATCH 164/897] Fix NPE in TippedArrow when it has no components (#4694) --- .../geyser/item/type/TippedArrowItem.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) 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 85291886e..db33bb584 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 @@ -41,16 +41,18 @@ public class TippedArrowItem extends ArrowItem { @Override public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { - PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); - if (potionContents != null) { - TippedArrowPotion tippedArrowPotion = TippedArrowPotion.of(potionContents.getPotionId()); - if (tippedArrowPotion != null) { - return ItemData.builder() - .definition(mapping.getBedrockDefinition()) - .damage(tippedArrowPotion.getBedrockId()) - .count(count); + if (components != null) { + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + TippedArrowPotion tippedArrowPotion = TippedArrowPotion.of(potionContents.getPotionId()); + if (tippedArrowPotion != null) { + return ItemData.builder() + .definition(mapping.getBedrockDefinition()) + .damage(tippedArrowPotion.getBedrockId()) + .count(count); + } + GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionContents.getPotionId()); } - GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionContents.getPotionId()); } return super.translateToBedrock(count, components, mapping, mappings); } From 3570caae258e43b61bfc628d18f0408e3b08af78 Mon Sep 17 00:00:00 2001 From: Valaphee The Meerkat <32491319+valaphee@users.noreply.github.com> Date: Mon, 27 May 2024 16:53:42 +0200 Subject: [PATCH 165/897] Fix crafting output not updating sometimes (#4692) * Only cancel crafting grid future if slot == 0 * Add some comments --- .../inventory/JavaContainerSetSlotTranslator.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 4372b5ea5..57da00b51 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 @@ -71,10 +71,6 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator= inventory.getSize()) { GeyserLogger logger = session.getGeyser().getLogger(); @@ -111,14 +107,22 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator Date: Mon, 27 May 2024 10:59:36 -0700 Subject: [PATCH 166/897] Switch to centralized GitHub actions (#4693) * Switch to centralized GitHub actions * Update PR actions as well * Publish preview only if success * Webhook on success & failure --- .github/workflows/build-remote.yml | 36 ++++----- .github/workflows/build.yml | 125 +++++++++++++---------------- .github/workflows/preview.yml | 57 +++++-------- 3 files changed, 97 insertions(+), 121 deletions(-) diff --git a/.github/workflows/build-remote.yml b/.github/workflows/build-remote.yml index d49920785..c815b4740 100644 --- a/.github/workflows/build-remote.yml +++ b/.github/workflows/build-remote.yml @@ -22,79 +22,79 @@ jobs: run: | echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - - name: Set up JDK 21 + - name: Setup Java # See https://github.com/actions/setup-java/commits - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 + uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 with: java-version: 21 distribution: temurin - name: Checkout repository and submodules # See https://github.com/actions/checkout/commits - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: repository: ${{ inputs.repository }} ref: ${{ inputs.ref }} submodules: recursive - path: geyser - name: Validate Gradle Wrapper # See https://github.com/gradle/wrapper-validation-action/commits - uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1 + uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + + - name: Setup Gradle + # See https://github.com/gradle/actions/commits + uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + with: + cache-read-only: true - name: Build Geyser - # See https://github.com/gradle/actions/commits - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 - with: - arguments: build - build-root-directory: geyser - cache-read-only: true + run: ./gradlew build - name: Archive artifacts (Geyser Fabric) # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: success() with: name: Geyser Fabric path: geyser/bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar if-no-files-found: error - name: Archive artifacts (Geyser NeoForge) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser NeoForge path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar if-no-files-found: error - name: Archive artifacts (Geyser Standalone) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser Standalone path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar if-no-files-found: error - name: Archive artifacts (Geyser Spigot) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser Spigot path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar if-no-files-found: error - name: Archive artifacts (Geyser BungeeCord) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser BungeeCord path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar if-no-files-found: error - name: Archive artifacts (Geyser Velocity) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser Velocity path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar if-no-files-found: error - name: Archive artifacts (Geyser ViaProxy) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser ViaProxy diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7ec013dc2..f2f2a2c82 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,84 +21,86 @@ on: jobs: build: runs-on: ubuntu-latest - env: - PROJECT: 'geyser' steps: - - name: Set Build Number - env: - BUILD_JSON: ${{ vars.RELEASEACTION_PREVRELEASE }} - run: | - BUILD_NUMBER=$(echo $BUILD_JSON | jq --arg branch "${GITHUB_REF_NAME}" 'if .[$branch] == null then 1 else .[$branch] | .t | tonumber + 1 end // 1') - echo "BUILD_NUMBER=${BUILD_NUMBER:=$GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + - name: Get Release Info + id: release-info + uses: GeyserMC/actions/previous-release@master + with: + data: ${{ vars.RELEASEACTION_PREVRELEASE }} - name: Checkout repository and submodules # See https://github.com/actions/checkout/commits - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive - name: Validate Gradle Wrapper - # See https://github.com/gradle/wrapper-validation-action/commits - uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1 + # See https://github.com/gradle/actions/commits + uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 # See https://github.com/actions/setup-java/commits - - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 + - name: Setup Java + uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 with: java-version: 21 distribution: temurin - - name: Build + - name: Setup Gradle # See https://github.com/gradle/actions/commits - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 with: - arguments: build gradle-home-cache-cleanup: true + + - name: Build Geyser + run: ./gradlew build + env: + BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} - name: Archive artifacts (Geyser Fabric) # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: success() with: name: Geyser Fabric path: bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar if-no-files-found: error - name: Archive artifacts (Geyser NeoForge) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser NeoForge path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar if-no-files-found: error - name: Archive artifacts (Geyser Standalone) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser Standalone path: bootstrap/standalone/build/libs/Geyser-Standalone.jar if-no-files-found: error - name: Archive artifacts (Geyser Spigot) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser Spigot path: bootstrap/spigot/build/libs/Geyser-Spigot.jar if-no-files-found: error - name: Archive artifacts (Geyser BungeeCord) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser BungeeCord path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar if-no-files-found: error - name: Archive artifacts (Geyser Velocity) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser Velocity path: bootstrap/velocity/build/libs/Geyser-Velocity.jar if-no-files-found: error - name: Archive artifacts (Geyser ViaProxy) - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 if: success() with: name: Geyser ViaProxy @@ -107,17 +109,23 @@ jobs: - name: Publish to Maven Repository if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 + run: ./gradlew publish env: + BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} - with: - arguments: publish + + - name: Get Version + if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + id: get-version + run: | + version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) + echo "VERSION=${version}" >> $GITHUB_OUTPUT - name: Get Release Metadata if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} - # See https://github.com/Kas-tle/base-release-action/releases/tag/main-11 - uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # main-11 + uses: GeyserMC/actions/release@master + id: metadata with: appID: ${{ secrets.RELEASE_APP_ID }} appPrivateKey: ${{ secrets.RELEASE_APP_PK }} @@ -131,61 +139,42 @@ jobs: viaproxy:bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar releaseEnabled: false saveMetadata: true - - name: Update Generated Metadata - if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} - run: | - cat metadata.json - echo - mv metadata.json metadata.json.tmp - version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) - jq --arg project "${PROJECT}" --arg version "${version}" ' - . - | .changes |= map({"commit", "summary", "message"}) - | .downloads |= map_values({"name", "sha256"}) - | {$project, "repo", $version, "number": .build, "changes", "downloads"} - ' metadata.json.tmp > metadata.json - cat metadata.json + releaseProject: 'geyser' + releaseVersion: ${{ steps.get-version.outputs.VERSION }} - name: Publish to Downloads API if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} - shell: bash - env: - DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }} - DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} - DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }} - run: | - # Save the private key to a file - echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa - chmod 600 id_ecdsa - # Create the build folder - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/" - # Copy over artifacts - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/mod/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ - # Run the build script - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/ + uses: GeyserMC/actions/upload-release@master + with: + username: ${{ vars.DOWNLOADS_USERNAME }} + privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} + host: ${{ secrets.DOWNLOADS_SERVER_IP }} + files: | + bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar + bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar + bootstrap/spigot/build/libs/Geyser-Spigot.jar + bootstrap/standalone/build/libs/Geyser-Standalone.jar + bootstrap/velocity/build/libs/Geyser-Velocity.jar + bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar - name: Publish to Modrinth (Fabric) - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} env: + BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} - with: - arguments: fabric:modrinth - gradle-home-cache-cleanup: true + run: ./gradlew fabric:modrinth - name: Publish to Modrinth (NeoForge) - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} env: + BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} - with: - arguments: neoforge:modrinth - gradle-home-cache-cleanup: true + run: ./gradlew neoforge:modrinth - name: Notify Discord if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }} - # See https://github.com/Tim203/actions-git-discord-webhook/commits - uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff + uses: GeyserMC/actions/notify-discord@master with: - webhook_url: ${{ secrets.DISCORD_WEBHOOK }} + discordWebhook: ${{ secrets.DISCORD_WEBHOOK }} status: ${{ job.status }} + body: ${{ steps.metadata.outputs.body }} diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 1268f0674..a90d60ef7 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -26,30 +26,30 @@ on: jobs: upload: runs-on: ubuntu-latest - env: - PROJECT: 'geyserpreview' steps: - name: Set Variables id: setvars run: | if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then echo "BUILD=${{ github.event.inputs.build }}" >> $GITHUB_ENV - echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV + echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT echo "RUN=${{ github.event.inputs.runId }}" >> $GITHUB_OUTPUT else echo "BUILD=${{ inputs.build }}" >> $GITHUB_ENV - echo "VERSION=${{ inputs.version }}" >> $GITHUB_ENV + echo "VERSION=${{ inputs.version }}" >> $GITHUB_OUTPUT echo "RUN=${{ github.run_id }}" >> $GITHUB_OUTPUT fi - - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 + - name: Download Artifacts + # See https://github.com/actions/download-artifact/commits + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.6 with: run-id: ${{ steps.setvars.outputs.RUN }} github-token: ${{ secrets.GITHUB_TOKEN }} merge-multiple: true - name: Get Preview Metadata if: success() - # See https://github.com/Kas-tle/base-release-action/releases/tag/main-11 - uses: Kas-tle/base-release-action@664c39985eb9d0d393ce98e7eb8414d3d98e762a # main-11 + uses: GeyserMC/actions/release@master + id: metadata with: appID: ${{ secrets.RELEASE_APP_ID }} appPrivateKey: ${{ secrets.RELEASE_APP_PK }} @@ -64,33 +64,20 @@ jobs: releaseEnabled: false saveMetadata: true updateReleaseData: false - - name: Update Generated Metadata - if: success() - run: | - cat metadata.json - echo - mv metadata.json metadata.json.tmp - jq --arg project "${PROJECT}" --arg version "${VERSION}" --arg number "${BUILD}" ' - . - | .downloads |= map_values({"name", "sha256"}) - | {$project, "repo", $version, "number": $number | tonumber, "changes": [], "downloads"} - ' metadata.json.tmp > metadata.json - cat metadata.json + releaseProject: 'geyserpreview' + releaseVersion: ${{ steps.setvars.outputs.VERSION }} - name: Publish to Downloads API if: success() - shell: bash - env: - DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }} - DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} - DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }} - run: | - # Save the private key to a file - echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa - chmod 600 id_ecdsa - # Create the build folder - ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$PROJECT/$BUILD/" - # Copy over artifacts - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/ - # Run the build script - # Push the metadata - rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/ + uses: GeyserMC/actions/upload-release@master + with: + username: ${{ vars.DOWNLOADS_USERNAME }} + privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} + host: ${{ secrets.DOWNLOADS_SERVER_IP }} + files: | + Geyser-BungeeCord.jar + Geyser-Fabric.jar + Geyser-NeoForge.jar + Geyser-Spigot.jar + Geyser-Standalone.jar + Geyser-Velocity.jar + Geyser-ViaProxy.jar From 444b5ecee8bf80e8ae93caa52dad8918a29a7542 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 27 May 2024 14:33:11 -0400 Subject: [PATCH 167/897] Remove BlockStateUpdater dependency Not currently used --- core/build.gradle.kts | 1 - .../populator/BlockRegistryPopulator.java | 15 --------------- gradle/libs.versions.toml | 3 --- 3 files changed, 19 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 42d4e13c5..a27c4fc89 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -24,7 +24,6 @@ dependencies { implementation(libs.websocket) api(libs.bundles.protocol) - implementation(libs.blockstateupdater) api(libs.mcauthlib) api(libs.mcprotocollib) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 936935306..6b856c509 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -35,8 +35,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.*; -import org.cloudburstmc.blockstateupdater.BlockStateUpdater; -import org.cloudburstmc.blockstateupdater.util.tagupdater.CompoundTagUpdaterContext; import org.cloudburstmc.nbt.*; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; @@ -85,19 +83,6 @@ public final class BlockRegistryPopulator { interface Remapper { NbtMap remap(NbtMap tag); - - static Remapper of(BlockStateUpdater... updaters) { - CompoundTagUpdaterContext context = new CompoundTagUpdaterContext(); - for (BlockStateUpdater updater : updaters) { - updater.registerUpdaters(context); - } - - return tag -> { - NbtMapBuilder updated = context.update(tag, 0).toBuilder(); - updated.remove("version"); // we already removed this, but the context adds it. remove it again. - return updated.build(); - }; - } } public static void populate(Stage stage) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8301029d2..1995a6ada 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,6 @@ gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" protocol = "3.0.0.Beta2-20240520.153053-5" raknet = "1.0.0.CR3-20240416.144209-1" -blockstateupdater="1.20.80-20240411.142413-1" mcauthlib = "e5b0bcc" mcprotocollib = "1.20.6-2-20240520.030045-8" adventure = "4.14.0" @@ -122,8 +121,6 @@ protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-con math = { group = "org.cloudburstmc.math", name = "immutable", version = "2.0" } -blockstateupdater = { group = "org.cloudburstmc", name = "block-state-updater", version.ref = "blockstateupdater"} - # plugins indra = { group = "net.kyori", name = "indra-common", version.ref = "indra" } shadow = { group = "com.github.johnrengelman", name = "shadow", version.ref = "shadow" } From 675faf6bb45676e248bb1f0b0f871429966e8feb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 27 May 2024 14:35:02 -0400 Subject: [PATCH 168/897] Remove unused chat class --- .../geysermc/geyser/text/ChatTypeEntry.java | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java deleted file mode 100644 index f139b0bba..000000000 --- a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java +++ /dev/null @@ -1,53 +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.text; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.protocol.bedrock.packet.TextPacket; -import org.geysermc.mcprotocollib.protocol.data.game.chat.BuiltinChatType; - -public record ChatTypeEntry(TextPacket.@NonNull Type bedrockChatType, @Nullable TextDecoration textDecoration) { - private static final ChatTypeEntry CHAT = new ChatTypeEntry(TextPacket.Type.CHAT, null); - private static final ChatTypeEntry RAW = new ChatTypeEntry(TextPacket.Type.RAW, null); - - /** - * Apply defaults to a map so it isn't empty in the event a chat message is sent before the login packet. - */ - public static void applyDefaults(Int2ObjectMap chatTypes) { - // So the proper way to do this, probably, would be to dump the NBT data from vanilla and load it. - // But, the only way this happens is if a chat message is sent to us before the login packet, which is rare. - // So we'll just make sure chat ends up in the right place. - chatTypes.put(BuiltinChatType.CHAT.ordinal(), CHAT); - chatTypes.put(BuiltinChatType.SAY_COMMAND.ordinal(), RAW); - chatTypes.put(BuiltinChatType.MSG_COMMAND_INCOMING.ordinal(), RAW); - chatTypes.put(BuiltinChatType.MSG_COMMAND_OUTGOING.ordinal(), RAW); - chatTypes.put(BuiltinChatType.TEAM_MSG_COMMAND_INCOMING.ordinal(), RAW); - chatTypes.put(BuiltinChatType.TEAM_MSG_COMMAND_OUTGOING.ordinal(), RAW); - chatTypes.put(BuiltinChatType.EMOTE_COMMAND.ordinal(), RAW); - } -} From fe63665d8818af2836e9db3447f8625d49beaeb6 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 28 May 2024 00:11:05 -0700 Subject: [PATCH 169/897] Composite gradle setup and artifact archival (#4696) * Composite gradle setup and artifact archival * Remove 'geyser' path for PRs * Move upload-preview workflow --- .github/workflows/build-remote.yml | 85 +++++-------------------- .github/workflows/build.yml | 86 +++++--------------------- .github/workflows/dispatch-preview.yml | 33 ++++++++++ .github/workflows/preview.yml | 83 ------------------------- .github/workflows/pull-request.yml | 16 ++++- 5 files changed, 77 insertions(+), 226 deletions(-) create mode 100644 .github/workflows/dispatch-preview.yml delete mode 100644 .github/workflows/preview.yml diff --git a/.github/workflows/build-remote.yml b/.github/workflows/build-remote.yml index c815b4740..7cb89cc61 100644 --- a/.github/workflows/build-remote.yml +++ b/.github/workflows/build-remote.yml @@ -22,81 +22,26 @@ jobs: run: | echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - - name: Setup Java - # See https://github.com/actions/setup-java/commits - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 - with: - java-version: 21 - distribution: temurin - - - name: Checkout repository and submodules - # See https://github.com/actions/checkout/commits - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - with: - repository: ${{ inputs.repository }} - ref: ${{ inputs.ref }} - submodules: recursive - - - name: Validate Gradle Wrapper - # See https://github.com/gradle/wrapper-validation-action/commits - uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 - - name: Setup Gradle - # See https://github.com/gradle/actions/commits - uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + uses: GeyserMC/actions/setup-gradle-composite@master with: - cache-read-only: true + checkout_repository: ${{ inputs.repository }} + checkout_ref: ${{ inputs.ref }} + setup-java_java-version: 21 + setup-gradle_cache-read-only: true - name: Build Geyser run: ./gradlew build - - name: Archive artifacts (Geyser Fabric) - # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - name: Archive Artifacts + uses: GeyserMC/actions/upload-multi-artifact@master if: success() with: - name: Geyser Fabric - path: geyser/bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar - if-no-files-found: error - - name: Archive artifacts (Geyser NeoForge) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser NeoForge - path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Standalone) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Standalone - path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Spigot) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Spigot - path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar - if-no-files-found: error - - name: Archive artifacts (Geyser BungeeCord) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser BungeeCord - path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Velocity) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Velocity - path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar - if-no-files-found: error - - name: Archive artifacts (Geyser ViaProxy) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser ViaProxy - path: geyser/bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar - if-no-files-found: error \ No newline at end of file + artifacts: | + bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar + bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar + bootstrap/standalone/build/libs/Geyser-Standalone.jar + bootstrap/spigot/build/libs/Geyser-Spigot.jar + bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + bootstrap/velocity/build/libs/Geyser-Velocity.jar + bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f2f2a2c82..b8f855a53 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,84 +28,28 @@ jobs: with: data: ${{ vars.RELEASEACTION_PREVRELEASE }} - - name: Checkout repository and submodules - # See https://github.com/actions/checkout/commits - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - with: - submodules: recursive - - - name: Validate Gradle Wrapper - # See https://github.com/gradle/actions/commits - uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 - - # See https://github.com/actions/setup-java/commits - - name: Setup Java - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 - with: - java-version: 21 - distribution: temurin - - name: Setup Gradle - # See https://github.com/gradle/actions/commits - uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + uses: GeyserMC/actions/setup-gradle-composite@master with: - gradle-home-cache-cleanup: true + setup-java_java-version: 21 - name: Build Geyser run: ./gradlew build env: BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} - - name: Archive artifacts (Geyser Fabric) - # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - name: Archive Artifacts + uses: GeyserMC/actions/upload-multi-artifact@master if: success() with: - name: Geyser Fabric - path: bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar - if-no-files-found: error - - name: Archive artifacts (Geyser NeoForge) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser NeoForge - path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Standalone) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Standalone - path: bootstrap/standalone/build/libs/Geyser-Standalone.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Spigot) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Spigot - path: bootstrap/spigot/build/libs/Geyser-Spigot.jar - if-no-files-found: error - - name: Archive artifacts (Geyser BungeeCord) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser BungeeCord - path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Velocity) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Velocity - path: bootstrap/velocity/build/libs/Geyser-Velocity.jar - if-no-files-found: error - - name: Archive artifacts (Geyser ViaProxy) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser ViaProxy - path: bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar - if-no-files-found: error + artifacts: | + bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar + bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar + bootstrap/standalone/build/libs/Geyser-Standalone.jar + bootstrap/spigot/build/libs/Geyser-Spigot.jar + bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + bootstrap/velocity/build/libs/Geyser-Velocity.jar + bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar - name: Publish to Maven Repository if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} @@ -116,14 +60,14 @@ jobs: ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} - name: Get Version - if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }} id: get-version run: | version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) echo "VERSION=${version}" >> $GITHUB_OUTPUT - name: Get Release Metadata - if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }} uses: GeyserMC/actions/release@master id: metadata with: @@ -141,6 +85,7 @@ jobs: saveMetadata: true releaseProject: 'geyser' releaseVersion: ${{ steps.get-version.outputs.VERSION }} + - name: Publish to Downloads API if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} uses: GeyserMC/actions/upload-release@master @@ -156,6 +101,7 @@ jobs: bootstrap/standalone/build/libs/Geyser-Standalone.jar bootstrap/velocity/build/libs/Geyser-Velocity.jar bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar + changelog: ${{ steps.metadata.outputs.body }} - name: Publish to Modrinth (Fabric) if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} diff --git a/.github/workflows/dispatch-preview.yml b/.github/workflows/dispatch-preview.yml new file mode 100644 index 000000000..83df08e37 --- /dev/null +++ b/.github/workflows/dispatch-preview.yml @@ -0,0 +1,33 @@ +name: Dispatch Preview + +on: + workflow_dispatch: + inputs: + runId: + required: true + description: 'ID of the action to pull artifacts from' + build: + required: true + description: 'Build number for the release' + version: + required: true + description: 'Version under which to upload to the Downloads API' + +jobs: + dispatch-preview: + # Allow access to secrets if we are uploading a preview + secrets: inherit + uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master + with: + build: ${{ inputs.build }} + version: ${{ inputs.version }} + files: | + bungeecord:Geyser-BungeeCord.jar + fabric:Geyser-Fabric.jar + neoforge:Geyser-NeoForge.jar + spigot:Geyser-Spigot.jar + standalone:Geyser-Standalone.jar + velocity:Geyser-Velocity.jar + viaproxy:Geyser-ViaProxy.jar + project: geyserpreview + runId: ${{ inputs.runId }} \ No newline at end of file diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml deleted file mode 100644 index a90d60ef7..000000000 --- a/.github/workflows/preview.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Upload Preview - -on: - workflow_dispatch: - inputs: - runId: - required: true - description: 'ID of the action to pull artifacts from' - build: - required: true - description: 'Build number for the release' - version: - required: true - description: 'Version under which to upload to the Downloads API' - workflow_call: - inputs: - build: - required: true - description: 'Build number for the release' - type: string - version: - required: true - description: 'Version under which to upload to the Downloads API' - type: string - -jobs: - upload: - runs-on: ubuntu-latest - steps: - - name: Set Variables - id: setvars - run: | - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - echo "BUILD=${{ github.event.inputs.build }}" >> $GITHUB_ENV - echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - echo "RUN=${{ github.event.inputs.runId }}" >> $GITHUB_OUTPUT - else - echo "BUILD=${{ inputs.build }}" >> $GITHUB_ENV - echo "VERSION=${{ inputs.version }}" >> $GITHUB_OUTPUT - echo "RUN=${{ github.run_id }}" >> $GITHUB_OUTPUT - fi - - name: Download Artifacts - # See https://github.com/actions/download-artifact/commits - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.6 - with: - run-id: ${{ steps.setvars.outputs.RUN }} - github-token: ${{ secrets.GITHUB_TOKEN }} - merge-multiple: true - - name: Get Preview Metadata - if: success() - uses: GeyserMC/actions/release@master - id: metadata - with: - appID: ${{ secrets.RELEASE_APP_ID }} - appPrivateKey: ${{ secrets.RELEASE_APP_PK }} - files: | - bungeecord:Geyser-BungeeCord.jar - fabric:Geyser-Fabric.jar - neoforge:Geyser-NeoForge.jar - spigot:Geyser-Spigot.jar - standalone:Geyser-Standalone.jar - velocity:Geyser-Velocity.jar - viaproxy:Geyser-ViaProxy.jar - releaseEnabled: false - saveMetadata: true - updateReleaseData: false - releaseProject: 'geyserpreview' - releaseVersion: ${{ steps.setvars.outputs.VERSION }} - - name: Publish to Downloads API - if: success() - uses: GeyserMC/actions/upload-release@master - with: - username: ${{ vars.DOWNLOADS_USERNAME }} - privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} - host: ${{ secrets.DOWNLOADS_SERVER_IP }} - files: | - Geyser-BungeeCord.jar - Geyser-Fabric.jar - Geyser-NeoForge.jar - Geyser-Spigot.jar - Geyser-Standalone.jar - Geyser-Velocity.jar - Geyser-ViaProxy.jar diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index bc5e57b6b..6167bb18e 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -8,7 +8,7 @@ jobs: # Forbid access to secrets nor GH Token perms while building the PR permissions: {} secrets: {} - uses: ./.github/workflows/build-remote.yml + uses: GeyserMC/Geyser/.github/workflows/build-remote.yml@master with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.sha }} @@ -18,7 +18,17 @@ jobs: contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing') # Allow access to secrets if we are uploading a preview secrets: inherit - uses: ./.github/workflows/preview.yml + uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master with: build: ${{ github.run_number }} - version: pr.${{ github.event.pull_request.number }} \ No newline at end of file + version: pr.${{ github.event.pull_request.number }} + files: | + bungeecord:Geyser-BungeeCord.jar + fabric:Geyser-Fabric.jar + neoforge:Geyser-NeoForge.jar + spigot:Geyser-Spigot.jar + standalone:Geyser-Standalone.jar + velocity:Geyser-Velocity.jar + viaproxy:Geyser-ViaProxy.jar + project: geyserpreview + runId: ${{ github.run_id }} \ No newline at end of file From 0fcf0f9b4f62e4b0deb03678f029f60b2112ae8b Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 28 May 2024 17:23:19 +0200 Subject: [PATCH 170/897] Update Bungee version check, create logger earlier (#4697) * use the logger where possible instead of system.out.print * make loggers final * yeet unused constructors * velocity is more complicated --- .../bungeecord/GeyserBungeeLogger.java | 7 +-- .../bungeecord/GeyserBungeePlugin.java | 23 +++++----- .../platform/mod/GeyserModBootstrap.java | 7 ++- .../geyser/platform/mod/GeyserModLogger.java | 4 -- .../platform/spigot/GeyserPaperLogger.java | 4 +- .../platform/spigot/GeyserSpigotLogger.java | 4 +- .../platform/spigot/GeyserSpigotPlugin.java | 43 +++++++++---------- .../standalone/GeyserStandaloneBootstrap.java | 4 +- .../velocity/GeyserVelocityLogger.java | 4 +- .../velocity/GeyserVelocityPlugin.java | 38 ++++++++-------- .../java/org/geysermc/geyser/GeyserImpl.java | 1 + .../geysermc/geyser/text/GeyserLocale.java | 11 ++--- 12 files changed, 67 insertions(+), 83 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java index daeb20102..e8cf7ee39 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java @@ -26,22 +26,19 @@ package org.geysermc.geyser.platform.bungeecord; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Setter; import org.geysermc.geyser.GeyserLogger; import java.util.logging.Level; import java.util.logging.Logger; +@RequiredArgsConstructor public class GeyserBungeeLogger implements GeyserLogger { private final Logger logger; @Getter @Setter private boolean debug; - public GeyserBungeeLogger(Logger logger, boolean debug) { - this.logger = logger; - this.debug = debug; - } - @Override public void severe(String message) { logger.severe(message); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 4191c8578..062ef6f76 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -58,14 +58,13 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { private GeyserCommandManager geyserCommandManager; private GeyserBungeeConfiguration geyserConfig; private GeyserBungeeInjector geyserInjector; - private GeyserBungeeLogger geyserLogger; + private final GeyserBungeeLogger geyserLogger = new GeyserBungeeLogger(getLogger()); private IGeyserPingPassthrough geyserBungeePingPassthrough; private GeyserImpl geyser; @@ -82,21 +81,21 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { // Copied from ViaVersion. // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 try { - ProtocolConstants.class.getField("MINECRAFT_1_20_3"); + ProtocolConstants.class.getField("MINECRAFT_1_20_5"); } catch (NoSuchFieldException e) { - getLogger().warning(" / \\"); - getLogger().warning(" / \\"); - getLogger().warning(" / | \\"); - getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); - getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); - getLogger().warning(" / o \\"); - getLogger().warning("/_____________\\"); + geyserLogger.error(" / \\"); + geyserLogger.error(" / \\"); + geyserLogger.error(" / | \\"); + geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); + geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); + geyserLogger.error(" / o \\"); + geyserLogger.error("/_____________\\"); } if (!this.loadConfig()) { return; } - this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode()); + this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this); this.geyserInjector = new GeyserBungeeInjector(this); @@ -293,7 +292,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class); } catch (IOException ex) { - getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); return false; } diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java index 786faac93..d7373f0a9 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java @@ -34,7 +34,6 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.server.MinecraftServer; import net.minecraft.world.entity.player.Player; -import org.apache.logging.log4j.LogManager; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserBootstrap; @@ -80,7 +79,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { private GeyserCommandManager geyserCommandManager; private GeyserModConfiguration geyserConfig; private GeyserModInjector geyserInjector; - private GeyserModLogger geyserLogger; + private final GeyserModLogger geyserLogger = new GeyserModLogger(); private IGeyserPingPassthrough geyserPingPassthrough; private WorldManager geyserWorldManager; @@ -92,7 +91,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { if (!loadConfig()) { return; } - this.geyserLogger = new GeyserModLogger(geyserConfig.isDebugMode()); + this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); this.geyser = GeyserImpl.load(this.platform.platformType(), this); @@ -288,7 +287,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class); return true; } catch (IOException ex) { - LogManager.getLogger("geyser").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); return false; } diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java index 444b725e9..9260288d7 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java @@ -37,10 +37,6 @@ public class GeyserModLogger implements GeyserLogger { private boolean debug; - public GeyserModLogger(boolean isDebug) { - debug = isDebug; - } - @Override public void severe(String message) { logger.fatal(message); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java index 930f84cec..9ebd6519a 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java @@ -34,8 +34,8 @@ import java.util.logging.Logger; public final class GeyserPaperLogger extends GeyserSpigotLogger { private final ComponentLogger componentLogger; - public GeyserPaperLogger(Plugin plugin, Logger logger, boolean debug) { - super(logger, debug); + public GeyserPaperLogger(Plugin plugin, Logger logger) { + super(logger); componentLogger = plugin.getComponentLogger(); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java index fe56cba1c..5c6101eae 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.platform.spigot; -import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Setter; import org.geysermc.geyser.GeyserLogger; import java.util.logging.Level; import java.util.logging.Logger; -@AllArgsConstructor +@RequiredArgsConstructor public class GeyserSpigotLogger implements GeyserLogger { private final Logger logger; @Getter @Setter diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index e33de5f9b..d138ad074 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -79,14 +79,14 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.UUID; -import java.util.logging.Level; public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { private GeyserSpigotCommandManager geyserCommandManager; private GeyserSpigotConfiguration geyserConfig; private GeyserSpigotInjector geyserInjector; - private GeyserSpigotLogger geyserLogger; + private final GeyserSpigotLogger geyserLogger = GeyserPaperLogger.supported() ? + new GeyserPaperLogger(this, getLogger()) : new GeyserSpigotLogger(getLogger()); private IGeyserPingPassthrough geyserSpigotPingPassthrough; private GeyserSpigotWorldManager geyserWorldManager; @@ -114,12 +114,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { // We depend on this as a fallback in certain scenarios BlockData.class.getMethod("getAsString"); } catch (ClassNotFoundException | NoSuchMethodException e) { - getLogger().severe("*********************************************"); - getLogger().severe(""); - getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header")); - getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2")); - getLogger().severe(""); - getLogger().severe("*********************************************"); + geyserLogger.error("*********************************************"); + geyserLogger.error(""); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header")); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2")); + geyserLogger.error(""); + geyserLogger.error("*********************************************"); Bukkit.getPluginManager().disablePlugin(this); return; } @@ -128,12 +128,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { Class.forName("net.md_5.bungee.chat.ComponentSerializer"); } catch (ClassNotFoundException e) { if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat - getLogger().severe("*********************************************"); - getLogger().severe(""); - getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName())); - getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper")); - getLogger().severe(""); - getLogger().severe("*********************************************"); + geyserLogger.error("*********************************************"); + geyserLogger.error(""); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName())); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper")); + geyserLogger.error(""); + geyserLogger.error("*********************************************"); Bukkit.getPluginManager().disablePlugin(this); return; } @@ -142,11 +142,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { try { Class.forName("io.netty.util.internal.ObjectPool$ObjectCreator"); } catch (ClassNotFoundException e) { - getLogger().severe("*********************************************"); - getLogger().severe(""); - getLogger().severe("This version of Spigot is using an outdated version of netty. Please use Paper instead!"); - getLogger().severe(""); - getLogger().severe("*********************************************"); + geyserLogger.error("*********************************************"); + geyserLogger.error(""); + geyserLogger.error("This version of Spigot is using an outdated version of netty. Please use Paper instead!"); + geyserLogger.error(""); + geyserLogger.error("*********************************************"); Bukkit.getPluginManager().disablePlugin(this); return; } @@ -154,8 +154,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { if (!loadConfig()) { return; } - this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode()) - : new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode()); + this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); // Turn "(MC: 1.16.4)" into 1.16.4. @@ -486,7 +485,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class); } catch (IOException ex) { - getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); Bukkit.getPluginManager().disablePlugin(this); return false; diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 039004867..f289fa2ba 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -71,7 +71,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { private GeyserCommandManager geyserCommandManager; private GeyserStandaloneConfiguration geyserConfig; - private GeyserStandaloneLogger geyserLogger; + private final GeyserStandaloneLogger geyserLogger = new GeyserStandaloneLogger(); private IGeyserPingPassthrough geyserPingPassthrough; private GeyserStandaloneGUI gui; @Getter @@ -181,8 +181,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { } } - this.geyserLogger = new GeyserStandaloneLogger(); - if (useGui && gui == null) { gui = new GeyserStandaloneGUI(geyserLogger); gui.redirectSystemStreams(); diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java index 567870e7f..4d10e4daf 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.platform.velocity; -import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Setter; import org.geysermc.geyser.GeyserLogger; import org.slf4j.Logger; -@AllArgsConstructor +@RequiredArgsConstructor public class GeyserVelocityLogger implements GeyserLogger { private final Logger logger; @Getter @Setter diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 347a47d63..539bdadbf 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -64,44 +64,44 @@ import java.util.UUID; @Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC") public class GeyserVelocityPlugin implements GeyserBootstrap { - @Inject - private Logger logger; - - @Inject - private ProxyServer proxyServer; - - @Inject - private CommandManager commandManager; + private final ProxyServer proxyServer; + private final CommandManager commandManager; + private final GeyserVelocityLogger geyserLogger; private GeyserCommandManager geyserCommandManager; private GeyserVelocityConfiguration geyserConfig; private GeyserVelocityInjector geyserInjector; - private GeyserVelocityLogger geyserLogger; private IGeyserPingPassthrough geyserPingPassthrough; - private GeyserImpl geyser; @Getter private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/"); + @Inject + public GeyserVelocityPlugin(ProxyServer server, Logger logger, CommandManager manager) { + this.geyserLogger = new GeyserVelocityLogger(logger); + this.proxyServer = server; + this.commandManager = manager; + } + @Override public void onGeyserInitialize() { GeyserLocale.init(this); if (!ProtocolVersion.isSupported(GameProtocol.getJavaProtocolVersion())) { - logger.error(" / \\"); - logger.error(" / \\"); - logger.error(" / | \\"); - logger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName())); - logger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); - logger.error(" / o \\"); - logger.error("/_____________\\"); + geyserLogger.error(" / \\"); + geyserLogger.error(" / \\"); + geyserLogger.error(" / | \\"); + geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName())); + geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); + geyserLogger.error(" / o \\"); + geyserLogger.error("/_____________\\"); } if (!loadConfig()) { return; } - this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode()); + this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this); @@ -249,7 +249,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class); } catch (IOException ex) { - logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); return false; } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index d5635acf9..6a404ae11 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -766,6 +766,7 @@ public class GeyserImpl implements GeyserApi { return 0; } + //noinspection DataFlowIssue return Integer.parseInt(BUILD_NUMBER); } diff --git a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java index c6a58e75e..cfe950409 100644 --- a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java @@ -148,9 +148,9 @@ public class GeyserLocale { } catch (IOException ignored) {} } } else { - if (GeyserImpl.getInstance() != null && !validLocalLanguage) { + if (!validLocalLanguage) { // Don't warn on missing locales if a local file has been found - GeyserImpl.getInstance().getLogger().warning("Missing locale: " + locale); + bootstrap.getGeyserLogger().warning("Missing locale: " + locale); } } @@ -162,12 +162,7 @@ public class GeyserLocale { localeProp.load(stream); } catch (IOException e) { String message = "Unable to load custom language override!"; - if (GeyserImpl.getInstance() != null) { - GeyserImpl.getInstance().getLogger().error(message, e); - } else { - System.err.println(message); - e.printStackTrace(); - } + bootstrap.getGeyserLogger().error(message, e); } LOCALE_MAPPINGS.putIfAbsent(locale, localeProp); From 63c84bc25bacc6df0384dcd2542fe1103358f096 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 29 May 2024 06:39:39 +0200 Subject: [PATCH 171/897] Yeet lectern cache (#4695) * attempt to yeet lectern cache * yeet lecternutils usage * properly update lecterns * yeet accidental diff --- .../mod/world/GeyserModWorldManager.java | 106 +----------------- .../manager/GeyserSpigotWorldManager.java | 72 ------------ .../geyser/level/GeyserWorldManager.java | 56 +-------- .../geysermc/geyser/level/WorldManager.java | 36 ------ .../geyser/level/block/type/Block.java | 65 +++++------ .../geyser/level/block/type/BlockState.java | 9 ++ .../geyser/level/block/type/LecternBlock.java | 66 ++++++++--- .../geyser/session/GeyserSession.java | 15 --- .../inventory/LecternInventoryTranslator.java | 35 +++--- .../level/JavaForgetLevelChunkTranslator.java | 12 -- .../JavaLevelChunkWithLightTranslator.java | 24 +--- .../geysermc/geyser/util/DimensionUtils.java | 3 - .../geysermc/geyser/util/InventoryUtils.java | 1 - 13 files changed, 108 insertions(+), 392 deletions(-) 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 656305690..7aac684bb 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 @@ -25,11 +25,6 @@ package org.geysermc.geyser.platform.mod.world; -import org.geysermc.mcprotocollib.protocol.data.game.Holder; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.SharedConstants; @@ -48,24 +43,19 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BannerBlockEntity; import net.minecraft.world.level.block.entity.BannerPatternLayers; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.LecternBlockEntity; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.LevelChunk; 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.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; -import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.platform.mod.GeyserModBootstrap; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -121,94 +111,6 @@ public class GeyserModWorldManager extends GeyserWorldManager { return SharedConstants.getCurrentVersion().getProtocolVersion() == GameProtocol.getJavaProtocolVersion(); } - @Override - public boolean shouldExpectLecternHandled(GeyserSession session) { - return true; - } - - @Override - public void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos) { - server.execute(() -> { - ServerPlayer player = getPlayer(session); - if (player == null) { - return; - } - - //noinspection resource - level() is just a getter - LevelChunk chunk = player.level().getChunk(x, z); - final int chunkBlockX = x << 4; - final int chunkBlockZ = z << 4; - //noinspection ForLoopReplaceableByForEach - avoid constructing iterator - for (int i = 0; i < blockEntityInfos.size(); i++) { - BlockEntityInfo blockEntityInfo = blockEntityInfos.get(i); - BlockEntity blockEntity = chunk.getBlockEntity(new BlockPos(chunkBlockX + blockEntityInfo.getX(), - blockEntityInfo.getY(), chunkBlockZ + blockEntityInfo.getZ())); - sendLecternData(session, blockEntity, true); - } - }); - } - - @Override - public void sendLecternData(GeyserSession session, int x, int y, int z) { - server.execute(() -> { - ServerPlayer player = getPlayer(session); - if (player == null) { - return; - } - //noinspection resource - level() is just a getter - BlockEntity blockEntity = player.level().getBlockEntity(new BlockPos(x, y, z)); - sendLecternData(session, blockEntity, false); - }); - } - - private void sendLecternData(GeyserSession session, BlockEntity blockEntity, boolean isChunkLoad) { - if (!(blockEntity instanceof LecternBlockEntity lectern)) { - return; - } - - int x = blockEntity.getBlockPos().getX(); - int y = blockEntity.getBlockPos().getY(); - int z = blockEntity.getBlockPos().getZ(); - - if (!lectern.hasBook()) { - if (!isChunkLoad) { - BlockEntityUtils.updateBlockEntity(session, LecternUtils.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z)); - } - return; - } - - ItemStack book = lectern.getBook(); - int pageCount = getPageCount(book); - boolean hasBookPages = pageCount > 0; - NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1); - lecternTag.putInt("page", lectern.getPage() / 2); - NbtMapBuilder bookTag = NbtMap.builder() - .putByte("Count", (byte) book.getCount()) - .putShort("Damage", (short) 0) - .putString("Name", "minecraft:writable_book"); - List pages = new ArrayList<>(hasBookPages ? pageCount : 1); - if (hasBookPages) { - List bookPages = getPages(book); - for (String page : bookPages) { - NbtMapBuilder pageBuilder = NbtMap.builder() - .putString("photoname", "") - .putString("text", page); - pages.add(pageBuilder.build()); - } - } else { - // Empty page - NbtMapBuilder pageBuilder = NbtMap.builder() - .putString("photoname", "") - .putString("text", ""); - pages.add(pageBuilder.build()); - } - - bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build()); - lecternTag.putCompound("book", bookTag.build()); - NbtMap blockEntityTag = lecternTag.build(); - BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z)); - } - @Override public boolean hasPermission(GeyserSession session, String permission) { ServerPlayer player = getPlayer(session); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index f45b68675..e247a72c7 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -27,16 +27,12 @@ package org.geysermc.geyser.platform.spigot.world.manager; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.erosion.bukkit.BukkitLecterns; -import org.geysermc.erosion.bukkit.BukkitUtils; import org.geysermc.erosion.bukkit.PickBlockUtils; import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.GeyserImpl; @@ -44,12 +40,9 @@ import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; -import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; @@ -58,11 +51,9 @@ import java.util.concurrent.CompletableFuture; */ public class GeyserSpigotWorldManager extends WorldManager { private final Plugin plugin; - private final BukkitLecterns lecterns; public GeyserSpigotWorldManager(Plugin plugin) { this.plugin = plugin; - this.lecterns = new BukkitLecterns(plugin); } @Override @@ -95,69 +86,6 @@ public class GeyserSpigotWorldManager extends WorldManager { return true; } - @Override - public void sendLecternData(GeyserSession session, int x, int y, int z) { - Player bukkitPlayer; - if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { - return; - } - - Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); - // Run as a task to prevent async issues - SchedulerUtils.runTask(this.plugin, () -> sendLecternData(session, block, false), block); - } - - public void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos) { - Player bukkitPlayer; - if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { - return; - } - if (SchedulerUtils.FOLIA) { - Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z); - if (chunk == null) { - return; - } - Bukkit.getRegionScheduler().execute(this.plugin, bukkitPlayer.getWorld(), x, z, () -> - sendLecternData(session, chunk, blockEntityInfos)); - } else { - Bukkit.getScheduler().runTask(this.plugin, () -> { - Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z); - if (chunk == null) { - return; - } - sendLecternData(session, chunk, blockEntityInfos); - }); - } - } - - private @Nullable Chunk getChunk(World world, int x, int z) { - if (!world.isChunkLoaded(x, z)) { - return null; - } - return world.getChunkAt(x, z); - } - - private void sendLecternData(GeyserSession session, Chunk chunk, List blockEntityInfos) { - //noinspection ForLoopReplaceableByForEach - avoid constructing Iterator - for (int i = 0; i < blockEntityInfos.size(); i++) { - BlockEntityInfo info = blockEntityInfos.get(i); - Block block = chunk.getBlock(info.getX(), info.getY(), info.getZ()); - sendLecternData(session, block, true); - } - } - - private void sendLecternData(GeyserSession session, Block block, boolean isChunkLoad) { - NbtMap blockEntityTag = this.lecterns.getLecternData(block, isChunkLoad); - if (blockEntityTag != null) { - BlockEntityUtils.updateBlockEntity(session, blockEntityTag, BukkitUtils.getVector(block.getLocation())); - } - } - - @Override - public boolean shouldExpectLecternHandled(GeyserSession session) { - return true; - } - public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { org.bukkit.GameRule bukkitGameRule = org.bukkit.GameRule.getByName(gameRule.getJavaID()); if (bukkitGameRule == null) { diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 3144f0cb2..9faa7424c 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -28,22 +28,17 @@ package org.geysermc.geyser.level; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.erosion.packet.backendbound.*; +import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockRequestPacket; +import org.geysermc.erosion.packet.backendbound.BackendboundBlockRequestPacket; +import org.geysermc.erosion.packet.backendbound.BackendboundPickBlockPacket; import org.geysermc.erosion.util.BlockPositionIterator; -import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; -import java.util.List; import java.util.concurrent.CompletableFuture; public class GeyserWorldManager extends WorldManager { @@ -92,51 +87,6 @@ public class GeyserWorldManager extends WorldManager { return false; } - @Override - public void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos) { - var erosionHandler = session.getErosionHandler().getAsActive(); - if (erosionHandler == null) { - // No-op - don't send any additional information other than what the chunk has already sent - return; - } - List vectors = new ObjectArrayList<>(blockEntityInfos.size()); - //noinspection ForLoopReplaceableByForEach - avoid constructing iterator - for (int i = 0; i < blockEntityInfos.size(); i++) { - BlockEntityInfo info = blockEntityInfos.get(i); - vectors.add(Vector3i.from(info.getX(), info.getY(), info.getZ())); - } - erosionHandler.sendPacket(new BackendboundBatchBlockEntityPacket(x, z, vectors)); - } - - @Override - public void sendLecternData(GeyserSession session, int x, int y, int z) { - var erosionHandler = session.getErosionHandler().getAsActive(); - if (erosionHandler != null) { - erosionHandler.sendPacket(new BackendboundBlockEntityPacket(Vector3i.from(x, y, z))); - return; - } - - // Without direct server access, we can't get lectern information on-the-fly. - // I should have set this up so it's only called when there is a book in the block state. - Camotoy - NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, 1); - lecternTag.putCompound("book", NbtMap.builder() - .putByte("Count", (byte) 1) - .putShort("Damage", (short) 0) - .putString("Name", "minecraft:written_book") - .putCompound("tag", NbtMap.builder() - .putString("photoname", "") - .putString("text", "") - .build()) - .build()); - lecternTag.putInt("page", -1); // I'm surprisingly glad this exists - it forces Bedrock to stop reading immediately. Usually. - BlockEntityUtils.updateBlockEntity(session, lecternTag.build(), Vector3i.from(x, y, z)); - } - - @Override - public boolean shouldExpectLecternHandled(GeyserSession session) { - return session.getErosionHandler().isActive(); - } - @Override public void setGameRule(GeyserSession session, String name, Object value) { super.setGameRule(session, name, value); diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index 6cd9c3e26..3670b6b73 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -40,11 +40,9 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen 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.ItemCodecHelper; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -118,40 +116,6 @@ public abstract class WorldManager { */ public abstract boolean hasOwnChunkCache(); - /** - * Sigh.
- * - * So, on Java Edition, the lectern is an inventory. Java opens it and gets the contents of the book there. - * On Bedrock, the lectern contents are part of the block entity tag. Therefore, Bedrock expects to have the contents - * of the lectern ready and present in the world. If the contents are not there, it takes at least two clicks for the - * lectern to update the tag and then present itself.
- * - * We solve this problem by querying all loaded lecterns, where possible, and sending their information in a block entity - * tag. - *

- * Note that the lectern data may be sent asynchronously. - * - * @param session the session of the player - * @param x the x coordinate of the lectern - * @param y the y coordinate of the lectern - * @param z the z coordinate of the lectern - */ - public abstract void sendLecternData(GeyserSession session, int x, int y, int z); - - /** - * {@link #sendLecternData(GeyserSession, int, int, int)} but batched for chunks. - * - * @param x chunk x - * @param z chunk z - * @param blockEntityInfos a list of coordinates (chunk local) to grab lecterns from. - */ - public abstract void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos); - - /** - * @return whether we should expect lectern data to update, or if we have to fall back on a workaround. - */ - public abstract boolean shouldExpectLecternHandled(GeyserSession session); - /** * Updates a gamerule value on the Java server * diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index 9fe70c0f1..ee99b652a 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -91,39 +91,35 @@ public class Block { BlockDefinition definition = session.getBlockMappings().getBedrockBlock(state); sendBlockUpdatePacket(session, state, definition, position); - { - // Extended collision boxes for custom blocks - if (!session.getBlockMappings().getExtendedCollisionBoxes().isEmpty()) { - int aboveBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() + 1, position.getZ()); - BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(state.javaId()); - int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ()); - BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock); - if (belowBedrockExtendedCollisionDefinition != null && state.is(Blocks.AIR)) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position); - updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); - updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } else if (aboveBlock == Block.JAVA_AIR_ID) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); - updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } + // Extended collision boxes for custom blocks + if (!session.getBlockMappings().getExtendedCollisionBoxes().isEmpty()) { + int aboveBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() + 1, position.getZ()); + BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(state.javaId()); + int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ()); + BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock); + if (belowBedrockExtendedCollisionDefinition != null && state.is(Blocks.AIR)) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position); + updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); + updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + } else if (aboveBlock == Block.JAVA_AIR_ID) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); + updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); } } - - handleLecternBlockUpdate(session, state, position); } protected void sendBlockUpdatePacket(GeyserSession session, BlockState state, BlockDefinition definition, Vector3i position) { @@ -153,13 +149,6 @@ public class Block { } } - protected void handleLecternBlockUpdate(GeyserSession session, BlockState state, Vector3i position) { - // Block state is out of bounds of this map - lectern has been destroyed, if it existed - if (!session.getGeyser().getWorldManager().shouldExpectLecternHandled(session)) { - session.getLecternCache().remove(position); - } - } - public Item asItem() { if (this.item == null) { return this.item = Item.byBlock(this); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index a312a7d5a..36c31f32e 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -56,6 +56,15 @@ public final class BlockState { return (T) get(property); } + public > T getValueNullable(Property property) { + var value = get(property); + if (value == null) { + return null; + } + //noinspection unchecked + return (T) get(property); + } + public boolean getValue(Property property, boolean def) { var value = get(property); if (value == null) { diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java index 6b8aa02b5..3139bd6de 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java @@ -27,35 +27,67 @@ package org.geysermc.geyser.level.block.type; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.erosion.util.LecternUtils; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.util.BlockEntityUtils; -public class LecternBlock extends Block { +import java.util.Collections; + +public class LecternBlock extends Block implements BedrockChunkWantsBlockEntityTag { public LecternBlock(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } @Override - protected void handleLecternBlockUpdate(GeyserSession session, BlockState state, Vector3i position) { - WorldManager worldManager = session.getGeyser().getWorldManager(); - if (worldManager.shouldExpectLecternHandled(session)) { - worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); - return; - } + public NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState) { + return getBaseLecternTag(position, blockState.getValue(Properties.HAS_BOOK)); + } + @Override + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + WorldManager worldManager = session.getGeyser().getWorldManager(); boolean currentHasBook = state.getValue(Properties.HAS_BOOK); - Boolean previousHasBook = worldManager.blockAt(session, position).getValue(Properties.HAS_BOOK); // Can be null if not a lectern, watch out - if (currentHasBook != previousHasBook) { - if (currentHasBook) { - worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); - } else { - session.getLecternCache().remove(position); - NbtMap newLecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build(); - BlockEntityUtils.updateBlockEntity(session, newLecternTag, position); - } + Boolean previousHasBook = worldManager.blockAt(session, position).getValueNullable(Properties.HAS_BOOK); // Can be null if not a lectern, watch out + if (previousHasBook == null || currentHasBook != previousHasBook) { + BlockEntityUtils.updateBlockEntity(session, getBaseLecternTag(position, currentHasBook), position); + } + super.updateBlock(session, state, position); + } + + public static NbtMap getBaseLecternTag(Vector3i position, boolean hasBook) { + if (hasBook) { + return getBaseLecternTag(position, 1) + .putCompound("book", NbtMap.builder() + .putByte("Count", (byte) 1) + .putShort("Damage", (short) 0) + .putString("Name", "minecraft:writable_book") + .putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, Collections.singletonList( + NbtMap.builder() + .putString("photoname", "") + .putString("text", "") + .build() + )).build()) + .build()) + .build(); + } else { + return getBaseLecternTag(position, 0).build(); } } + + public static NbtMapBuilder getBaseLecternTag(Vector3i position, int pages) { + NbtMapBuilder builder = BlockEntityTranslator.getConstantBedrockTag("Lectern", position); + builder.putBoolean("isMovable", true); + + if (pages != 0) { + builder.putByte("hasBook", (byte) 1); + builder.putInt("totalPages", 1); // we'll override it anyway + } + + return builder; + } } 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 9d2a3ef06..17010e966 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -99,7 +99,6 @@ import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.level.JavaDimension; -import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.registry.Registries; @@ -257,13 +256,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { */ private final Map itemFrameCache = new Object2ObjectOpenHashMap<>(); - /** - * Stores a list of all lectern locations and their block entity tags. - * See {@link WorldManager#sendLecternData(GeyserSession, int, int, int)} - * for more information. - */ - private final @Nullable Set lecternCache; - /** * A list of all players that have a player head on with a custom texture. * Our workaround for these players is to give them a custom skin and geometry to emulate wearing a custom skull. @@ -609,13 +601,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.spawned = false; this.loggedIn = false; - if (geyser.getWorldManager().shouldExpectLecternHandled(this)) { - // Unneeded on these platforms - this.lecternCache = null; - } else { - this.lecternCache = new ObjectOpenHashSet<>(); - } - if (geyser.getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.NO_EMOTES) { this.emotes = new HashSet<>(); geyser.getSessionManager().getSessions().values().forEach(player -> this.emotes.addAll(player.getEmotes())); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 8fe1e96c0..3b33f5909 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -28,13 +28,18 @@ package org.geysermc.geyser.translator.inventory; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.*; +import org.geysermc.geyser.inventory.Container; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.inventory.LecternContainer; +import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.LecternBlock; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.InventoryUtils; @@ -44,8 +49,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBook import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; -import java.util.Collections; - public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator { /** @@ -95,7 +98,10 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator // Now: Restore the lectern, if it actually exists if (lecternContainer.isUsingRealBlock()) { - GeyserImpl.getInstance().getWorldManager().sendLecternData(session, position.getX(), position.getY(), position.getZ()); + boolean hasBook = session.getGeyser().getWorldManager().blockAt(session, position).getValue(Properties.HAS_BOOK, false); + + NbtMap map = LecternBlock.getBaseLecternTag(position, hasBook); + BlockEntityUtils.updateBlockEntity(session, map, position); } } @@ -148,7 +154,8 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator session.setDroppingLecternBook(false); InventoryUtils.closeInventory(session, inventory.getJavaId(), false); } else if (lecternContainer.getBlockEntityTag() == null) { - Vector3i position = lecternContainer.isUsingRealBlock() ? session.getLastInteractionBlockPosition() : inventory.getHolderPosition(); + Vector3i position = lecternContainer.isUsingRealBlock() ? + session.getLastInteractionBlockPosition() : inventory.getHolderPosition(); NbtMap blockEntityTag; if (book.getComponents() != null) { @@ -164,7 +171,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator } ItemData itemData = book.getItemData(session); - NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pages); + NbtMapBuilder lecternTag = LecternBlock.getBaseLecternTag(position, pages); lecternTag.putCompound("book", NbtMap.builder() .putByte("Count", (byte) itemData.getCount()) .putShort("Damage", (short) 0) @@ -175,19 +182,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator blockEntityTag = lecternTag.build(); } else { // There is *a* book here, but... no NBT. - NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 1); - NbtMapBuilder bookTag = NbtMap.builder() - .putByte("Count", (byte) 1) - .putShort("Damage", (short) 0) - .putString("Name", "minecraft:writable_book") - .putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, Collections.singletonList( - NbtMap.builder() - .putString("photoname", "") - .putString("text", "") - .build() - )).build()); - - blockEntityTag = lecternTag.putCompound("book", bookTag.build()).build(); + blockEntityTag = LecternBlock.getBaseLecternTag(position, true); } // Even with serverside access to lecterns, we don't easily know which lectern this is, so we need to rebuild diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java index b0abe0f59..e687e6f46 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaForgetLevelChunkTranslator.java @@ -33,7 +33,6 @@ import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundForgetLevelChunkPacket; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; @Translator(packet = ClientboundForgetLevelChunkPacket.class) @@ -52,17 +51,6 @@ public class JavaForgetLevelChunkTranslator extends PacketTranslator iterator = session.getLecternCache().iterator(); - while (iterator.hasNext()) { - Vector3i position = iterator.next(); - if ((position.getX() >> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) { - iterator.remove(); - } - } - } - ChunkUtils.sendEmptyChunk(session, packet.getX(), packet.getZ(), false); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index 18d12422e..e37edef66 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -34,14 +34,11 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NBTOutputStream; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; -import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.BedrockDimension; -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.level.chunk.BlockStorage; @@ -98,7 +95,6 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator bedrockBlockEntities = new ObjectArrayList<>(blockEntities.length); - final List lecterns = new ObjectArrayList<>(); BitSet waterloggedPaletteIds = new BitSet(); BitSet bedrockOnlyBlockEntityIds = new BitSet(); @@ -318,7 +314,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4) - yOffset]; BlockState blockState = BlockRegistries.BLOCK_STATES.get(section.get(x, y & 0xF, z)); - if (type == BlockEntityType.LECTERN && blockState.getValue(Properties.HAS_BOOK)) { - // If getLecternBookStates is false, let's just treat it like a normal block entity - // Fill in tag with a default value - NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x + chunkBlockX, y, z + chunkBlockZ, 1); - lecternTag.putCompound("book", NbtMap.builder() - .putByte("Count", (byte) 1) - .putShort("Damage", (short) 0) - .putString("Name", "minecraft:written_book").build()); - lecternTag.putInt("page", -1); - bedrockBlockEntities.add(lecternTag.build()); - lecterns.add(blockEntity); - continue; - } - // Note that, since 1.20.5, tags can be null, but Bedrock still needs a default tag to render the item // Also, some properties - like banner base colors - are part of the tag and is processed here. BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(type); @@ -525,10 +507,6 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator entry : session.getItemFrameCache().entrySet()) { Vector3i position = entry.getKey(); if ((position.getX() >> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) { diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index 54e1cc34a..8446a340a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -65,9 +65,6 @@ public class DimensionUtils { session.getChunkCache().clear(); session.getEntityCache().removeAllEntities(); session.getItemFrameCache().clear(); - if (session.getLecternCache() != null) { - session.getLecternCache().clear(); - } session.getLodestoneCache().clear(); session.getPistonCache().clear(); session.getSkullCache().clear(); 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 d253d2f8b..48ade52e2 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -479,7 +479,6 @@ public class InventoryUtils { for (int col = firstCol; col < width + firstCol; col++) { GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); if (geyserItemStack.isEmpty()) { - //noinspection ConstantValue inventoryHasItem = itemStack == null || itemStack.getId() == 0; if (inventoryHasItem) { break crafting; From 7ba95f1ad3715c2e9fe3676c44ed18659c64b097 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Tue, 28 May 2024 00:11:05 -0700 Subject: [PATCH 172/897] Composite gradle setup and artifact archival (#4696) * Composite gradle setup and artifact archival * Remove 'geyser' path for PRs * Move upload-preview workflow --- .github/workflows/build-remote.yml | 85 +++++-------------------- .github/workflows/build.yml | 86 +++++--------------------- .github/workflows/dispatch-preview.yml | 33 ++++++++++ .github/workflows/preview.yml | 83 ------------------------- .github/workflows/pull-request.yml | 16 ++++- 5 files changed, 77 insertions(+), 226 deletions(-) create mode 100644 .github/workflows/dispatch-preview.yml delete mode 100644 .github/workflows/preview.yml diff --git a/.github/workflows/build-remote.yml b/.github/workflows/build-remote.yml index c815b4740..7cb89cc61 100644 --- a/.github/workflows/build-remote.yml +++ b/.github/workflows/build-remote.yml @@ -22,81 +22,26 @@ jobs: run: | echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - - name: Setup Java - # See https://github.com/actions/setup-java/commits - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 - with: - java-version: 21 - distribution: temurin - - - name: Checkout repository and submodules - # See https://github.com/actions/checkout/commits - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - with: - repository: ${{ inputs.repository }} - ref: ${{ inputs.ref }} - submodules: recursive - - - name: Validate Gradle Wrapper - # See https://github.com/gradle/wrapper-validation-action/commits - uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 - - name: Setup Gradle - # See https://github.com/gradle/actions/commits - uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + uses: GeyserMC/actions/setup-gradle-composite@master with: - cache-read-only: true + checkout_repository: ${{ inputs.repository }} + checkout_ref: ${{ inputs.ref }} + setup-java_java-version: 21 + setup-gradle_cache-read-only: true - name: Build Geyser run: ./gradlew build - - name: Archive artifacts (Geyser Fabric) - # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - name: Archive Artifacts + uses: GeyserMC/actions/upload-multi-artifact@master if: success() with: - name: Geyser Fabric - path: geyser/bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar - if-no-files-found: error - - name: Archive artifacts (Geyser NeoForge) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser NeoForge - path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Standalone) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Standalone - path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Spigot) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Spigot - path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar - if-no-files-found: error - - name: Archive artifacts (Geyser BungeeCord) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser BungeeCord - path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Velocity) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Velocity - path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar - if-no-files-found: error - - name: Archive artifacts (Geyser ViaProxy) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser ViaProxy - path: geyser/bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar - if-no-files-found: error \ No newline at end of file + artifacts: | + bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar + bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar + bootstrap/standalone/build/libs/Geyser-Standalone.jar + bootstrap/spigot/build/libs/Geyser-Spigot.jar + bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + bootstrap/velocity/build/libs/Geyser-Velocity.jar + bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f2f2a2c82..b8f855a53 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,84 +28,28 @@ jobs: with: data: ${{ vars.RELEASEACTION_PREVRELEASE }} - - name: Checkout repository and submodules - # See https://github.com/actions/checkout/commits - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - with: - submodules: recursive - - - name: Validate Gradle Wrapper - # See https://github.com/gradle/actions/commits - uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 - - # See https://github.com/actions/setup-java/commits - - name: Setup Java - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 - with: - java-version: 21 - distribution: temurin - - name: Setup Gradle - # See https://github.com/gradle/actions/commits - uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2 + uses: GeyserMC/actions/setup-gradle-composite@master with: - gradle-home-cache-cleanup: true + setup-java_java-version: 21 - name: Build Geyser run: ./gradlew build env: BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} - - name: Archive artifacts (Geyser Fabric) - # See https://github.com/actions/upload-artifact/commits - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - name: Archive Artifacts + uses: GeyserMC/actions/upload-multi-artifact@master if: success() with: - name: Geyser Fabric - path: bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar - if-no-files-found: error - - name: Archive artifacts (Geyser NeoForge) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser NeoForge - path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Standalone) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Standalone - path: bootstrap/standalone/build/libs/Geyser-Standalone.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Spigot) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Spigot - path: bootstrap/spigot/build/libs/Geyser-Spigot.jar - if-no-files-found: error - - name: Archive artifacts (Geyser BungeeCord) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser BungeeCord - path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar - if-no-files-found: error - - name: Archive artifacts (Geyser Velocity) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser Velocity - path: bootstrap/velocity/build/libs/Geyser-Velocity.jar - if-no-files-found: error - - name: Archive artifacts (Geyser ViaProxy) - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 - if: success() - with: - name: Geyser ViaProxy - path: bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar - if-no-files-found: error + artifacts: | + bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar + bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar + bootstrap/standalone/build/libs/Geyser-Standalone.jar + bootstrap/spigot/build/libs/Geyser-Spigot.jar + bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + bootstrap/velocity/build/libs/Geyser-Velocity.jar + bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar - name: Publish to Maven Repository if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} @@ -116,14 +60,14 @@ jobs: ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} - name: Get Version - if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }} id: get-version run: | version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) echo "VERSION=${version}" >> $GITHUB_OUTPUT - name: Get Release Metadata - if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }} uses: GeyserMC/actions/release@master id: metadata with: @@ -141,6 +85,7 @@ jobs: saveMetadata: true releaseProject: 'geyser' releaseVersion: ${{ steps.get-version.outputs.VERSION }} + - name: Publish to Downloads API if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} uses: GeyserMC/actions/upload-release@master @@ -156,6 +101,7 @@ jobs: bootstrap/standalone/build/libs/Geyser-Standalone.jar bootstrap/velocity/build/libs/Geyser-Velocity.jar bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar + changelog: ${{ steps.metadata.outputs.body }} - name: Publish to Modrinth (Fabric) if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} diff --git a/.github/workflows/dispatch-preview.yml b/.github/workflows/dispatch-preview.yml new file mode 100644 index 000000000..83df08e37 --- /dev/null +++ b/.github/workflows/dispatch-preview.yml @@ -0,0 +1,33 @@ +name: Dispatch Preview + +on: + workflow_dispatch: + inputs: + runId: + required: true + description: 'ID of the action to pull artifacts from' + build: + required: true + description: 'Build number for the release' + version: + required: true + description: 'Version under which to upload to the Downloads API' + +jobs: + dispatch-preview: + # Allow access to secrets if we are uploading a preview + secrets: inherit + uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master + with: + build: ${{ inputs.build }} + version: ${{ inputs.version }} + files: | + bungeecord:Geyser-BungeeCord.jar + fabric:Geyser-Fabric.jar + neoforge:Geyser-NeoForge.jar + spigot:Geyser-Spigot.jar + standalone:Geyser-Standalone.jar + velocity:Geyser-Velocity.jar + viaproxy:Geyser-ViaProxy.jar + project: geyserpreview + runId: ${{ inputs.runId }} \ No newline at end of file diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml deleted file mode 100644 index a90d60ef7..000000000 --- a/.github/workflows/preview.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Upload Preview - -on: - workflow_dispatch: - inputs: - runId: - required: true - description: 'ID of the action to pull artifacts from' - build: - required: true - description: 'Build number for the release' - version: - required: true - description: 'Version under which to upload to the Downloads API' - workflow_call: - inputs: - build: - required: true - description: 'Build number for the release' - type: string - version: - required: true - description: 'Version under which to upload to the Downloads API' - type: string - -jobs: - upload: - runs-on: ubuntu-latest - steps: - - name: Set Variables - id: setvars - run: | - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - echo "BUILD=${{ github.event.inputs.build }}" >> $GITHUB_ENV - echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - echo "RUN=${{ github.event.inputs.runId }}" >> $GITHUB_OUTPUT - else - echo "BUILD=${{ inputs.build }}" >> $GITHUB_ENV - echo "VERSION=${{ inputs.version }}" >> $GITHUB_OUTPUT - echo "RUN=${{ github.run_id }}" >> $GITHUB_OUTPUT - fi - - name: Download Artifacts - # See https://github.com/actions/download-artifact/commits - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.6 - with: - run-id: ${{ steps.setvars.outputs.RUN }} - github-token: ${{ secrets.GITHUB_TOKEN }} - merge-multiple: true - - name: Get Preview Metadata - if: success() - uses: GeyserMC/actions/release@master - id: metadata - with: - appID: ${{ secrets.RELEASE_APP_ID }} - appPrivateKey: ${{ secrets.RELEASE_APP_PK }} - files: | - bungeecord:Geyser-BungeeCord.jar - fabric:Geyser-Fabric.jar - neoforge:Geyser-NeoForge.jar - spigot:Geyser-Spigot.jar - standalone:Geyser-Standalone.jar - velocity:Geyser-Velocity.jar - viaproxy:Geyser-ViaProxy.jar - releaseEnabled: false - saveMetadata: true - updateReleaseData: false - releaseProject: 'geyserpreview' - releaseVersion: ${{ steps.setvars.outputs.VERSION }} - - name: Publish to Downloads API - if: success() - uses: GeyserMC/actions/upload-release@master - with: - username: ${{ vars.DOWNLOADS_USERNAME }} - privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} - host: ${{ secrets.DOWNLOADS_SERVER_IP }} - files: | - Geyser-BungeeCord.jar - Geyser-Fabric.jar - Geyser-NeoForge.jar - Geyser-Spigot.jar - Geyser-Standalone.jar - Geyser-Velocity.jar - Geyser-ViaProxy.jar diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index bc5e57b6b..6167bb18e 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -8,7 +8,7 @@ jobs: # Forbid access to secrets nor GH Token perms while building the PR permissions: {} secrets: {} - uses: ./.github/workflows/build-remote.yml + uses: GeyserMC/Geyser/.github/workflows/build-remote.yml@master with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.sha }} @@ -18,7 +18,17 @@ jobs: contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing') # Allow access to secrets if we are uploading a preview secrets: inherit - uses: ./.github/workflows/preview.yml + uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master with: build: ${{ github.run_number }} - version: pr.${{ github.event.pull_request.number }} \ No newline at end of file + version: pr.${{ github.event.pull_request.number }} + files: | + bungeecord:Geyser-BungeeCord.jar + fabric:Geyser-Fabric.jar + neoforge:Geyser-NeoForge.jar + spigot:Geyser-Spigot.jar + standalone:Geyser-Standalone.jar + velocity:Geyser-Velocity.jar + viaproxy:Geyser-ViaProxy.jar + project: geyserpreview + runId: ${{ github.run_id }} \ No newline at end of file From dc154915f0637ec02c04ef582f30e5ca0f4b814f Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Wed, 29 May 2024 01:48:33 -0700 Subject: [PATCH 173/897] Only include downloads on master --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b8f855a53..0e94ce965 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -124,3 +124,4 @@ jobs: discordWebhook: ${{ secrets.DISCORD_WEBHOOK }} status: ${{ job.status }} body: ${{ steps.metadata.outputs.body }} + includeDownloads: ${{ github.ref_name == 'master' }} From 8be60b41bf64e9dfec184d9047aa604bb7836b2a Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 29 May 2024 22:36:38 +0200 Subject: [PATCH 174/897] Remove lectern/item frame dropping handling for pre 1.20.60 --- .../BedrockItemFrameDropItemTranslator.java | 57 ------------ .../BedrockLecternUpdateTranslator.java | 88 +++++++------------ 2 files changed, 34 insertions(+), 111 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java deleted file mode 100644 index dff4631b0..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java +++ /dev/null @@ -1,57 +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.cloudburstmc.protocol.bedrock.packet.ItemFrameDropItemPacket; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.ItemFrameEntity; -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.data.game.entity.player.InteractAction; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; - -/** - * Pre-1.16.210: used for both survival and creative item frame item removal - *

- * 1.16.210: only used in creative. - * 1.20.70: no longer used. - */ -@Translator(packet = ItemFrameDropItemPacket.class) -public class BedrockItemFrameDropItemTranslator extends PacketTranslator { - - // TODO: Remove when 1.20.60 is no longer supported - @Override - public void translate(GeyserSession session, ItemFrameDropItemPacket packet) { - Entity entity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition()); - if (entity != null) { - ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(), - InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamGamePacket(interactPacket); - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java index e6d3d4dce..31a2d74cf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java @@ -25,11 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; -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.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; import org.cloudburstmc.protocol.bedrock.packet.LecternUpdatePacket; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.LecternContainer; @@ -38,6 +33,8 @@ import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; 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.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; /** * Used to translate moving pages, or closing the inventory @@ -47,61 +44,44 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator currentJavaPage) { + for (int i = currentJavaPage; i < newJavaPage; i++) { + ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 2); + session.sendDownstreamGamePacket(clickButtonPacket); } - - // Send as many click button packets as we need to - // Java has the option to specify exact page numbers by adding 100 to the number, but buttonId variable - // is a byte when transmitted over the network and therefore this stops us at 128 - if (newJavaPage > currentJavaPage) { - for (int i = currentJavaPage; i < newJavaPage; i++) { - ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 2); - session.sendDownstreamGamePacket(clickButtonPacket); - } - } else { - for (int i = currentJavaPage; i > newJavaPage; i--) { - ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 1); - session.sendDownstreamGamePacket(clickButtonPacket); - } + } else { + for (int i = currentJavaPage; i > newJavaPage; i--) { + ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 1); + session.sendDownstreamGamePacket(clickButtonPacket); } } } From 66f30a2cb6f477ec8ff9d9aa34ec015a6cd6891d Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 29 May 2024 23:43:39 +0200 Subject: [PATCH 175/897] Ensure we send commands/chat the same way a Java client would (#4703) * Ensure we send commands/chat the same way a Java client would * yeet static import, move blank check --- .../BedrockCommandRequestTranslator.java | 12 ++++--- .../bedrock/BedrockTextTranslator.java | 11 ++++++- .../translator/text/MessageTranslator.java | 33 +++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java index 322d64cce..8d4df6f3f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java @@ -26,8 +26,8 @@ package org.geysermc.geyser.translator.protocol.bedrock; import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -39,15 +39,17 @@ public class BedrockCommandRequestTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, TextPacket packet) { - String message = MessageTranslator.convertToPlainText(packet.getMessage()); + // Java trims all messages, and then checks for the leading slash + String message = MessageTranslator.convertToPlainText( + MessageTranslator.normalizeSpace(packet.getMessage()) + ); if (message.isBlank()) { // Java Edition (as of 1.17.1) just doesn't pass on these messages, so... we won't either! return; } + if (message.startsWith("/")) { + // Yes, Java actually allows whitespaces before commands and will still see those as valid + BedrockCommandRequestTranslator.handleCommand(session, message.substring(1)); + return; + } + if (MessageTranslator.isTooLong(message, session)) { return; } 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 5a0121039..bf6fdd763 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 @@ -387,6 +387,39 @@ public class MessageTranslator { return false; } + /** + * Normalizes whitespaces - a thing a vanilla client apparently does with commands and chat messages. + */ + public static String normalizeSpace(String string) { + if (string == null || string.isEmpty()) { + return string; + } + final int size = string.length(); + final char[] newChars = new char[size]; + int count = 0; + int whitespacesCount = 0; + boolean startWhitespaces = true; + for (int i = 0; i < size; i++) { + final char actualChar = string.charAt(i); + final boolean isWhitespace = Character.isWhitespace(actualChar); + if (isWhitespace) { + if (whitespacesCount == 0 && !startWhitespaces) { + newChars[count++] = ' '; + } + whitespacesCount++; + } else { + startWhitespaces = false; + // Replace non-breaking spaces with regular spaces for normalization + newChars[count++] = (actualChar == '\u00A0' ? ' ' : actualChar); + whitespacesCount = 0; + } + } + if (startWhitespaces) { + return ""; + } + return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); + } + public static void init() { // no-op } From c8fbffb6383713f64fe8c4a902cd78332b02941a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 29 May 2024 21:47:50 -0400 Subject: [PATCH 176/897] Piston head correct pick block behavior --- .../geysermc/geyser/level/block/Blocks.java | 2 +- .../level/block/type/PistonHeadBlock.java | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/PistonHeadBlock.java 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 fa605c079..857a3fc13 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 @@ -315,7 +315,7 @@ public final class Blocks { 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))); - public static final Block PISTON_HEAD = register(new Block("piston_head", builder().destroyTime(1.5f).pushReaction(PistonBehavior.BLOCK) + 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))); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/PistonHeadBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/PistonHeadBlock.java new file mode 100644 index 000000000..8a6b4f41c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/PistonHeadBlock.java @@ -0,0 +1,42 @@ +/* + * 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.level.block.type; + +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; + +public class PistonHeadBlock extends Block { + public PistonHeadBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public ItemStack pickItem(BlockState state) { + Block block = state.getValue(Properties.PISTON_TYPE).equals("sticky") ? Blocks.STICKY_PISTON : Blocks.PISTON; + return new ItemStack(block.asItem().javaId()); + } +} From da5d8006ad182b550392393bb68187677be36c30 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 30 May 2024 22:29:00 -0400 Subject: [PATCH 177/897] Add native offhand support for *some* items About 46 items are data-driven enough where we can tell Bedrock these items are permitted in the offhand. --- .../populator/ItemRegistryPopulator.java | 27 +++++++++++++++++++ core/src/main/resources/mappings | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 5fcea504f..8f515c1cb 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -38,6 +38,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; @@ -102,6 +103,13 @@ public class ItemRegistryPopulator { throw new AssertionError("Unable to load Java runtime item IDs", e); } + NbtMap vanillaComponents; + try (InputStream stream = bootstrap.getResourceOrThrow("mappings/item_components.nbt")) { + vanillaComponents = (NbtMap) NbtUtils.createGZIPReader(stream, true, true).readTag(); + } catch (Exception e) { + throw new AssertionError("Unable to load Bedrock item components", e); + } + boolean customItemsAllowed = GeyserImpl.getInstance().getConfig().isAddNonBedrockItems(); // List values here is important compared to HashSet - we need to preserve the order of what's given to us @@ -531,6 +539,25 @@ public class ItemRegistryPopulator { } } + for (Map.Entry entry : vanillaComponents.entrySet()) { + String id = entry.getKey(); + ItemDefinition definition = definitions.get(id); + if (definition == null) { + // Newer item most likely + GeyserImpl.getInstance().getLogger().debug( + "Skipping vanilla component " + id + " for protocol " + palette.protocolVersion() + ); + continue; + } + + NbtMapBuilder root = NbtMap.builder() + .putString("name", id) + .putInt("id", definition.getRuntimeId()) + .putCompound("components", (NbtMap) entry.getValue()); + + componentItemData.add(new ComponentItemData(id, root.build())); + } + // Register the item forms of custom blocks if (BlockRegistries.CUSTOM_BLOCKS.get().length != 0) { for (CustomBlockData customBlock : BlockRegistries.CUSTOM_BLOCKS.get()) { diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index ec45f59c8..88e50df10 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit ec45f59c8590945c9226921ef7e339f510983dc1 +Subproject commit 88e50df1008916c266428ac11f76f07dc24638c5 From 214cc5a8240faa733ebf19682599fa3ab546198d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 1 Jun 2024 01:25:30 -0400 Subject: [PATCH 178/897] Initial changes for Java 1.21 --- core/src/main/java/org/geysermc/geyser/item/Items.java | 9 ++++++--- .../java/org/geysermc/geyser/network/GameProtocol.java | 2 +- .../geyser/registry/populator/Conversion685_671.java | 6 ++++++ 3 files changed, 13 insertions(+), 4 deletions(-) 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 8c271a7bb..732ee558a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -838,6 +838,7 @@ public final class Items { public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder())); public static final Item WOLF_ARMOR = register(new ArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder().stackSize(1).maxDamage(64))); public static final Item FLINT_AND_STEEL = register(new Item("flint_and_steel", builder().stackSize(1).maxDamage(64))); + public static final Item BOWL = register(new Item("bowl", builder())); public static final Item APPLE = register(new Item("apple", builder())); public static final Item BOW = register(new Item("bow", builder().stackSize(1).maxDamage(384))); public static final Item ARROW = register(new ArrowItem("arrow", builder())); @@ -887,7 +888,6 @@ public final class Items { public static final Item NETHERITE_AXE = register(new TieredItem("netherite_axe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(10.0))); public static final Item NETHERITE_HOE = register(new TieredItem("netherite_hoe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(1.0))); public static final Item STICK = register(new Item("stick", builder())); - public static final Item BOWL = register(new Item("bowl", builder())); public static final Item MUSHROOM_STEW = register(new Item("mushroom_stew", builder().stackSize(1))); public static final Item STRING = register(new BlockItem("string", builder(), Blocks.TRIPWIRE)); public static final Item FEATHER = register(new Item("feather", builder())); @@ -1044,7 +1044,7 @@ public final class Items { 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.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.WATER_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())); @@ -1132,7 +1132,7 @@ public final class Items { 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(250))); + 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)); @@ -1211,6 +1211,8 @@ public final class Items { 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))); @@ -1223,6 +1225,7 @@ public final class Items { 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))); public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder())); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 1c58288c7..773f0ae32 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -106,7 +106,7 @@ public final class GameProtocol { * @return the supported Minecraft: Java Edition version names */ public static List getJavaVersions() { - return List.of("1.20.5", DEFAULT_JAVA_CODEC.getMinecraftVersion()); + return List.of(DEFAULT_JAVA_CODEC.getMinecraftVersion()); } /** diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java index 250fd9d9f..3bb6b5faf 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.registry.populator; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.type.GeyserMappingItem; @@ -41,10 +42,15 @@ public class Conversion685_671 { private static final List OMINOUS_BLOCKS = List.of("minecraft:trial_spawner", "minecraft:vault"); private static final List NEW_BLOCKS = Stream.of(NEW_CORAL_BLOCKS, NEW_DOUBLE_PLANTS, NEW_STONE_BLOCK_SLABS, NEW_TALLGRASSES).flatMap(List::stream).toList(); private static final List MODIFIED_BLOCKS = Stream.of(NEW_BLOCKS, OMINOUS_BLOCKS).flatMap(List::stream).toList(); + private static final List NEW_MUSIC_DISCS = List.of(Items.MUSIC_DISC_CREATOR, Items.MUSIC_DISC_CREATOR_MUSIC_BOX, Items.MUSIC_DISC_PRECIPICE); static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { String identifer = mapping.getBedrockIdentifier(); + if (NEW_MUSIC_DISCS.contains(item)) { + return mapping.withBedrockIdentifier("minecraft:music_disc_otherside"); + } + if (!NEW_BLOCKS.contains(identifer)) { return mapping; } From 65fd409a0099be88abe31d00ba21903dbd92eed0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:42:53 -0400 Subject: [PATCH 179/897] Painting re-implemented. Started on enchantments --- .../geyser/entity/type/PaintingEntity.java | 14 ++- .../living/animal/tameable/WolfEntity.java | 38 ++++---- .../org/geysermc/geyser/item/Enchantment.java | 47 +++++++++ .../geysermc/geyser/item/type/BannerItem.java | 4 +- .../geysermc/geyser/level/PaintingType.java | 32 +++++-- .../registry/populator/Conversion685_671.java | 2 +- .../geyser/session/GeyserSession.java | 14 ++- .../geyser/session/cache/RegistryCache.java | 13 ++- .../cache/registry/SimpleJavaRegistry.java | 5 + .../geysermc/geyser/text/TextDecoration.java | 96 ++++++++----------- ...BedrockInventoryTransactionTranslator.java | 6 +- .../BedrockMobEquipmentTranslator.java | 7 +- .../protocol/java/JavaRespawnTranslator.java | 2 +- .../translator/text/MessageTranslator.java | 22 +++-- gradle/libs.versions.toml | 2 +- 15 files changed, 187 insertions(+), 117 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/Enchantment.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java index f5145c11f..6d0294783 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java @@ -30,6 +30,8 @@ import org.cloudburstmc.protocol.bedrock.packet.AddPaintingPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.PaintingType; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PaintingVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; @@ -49,8 +51,14 @@ public class PaintingEntity extends Entity { // Wait until we get the metadata needed } - public void setPaintingType(ObjectEntityMetadata entityMetadata) { - PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue()); + public void setPaintingType(ObjectEntityMetadata> entityMetadata) { + if (!entityMetadata.getValue().isId()) { + return; + } + PaintingType type = session.getRegistryCache().paintings().byId(entityMetadata.getValue().id()); + if (type == null) { + return; + } AddPaintingPacket addPaintingPacket = new AddPaintingPacket(); addPaintingPacket.setUniqueEntityId(geyserId); addPaintingPacket.setRuntimeEntityId(geyserId); @@ -79,7 +87,7 @@ public class PaintingEntity extends Entity { private Vector3f fixOffset(PaintingType paintingName) { Vector3f position = super.position; position = position.add(0.5, 0.5, 0.5); - double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0; + double widthOffset = paintingName.getWidth() > 1 && paintingName.getWidth() != 3 ? 0.5 : 0; double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0; return switch (direction) { 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 4573f0e7a..57fb901b4 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,33 +36,25 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.Enchantment; 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.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.ItemUtils; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; 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.item.ItemStack; import java.util.Collections; import java.util.Locale; -import java.util.Set; import java.util.UUID; public class WolfEntity extends TameableEntity { - /** - * A list of all foods a wolf can eat on Java Edition. - * Used to display interactive tag or particles if needed. - * TODO generate - */ - private static final Set WOLF_FOODS = Set.of(Items.PUFFERFISH, Items.TROPICAL_FISH, Items.CHICKEN, Items.COOKED_CHICKEN, - Items.PORKCHOP, Items.BEEF, Items.RABBIT, Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.ROTTEN_FLESH, Items.MUTTON, Items.COOKED_MUTTON, - Items.COOKED_RABBIT); - private byte collarColor = 14; // Red - default private boolean isCurseOfBinding = false; @@ -112,12 +104,14 @@ public class WolfEntity extends TameableEntity { } // 1.20.5+ - public void setWolfVariant(IntEntityMetadata entityMetadata) { - WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(entityMetadata.getPrimitiveValue()); - if (wolfVariant == null) { - wolfVariant = WolfVariant.PALE; - } - dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal()); + public void setWolfVariant(ObjectEntityMetadata> entityMetadata) { + entityMetadata.getValue().ifId(id -> { + BuiltInWolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(id); + if (wolfVariant == null) { + wolfVariant = BuiltInWolfVariant.PALE; + } + dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal()); + }); } @Override @@ -187,7 +181,7 @@ public class WolfEntity extends TameableEntity { } // Ordered by bedrock id - public enum WolfVariant { + public enum BuiltInWolfVariant { PALE, ASHEN, BLACK, @@ -198,16 +192,16 @@ public class WolfEntity extends TameableEntity { STRIPED, WOODS; - private static final WolfVariant[] VALUES = values(); + private static final BuiltInWolfVariant[] VALUES = values(); private final String javaIdentifier; - WolfVariant() { + BuiltInWolfVariant() { this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT); } - public static @Nullable WolfVariant getByJavaIdentifier(String javaIdentifier) { - for (WolfVariant wolfVariant : VALUES) { + public static @Nullable BuiltInWolfVariant getByJavaIdentifier(String javaIdentifier) { + for (BuiltInWolfVariant wolfVariant : VALUES) { if (wolfVariant.javaIdentifier.equals(javaIdentifier)) { return wolfVariant; } diff --git a/core/src/main/java/org/geysermc/geyser/item/Enchantment.java b/core/src/main/java/org/geysermc/geyser/item/Enchantment.java new file mode 100644 index 000000000..506467afd --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/Enchantment.java @@ -0,0 +1,47 @@ +/* + * 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.item; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; + +/** + * @param anvilCost also as a rarity multiplier + */ +public record Enchantment(String supportedItemsTag, int maxLevel, int anvilCost, @Nullable String exclusiveSetTag) { + + // Implementation note: I have a feeling the tags can be a list of items, because in vanilla they're HolderSet classes. + // I'm not sure how that's wired over the network, so we'll put it off. + public static Enchantment read(RegistryEntry entry) { + NbtMap data = entry.getData(); + String supportedItems = data.getString("supported_items"); + int maxLevel = data.getInt("max_level"); + int anvilCost = data.getInt("anvil_cost"); + String exclusiveSet = data.getString("exclusive_set", null); + return new Enchantment(supportedItems, maxLevel, anvilCost, exclusiveSet); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index b53843882..cf0105622 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -146,8 +146,8 @@ public class BannerItem extends BlockItem { } else { List patternList = new ArrayList<>(patterns.size()); for (BannerPatternLayer patternLayer : patterns) { - patternLayer.getPattern().ifId(holder -> { - BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(holder.id()); + patternLayer.getPattern().ifId(id -> { + BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(id); if (bannerPattern != null) { NbtMap tag = NbtMap.builder() .putString("Pattern", bannerPattern.getBedrockIdentifier()) diff --git a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java index 643fd735d..de35d97f1 100644 --- a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java +++ b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java @@ -29,6 +29,8 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.Locale; + @AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter public enum PaintingType { @@ -61,7 +63,27 @@ public enum PaintingType { EARTH("Earth", 2, 2), WIND("Wind", 2, 2), WATER("Water", 2, 2), - FIRE("Fire", 2, 2); + FIRE("Fire", 2, 2), + MEDITATIVE("meditative", 1, 1), + PRAIRIE_RIDE("prairie_ride", 1, 2), + BAROQUE("baroque", 2, 2), + HUMBLE("humble", 2, 2), + UNPACKED("unpacked", 4, 4), + BACKYARD("backyard", 3, 4), + BOUQUET("bouquet", 3, 3), + CAVEBIRD("cavebird", 3, 3), + CHANGING("changing", 4, 2), + COTAN("cotan", 3, 3), + ENDBOSS("endboss", 3, 3), + FERN("fern", 3, 3), + FINDING("finding", 4, 2), + LOWMIST("lowmist", 4, 2), + ORB("orb", 4, 4), + OWLEMONS("owlemons", 3, 3), + PASSAGE("passage", 4, 2), + POND("pond", 3, 4), + SUNFLOWERS("sunflowers", 3, 3), + TIDES("tides", 3, 3); private static final PaintingType[] VALUES = values(); private final String bedrockName; @@ -70,12 +92,8 @@ public enum PaintingType { public static PaintingType getByName(String javaName) { for (PaintingType paintingName : VALUES) { - if (paintingName.name().equalsIgnoreCase(javaName)) return paintingName; + if (("minecraft:" + paintingName.name().toLowerCase(Locale.ROOT)).equals(javaName)) return paintingName; } - return KEBAB; - } - - public static PaintingType getByPaintingType(org.geysermc.mcprotocollib.protocol.data.game.entity.type.PaintingType paintingType) { - return getByName(paintingType.name()); + return null; } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java index 3bb6b5faf..c96966927 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java @@ -44,7 +44,7 @@ public class Conversion685_671 { private static final List MODIFIED_BLOCKS = Stream.of(NEW_BLOCKS, OMINOUS_BLOCKS).flatMap(List::stream).toList(); private static final List NEW_MUSIC_DISCS = List.of(Items.MUSIC_DISC_CREATOR, Items.MUSIC_DISC_CREATOR_MUSIC_BOX, Items.MUSIC_DISC_PRECIPICE); - static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { + static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { String identifer = mapping.getBedrockIdentifier(); if (NEW_MUSIC_DISCS.contains(item)) { 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 17010e966..9543c7943 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1302,22 +1302,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } } + /** + * Convenience method to reduce amount of duplicate code. Sends ServerboundUseItemPacket. + */ + public void useItem(Hand hand) { + sendDownstreamGamePacket(new ServerboundUseItemPacket( + hand, worldCache.nextPredictionSequence(), playerEntity.getPitch(), playerEntity.getYaw())); + } + /** * Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display * blocking and sends a packet to the Java server. */ private boolean attemptToBlock() { - ServerboundUseItemPacket useItemPacket; if (playerInventory.getItemInHand().asItem() == Items.SHIELD) { - useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, worldCache.nextPredictionSequence()); + useItem(Hand.MAIN_HAND); } else if (playerInventory.getOffhand().asItem() == Items.SHIELD) { - useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, worldCache.nextPredictionSequence()); + useItem(Hand.OFF_HAND); } else { // No blocking return false; } - sendDownstreamGamePacket(useItemPacket); playerEntity.setFlag(EntityFlag.BLOCKING, true); // Metadata should be updated later return true; 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 fa4503635..a9b14fdc0 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 @@ -38,7 +38,9 @@ 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.recipe.TrimRecipe; +import org.geysermc.geyser.item.Enchantment; import org.geysermc.geyser.level.JavaDimension; +import org.geysermc.geyser.level.PaintingType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.registry.JavaRegistry; import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; @@ -46,6 +48,7 @@ import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; +import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType; import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; import java.util.ArrayList; @@ -72,11 +75,13 @@ public final class RegistryCache { static { register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry)); register("dimension_type", cache -> cache.dimensions, ($, entry) -> JavaDimension.read(entry)); + register("enchantment", cache -> cache.enchantments, ($, entry) -> Enchantment.read(entry)); + register("painting_variant", cache -> cache.paintings, ($, entry) -> PaintingType.getByName(entry.getId())); register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); - register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId())); + register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(entry.getId())); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); @@ -104,16 +109,18 @@ public final class RegistryCache { * Java -> Bedrock biome network IDs. */ private int[] biomeTranslations; - private final JavaRegistry chatTypes = new SimpleJavaRegistry<>(); + private final JavaRegistry chatTypes = new SimpleJavaRegistry<>(); /** * All dimensions that the client could possibly connect to. */ private final JavaRegistry dimensions = new SimpleJavaRegistry<>(); + private final JavaRegistry enchantments = new SimpleJavaRegistry<>(); + private final JavaRegistry paintings = new SimpleJavaRegistry<>(); private final JavaRegistry trimMaterials = new SimpleJavaRegistry<>(); private final JavaRegistry trimPatterns = new SimpleJavaRegistry<>(); private final JavaRegistry bannerPatterns = new SimpleJavaRegistry<>(); - private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); public RegistryCache(GeyserSession session) { this.session = session; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java index 9839a1568..7b79a40be 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java @@ -57,4 +57,9 @@ public class SimpleJavaRegistry implements JavaRegistry { public List values() { return this.values; } + + @Override + public String toString() { + return this.values.toString(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java index b2222d3b9..cf2071173 100644 --- a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -30,21 +30,49 @@ import net.kyori.adventure.text.format.Style; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; +import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType; +import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatTypeDecoration; -import java.util.EnumSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; +import java.util.*; -public final class TextDecoration { - private final String translationKey; - private final Style style; - private final Set parameters; +public record TextDecoration(String translationKey, List parameters, Style deserializedStyle) implements ChatTypeDecoration { - public TextDecoration(NbtMap tag) { - translationKey = tag.getString("translation_key"); + @Override + public NbtMap style() { + // Should not ever be called. + throw new UnsupportedOperationException(); + } - NbtMap styleTag = tag.getCompound("style"); + public static ChatType readChatType(RegistryEntry entry) { + // Note: The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. + // (This note has been passed around through several classes and iterations. It stays as a warning + // to anyone that dares to try and hardcode registry IDs.) + NbtMap tag = entry.getData(); + NbtMap chat = tag.getCompound("chat", null); + if (chat != null) { + String translationKey = tag.getString("translation_key"); + + NbtMap styleTag = tag.getCompound("style"); + Style style = deserializeStyle(styleTag); + + List parameters = new ArrayList<>(); + List parametersNbt = tag.getList("parameters", NbtType.STRING); + for (String parameter : parametersNbt) { + parameters.add(ChatTypeDecoration.Parameter.valueOf(parameter.toUpperCase(Locale.ROOT))); + } + return new ChatType(new TextDecoration(translationKey, parameters, style), null); + } + return new ChatType(null, null); + } + + public static Style getStyle(ChatTypeDecoration decoration) { + if (decoration instanceof TextDecoration textDecoration) { + return textDecoration.deserializedStyle(); + } + return deserializeStyle(decoration.style()); + } + + private static Style deserializeStyle(NbtMap styleTag) { Style.Builder builder = Style.style(); if (!styleTag.isEmpty()) { String color = styleTag.getString("color", null); @@ -57,50 +85,6 @@ public final class TextDecoration { builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC); } } - style = builder.build(); - - this.parameters = EnumSet.noneOf(Parameter.class); - List parameters = tag.getList("parameters", NbtType.STRING); - for (String parameter : parameters) { - this.parameters.add(Parameter.valueOf(parameter.toUpperCase(Locale.ROOT))); - } - } - - public String translationKey() { - return translationKey; - } - - public Style style() { - return style; - } - - public Set parameters() { - return parameters; - } - - @Override - public String toString() { - return "TextDecoration{" + - "translationKey='" + translationKey + '\'' + - ", style=" + style + - ", parameters=" + parameters + - '}'; - } - - public static TextDecoration readChatType(RegistryEntry entry) { - // Note: The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. - NbtMap tag = entry.getData(); - NbtMap chat = tag.getCompound("chat", null); - TextDecoration textDecoration = null; - if (chat != null) { - textDecoration = new TextDecoration(chat); - } - return textDecoration; - } - - public enum Parameter { - CONTENT, - SENDER, - TARGET + return builder.build(); } } 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 878d326ac..534a89e23 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 @@ -394,8 +394,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator legacySlots = packet.getLegacySlots(); if (packet.getActions().size() == 1 && !legacySlots.isEmpty()) { @@ -639,8 +638,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator session.sendDownstreamGamePacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence())), + session.scheduleInEventLoop(() -> session.useItem(Hand.MAIN_HAND), 50, TimeUnit.MILLISECONDS); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index fe0868253..44ce51352 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -53,7 +53,7 @@ public class JavaRespawnTranslator extends PacketTranslator chatTypeHolder, Component targetName, Component sender) { TextPacket textPacket = new TextPacket(); textPacket.setPlatformChatId(""); textPacket.setSourceName(""); @@ -330,14 +333,15 @@ public class MessageTranslator { textPacket.setNeedsTranslation(false); - TextDecoration decoration = session.getRegistryCache().chatTypes().byId(chatType); - if (decoration != null) { + ChatType chatType = chatTypeHolder.getOrCompute(session.getRegistryCache().chatTypes()::byId); + if (chatType != null && chatType.chat() != null) { + var chat = chatType.chat(); // As of 1.19 - do this to apply all the styling for signed messages // Though, Bedrock cannot care about the signed stuff. TranslatableComponent.Builder withDecoration = Component.translatable() - .key(decoration.translationKey()) - .style(decoration.style()); - Set parameters = decoration.parameters(); + .key(chat.translationKey()) + .style(TextDecoration.getStyle(chat)); + List parameters = chat.parameters(); List args = new ArrayList<>(3); if (parameters.contains(TextDecoration.Parameter.TARGET)) { args.add(targetName); @@ -348,7 +352,7 @@ public class MessageTranslator { if (parameters.contains(TextDecoration.Parameter.CONTENT)) { args.add(message); } - withDecoration.args(args); + withDecoration.arguments(args); textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.locale())); } else { session.getGeyser().getLogger().debug("Likely illegal chat type detection found."); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1995a6ada..f1b765e0f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ websocket = "1.5.1" protocol = "3.0.0.Beta2-20240520.153053-5" raknet = "1.0.0.CR3-20240416.144209-1" mcauthlib = "e5b0bcc" -mcprotocollib = "1.20.6-2-20240520.030045-8" +mcprotocollib = "1.21-SNAPSHOT" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 8ad10f8a9ea686043837d60057b70fdb83dc6321 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:36:44 -0400 Subject: [PATCH 180/897] Boats are leashable --- .../geyser/entity/type/BoatEntity.java | 23 +++++++++- .../geysermc/geyser/entity/type/Entity.java | 24 ++++++++++ .../geyser/entity/type/Leashable.java | 44 +++++++++++++++++++ .../entity/type/living/AmbientEntity.java | 2 +- .../entity/type/living/DolphinEntity.java | 2 +- .../geyser/entity/type/living/MobEntity.java | 27 +++++------- .../entity/type/living/SquidEntity.java | 2 +- .../entity/type/living/WaterEntity.java | 2 +- .../type/living/animal/AxolotlEntity.java | 2 +- .../type/living/animal/HoglinEntity.java | 2 +- .../type/living/animal/PandaEntity.java | 2 +- .../type/living/animal/TurtleEntity.java | 2 +- .../animal/tameable/TameableEntity.java | 2 +- .../living/animal/tameable/WolfEntity.java | 2 +- .../merchant/AbstractMerchantEntity.java | 2 +- .../type/living/monster/ZoglinEntity.java | 2 +- .../entity/JavaSetEntityLinkTranslator.java | 16 +++---- 17 files changed, 120 insertions(+), 38 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java 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 d9a64ccc6..47ae6777a 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 @@ -41,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class BoatEntity extends Entity implements Tickable { +public class BoatEntity extends Entity implements Leashable, Tickable { /** * Required when IS_BUOYANT is sent in order for boats to work in the water.
@@ -65,6 +65,8 @@ public class BoatEntity extends Entity implements Tickable { @Getter private int 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; @@ -147,8 +149,18 @@ public class BoatEntity extends Entity implements Tickable { } } + @Override + public void setLeashHolderBedrockId(long bedrockId) { + this.leashHolderBedrockId = bedrockId; + dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId); + } + @Override protected InteractiveTag testInteraction(Hand hand) { + InteractiveTag tag = super.testInteraction(hand); + if (tag != InteractiveTag.NONE) { + return tag; + } if (session.isSneaking()) { return InteractiveTag.NONE; } else if (passengers.size() < 2) { @@ -160,6 +172,10 @@ public class BoatEntity extends Entity implements Tickable { @Override public InteractionResult interact(Hand hand) { + InteractionResult result = super.interact(hand); + if (result != InteractionResult.PASS) { + return result; + } if (session.isSneaking()) { return InteractionResult.PASS; } else { @@ -191,6 +207,11 @@ public class BoatEntity extends Entity implements Tickable { } } + @Override + public long leashHolderBedrockId() { + return leashHolderBedrockId; + } + private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) { AnimatePacket packet = new AnimatePacket(); packet.setRuntimeEntityId(rower.getGeyserId()); 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 6267ee791..08e87dc03 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 @@ -40,6 +40,7 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.GeyserDirtyMetadata; import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.EntityUtils; @@ -557,6 +558,17 @@ public class Entity implements GeyserEntity { * Should usually mirror {@link #interact(Hand)} without any side effects. */ protected InteractiveTag testInteraction(Hand hand) { + if (isAlive() && this instanceof Leashable leashable) { + if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) { + // Note this might be client side. Has yet to be an issue though, as of Java 1.21. + return InteractiveTag.REMOVE_LEASH; + } + if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) { + // We shall leash + return InteractiveTag.LEASH; + } + } + return InteractiveTag.NONE; } @@ -565,6 +577,18 @@ public class Entity implements GeyserEntity { * to ensure packet parity as well as functionality parity (such as sound effect responses). */ public InteractionResult interact(Hand hand) { + if (isAlive() && this instanceof Leashable leashable) { + if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) { + // Note this might also update client side (a theoretical Geyser/client desync and Java parity issue). + // Has yet to be an issue though, as of Java 1.21. + return InteractionResult.SUCCESS; + } + if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) { + // We shall leash + return InteractionResult.SUCCESS; + } + } + return InteractionResult.PASS; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java b/core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java new file mode 100644 index 000000000..64d95ba3c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java @@ -0,0 +1,44 @@ +/* + * 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; + +/** + * I can haz lead + * (The item, not the mineral) + */ +public interface Leashable { + void setLeashHolderBedrockId(long bedrockId); + + long leashHolderBedrockId(); + + default boolean canBeLeashed() { + return isNotLeashed(); + } + + default boolean isNotLeashed() { + return leashHolderBedrockId() == -1L; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java index 8f81125d0..f4b80edf1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java @@ -38,7 +38,7 @@ public class AmbientEntity extends MobEntity { } @Override - protected boolean canBeLeashed() { + 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 6182a27f4..a0ea79d67 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 @@ -43,7 +43,7 @@ public class DolphinEntity extends WaterEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return true; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java index 95145ae60..9accf178f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.entity.type.living; -import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; 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.entity.type.Leashable; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; @@ -43,11 +43,10 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class MobEntity extends LivingEntity { +public class MobEntity extends LivingEntity implements Leashable { /** * If another mob is holding this mob by a leash, this variable tracks their Bedrock entity ID. */ - @Getter private long leashHolderBedrockId; public MobEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -65,6 +64,7 @@ public class MobEntity extends LivingEntity { setFlag(EntityFlag.NO_AI, (xd & 0x01) == 0x01); } + @Override public void setLeashHolderBedrockId(long bedrockId) { this.leashHolderBedrockId = bedrockId; dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId); @@ -79,10 +79,7 @@ public class MobEntity extends LivingEntity { return InteractiveTag.REMOVE_LEASH; } else { GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(hand); - if (itemStack.asItem() == Items.LEAD && canBeLeashed()) { - // We shall leash - return InteractiveTag.LEASH; - } else if (itemStack.asItem() == Items.NAME_TAG) { + if (itemStack.asItem() == Items.NAME_TAG) { InteractionResult result = checkInteractWithNameTag(itemStack); if (result.consumesAction()) { return InteractiveTag.NAME; @@ -99,9 +96,6 @@ public class MobEntity extends LivingEntity { if (!isAlive()) { // dead lol return InteractionResult.PASS; - } else if (leashHolderBedrockId == session.getPlayerEntity().getGeyserId()) { - // TODO looks like the client assumes it will go through and removes the attachment itself? - return InteractionResult.SUCCESS; } else { GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand(hand); InteractionResult result = checkPriorityInteractions(itemInHand); @@ -115,10 +109,7 @@ public class MobEntity extends LivingEntity { } private InteractionResult checkPriorityInteractions(GeyserItemStack itemInHand) { - if (itemInHand.asItem() == Items.LEAD && canBeLeashed()) { - // We shall leash - return InteractionResult.SUCCESS; - } else if (itemInHand.asItem() == Items.NAME_TAG) { + if (itemInHand.asItem() == Items.NAME_TAG) { InteractionResult result = checkInteractWithNameTag(itemInHand); if (result.consumesAction()) { return result; @@ -143,12 +134,14 @@ public class MobEntity extends LivingEntity { return InteractionResult.PASS; } - protected boolean canBeLeashed() { + @Override + public boolean canBeLeashed() { return isNotLeashed() && !isEnemy(); } - protected final boolean isNotLeashed() { - return leashHolderBedrockId == -1L; + @Override + public long leashHolderBedrockId() { + return leashHolderBedrockId; } /** 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 80a5af442..6285bd9a4 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 @@ -122,7 +122,7 @@ public class SquidEntity extends WaterEntity implements Tickable { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return isNotLeashed(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java index a847c4cd7..ae9d0d659 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java @@ -38,7 +38,7 @@ public class WaterEntity extends CreatureEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return false; } } 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 a87b1dd5e..a0ab56ead 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 @@ -72,7 +72,7 @@ public class AxolotlEntity extends AnimalEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return true; } 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 74c937417..cc23fc607 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 @@ -63,7 +63,7 @@ public class HoglinEntity extends AnimalEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return isNotLeashed(); } 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 79401f63f..aaa7c2d7e 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 @@ -123,7 +123,7 @@ public class PandaEntity extends AnimalEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return false; } 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 b3c1128e3..16901a844 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 @@ -56,7 +56,7 @@ public class TurtleEntity extends AnimalEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return false; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java index e16823d37..ea347d193 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java @@ -84,7 +84,7 @@ public abstract class TameableEntity extends AnimalEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return isNotLeashed(); } } 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 57fb901b4..c6b8051e7 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 @@ -127,7 +127,7 @@ public class WolfEntity extends TameableEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java index 64e35e52e..2492aabd7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java @@ -47,7 +47,7 @@ public class AbstractMerchantEntity extends AgeableEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return false; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java index 206746fb9..3d6e381c7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java @@ -58,7 +58,7 @@ public class ZoglinEntity extends MonsterEntity { } @Override - protected boolean canBeLeashed() { + public boolean canBeLeashed() { return isNotLeashed(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityLinkTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityLinkTranslator.java index d595e928f..15d47a285 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityLinkTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEntityLinkTranslator.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityLinkPacket; 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.type.Entity; -import org.geysermc.geyser.entity.type.living.MobEntity; +import org.geysermc.geyser.entity.type.Leashable; 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.ClientboundSetEntityLinkPacket; /** * Called when a leash is attached, removed or updated from an entity @@ -44,16 +44,16 @@ public class JavaSetEntityLinkTranslator extends PacketTranslator Date: Mon, 3 Jun 2024 21:00:08 +0200 Subject: [PATCH 181/897] Feature: Add API to show/hide GUI elements (#4705) * Add API to show/hide GUI elements * Bump version to 2.3.2 --------- Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../geyser/api/bedrock/camera/CameraData.java | 34 +++++- .../geyser/api/bedrock/camera/GuiElement.java | 60 ++++++++++ .../geyser/impl/camera/GeyserCameraData.java | 109 +++++++++++++++++- .../geyser/session/GeyserSession.java | 7 +- gradle.properties | 2 +- 5 files changed, 203 insertions(+), 9 deletions(-) create mode 100644 api/src/main/java/org/geysermc/geyser/api/bedrock/camera/GuiElement.java diff --git a/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraData.java b/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraData.java index 2f715fa1e..f208879d1 100644 --- a/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraData.java +++ b/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraData.java @@ -145,4 +145,36 @@ public interface CameraData { * @return whether the camera is currently locked */ boolean isCameraLocked(); -} \ No newline at end of file + + /** + * Hides a {@link GuiElement} on the client's side. + * + * @param element the {@link GuiElement} to hide + */ + void hideElement(@NonNull GuiElement... element); + + /** + * Resets a {@link GuiElement} on the client's side. + * This makes the client decide on its own - e.g. based on client settings - + * whether to show or hide the gui element. + *

+ * If no elements are specified, this will reset all currently hidden elements + * + * @param element the {@link GuiElement} to reset + */ + void resetElement(@NonNull GuiElement @Nullable... element); + + /** + * Determines whether a {@link GuiElement} is currently hidden. + * + * @param element the {@link GuiElement} to check + */ + boolean isHudElementHidden(@NonNull GuiElement element); + + /** + * Returns the currently hidden {@link GuiElement}s. + * + * @return an unmodifiable view of all currently hidden {@link GuiElement}s + */ + @NonNull Set hiddenElements(); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/GuiElement.java b/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/GuiElement.java new file mode 100644 index 000000000..4d3653648 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/GuiElement.java @@ -0,0 +1,60 @@ +/* + * 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.api.bedrock.camera; + +/** + * Represent GUI elements on the players HUD display. + * These can be hidden using {@link CameraData#hideElement(GuiElement...)}, + * and one can reset their visibility using {@link CameraData#resetElement(GuiElement...)}. + */ +public class GuiElement { + public static final GuiElement PAPER_DOLL = new GuiElement(0); + public static final GuiElement ARMOR = new GuiElement(1); + public static final GuiElement TOOL_TIPS = new GuiElement(2); + public static final GuiElement TOUCH_CONTROLS = new GuiElement(3); + public static final GuiElement CROSSHAIR = new GuiElement(4); + public static final GuiElement HOTBAR = new GuiElement(5); + public static final GuiElement HEALTH = new GuiElement(6); + public static final GuiElement PROGRESS_BAR = new GuiElement(7); + public static final GuiElement FOOD_BAR = new GuiElement(8); + public static final GuiElement AIR_BUBBLES_BAR = new GuiElement(9); + public static final GuiElement VEHICLE_HEALTH = new GuiElement(10); + public static final GuiElement EFFECTS_BAR = new GuiElement(11); + public static final GuiElement ITEM_TEXT_POPUP = new GuiElement(12); + + private GuiElement(int id) { + this.id = id; + } + + private final int id; + + /** + * Internal use only; don't depend on these values being consistent. + */ + public int id() { + return this.id; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java index 2a93c89e3..7582502b3 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java @@ -32,24 +32,50 @@ import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.CameraShakeAction; import org.cloudburstmc.protocol.bedrock.data.CameraShakeType; +import org.cloudburstmc.protocol.bedrock.data.HudElement; +import org.cloudburstmc.protocol.bedrock.data.HudVisibility; import org.cloudburstmc.protocol.bedrock.data.camera.CameraEase; import org.cloudburstmc.protocol.bedrock.data.camera.CameraFadeInstruction; import org.cloudburstmc.protocol.bedrock.data.camera.CameraSetInstruction; import org.cloudburstmc.protocol.bedrock.packet.CameraInstructionPacket; import org.cloudburstmc.protocol.bedrock.packet.CameraShakePacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerFogPacket; -import org.geysermc.geyser.api.bedrock.camera.*; +import org.cloudburstmc.protocol.bedrock.packet.SetHudPacket; +import org.geysermc.geyser.api.bedrock.camera.CameraData; +import org.geysermc.geyser.api.bedrock.camera.CameraEaseType; +import org.geysermc.geyser.api.bedrock.camera.CameraFade; +import org.geysermc.geyser.api.bedrock.camera.CameraPerspective; +import org.geysermc.geyser.api.bedrock.camera.CameraPosition; +import org.geysermc.geyser.api.bedrock.camera.CameraShake; +import org.geysermc.geyser.api.bedrock.camera.GuiElement; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import java.util.*; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; public class GeyserCameraData implements CameraData { + private static final HudElement[] HUD_ELEMENT_VALUES = HudElement.values(); + private static final Set ALL_HUD_ELEMENTS = Set.of(HUD_ELEMENT_VALUES); + + /** + * An array of elements to hide when the player is in spectator mode. + * Helps with tidying up the GUI; Java-style. + */ + private static final GuiElement[] SPECTATOR_HIDDEN_ELEMENTS = { + GuiElement.AIR_BUBBLES_BAR, + GuiElement.ARMOR, + GuiElement.HEALTH, + GuiElement.FOOD_BAR, + GuiElement.PROGRESS_BAR, + GuiElement.TOOL_TIPS + }; private final GeyserSession session; - @Getter - private CameraPerspective cameraPerspective; - /** * All fog effects that are currently applied to the client. */ @@ -57,6 +83,14 @@ public class GeyserCameraData implements CameraData { private final Set cameraLockOwners = new HashSet<>(); + /** + * All currently hidden HUD elements + */ + private final Set hiddenHudElements = new HashSet<>(); + + @Getter + private CameraPerspective cameraPerspective; + public GeyserCameraData(GeyserSession session) { this.session = session; } @@ -223,4 +257,67 @@ public class GeyserCameraData implements CameraData { public boolean isCameraLocked() { return !this.cameraLockOwners.isEmpty(); } -} \ No newline at end of file + + @Override + public void hideElement(GuiElement... elements) { + Objects.requireNonNull(elements); + SetHudPacket packet = new SetHudPacket(); + packet.setVisibility(HudVisibility.HIDE); + Set elementSet = packet.getElements(); + + for (GuiElement element : elements) { + this.hiddenHudElements.add(element); + elementSet.add(HUD_ELEMENT_VALUES[element.id()]); + } + + session.sendUpstreamPacket(packet); + } + + @Override + public void resetElement(GuiElement... elements) { + SetHudPacket packet = new SetHudPacket(); + packet.setVisibility(HudVisibility.RESET); + Set elementSet = packet.getElements(); + + if (elements != null && elements.length != 0) { + for (GuiElement element : elements) { + this.hiddenHudElements.remove(element); + elementSet.add(HUD_ELEMENT_VALUES[element.id()]); + } + } else { + this.hiddenHudElements.clear(); + elementSet.addAll(ALL_HUD_ELEMENTS); + } + + session.sendUpstreamPacket(packet); + } + + @Override + public boolean isHudElementHidden(@NonNull GuiElement element) { + Objects.requireNonNull(element); + return this.hiddenHudElements.contains(element); + } + + @Override + public @NonNull Set hiddenElements() { + return Collections.unmodifiableSet(hiddenHudElements); + } + + /** + * Deals with hiding hud elements while in spectator. + * + * @param currentlySpectator whether the player is currently in spectator mode + * @param newGameMode the new GameMode to switch to + */ + public void handleGameModeChange(boolean currentlySpectator, GameMode newGameMode) { + if (newGameMode == GameMode.SPECTATOR) { + if (!currentlySpectator) { + hideElement(SPECTATOR_HIDDEN_ELEMENTS); + } + } else { + if (currentlySpectator) { + resetElement(SPECTATOR_HIDDEN_ELEMENTS); + } + } + } +} 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 17010e966..fc000b95f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -284,7 +284,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { */ private volatile boolean closed; - @Setter private GameMode gameMode = GameMode.SURVIVAL; /** @@ -1302,6 +1301,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } } + public void setGameMode(GameMode newGamemode) { + boolean currentlySpectator = this.gameMode == GameMode.SPECTATOR; + this.gameMode = newGamemode; + this.cameraData.handleGameModeChange(currentlySpectator, newGamemode); + } + /** * Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display * blocking and sends a packet to the Java server. diff --git a/gradle.properties b/gradle.properties index 40d8a36db..ea473906a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.3.1-SNAPSHOT +version=2.3.2-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From 6c245a66e250bee57b98b5b3b07c08da44ea2afa Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:43:35 -0400 Subject: [PATCH 182/897] Adapt for new enchantment changes --- .../living/animal/tameable/WolfEntity.java | 4 +- .../geyser/inventory/GeyserEnchantOption.java | 25 +- ...chantment.java => BedrockEnchantment.java} | 49 +--- .../updater/AnvilInventoryUpdater.java | 52 ++--- .../geyser/item/enchantment/Enchantment.java | 90 ++++++++ .../enchantment/EnchantmentComponent.java | 33 +++ .../geyser/item/type/EnchantedBookItem.java | 6 +- .../org/geysermc/geyser/item/type/Item.java | 36 ++- .../geysermc/geyser/registry/Registries.java | 25 +- .../loader/EnchantmentRegistryLoader.java | 86 ------- .../geyser/registry/type/EnchantmentData.java | 2 +- .../geyser/session/GeyserSession.java | 2 +- .../geyser/session/cache/RegistryCache.java | 2 +- .../geyser/session/cache/TagCache.java | 83 ++++--- .../geyser/session/cache/tags/BlockTag.java | 214 ++++++++++++++++-- .../session/cache/tags/EnchantmentTag.java | 89 ++++++++ .../geyser/session/cache/tags/ItemTag.java | 198 +++++++++++++--- .../EnchantingInventoryTranslator.java | 11 +- .../protocol/java/JavaCommandsTranslator.java | 23 +- .../org/geysermc/geyser/util/BlockUtils.java | 14 +- .../org/geysermc/geyser/util/ItemUtils.java | 45 +++- .../Enchantment.java => util/Ordered.java} | 22 +- core/src/main/resources/mappings | 2 +- 23 files changed, 775 insertions(+), 338 deletions(-) rename core/src/main/java/org/geysermc/geyser/inventory/item/{Enchantment.java => BedrockEnchantment.java} (69%) create mode 100644 core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java create mode 100644 core/src/main/java/org/geysermc/geyser/item/enchantment/EnchantmentComponent.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/tags/EnchantmentTag.java rename core/src/main/java/org/geysermc/geyser/{item/Enchantment.java => util/Ordered.java} (55%) 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 c6b8051e7..9c6c5e08d 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 @@ -33,8 +33,8 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.enchantment.EnchantmentComponent; import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; @@ -123,7 +123,7 @@ public class WolfEntity extends TameableEntity { @Override public void setChestplate(ItemStack stack) { super.setChestplate(stack); - isCurseOfBinding = ItemUtils.getEnchantmentLevel(stack.getDataComponents(), Enchantment.JavaEnchantment.BINDING_CURSE) > 0; + isCurseOfBinding = ItemUtils.hasEffect(session, stack.getDataComponents(), EnchantmentComponent.PREVENT_ARMOR_CHANGE); // TODO test } @Override diff --git a/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java index 23365e392..de0bd7300 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java @@ -25,12 +25,11 @@ package org.geysermc.geyser.inventory; +import lombok.Getter; import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantData; import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData; -import lombok.Getter; import org.geysermc.geyser.session.GeyserSession; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -44,13 +43,13 @@ public class GeyserEnchantOption { * is controlled by the server. * So, of course, we have to throw in some easter eggs. ;) */ - private static final List ENCHANT_NAMES = Arrays.asList("tougher armor", "lukeeey", "fall better", - "explode less", "camo toy", "breathe better", "rtm five one six", "armor stab", "water walk", "you are elsa", - "tim two zero three", "fast walk nether", "davchoo", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned", - "more items thx", "long sword reach", "fast tool", "give me block", "less breaky break", "cube craft", - "strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", "come here fish", "i like this", - "stabby stab", "supreme mortal", "avatar i guess", "more arrows", "fly finder seventeen", "in and out", - "xp heals tools", "dragon proxy waz here"); + private static final List ENCHANT_NAMES = List.of("tougher armor", "lukeeey", "fall better", + "explode less", "camo toy", "armor stab", "breathe better", "water walk", "rtm five one six", "oof ouch owie", + "enemy on fire", "spider sad", "aj ferguson", "redned", "more items thx", "fast tool", "give me block", + "less breaky break", "cube craft", "strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", + "come here fish", "you are elsa", "xp heals tools", "tim two zero three", "dragon proxy waz here", + "stabby stab", "supreme mortal", "i like this", "avatar i guess", "more arrows", "in and out", + "fly finder seventeen", "fast walk nether", "davchoo", "onechris", "death bringer thirteen", "kastle"); @Getter private final int javaIndex; @@ -62,7 +61,6 @@ public class GeyserEnchantOption { private boolean hasChanged; private int xpCost = 0; - private int javaEnchantIndex = -1; private int bedrockEnchantIndex = -1; private int enchantLevel = -1; @@ -74,7 +72,7 @@ public class GeyserEnchantOption { this.hasChanged = false; return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY, enchantLevel == -1 ? EMPTY : Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY, - javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId()); + bedrockEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(bedrockEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId()); } public boolean hasChanged() { @@ -88,10 +86,9 @@ public class GeyserEnchantOption { } } - public void setEnchantIndex(int javaEnchantIndex, int bedrockEnchantIndex) { - if (this.javaEnchantIndex != javaEnchantIndex) { + public void setEnchantIndex(int bedrockEnchantIndex) { + if (this.bedrockEnchantIndex != bedrockEnchantIndex) { hasChanged = true; - this.javaEnchantIndex = javaEnchantIndex; this.bedrockEnchantIndex = bedrockEnchantIndex; } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java similarity index 69% rename from core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java rename to core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java index 773de29b1..a9125421e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java @@ -25,13 +25,11 @@ package org.geysermc.geyser.inventory.item; -import lombok.Getter; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Locale; -@Getter -public enum Enchantment { +public enum BedrockEnchantment { PROTECTION, FIRE_PROTECTION, FEATHER_FALLING, @@ -69,18 +67,21 @@ public enum Enchantment { PIERCING, QUICK_CHARGE, SOUL_SPEED, - SWIFT_SNEAK; + SWIFT_SNEAK, + WIND_BURST, + DENSITY, + BREACH; - private static final Enchantment[] VALUES = values(); + private static final BedrockEnchantment[] VALUES = values(); private final String javaIdentifier; - Enchantment() { + BedrockEnchantment() { this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH); } - public static @Nullable Enchantment getByJavaIdentifier(String javaIdentifier) { - for (Enchantment enchantment : VALUES) { + public static @Nullable BedrockEnchantment getByJavaIdentifier(String javaIdentifier) { + for (BedrockEnchantment enchantment : VALUES) { if (enchantment.javaIdentifier.equals(javaIdentifier) || enchantment.name().toLowerCase(Locale.ENGLISH).equalsIgnoreCase(javaIdentifier)) { return enchantment; } @@ -88,7 +89,7 @@ public enum Enchantment { return null; } - public static @Nullable Enchantment getByBedrockId(int bedrockId) { + public static @Nullable BedrockEnchantment getByBedrockId(int bedrockId) { if (bedrockId >= 0 && bedrockId < VALUES.length) { return VALUES[bedrockId]; } @@ -141,35 +142,5 @@ public enum Enchantment { WIND_BURST, MENDING, VANISHING_CURSE; - - private static final JavaEnchantment[] VALUES = JavaEnchantment.values(); - - public static JavaEnchantment of(int index) { - return VALUES[index]; - } - - /** - * A list of all enchantment Java identifiers for use with command suggestions. - */ - public static final String[] ALL_JAVA_IDENTIFIERS; - - public static @Nullable JavaEnchantment getByJavaIdentifier(String javaIdentifier) { - if (!javaIdentifier.startsWith("minecraft:")) { - javaIdentifier = "minecraft:" + javaIdentifier; - } - for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) { - if (ALL_JAVA_IDENTIFIERS[i].equalsIgnoreCase(javaIdentifier)) { - return VALUES[i]; - } - } - return null; - } - - static { - ALL_JAVA_IDENTIFIERS = new String[VALUES.length]; - for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) { - ALL_JAVA_IDENTIFIERS[i] = "minecraft:" + VALUES[i].name().toLowerCase(Locale.ENGLISH); - } - } } } 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 d6a0d922b..c3ac73372 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 @@ -26,7 +26,6 @@ package org.geysermc.geyser.inventory.updater; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntMaps; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.kyori.adventure.text.Component; import org.cloudburstmc.nbt.NbtMap; @@ -38,10 +37,9 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.AnvilContainer; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment; +import org.geysermc.geyser.inventory.item.BedrockEnchantment; +import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.EnchantmentData; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -307,22 +305,22 @@ public class AnvilInventoryUpdater extends InventoryUpdater { */ private int calcMergeEnchantmentCost(GeyserSession session, GeyserItemStack input, GeyserItemStack material, boolean bedrock) { boolean hasCompatible = false; - Object2IntMap combinedEnchantments = getEnchantments(input); + Object2IntMap combinedEnchantments = getEnchantments(session, input); int cost = 0; - for (Object2IntMap.Entry entry : getEnchantments(material).object2IntEntrySet()) { - JavaEnchantment enchantment = entry.getKey(); - EnchantmentData data = Registries.ENCHANTMENTS.get(enchantment); - if (data == null) { - GeyserImpl.getInstance().getLogger().debug("Java enchantment not in registry: " + enchantment); - continue; - } + for (Object2IntMap.Entry entry : getEnchantments(session, material).object2IntEntrySet()) { + Enchantment enchantment = entry.getKey(); - boolean canApply = isEnchantedBook(input) || data.validItems().contains(input.getJavaId()); - for (JavaEnchantment incompatible : data.incompatibleEnchantments()) { - if (combinedEnchantments.containsKey(incompatible)) { - canApply = false; - if (!bedrock) { - cost++; + boolean canApply = isEnchantedBook(input) || session.getTagCache().is(enchantment.supportedItems(), input); + var exclusiveSet = enchantment.exclusiveSet(); + if (exclusiveSet != null) { + int[] incompatibleEnchantments = session.getTagCache().get(exclusiveSet); + for (int i : incompatibleEnchantments) { + Enchantment incompatible = session.getRegistryCache().enchantments().byId(i); + if (combinedEnchantments.containsKey(incompatible)) { + canApply = false; + if (!bedrock) { + cost++; + } } } } @@ -334,12 +332,12 @@ public class AnvilInventoryUpdater extends InventoryUpdater { newLevel++; } newLevel = Math.max(currentLevel, newLevel); - if (newLevel > data.maxLevel()) { - newLevel = data.maxLevel(); + if (newLevel > enchantment.maxLevel()) { + newLevel = enchantment.maxLevel(); } combinedEnchantments.put(enchantment, newLevel); - int rarityMultiplier = data.rarityMultiplier(); + int rarityMultiplier = enchantment.anvilCost(); if (isEnchantedBook(material) && rarityMultiplier > 1) { rarityMultiplier /= 2; } @@ -347,11 +345,11 @@ public class AnvilInventoryUpdater extends InventoryUpdater { if (newLevel > currentLevel) { hasCompatible = true; } - if (enchantment == JavaEnchantment.IMPALING) { + if (enchantment.bedrockEnchantment() == BedrockEnchantment.IMPALING) { // Multiplier is halved on Bedrock for some reason rarityMultiplier /= 2; - } else if (enchantment == JavaEnchantment.SWEEPING_EDGE) { - // Doesn't exist on Bedrock + } else if (enchantment.bedrockEnchantment() == null) { + // Whatever this is, doesn't exist on Bedrock rarityMultiplier = 0; } cost += rarityMultiplier * (newLevel - currentLevel); @@ -368,7 +366,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { return cost; } - private Object2IntMap getEnchantments(GeyserItemStack itemStack) { + private Object2IntMap getEnchantments(GeyserSession session, GeyserItemStack itemStack) { ItemEnchantments enchantmentComponent; if (isEnchantedBook(itemStack)) { enchantmentComponent = itemStack.getComponent(DataComponentType.STORED_ENCHANTMENTS); @@ -376,9 +374,9 @@ public class AnvilInventoryUpdater extends InventoryUpdater { enchantmentComponent = itemStack.getComponent(DataComponentType.ENCHANTMENTS); } if (enchantmentComponent != null) { - Object2IntMap enchantments = new Object2IntOpenHashMap<>(); + Object2IntMap enchantments = new Object2IntOpenHashMap<>(); for (Map.Entry entry : enchantmentComponent.getEnchantments().entrySet()) { - JavaEnchantment enchantment = JavaEnchantment.of(entry.getKey()); + Enchantment enchantment = session.getRegistryCache().enchantments().byId(entry.getKey()); if (enchantment == null) { GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + entry.getKey()); continue; 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 new file mode 100644 index 000000000..41cc36894 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java @@ -0,0 +1,90 @@ +/* + * 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.item.enchantment; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.inventory.item.BedrockEnchantment; +import org.geysermc.geyser.session.cache.tags.EnchantmentTag; +import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; + +import java.util.*; + +/** + * @param description only populated if {@link #bedrockEnchantment()} is not null. + * @param anvilCost also as a rarity multiplier + */ +public record Enchantment(String identifier, + Set effects, + ItemTag supportedItems, + int maxLevel, + String description, + int anvilCost, + @Nullable EnchantmentTag exclusiveSet, + @Nullable BedrockEnchantment bedrockEnchantment) { + + // Implementation note: I have a feeling the tags can be a list of items, because in vanilla they're HolderSet classes. + // I'm not sure how that's wired over the network, so we'll put it off. + public static Enchantment read(RegistryEntry entry) { + NbtMap data = entry.getData(); + Set effects = readEnchantmentComponents(data.getCompound("effects")); + String supportedItems = data.getString("supported_items").substring(1); // Remove '#' at beginning that indicates tag + int maxLevel = data.getInt("max_level"); + int anvilCost = data.getInt("anvil_cost"); + String exclusiveSet = data.getString("exclusive_set", null); + EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(exclusiveSet.substring(1)); + BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId()); + String description = bedrockEnchantment == null ? readDescription(data) : null; + + return new Enchantment(entry.getId(), effects, ItemTag.ALL_ITEM_TAGS.get(supportedItems), maxLevel, + description, anvilCost, exclusiveSetTag, bedrockEnchantment); + } + + private static Set readEnchantmentComponents(NbtMap effects) { + if (effects.isEmpty()) { + return Collections.emptySet(); + } + Set components = new HashSet<>(); + for (Map.Entry entry : effects.entrySet()) { + switch (entry.getKey()) { + case "minecraft:prevent_armor_change" -> components.add(EnchantmentComponent.PREVENT_ARMOR_CHANGE); + } + } + return components; + } + + private static String readDescription(NbtMap tag) { + NbtMap description = tag.getCompound("description"); + String translate = description.getString("translate", null); + if (translate == null) { + GeyserImpl.getInstance().getLogger().debug("Don't know how to read description! " + tag); + return ""; + } + return translate; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/item/enchantment/EnchantmentComponent.java b/core/src/main/java/org/geysermc/geyser/item/enchantment/EnchantmentComponent.java new file mode 100644 index 000000000..66d110f98 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/enchantment/EnchantmentComponent.java @@ -0,0 +1,33 @@ +/* + * 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.item.enchantment; + +public class EnchantmentComponent { + /** + * Singleton with no additional data + */ + public static final EnchantmentComponent PREVENT_ARMOR_CHANGE = new EnchantmentComponent(); +} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index 98e98b4b8..540270555 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -31,7 +31,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.item.Enchantment; +import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -78,11 +78,11 @@ public class EnchantedBookItem extends Item { for (NbtMap bedrockEnchantment : enchantmentTag) { short bedrockId = bedrockEnchantment.getShort("id"); - Enchantment enchantment = Enchantment.getByBedrockId(bedrockId); + BedrockEnchantment enchantment = BedrockEnchantment.getByBedrockId(bedrockId); if (enchantment != null) { int level = bedrockEnchantment.getShort("lvl", (short) 1); // TODO - javaEnchantments.put(Enchantment.JavaEnchantment.valueOf(enchantment.name()).ordinal(), level); + //javaEnchantments.put(BedrockEnchantment.JavaEnchantment.valueOf(enchantment.name()).ordinal(), level); } else { GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId); } 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 1ec410eaf..8c67d7d5f 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 @@ -33,8 +33,9 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.inventory.item.Enchantment; +import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; @@ -201,7 +202,7 @@ public class Item { // ShortTag bedrockId = tagValue.get("id"); // if (bedrockId == null) continue; // -// Enchantment enchantment = Enchantment.getByBedrockId(bedrockId.getValue()); +// BedrockEnchantment enchantment = BedrockEnchantment.getByBedrockId(bedrockId.getValue()); // if (enchantment != null) { // CompoundTag javaTag = new CompoundTag(""); // Map javaValue = javaTag.getValue(); @@ -226,33 +227,22 @@ public class Item { // } } - /** - * This is a map from Java-only enchantments to their translation keys so that we can - * map these enchantments to Bedrock clients, since they don't actually exist there. - */ - private static final Map ENCHANTMENT_TRANSLATION_KEYS = Map.of( - Enchantment.JavaEnchantment.SWEEPING_EDGE, "enchantment.minecraft.sweeping", - Enchantment.JavaEnchantment.DENSITY, "enchantment.minecraft.density", - Enchantment.JavaEnchantment.BREACH, "enchantment.minecraft.breach", - Enchantment.JavaEnchantment.WIND_BURST, "enchantment.minecraft.wind_burst"); - protected final @Nullable NbtMap remapEnchantment(GeyserSession session, int enchantId, int level, BedrockItemBuilder builder) { - // TODO verify - // TODO streamline Enchantment process - Enchantment.JavaEnchantment enchantment = Enchantment.JavaEnchantment.of(enchantId); - String translationKey = ENCHANTMENT_TRANSLATION_KEYS.get(enchantment); - if (translationKey != null) { - String enchantmentTranslation = MinecraftLocale.getLocaleString(translationKey, session.locale()); - addJavaOnlyEnchantment(session, builder, enchantmentTranslation, level); - return null; - } + Enchantment enchantment = session.getRegistryCache().enchantments().byId(enchantId); if (enchantment == null) { GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + enchantId); return null; } + BedrockEnchantment bedrockEnchantment = enchantment.bedrockEnchantment(); + if (bedrockEnchantment == null) { + String enchantmentTranslation = MinecraftLocale.getLocaleString(enchantment.description(), session.locale()); + addJavaOnlyEnchantment(session, builder, enchantmentTranslation, level); + return null; + } + return NbtMap.builder() - .putShort("id", (short) Enchantment.valueOf(enchantment.name()).ordinal()) + .putShort("id", (short) bedrockEnchantment.ordinal()) .putShort("lvl", (short) level) .build(); } @@ -260,7 +250,7 @@ public class Item { private void addJavaOnlyEnchantment(GeyserSession session, BedrockItemBuilder builder, String enchantmentName, int level) { String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale()); - builder.getOrCreateLore().add(ChatColor.RESET + ChatColor.GRAY + enchantmentName + " " + lvlTranslation); + builder.getOrCreateLore().add(0, ChatColor.RESET + ChatColor.GRAY + enchantmentName + " " + lvlTranslation); } /* Translation methods end */ 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 54d013140..c6980efd1 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -25,12 +25,6 @@ package org.geysermc.geyser.registry; -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 org.geysermc.mcprotocollib.network.packet.Packet; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -43,7 +37,6 @@ import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.loader.*; @@ -51,7 +44,6 @@ import org.geysermc.geyser.registry.populator.ItemRegistryPopulator; import org.geysermc.geyser.registry.populator.PacketRegistryPopulator; import org.geysermc.geyser.registry.populator.RecipeRegistryPopulator; import org.geysermc.geyser.registry.provider.ProviderSupplier; -import org.geysermc.geyser.registry.type.EnchantmentData; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ParticleMapping; import org.geysermc.geyser.registry.type.SoundMapping; @@ -59,6 +51,12 @@ import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.event.LevelEventTranslator; import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; +import org.geysermc.mcprotocollib.network.packet.Packet; +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.*; @@ -102,11 +100,6 @@ public final class Registries { */ public static final VersionedRegistry>> CRAFTING_DATA = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); - /** - * A registry holding data of all the known enchantments. - */ - public static final SimpleMappedRegistry ENCHANTMENTS; - /** * A map containing all entity types and their respective Geyser definitions */ @@ -127,7 +120,10 @@ public final class Registries { */ public static final PacketTranslatorRegistry JAVA_PACKET_TRANSLATORS = PacketTranslatorRegistry.create(); - public static final SimpleRegistry> JAVA_ITEMS = SimpleRegistry.create(RegistryLoaders.empty(ArrayList::new)); + /** + * A registry containing all Java items ordered by their network ID. + */ + public static final ListRegistry JAVA_ITEMS = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); public static final SimpleMappedRegistry JAVA_ITEM_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); @@ -190,7 +186,6 @@ public final class Registries { // Create registries that require other registries to load first POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); - ENCHANTMENTS = SimpleMappedRegistry.create("mappings/enchantments.json", EnchantmentRegistryLoader::new); // Remove unneeded client generation data from NbtMapBuilder NbtMapBuilder biomesNbt = NbtMap.builder(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java deleted file mode 100644 index 8a0fb1f40..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java +++ /dev/null @@ -1,86 +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.registry.loader; - -import com.fasterxml.jackson.databind.JsonNode; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.EnchantmentData; - -import java.io.InputStream; -import java.util.EnumMap; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.Map; - -public class EnchantmentRegistryLoader implements RegistryLoader> { - @Override - public Map load(String input) { - JsonNode enchantmentsNode; - try (InputStream enchantmentsStream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input)) { - enchantmentsNode = GeyserImpl.JSON_MAPPER.readTree(enchantmentsStream); - } catch (Exception e) { - throw new AssertionError("Unable to load enchantment data", e); - } - - Map enchantments = new EnumMap<>(JavaEnchantment.class); - Iterator> it = enchantmentsNode.fields(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - JavaEnchantment key = JavaEnchantment.getByJavaIdentifier(entry.getKey()); - JsonNode node = entry.getValue(); - int rarityMultiplier = node.get("anvil_cost").asInt(); - int maxLevel = node.get("max_level").asInt(); - - EnumSet incompatibleEnchantments = EnumSet.noneOf(JavaEnchantment.class); - JsonNode incompatibleEnchantmentsNode = node.get("incompatible_enchantments"); - if (incompatibleEnchantmentsNode != null) { - for (JsonNode incompatibleNode : incompatibleEnchantmentsNode) { - incompatibleEnchantments.add(JavaEnchantment.getByJavaIdentifier(incompatibleNode.textValue())); - } - } - - IntSet validItems = new IntOpenHashSet(); - for (JsonNode itemNode : node.get("valid_items")) { - String javaIdentifier = itemNode.textValue(); - Item item = Registries.JAVA_ITEM_IDENTIFIERS.get(javaIdentifier); - if (item != null) { - validItems.add(item.javaId()); - } else { - throw new NullPointerException("No item entry exists for java identifier: " + javaIdentifier); - } - } - - EnchantmentData enchantmentData = new EnchantmentData(rarityMultiplier, maxLevel, incompatibleEnchantments, validItems); - enchantments.put(key, enchantmentData); - } - return enchantments; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java b/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java index 970e128a4..d341cd9e3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.registry.type; import it.unimi.dsi.fastutil.ints.IntSet; -import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment; +import org.geysermc.geyser.inventory.item.BedrockEnchantment.JavaEnchantment; import java.util.Set; 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 9543c7943..fc487b17e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1307,7 +1307,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { */ public void useItem(Hand hand) { sendDownstreamGamePacket(new ServerboundUseItemPacket( - hand, worldCache.nextPredictionSequence(), playerEntity.getPitch(), playerEntity.getYaw())); + hand, worldCache.nextPredictionSequence(), playerEntity.getYaw(), playerEntity.getPitch())); } /** 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 a9b14fdc0..fe970ee2b 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 @@ -38,7 +38,7 @@ 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.recipe.TrimRecipe; -import org.geysermc.geyser.item.Enchantment; +import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.PaintingType; import org.geysermc.geyser.session.GeyserSession; 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 95f5c1cc3..335e940f4 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 @@ -25,47 +25,40 @@ package org.geysermc.geyser.session.cache; -import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.IntArrays; +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.util.Ordered; import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import javax.annotation.ParametersAreNonnullByDefault; -import java.util.EnumMap; -import java.util.HashMap; +import java.util.Arrays; 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. - * - * This system is designed for easy extensibility - just add an enum to {@link BlockTag} or {@link ItemTag}. */ @ParametersAreNonnullByDefault public final class TagCache { - // Put these here so the enums can load without a static map - public static final Map ALL_BLOCK_TAGS = new HashMap<>(); - public static final Map ALL_ITEM_TAGS = new HashMap<>(); - - private final Map blocks = new EnumMap<>(BlockTag.class); - private final Map items = new EnumMap<>(ItemTag.class); + 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()][]; public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) { Map blockTags = packet.getTags().get("minecraft:block"); - this.blocks.clear(); - ALL_BLOCK_TAGS.forEach((location, tag) -> { - int[] values = blockTags.get(location); - if (values != null) { - this.blocks.put(tag, IntList.of(values)); - } else { - session.getGeyser().getLogger().debug("Block tag not found from server: " + location); - } - }); + loadTags("Block", blockTags, ALL_BLOCK_TAGS, this.blocks); // Hack btw GeyserLogger logger = session.getGeyser().getLogger(); @@ -77,15 +70,7 @@ public final class TagCache { } Map itemTags = packet.getTags().get("minecraft:item"); - this.items.clear(); - ALL_ITEM_TAGS.forEach((location, tag) -> { - int[] values = itemTags.get(location); - if (values != null) { - this.items.put(tag, IntList.of(values)); - } else { - session.getGeyser().getLogger().debug("Item tag not found from server: " + location); - } - }); + loadTags("Item", itemTags, ALL_ITEM_TAGS, this.items); // Hack btw boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1; @@ -93,17 +78,31 @@ public final class TagCache { if (logger.isDebug()) { logger.debug("Emulating post 1.13 villager logic for " + session.bedrockUsername() + "? " + emulatePost1_13Logic); } + + Map enchantmentTags = packet.getTags().get("minecraft:enchantment"); + loadTags("Enchantment", enchantmentTags, ALL_ENCHANTMENT_TAGS, this.enchantments); + } + + private void loadTags(String type, Map packetTags, Map allTags, int[][] localValues) { + Arrays.fill(localValues, IntArrays.EMPTY_ARRAY); + allTags.forEach((location, tag) -> { + int[] values = packetTags.get(location); + if (values != null) { + if (values.length != 0) { + localValues[tag.ordinal()] = values; + } + } else { + GeyserImpl.getInstance().getLogger().debug(type + " tag not found from server: " + location); + } + }); } /** * @return true if the block tag is present and contains this block mapping's Java ID. */ public boolean is(BlockTag tag, Block block) { - IntList values = this.blocks.get(tag); - if (values != null) { - return values.contains(block.javaId()); - } - return false; + int[] values = this.blocks[tag.ordinal()]; + return contains(values, block.javaId()); } /** @@ -117,9 +116,19 @@ public final class TagCache { * @return true if the item tag is present and contains this item's Java ID. */ public boolean is(ItemTag tag, Item item) { - IntList values = this.items.get(tag); - if (values != null) { - return values.contains(item.javaId()); + int[] values = this.items[tag.ordinal()]; + return contains(values, item.javaId()); + } + + public int[] get(EnchantmentTag tag) { + return this.enchantments[tag.ordinal()]; + } + + private static boolean contains(int[] array, int i) { + for (int item : array) { + if (item == i) { + return true; + } } return false; } 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 7017ad55c..32d708eca 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,24 +25,212 @@ package org.geysermc.geyser.session.cache.tags; -import org.geysermc.geyser.session.cache.TagCache; +import org.geysermc.geyser.util.Ordered; -public enum BlockTag { - LEAVES("leaves"), - WOOL("wool"), - AXE_EFFECTIVE("mineable/axe"), - HOE_EFFECTIVE("mineable/hoe"), - PICKAXE_EFFECTIVE("mineable/pickaxe"), - SHOVEL_EFFECTIVE("mineable/shovel"), - NEEDS_STONE_TOOL("needs_stone_tool"), - NEEDS_IRON_TOOL("needs_iron_tool"), - NEEDS_DIAMOND_TOOL("needs_diamond_tool"); +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unused") +public final class BlockTag implements Ordered { + public static final Map ALL_BLOCK_TAGS = new HashMap<>(); + + 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 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 final int id; - BlockTag(String identifier) { + 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) { - TagCache.ALL_BLOCK_TAGS.put("minecraft:" + name, tag); + ALL_BLOCK_TAGS.put(("minecraft:" + name).intern(), tag); } } 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 new file mode 100644 index 000000000..3c5446adc --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/EnchantmentTag.java @@ -0,0 +1,89 @@ +/* + * 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 org.geysermc.geyser.util.Ordered; + +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unused") +public final class EnchantmentTag implements Ordered { + public static final Map ALL_ENCHANTMENT_TAGS = new HashMap<>(); + + 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 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(("minecraft:" + name).intern(), tag); + } +} 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 f064d0763..e1fbf4634 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,44 +25,176 @@ package org.geysermc.geyser.session.cache.tags; -import org.geysermc.geyser.session.cache.TagCache; +import org.geysermc.geyser.util.Ordered; -public enum ItemTag { - AXOLOTL_FOOD("axolotl_food"), - CREEPER_IGNITERS("creeper_igniters"), - FISHES("fishes"), - FOX_FOOD("fox_food"), - PIGLIN_LOVED("piglin_loved"), - SMALL_FLOWERS("small_flowers"), - SNIFFER_FOOD("sniffer_food"), - PIGLIN_FOOD("piglin_food"), - COW_FOOD("cow_food"), - GOAT_FOOD("goat_food"), - SHEEP_FOOD("sheep_food"), - WOLF_FOOD("wolf_food"), - CAT_FOOD("cat_food"), - HORSE_FOOD("horse_food"), - CAMEL_FOOD("camel_food"), - ARMADILLO_FOOD("armadillo_food"), - BEE_FOOD("bee_food"), - CHICKEN_FOOD("chicken_food"), - FROG_FOOD("frog_food"), - HOGLIN_FOOD("hoglin_food"), - LLAMA_FOOD("llama_food"), - OCELOT_FOOD("ocelot_food"), - PANDA_FOOD("panda_food"), - PIG_FOOD("pig_food"), - RABBIT_FOOD("rabbit_food"), - STRIDER_FOOD("strider_food"), - TURTLE_FOOD("turtle_food"), - PARROT_FOOD("parrot_food"), - PARROT_POISONOUS_FOOD("parrot_poisonous_food"); +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unused") +public final class ItemTag implements Ordered { + public static final Map ALL_ITEM_TAGS = new HashMap<>(); + + 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 final int id; - ItemTag(String identifier) { + 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) { - TagCache.ALL_ITEM_TAGS.put("minecraft:" + name, tag); + ALL_ITEM_TAGS.put(("minecraft:" + name).intern(), tag); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java index e1407346a..b51d86d13 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java @@ -36,15 +36,14 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse; import org.cloudburstmc.protocol.bedrock.packet.PlayerEnchantOptionsPacket; import org.geysermc.geyser.inventory.*; -import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import java.util.Arrays; -import java.util.Locale; public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator { public EnchantingInventoryTranslator() { @@ -73,16 +72,16 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla // The Bedrock index might need changed, so let's look it up and see. int bedrockIndex = value; if (bedrockIndex != -1) { - Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + Enchantment.JavaEnchantment.of(bedrockIndex).name().toLowerCase(Locale.ROOT)); - if (enchantment != null) { + Enchantment enchantment = session.getRegistryCache().enchantments().byId(value); + if (enchantment != null && enchantment.bedrockEnchantment() != null) { // Convert the Java enchantment index to Bedrock's - bedrockIndex = enchantment.ordinal(); + bedrockIndex = enchantment.bedrockEnchantment().ordinal(); } else { // There is no Bedrock enchantment equivalent bedrockIndex = -1; } } - enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setEnchantIndex(value, bedrockIndex); + enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setEnchantIndex(bedrockIndex); break; case 7: case 8: diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 89c50b12f..1ecc5bf82 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -26,11 +26,6 @@ package org.geysermc.geyser.translator.protocol.java; import com.google.common.base.Suppliers; -import org.geysermc.mcprotocollib.protocol.data.game.command.CommandNode; -import org.geysermc.mcprotocollib.protocol.data.game.command.CommandParser; -import org.geysermc.mcprotocollib.protocol.data.game.command.properties.ResourceProperties; -import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCommandsPacket; import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -46,13 +41,18 @@ import org.cloudburstmc.protocol.bedrock.packet.AvailableCommandsPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.java.ServerDefineCommandsEvent; import org.geysermc.geyser.command.GeyserCommandManager; -import org.geysermc.geyser.inventory.item.Enchantment; +import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; 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.EntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.command.CommandNode; +import org.geysermc.mcprotocollib.protocol.data.game.command.CommandParser; +import org.geysermc.mcprotocollib.protocol.data.game.command.properties.ResourceProperties; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCommandsPacket; import java.util.*; import java.util.function.Supplier; @@ -267,7 +267,7 @@ public class JavaCommandsTranslator extends PacketTranslator ATTRIBUTES; - case "minecraft:enchantment" -> Enchantment.JavaEnchantment.ALL_JAVA_IDENTIFIERS; + case "minecraft:enchantment" -> context.getEnchantments(); case "minecraft:entity_type" -> context.getEntityTypes(); case "minecraft:mob_effect" -> ALL_EFFECT_IDENTIFIERS; case "minecraft:worldgen/biome" -> tags ? context.getBiomesWithTags() : context.getBiomes(); @@ -292,6 +292,7 @@ public class JavaCommandsTranslator extends PacketTranslator session.getTagCache().is(BlockTag.AXE_EFFECTIVE, block); - case "hoe" -> session.getTagCache().is(BlockTag.HOE_EFFECTIVE, block); - case "pickaxe" -> session.getTagCache().is(BlockTag.PICKAXE_EFFECTIVE, block); + case "axe" -> session.getTagCache().is(BlockTag.MINEABLE_AXE, block); + case "hoe" -> session.getTagCache().is(BlockTag.MINEABLE_HOE, block); + case "pickaxe" -> session.getTagCache().is(BlockTag.MINEABLE_PICKAXE, block); case "shears" -> session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); - case "shovel" -> session.getTagCache().is(BlockTag.SHOVEL_EFFECTIVE, block); + case "shovel" -> session.getTagCache().is(BlockTag.MINEABLE_SHOVEL, block); case "sword" -> block == Blocks.COBWEB; default -> { session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType); @@ -145,7 +145,7 @@ public final class BlockUtils { toolCanBreak = canToolTierBreakBlock(session, block, toolTier); } - int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY); + int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(session, components, BedrockEnchantment.EFFICIENCY); int hasteLevel = 0; int miningFatigueLevel = 0; @@ -160,7 +160,7 @@ public final class BlockUtils { boolean waterInEyes = session.getCollisionManager().isWaterInEyes(); boolean insideOfWaterWithoutAquaAffinity = waterInEyes && - ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY) < 1; + ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1; return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index c9d9903d4..bbb64a41e 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -27,17 +27,26 @@ package org.geysermc.geyser.util; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.inventory.item.Enchantment; +import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.enchantment.Enchantment; +import org.geysermc.geyser.item.enchantment.EnchantmentComponent; import org.geysermc.geyser.item.type.FishingRodItem; import org.geysermc.geyser.item.type.Item; +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.ItemEnchantments; -public class ItemUtils { +import java.util.Map; - public static int getEnchantmentLevel(@Nullable DataComponents components, Enchantment.JavaEnchantment enchantment) { +public final class ItemUtils { + + /** + * Cheap hack. Proper solution is to read the enchantment effects. + */ + @Deprecated + public static int getEnchantmentLevel(GeyserSession session, @Nullable DataComponents components, BedrockEnchantment bedrockEnchantment) { if (components == null) { return 0; } @@ -47,7 +56,32 @@ public class ItemUtils { return 0; } - return enchantmentData.getEnchantments().getOrDefault(enchantment.ordinal(), 0); + for (Map.Entry entry : enchantmentData.getEnchantments().entrySet()) { + Enchantment enchantment = session.getRegistryCache().enchantments().byId(entry.getKey()); + if (enchantment.bedrockEnchantment() == bedrockEnchantment) { + return entry.getValue(); + } + } + return 0; + } + + public static boolean hasEffect(GeyserSession session, @Nullable DataComponents components, EnchantmentComponent component) { + if (components == null) { + return false; + } + + ItemEnchantments enchantmentData = components.get(DataComponentType.ENCHANTMENTS); + if (enchantmentData == null) { + return false; + } + + for (Integer id : enchantmentData.getEnchantments().keySet()) { + Enchantment enchantment = session.getRegistryCache().enchantments().byId(id); + if (enchantment.effects().contains(component)) { + return true; + } + } + return false; } /** @@ -73,4 +107,7 @@ public class ItemUtils { } return components.get(DataComponentType.CUSTOM_NAME); } + + private ItemUtils() { + } } diff --git a/core/src/main/java/org/geysermc/geyser/item/Enchantment.java b/core/src/main/java/org/geysermc/geyser/util/Ordered.java similarity index 55% rename from core/src/main/java/org/geysermc/geyser/item/Enchantment.java rename to core/src/main/java/org/geysermc/geyser/util/Ordered.java index 506467afd..08ff5df72 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Enchantment.java +++ b/core/src/main/java/org/geysermc/geyser/util/Ordered.java @@ -23,25 +23,11 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.item; - -import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; +package org.geysermc.geyser.util; /** - * @param anvilCost also as a rarity multiplier + * Represents anything that could be tracked like a enum, without also creating a name and enum-wide array. */ -public record Enchantment(String supportedItemsTag, int maxLevel, int anvilCost, @Nullable String exclusiveSetTag) { - - // Implementation note: I have a feeling the tags can be a list of items, because in vanilla they're HolderSet classes. - // I'm not sure how that's wired over the network, so we'll put it off. - public static Enchantment read(RegistryEntry entry) { - NbtMap data = entry.getData(); - String supportedItems = data.getString("supported_items"); - int maxLevel = data.getInt("max_level"); - int anvilCost = data.getInt("anvil_cost"); - String exclusiveSet = data.getString("exclusive_set", null); - return new Enchantment(supportedItems, maxLevel, anvilCost, exclusiveSet); - } +public interface Ordered { + int ordinal(); } diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 88e50df10..1f1d5ce8c 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 88e50df1008916c266428ac11f76f07dc24638c5 +Subproject commit 1f1d5ce8c482dac142f13e95e19368e3f36de144 From 3ead9e94aa3aefd35db170027f1c8eff240f30b6 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:48:45 -0400 Subject: [PATCH 183/897] More unneeded classes --- .../inventory/item/BedrockEnchantment.java | 48 ------------------- .../geyser/registry/type/EnchantmentData.java | 35 -------------- 2 files changed, 83 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java index a9125421e..6d3fdbc27 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java @@ -95,52 +95,4 @@ public enum BedrockEnchantment { } return null; } - - /** - * Enchantments classified by their Java index - */ - public enum JavaEnchantment { - PROTECTION, - FIRE_PROTECTION, - FEATHER_FALLING, - BLAST_PROTECTION, - PROJECTILE_PROTECTION, - RESPIRATION, - AQUA_AFFINITY, - THORNS, - DEPTH_STRIDER, - FROST_WALKER, - BINDING_CURSE, - SOUL_SPEED, - SWIFT_SNEAK, - SHARPNESS, - SMITE, - BANE_OF_ARTHROPODS, - KNOCKBACK, - FIRE_ASPECT, - LOOTING, - SWEEPING_EDGE, - EFFICIENCY, - SILK_TOUCH, - UNBREAKING, - FORTUNE, - POWER, - PUNCH, - FLAME, - INFINITY, - LUCK_OF_THE_SEA, - LURE, - LOYALTY, - IMPALING, - RIPTIDE, - CHANNELING, - MULTISHOT, - QUICK_CHARGE, - PIERCING, - DENSITY, - BREACH, - WIND_BURST, - MENDING, - VANISHING_CURSE; - } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java b/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java deleted file mode 100644 index d341cd9e3..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java +++ /dev/null @@ -1,35 +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.registry.type; - -import it.unimi.dsi.fastutil.ints.IntSet; -import org.geysermc.geyser.inventory.item.BedrockEnchantment.JavaEnchantment; - -import java.util.Set; - -public record EnchantmentData(int rarityMultiplier, int maxLevel, Set incompatibleEnchantments, - IntSet validItems) { -} From 087322f6cd9b2e61979c5561ab59a795e4ecd3a6 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 4 Jun 2024 00:01:59 -0400 Subject: [PATCH 184/897] Small set optimization --- .../org/geysermc/geyser/item/enchantment/Enchantment.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 41cc36894..8d1d92f6c 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 @@ -66,16 +66,13 @@ public record Enchantment(String identifier, } private static Set readEnchantmentComponents(NbtMap effects) { - if (effects.isEmpty()) { - return Collections.emptySet(); - } Set components = new HashSet<>(); for (Map.Entry entry : effects.entrySet()) { switch (entry.getKey()) { case "minecraft:prevent_armor_change" -> components.add(EnchantmentComponent.PREVENT_ARMOR_CHANGE); } } - return components; + return Set.copyOf(components); // Also ensures any empty sets are consolidated } private static String readDescription(NbtMap tag) { From 688b642520fa8c14c09667003f0d61dd1c552044 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 4 Jun 2024 22:14:42 +0200 Subject: [PATCH 185/897] Ignore PurchaseReceiptPacket (#4719) --- .../main/java/org/geysermc/geyser/network/CodecProcessor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6bd767fb7..b91f8d7dc 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -232,8 +232,8 @@ class CodecProcessor { .updateSerializer(CreatePhotoPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(NpcRequestPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(PhotoInfoRequestPacket.class, ILLEGAL_SERIALIZER) - // Illegal unused serverbound packets for featured servers - .updateSerializer(PurchaseReceiptPacket.class, ILLEGAL_SERIALIZER) + // Unused serverbound packets for featured servers, which is for some reason still occasionally sent + .updateSerializer(PurchaseReceiptPacket.class, IGNORED_SERIALIZER) // Illegal unused serverbound packets that are deprecated .updateSerializer(ClientCheatAbilityPacket.class, ILLEGAL_SERIALIZER) // Illegal unusued serverbound packets that relate to unused features From 42ae9eba559f947e1b4fdd15c2ff0f47f4cc26bb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:09:57 -0400 Subject: [PATCH 186/897] Fix air bubbles for Bedrock 1.21 --- .../entity/type/player/SessionPlayerEntity.java | 12 +++++++++++- .../geyser/network/UpstreamPacketHandler.java | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) 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 44b28ceaa..ad6729c42 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 @@ -31,9 +31,11 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; 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.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.DimensionUtils; @@ -65,6 +67,8 @@ public class SessionPlayerEntity extends PlayerEntity { @Getter private boolean isRidingInFront; + private int lastAirSupply = getMaxAir(); + public SessionPlayerEntity(GeyserSession session) { super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null); @@ -159,7 +163,13 @@ public class SessionPlayerEntity extends PlayerEntity { @Override protected void setAirSupply(int amount) { - if (amount == getMaxAir()) { + // Seemingly required to be sent as of Bedrock 1.21. Otherwise, bubbles will appear as empty + // Also, this changes how the air bubble graphics/sounds are presented. Breathing on means sound effects and + // the bubbles visually pop + setFlag(EntityFlag.BREATHING, amount >= this.lastAirSupply); + this.lastAirSupply = amount; + + if (amount == getMaxAir() && GameProtocol.isPre1_21_0(session)) { super.setAirSupply(0); // Hide the bubble counter from the UI for the player } else { super.setAirSupply(amount); 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 23ab1697f..c7aabb806 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -132,6 +132,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } session.getUpstream().getSession().setCodec(packetCodec); + // FIXME temporary until 1.20.80 is dropped + session.getPlayerEntity().resetAir(); return true; } From fcdd1b91a1bcf3b9277927d13c09bf0959e3ad23 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 4 Jun 2024 22:47:31 -0400 Subject: [PATCH 187/897] New banner patterns --- .../org/geysermc/geyser/inventory/item/BannerPattern.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java index 442690d7d..b6cc2c206 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java @@ -72,7 +72,9 @@ public enum BannerPattern { SKULL("sku"), FLOWER("flo"), MOJANG("moj"), - PIGLIN("pig"); + PIGLIN("pig"), + FLOW("flw"), + GUSTER("gus"); private static final BannerPattern[] VALUES = values(); From 4ee9dd5d1708858c7842068b55187d7cba36fe4e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 5 Jun 2024 16:45:11 -0400 Subject: [PATCH 188/897] New potions and merge potion enums --- .../geyser/entity/type/ArrowEntity.java | 9 +- .../geyser/inventory/item/Potion.java | 137 +++++++++++----- .../inventory/item/TippedArrowPotion.java | 153 ------------------ .../geysermc/geyser/item/type/ArrowItem.java | 10 +- .../geyser/item/type/TippedArrowItem.java | 8 +- 5 files changed, 104 insertions(+), 213 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java index 1ee706811..ba1241434 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.inventory.item.TippedArrowPotion; +import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; @@ -46,12 +46,7 @@ public class ArrowEntity extends AbstractArrowEntity { if (potionColor == -1) { dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0); } else { - TippedArrowPotion potion = TippedArrowPotion.getByJavaColor(potionColor); - if (potion != null && potion.getJavaColor() != -1) { - dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) potion.getBedrockId()); - } else { - dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0); - } + dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, Potion.toTippedArrowId(potionColor)); } } } 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 86c19de80..c4d20c623 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 @@ -34,57 +34,68 @@ import java.util.Locale; @Getter public enum Potion { - WATER(0), - MUNDANE(1), - THICK(3), - AWKWARD(4), - NIGHT_VISION(5), - LONG_NIGHT_VISION(6), - INVISIBILITY(7), - LONG_INVISIBILITY(8), - LEAPING(9), - LONG_LEAPING(10), - STRONG_LEAPING(11), - FIRE_RESISTANCE(12), - LONG_FIRE_RESISTANCE(13), - SWIFTNESS(14), - LONG_SWIFTNESS(15), - STRONG_SWIFTNESS(16), - SLOWNESS(17), - LONG_SLOWNESS(18), - STRONG_SLOWNESS(42), - TURTLE_MASTER(37), - LONG_TURTLE_MASTER(38), - STRONG_TURTLE_MASTER(39), - WATER_BREATHING(19), - LONG_WATER_BREATHING(20), - HEALING(21), - STRONG_HEALING(22), - HARMING(23), - STRONG_HARMING(24), - POISON(25), - LONG_POISON(26), - STRONG_POISON(27), - REGENERATION(28), - LONG_REGENERATION(29), - STRONG_REGENERATION(30), - STRENGTH(31), - LONG_STRENGTH(32), - STRONG_STRENGTH(33), - WEAKNESS(34), - LONG_WEAKNESS(35), - LUCK(2), //does not exist - SLOW_FALLING(40), - LONG_SLOW_FALLING(41); + WATER(0, ArrowParticleColors.NONE), + MUNDANE(1, ArrowParticleColors.NONE), // 2 is extended? + THICK(3, ArrowParticleColors.NONE), + AWKWARD(4, ArrowParticleColors.NONE), + NIGHT_VISION(5, ArrowParticleColors.NIGHT_VISION), + LONG_NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION), + INVISIBILITY(7, ArrowParticleColors.INVISIBILITY), + LONG_INVISIBILITY(8, ArrowParticleColors.INVISIBILITY), + LEAPING(9, ArrowParticleColors.LEAPING), + LONG_LEAPING(10, ArrowParticleColors.LEAPING), + STRONG_LEAPING(11, ArrowParticleColors.LEAPING), + FIRE_RESISTANCE(12, ArrowParticleColors.FIRE_RESISTANCE), + LONG_FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE), + SWIFTNESS(14, ArrowParticleColors.SWIFTNESS), + LONG_SWIFTNESS(15, ArrowParticleColors.SWIFTNESS), + STRONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS), + SLOWNESS(17, ArrowParticleColors.SLOWNESS), + LONG_SLOWNESS(18, ArrowParticleColors.SLOWNESS), + STRONG_SLOWNESS(42, ArrowParticleColors.SLOWNESS), + TURTLE_MASTER(37, ArrowParticleColors.TURTLE_MASTER), + LONG_TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER), + STRONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER), + WATER_BREATHING(19, ArrowParticleColors.WATER_BREATHING), + LONG_WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING), + HEALING(21, ArrowParticleColors.HEALING), + STRONG_HEALING(22, ArrowParticleColors.HEALING), + HARMING(23, ArrowParticleColors.HARMING), + STRONG_HARMING(24, ArrowParticleColors.HARMING), + POISON(25, ArrowParticleColors.POISON), + LONG_POISON(26, ArrowParticleColors.POISON), + STRONG_POISON(27, ArrowParticleColors.POISON), + REGENERATION(28, ArrowParticleColors.REGENERATION), + LONG_REGENERATION(29, ArrowParticleColors.REGENERATION), + STRONG_REGENERATION(30, ArrowParticleColors.REGENERATION), + STRENGTH(31, ArrowParticleColors.STRENGTH), + LONG_STRENGTH(32, ArrowParticleColors.STRENGTH), + STRONG_STRENGTH(33, ArrowParticleColors.STRENGTH), + WEAKNESS(34, ArrowParticleColors.WEAKNESS), + LONG_WEAKNESS(35, ArrowParticleColors.WEAKNESS), + LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock + SLOW_FALLING(40, ArrowParticleColors.SLOW_FALLING), + LONG_SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING), + WIND_CHARGING(43, ArrowParticleColors.WIND_CHARGING), + WEAVING(44, ArrowParticleColors.WEAVING), + OOZING(45, ArrowParticleColors.OOZING), + INFESTATION(46, ArrowParticleColors.INFESTATION); public static final Potion[] VALUES = values(); private final String javaIdentifier; private final short bedrockId; + private final int javaColor; - Potion(int bedrockId) { + Potion(int bedrockId, int javaColor) { this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH); this.bedrockId = (short) bedrockId; + this.javaColor = javaColor; + } + + public int tippedArrowId() { + // +1 likely to offset 0 as nothing? + return this.bedrockId + 1; } public PotionContents toComponent() { @@ -106,4 +117,44 @@ public enum Potion { } return null; } + + public static @Nullable Potion getByTippedArrowDamage(int bedrockId) { + return getByBedrockId(bedrockId - 1); + } + + public static byte toTippedArrowId(int javaParticleColor) { + for (Potion potion : VALUES) { + if (potion.javaColor == javaParticleColor) { + return (byte) (potion.bedrockId + 1); + } + } + return (byte) 0; + } + + /** + * For tipped arrow usage + */ + private static final class ArrowParticleColors { + static final int NONE = 1; + static final int NIGHT_VISION = 2039713; + static final int INVISIBILITY = 8356754; + static final int LEAPING = 2293580; + static final int FIRE_RESISTANCE = 14981690; + static final int SWIFTNESS = 8171462; + static final int SLOWNESS = 5926017; + static final int TURTLE_MASTER = 7691106; + static final int WATER_BREATHING = 3035801; + static final int HEALING = 16262179; + static final int HARMING = 4393481; + static final int POISON = 5149489; + static final int REGENERATION = 13458603; + static final int STRENGTH = 9643043; + static final int WEAKNESS = 4738376; + static final int LUCK = 3381504; + static final int SLOW_FALLING = 16773073; + static final int WIND_CHARGING = 12438015; + static final int WEAVING = 7891290; + static final int OOZING = 10092451; + static final int INFESTATION = 9214860; + } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java deleted file mode 100644 index b849e07e2..000000000 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java +++ /dev/null @@ -1,153 +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.inventory.item; - -import lombok.Getter; -import org.checkerframework.checker.nullness.qual.Nullable; - -import java.util.Locale; - -/** - * Potion identifiers and their respective Bedrock IDs used with arrows. - * See here - */ -@Getter -public enum TippedArrowPotion { - WATER(-1, ArrowParticleColors.NONE), // Guessing this based off of the Potion enum. TODO merge? - MUNDANE(2, ArrowParticleColors.NONE), // 3 is extended? - THICK(4, ArrowParticleColors.NONE), - AWKWARD(5, ArrowParticleColors.NONE), - NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION), - LONG_NIGHT_VISION(7, ArrowParticleColors.NIGHT_VISION), - INVISIBILITY(8, ArrowParticleColors.INVISIBILITY), - LONG_INVISIBILITY(9, ArrowParticleColors.INVISIBILITY), - LEAPING(10, ArrowParticleColors.LEAPING), - LONG_LEAPING(11, ArrowParticleColors.LEAPING), - STRONG_LEAPING(12, ArrowParticleColors.LEAPING), - FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE), - LONG_FIRE_RESISTANCE(14, ArrowParticleColors.FIRE_RESISTANCE), - SWIFTNESS(15, ArrowParticleColors.SWIFTNESS), - LONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS), - STRONG_SWIFTNESS(17, ArrowParticleColors.SWIFTNESS), - SLOWNESS(18, ArrowParticleColors.SLOWNESS), - LONG_SLOWNESS(19, ArrowParticleColors.SLOWNESS), - STRONG_SLOWNESS(43, ArrowParticleColors.SLOWNESS), - WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING), - LONG_WATER_BREATHING(21, ArrowParticleColors.WATER_BREATHING), - HEALING(22, ArrowParticleColors.HEALING), - STRONG_HEALING(23, ArrowParticleColors.HEALING), - HARMING(24, ArrowParticleColors.HARMING), - STRONG_HARMING(25, ArrowParticleColors.HARMING), - POISON(26, ArrowParticleColors.POISON), - LONG_POISON(27, ArrowParticleColors.POISON), - STRONG_POISON(28, ArrowParticleColors.POISON), - REGENERATION(29, ArrowParticleColors.REGENERATION), - LONG_REGENERATION(30, ArrowParticleColors.REGENERATION), - STRONG_REGENERATION(31, ArrowParticleColors.REGENERATION), - STRENGTH(32, ArrowParticleColors.STRENGTH), - LONG_STRENGTH(33, ArrowParticleColors.STRENGTH), - STRONG_STRENGTH(34, ArrowParticleColors.STRENGTH), - WEAKNESS(35, ArrowParticleColors.WEAKNESS), - LONG_WEAKNESS(36, ArrowParticleColors.WEAKNESS), - LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock - TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER), - LONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER), - STRONG_TURTLE_MASTER(40, ArrowParticleColors.TURTLE_MASTER), - SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING), - LONG_SLOW_FALLING(42, ArrowParticleColors.SLOW_FALLING); - - private static final TippedArrowPotion[] VALUES = values(); - - private final String javaIdentifier; - private final short bedrockId; - /** - * The Java color associated with this ID. - * Used for looking up Java arrow color entity metadata as Bedrock potion IDs, which is what is used for entities in Bedrock - */ - private final int javaColor; - - TippedArrowPotion(int bedrockId, ArrowParticleColors arrowParticleColor) { - this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH); - this.bedrockId = (short) bedrockId; - this.javaColor = arrowParticleColor.getColor(); - } - - public static @Nullable TippedArrowPotion of(int id) { - if (id >= 0 && id < VALUES.length) { - return VALUES[id]; - } - return null; - } - - public static @Nullable TippedArrowPotion getByBedrockId(int bedrockId) { - for (TippedArrowPotion potion : VALUES) { - if (potion.bedrockId == bedrockId) { - return potion; - } - } - return null; - } - - /** - * @param color the potion color to look up - * @return the tipped arrow potion that most closely resembles that color. - */ - public static @Nullable TippedArrowPotion getByJavaColor(int color) { - for (TippedArrowPotion potion : VALUES) { - if (potion.javaColor == color) { - return potion; - } - } - return null; - } - - private enum ArrowParticleColors { - NONE(-1), - NIGHT_VISION(2039713), - INVISIBILITY(8356754), - LEAPING(2293580), - FIRE_RESISTANCE(14981690), - SWIFTNESS(8171462), - SLOWNESS(5926017), - TURTLE_MASTER(7691106), - WATER_BREATHING(3035801), - HEALING(16262179), - HARMING(4393481), - POISON(5149489), - REGENERATION(13458603), - STRENGTH(9643043), - WEAKNESS(4738376), - LUCK(3381504), - SLOW_FALLING(16773073); - - @Getter - private final int color; - - ArrowParticleColors(int color) { - this.color = color; - } - } -} 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 84c3b1a39..c06a143ac 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 @@ -28,15 +28,13 @@ 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.TippedArrowPotion; +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.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; -import java.util.Collections; - public class ArrowItem extends Item { public ArrowItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); @@ -44,11 +42,11 @@ public class ArrowItem extends Item { @Override public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { - TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); + Potion potion = Potion.getByTippedArrowDamage(itemData.getDamage()); GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); - if (tippedArrowPotion != null) { + if (potion != null) { itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents()); - PotionContents contents = new PotionContents(tippedArrowPotion.ordinal(), -1, Collections.emptyList()); + PotionContents contents = potion.toComponent(); itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, contents); } return itemStack; 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 db33bb584..d9e58eaf9 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 @@ -27,7 +27,7 @@ package org.geysermc.geyser.item.type; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.item.TippedArrowPotion; +import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; @@ -44,11 +44,11 @@ public class TippedArrowItem extends ArrowItem { if (components != null) { PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); if (potionContents != null) { - TippedArrowPotion tippedArrowPotion = TippedArrowPotion.of(potionContents.getPotionId()); - if (tippedArrowPotion != null) { + Potion potion = Potion.getByJavaId(potionContents.getPotionId()); + if (potion != null) { return ItemData.builder() .definition(mapping.getBedrockDefinition()) - .damage(tippedArrowPotion.getBedrockId()) + .damage(potion.tippedArrowId()) .count(count); } GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionContents.getPotionId()); From 3f8739a88fe3b00d8d54a9208fe4239d26dd710f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 5 Jun 2024 16:56:44 -0400 Subject: [PATCH 189/897] New effects --- .../src/main/java/org/geysermc/geyser/util/EntityUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 d11c1f9e4..bfb70a4ed 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -77,6 +77,12 @@ public final class EntityUtils { case BAD_OMEN -> 28; case HERO_OF_THE_VILLAGE -> 29; case DARKNESS -> 30; + case TRIAL_OMEN -> 31; + case WIND_CHARGED -> 32; + case WEAVING -> 33; + case OOZING -> 34; + case INFESTED -> 35; + case RAID_OMEN -> 36; default -> effect.ordinal() + 1; }; } From 8f5d1560a22bab61dea004b2d355c4d4e4e7f0fa Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 6 Jun 2024 18:20:24 -0400 Subject: [PATCH 190/897] Implement Bogged entity --- .../geyser/entity/EntityDefinitions.java | 6 ++ .../type/living/monster/BoggedEntity.java | 73 ++++++++++++++++++ .../type/living/monster/BreezeEntity.java | 44 +++++++++++ .../resources/bedrock/entity_identifiers.dat | Bin 8314 -> 8314 bytes 4 files changed, 123 insertions(+) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BoggedEntity.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java 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 21cc526dd..76c65e9c8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -63,6 +63,7 @@ public final class EntityDefinitions { public static final EntityDefinition BEE; public static final EntityDefinition BLAZE; public static final EntityDefinition BOAT; + public static final EntityDefinition BOGGED; public static final EntityDefinition CAMEL; public static final EntityDefinition CAT; public static final EntityDefinition CAVE_SPIDER; @@ -503,6 +504,11 @@ public final class EntityDefinitions { .height(0.9f).width(0.5f) .addTranslator(MetadataType.BYTE, BatEntity::setBatFlags) .build(); + BOGGED = EntityDefinition.inherited(BoggedEntity::new, mobEntityBase) + .type(EntityType.BOGGED) + .height(1.99f).width(0.6f) + .addTranslator(MetadataType.BOOLEAN, BoggedEntity::setSheared) + .build(); BLAZE = EntityDefinition.inherited(BlazeEntity::new, mobEntityBase) .type(EntityType.BLAZE) .height(1.8f).width(0.6f) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BoggedEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BoggedEntity.java new file mode 100644 index 000000000..806d58ed1 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BoggedEntity.java @@ -0,0 +1,73 @@ +/* + * 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.monster; + +import org.checkerframework.checker.nullness.qual.NonNull; +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.Items; +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.player.Hand; + +import java.util.UUID; + +public class BoggedEntity extends AbstractSkeletonEntity { + private boolean sheared = false; + + public BoggedEntity(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 void setSheared(BooleanEntityMetadata entityMetadata) { + this.sheared = entityMetadata.getPrimitiveValue(); + setFlag(EntityFlag.SHEARED, this.sheared); + } + + @Override + protected @NonNull InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { + if (itemInHand.asItem() == Items.SHEARS && readyForShearing()) { + return InteractiveTag.SHEAR; + } + return super.testMobInteraction(hand, itemInHand); + } + + @Override + protected @NonNull InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { + if (itemInHand.asItem() == Items.SHEARS && readyForShearing()) { + return InteractionResult.SUCCESS; + } + return super.mobInteract(hand, itemInHand); + } + + private boolean readyForShearing() { + return !this.sheared && this.isAlive(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java new file mode 100644 index 000000000..25d466aaf --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java @@ -0,0 +1,44 @@ +/* + * 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.monster; + +import org.cloudburstmc.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; + +import java.util.UUID; + +public class BreezeEntity extends MonsterEntity { + public BreezeEntity(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 void setPose(Pose pose) { + super.setPose(pose); + } +} diff --git a/core/src/main/resources/bedrock/entity_identifiers.dat b/core/src/main/resources/bedrock/entity_identifiers.dat index e7cdeb08e65d446bef173af7cea4bc56d5023df3..95d00c246abac44e32f992549d970a3e650fa440 100644 GIT binary patch delta 890 zcmX|9OGuPa6n5T^`~NflJe;?VlojFYpBWvSmouX?rm0~I3koVo7eZiQ8=;1T7OkS; z10yLCf@tMFvd9qH2t`D-ilJI&M9@aWI`>$v&b{ZJ`+eW}&e<+)msDqy!#X>Cd3OG) z^M(-fi6^lf8$rz>(B9h1xwDkJ5X<3wi@=rW z06xVBuo_L#{TZ%@1TMAa@tJDnpNACPMuEHWK?K|4Xn1{C@d$KAGtBoZ(t{_FEG9h` zye0nmNFO>Qc{IY~s5u25gojWFPuANkxMmjEiY2&o%`adLC;z86LVT1Bs39FsgB3J9 z8fw8bS9b(Q&=C~)5h!3eFp4$5g6TjSt3GNlkmLBVIfpyVc_y7`9>T7_LUn^!@DH)z zqCd+5|M>c-{uCA{rhLQL^-94CUU?Ik^B$*v0%>oCF@Jh;^tXyB&lrN90esNPjCEhj z;_@d`wZAIO9sA+b$4xx$s3jBELU37xCLN%;Q_M=+K0Md#cXkcGx=i z6)akFoLf>73^k>c5vKE|807nsNE4R88PQ7^d2Bi>EM?r;wMRn(a>~uf;9^vR-NET@ zdzG1YZ8}%4+X}c9O5mib;3l0bmL$yT30gV@?~O+#lG`{28>Qv0*6b;XR$ooYm8#F{ zB&Eziw@pcsChGd0Axp-tfBqGD`G&0>5=(kAVM?PADskiIj5^C%G4S(_NyQ6GKR?YF mbW&9$TG|e4fzcXaX=Ryw$unuyCUs<~Nu|D(M9JK4X!;8-wi;dl delta 925 zcmX|AOK1~e5N^^WP4e$1n`iTG)Psn&+07=g-8`G5r7xtV2T#R7oD9-56k>J^M5n*&3yk}ZLcP~J6w*r za~I|om)uva@Wmq7jyLcyAwiF4(6$Qvis^Xc7dV{Ou^Scm){{XsBycFD;YUQ^QSvzM zI_#KDRBJs>xDDa)9@hsh zJi#5Atk!z=S>>Y@ypEJ{Eu!K|K%f*cINdX1ZL%_a^#jb`?q2q7$O0B$j{W9j-gft~ ze_a`5pV{v9Zi-W#A;u_}S1KI)6K*n%cVUfaRk^>RaDk>S&>23-vG*a0g(fgY*35C+ zpT*IKO)J}1kLqIBOZ< z`K213on>cmMzZ From c3994a677be4fb3065db2151c71c24f53faa7308 Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Fri, 7 Jun 2024 00:54:33 +0200 Subject: [PATCH 191/897] Override forward-hostname setting if ViaProxy wildcard domain handling is enabled (#4720) --- .../viaproxy/GeyserViaProxyConfiguration.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java index bf9d6816c..1b82e9f67 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.platform.viaproxy; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import net.raphimc.vialegacy.api.LegacyProtocolVersion; import net.raphimc.viaproxy.ViaProxy; +import net.raphimc.viaproxy.protocoltranslator.viaproxy.ViaProxyConfig; import org.geysermc.geyser.configuration.GeyserJacksonConfiguration; import java.io.File; @@ -50,4 +51,16 @@ public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration { return interval; } + @Override + public RemoteConfiguration getRemote() { + return new RemoteConfiguration() { + + @Override + public boolean isForwardHost() { + return super.isForwardHost() || !ViaProxy.getConfig().getWildcardDomainHandling().equals(ViaProxyConfig.WildcardDomainHandling.NONE); + } + + }; + } + } From 29c9515d55b1bf4dc734b935f905806ca0463414 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:28:38 -0400 Subject: [PATCH 192/897] Re-implement jukebox songs --- .../geyser/item/enchantment/Enchantment.java | 18 ++-- .../geysermc/geyser/level/JukeboxSong.java | 40 +++++++++ .../geyser/session/cache/RegistryCache.java | 3 + .../geyser/session/cache/WorldCache.java | 16 ++++ .../java/level/JavaLevelEventTranslator.java | 90 +++++++++++++------ .../translator/text/MessageTranslator.java | 15 ++++ .../org/geysermc/geyser/util/SoundUtils.java | 3 +- 7 files changed, 141 insertions(+), 44 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java 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 8d1d92f6c..468b88e87 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 @@ -27,13 +27,15 @@ package org.geysermc.geyser.item.enchantment; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.session.cache.tags.EnchantmentTag; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; -import java.util.*; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; /** * @param description only populated if {@link #bedrockEnchantment()} is not null. @@ -59,7 +61,7 @@ public record Enchantment(String identifier, String exclusiveSet = data.getString("exclusive_set", null); EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(exclusiveSet.substring(1)); BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId()); - String description = bedrockEnchantment == null ? readDescription(data) : null; + String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(data) : null; return new Enchantment(entry.getId(), effects, ItemTag.ALL_ITEM_TAGS.get(supportedItems), maxLevel, description, anvilCost, exclusiveSetTag, bedrockEnchantment); @@ -74,14 +76,4 @@ public record Enchantment(String identifier, } return Set.copyOf(components); // Also ensures any empty sets are consolidated } - - private static String readDescription(NbtMap tag) { - NbtMap description = tag.getCompound("description"); - String translate = description.getString("translate", null); - if (translate == null) { - GeyserImpl.getInstance().getLogger().debug("Don't know how to read description! " + tag); - return ""; - } - return translate; - } } diff --git a/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java b/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java new file mode 100644 index 000000000..fd6ce693d --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java @@ -0,0 +1,40 @@ +/* + * 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.level; + +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; + +public record JukeboxSong(String soundEvent, String description) { + + public static JukeboxSong read(RegistryEntry entry) { + NbtMap data = entry.getData(); + String soundEvent = data.getString("sound_event"); + String description = MessageTranslator.deserializeDescription(data); + return new JukeboxSong(soundEvent, description); + } +} 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 fe970ee2b..266a0a418 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,6 +40,7 @@ import org.geysermc.geyser.inventory.item.BannerPattern; 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.JavaRegistry; @@ -76,6 +77,7 @@ public final class RegistryCache { register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry)); register("dimension_type", cache -> cache.dimensions, ($, entry) -> JavaDimension.read(entry)); register("enchantment", cache -> cache.enchantments, ($, entry) -> Enchantment.read(entry)); + register("jukebox_song", cache -> cache.jukeboxSongs, ($, entry) -> JukeboxSong.read(entry)); register("painting_variant", cache -> cache.paintings, ($, entry) -> PaintingType.getByName(entry.getId())); register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); @@ -115,6 +117,7 @@ public final class RegistryCache { */ private final JavaRegistry dimensions = new SimpleJavaRegistry<>(); private final JavaRegistry enchantments = new SimpleJavaRegistry<>(); + private final JavaRegistry jukeboxSongs = new SimpleJavaRegistry<>(); private final JavaRegistry paintings = new SimpleJavaRegistry<>(); private final JavaRegistry trimMaterials = new SimpleJavaRegistry<>(); private final JavaRegistry trimPatterns = new SimpleJavaRegistry<>(); 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 44ec7a6b9..8eb715560 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 @@ -28,8 +28,10 @@ package org.geysermc.geyser.session.cache; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.Setter; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.geysermc.geyser.scoreboard.Scoreboard; @@ -39,6 +41,7 @@ import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import java.util.Iterator; +import java.util.Map; public final class WorldCache { private final GeyserSession session; @@ -61,6 +64,8 @@ public final class WorldCache { private int currentSequence; private final Object2IntMap unverifiedPredictions = new Object2IntOpenHashMap<>(1); + private final Map activeRecords = new Object2ObjectOpenHashMap<>(1); // Assume the average player won't be listening to many records + @Getter @Setter private boolean editingSignOnFront; @@ -185,4 +190,15 @@ public final class WorldCache { } } } + + public void addActiveRecord(Vector3i pos, String bedrockPlaySound) { + this.activeRecords.put(pos, bedrockPlaySound); + } + + // Implementation note: positions aren't removed unless the server calls, but this seems to match 1.21 Java + // client behavior. + @Nullable + public String removeActiveRecord(Vector3i pos) { + return this.activeRecords.remove(pos); + } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index cb8a8e60f..ef0329209 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -25,28 +25,27 @@ package org.geysermc.geyser.translator.protocol.java.level; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; -import org.geysermc.mcprotocollib.protocol.data.game.level.event.*; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.TextPacket; +import org.cloudburstmc.protocol.bedrock.packet.*; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.level.JukeboxSong; import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.type.SoundMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.level.event.LevelEventTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.SoundUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.*; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import java.util.Collections; -import java.util.Locale; import java.util.Set; @Translator(packet = ClientboundLevelEventPacket.class) @@ -60,23 +59,48 @@ public class JavaLevelEventTranslator extends PacketTranslator { - LevelSoundEventPacket levelSoundEvent = new LevelSoundEventPacket(); - levelSoundEvent.setIdentifier(""); - levelSoundEvent.setSound(SoundEvent.STOP_RECORD); - levelSoundEvent.setPosition(pos); - levelSoundEvent.setRelativeVolumeDisabled(false); - levelSoundEvent.setExtraData(-1); - levelSoundEvent.setBabySound(false); - session.sendUpstreamPacket(levelSoundEvent); + String bedrockSound = session.getWorldCache().removeActiveRecord(origin); + if (bedrockSound == null) { + // Vanilla record + LevelSoundEventPacket levelSoundEvent = new LevelSoundEventPacket(); + levelSoundEvent.setIdentifier(""); + levelSoundEvent.setSound(SoundEvent.STOP_RECORD); + levelSoundEvent.setPosition(pos); + levelSoundEvent.setRelativeVolumeDisabled(false); + levelSoundEvent.setExtraData(-1); + levelSoundEvent.setBabySound(false); + session.sendUpstreamPacket(levelSoundEvent); + } else { + // Custom record + StopSoundPacket stopSound = new StopSoundPacket(); + stopSound.setSoundName(bedrockSound); + session.sendUpstreamPacket(stopSound); + } return; } default -> { 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 3507567be..152bf4160 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 @@ -35,6 +35,7 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.CharacterAndFormat; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.packet.TextPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; @@ -424,6 +425,20 @@ public class MessageTranslator { return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); } + /** + * Deserialize an NbtMap provided from a registry into a string. + */ + // This may be a Component in the future. + public static String deserializeDescription(NbtMap tag) { + NbtMap description = tag.getCompound("description"); + String translate = description.getString("translate", null); + if (translate == null) { + GeyserImpl.getInstance().getLogger().debug("Don't know how to read description! " + tag); + return ""; + } + return translate; + } + public static void init() { // no-op } 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 7559347e9..524d241db 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -33,7 +33,6 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -52,7 +51,7 @@ public final class SoundUtils { * @param sound the sound name * @return a sound event from the given sound */ - private static @Nullable SoundEvent toSoundEvent(String sound) { + public static @Nullable SoundEvent toSoundEvent(String sound) { try { return SoundEvent.valueOf(sound.toUpperCase(Locale.ROOT).replace(".", "_")); } catch (Exception ex) { From 79bcc790ce6c4670569f78a819a7eab4f3c613eb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:30:55 -0400 Subject: [PATCH 193/897] Remove Registries.RECORDS --- .../geyser/registry/IntMappedRegistry.java | 122 ------------------ .../geysermc/geyser/registry/Registries.java | 6 - .../populator/ItemRegistryPopulator.java | 5 - 3 files changed, 133 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/IntMappedRegistry.java diff --git a/core/src/main/java/org/geysermc/geyser/registry/IntMappedRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/IntMappedRegistry.java deleted file mode 100644 index 981ed0f8c..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/IntMappedRegistry.java +++ /dev/null @@ -1,122 +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.registry; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.registry.loader.RegistryLoader; - -import java.util.function.Supplier; - -/** - * A mapped registry with an integer as the key. This class is designed to minimize the need for boxing/unboxing keys. - * - * @param the value - */ -public class IntMappedRegistry extends AbstractMappedRegistry> { - protected IntMappedRegistry(I input, RegistryLoader> registryLoader) { - super(input, registryLoader); - } - - /** - * Returns the value registered by the given integer. - * - * @param i the integer - * @return the value registered by the given integer. - */ - public V get(int i) { - return this.mappings.get(i); - } - - @Nullable - @Override - @Deprecated - public V get(Integer key) { - return super.get(key); - } - - /** - * Returns the value registered by the given key or the default value - * specified if null. - * - * @param i the key - * @param defaultValue the default value - * @return the value registered by the given key or the default value - * specified if null. - */ - public V getOrDefault(int i, V defaultValue) { - return this.mappings.getOrDefault(i, defaultValue); - } - - @Override - @Deprecated - public V getOrDefault(Integer key, V defaultValue) { - return super.getOrDefault(key, defaultValue); - } - - /** - * Registers a new value into this registry with the given key. - * - * @param i the key - * @param value the value - * @return a new value into this registry with the given key. - */ - public V register(int i, V value) { - return this.mappings.put(i, value); - } - - @Override - @Deprecated - public V register(Integer key, V value) { - return super.register(key, value); - } - - /** - * Creates a new integer mapped registry with the given {@link RegistryLoader}. The - * input type is not specified here, meaning the loader return type is either - * predefined, or the registry is populated at a later point. - * - * @param registryLoader the registry loader - * @param the input - * @param the map value - * @return a new registry with the given RegistryLoader - */ - public static IntMappedRegistry create(RegistryLoader> registryLoader) { - return new IntMappedRegistry<>(null, registryLoader); - } - - /** - * Creates a new integer mapped registry with the given {@link RegistryLoader} and input. - * - * @param registryLoader the registry loader - * @param the input - * @param the map value - * @return a new registry with the given RegistryLoader supplier - */ - public static IntMappedRegistry create(I input, Supplier>> registryLoader) { - return new IntMappedRegistry<>(input, registryLoader.get()); - } -} 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 c6980efd1..7815768ef 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -149,12 +149,6 @@ public final class Registries { */ public static final VersionedRegistry> RECIPES = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); - /** - * A mapped registry holding the available records, with the ID of the record being the key, and the {@link org.cloudburstmc.protocol.bedrock.data.SoundEvent} - * as the value. - */ - public static final IntMappedRegistry RECORDS = IntMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); - /** * A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys. */ diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 8f515c1cb..e19066462 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -41,7 +41,6 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; -import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; @@ -458,10 +457,6 @@ public class ItemRegistryPopulator { if (javaItem.javaIdentifier().contains("bucket") && !javaItem.javaIdentifier().contains("milk")) { buckets.add(definition); - } else if (javaItem.javaIdentifier().startsWith("minecraft:music_disc_")) { - // The Java record level event uses the item ID as the "key" to play the record - Registries.RECORDS.register(javaItem.javaId(), SoundEvent.valueOf("RECORD_" + - mapping.getBedrockIdentifier().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH))); } mappings.add(mapping); From b7931f8d704f638273bb13215df0077fd144e049 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 6 Jun 2024 23:34:06 +0200 Subject: [PATCH 194/897] Update protocol to suppress packet warnings --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1995a6ada..9ff1f3afd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "3.0.0.Beta2-20240520.153053-5" +protocol = "3.0.0.Beta2-20240606.172607-7" raknet = "1.0.0.CR3-20240416.144209-1" mcauthlib = "e5b0bcc" mcprotocollib = "1.20.6-2-20240520.030045-8" From 9b776b5321b0f98bd5ccbda9a692770f0c52e85f Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:26:59 +0200 Subject: [PATCH 195/897] Fixed remote config being reset everytime when accessed on Geyser-ViaProxy (#4722) --- .../viaproxy/GeyserViaProxyConfiguration.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java index 1b82e9f67..afc46fa6a 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java @@ -34,8 +34,16 @@ import java.io.File; import java.nio.file.Path; @JsonIgnoreProperties(ignoreUnknown = true) +@SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration { + private RemoteConfiguration remote = new RemoteConfiguration() { + @Override + public boolean isForwardHost() { + return super.isForwardHost() || !ViaProxy.getConfig().getWildcardDomainHandling().equals(ViaProxyConfig.WildcardDomainHandling.NONE); + } + }; + @Override public Path getFloodgateKeyPath() { return new File(GeyserViaProxyPlugin.ROOT_FOLDER, this.getFloodgateKeyFile()).toPath(); @@ -53,14 +61,7 @@ public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration { @Override public RemoteConfiguration getRemote() { - return new RemoteConfiguration() { - - @Override - public boolean isForwardHost() { - return super.isForwardHost() || !ViaProxy.getConfig().getWildcardDomainHandling().equals(ViaProxyConfig.WildcardDomainHandling.NONE); - } - - }; + return this.remote; } } From 8ae1150c8026af625bd39143b50f3b9a08acdfed Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Fri, 7 Jun 2024 19:47:21 +0200 Subject: [PATCH 196/897] Remove unused lectern code in ModWorldManager, fix spelling error in SessionLoginEvent --- .../api/event/bedrock/SessionLoginEvent.java | 6 +-- .../mod/world/GeyserModWorldManager.java | 38 ------------------- 2 files changed, 3 insertions(+), 41 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java index 522562d11..86a5ec6f8 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java @@ -36,7 +36,7 @@ import java.util.Map; import java.util.Objects; /** - * Called when a session has logged in, and is about to connect to a remote java server. + * Called when a session has logged in, and is about to connect to a remote Java server. * This event is cancellable, and can be used to prevent the player from connecting to the remote server. */ public final class SessionLoginEvent extends ConnectionEvent implements Cancellable { @@ -99,9 +99,9 @@ public final class SessionLoginEvent extends ConnectionEvent implements Cancella } /** - * Gets the {@link RemoteServer} the section will attempt to connect to. + * Gets the {@link RemoteServer} the session will attempt to connect to. * - * @return the {@link RemoteServer} the section will attempt to connect to. + * @return the {@link RemoteServer} the session will attempt to connect to. */ public @NonNull RemoteServer remoteServer() { return this.remoteServer; 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 7aac684bb..5543dbcee 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 @@ -26,7 +26,6 @@ package org.geysermc.geyser.platform.mod.world; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; import net.minecraft.core.RegistryAccess; @@ -34,10 +33,7 @@ import net.minecraft.core.component.DataComponents; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.network.Filterable; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.component.WritableBookContent; -import net.minecraft.world.item.component.WrittenBookContent; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BannerBlockEntity; @@ -63,7 +59,6 @@ import java.util.concurrent.CompletableFuture; public class GeyserModWorldManager extends GeyserWorldManager { private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.gson(); - private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection(); private final MinecraftServer server; public GeyserModWorldManager(MinecraftServer server) { @@ -169,39 +164,6 @@ public class GeyserModWorldManager extends GeyserWorldManager { return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid()); } - private static int getPageCount(ItemStack itemStack) { - WrittenBookContent writtenBookContent = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT); - if (writtenBookContent != null) { - return writtenBookContent.pages().size(); - } else { - WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT); - return writableBookContent != null ? writableBookContent.pages().size() : 0; - } - } - - private static List getPages(ItemStack itemStack) { - WrittenBookContent writtenBookContent = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT); - if (writtenBookContent != null) { - return writtenBookContent.pages().stream() - .map(Filterable::raw) - .map(GeyserModWorldManager::fromComponent) - .toList(); - } else { - WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT); - if (writableBookContent == null) { - return List.of(); - } - return writableBookContent.pages().stream() - .map(Filterable::raw) - .toList(); - } - } - - private static String fromComponent(Component component) { - String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY); - return LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty())); - } - private static net.kyori.adventure.text.Component toKyoriComponent(Component component) { String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY); return GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty()); From 007ecb4363dcb7ca0f396732b4440f274d5b9842 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 9 Jun 2024 15:06:39 -0400 Subject: [PATCH 197/897] Ensure custom blocks can be represented at any index --- .../java/org/geysermc/geyser/item/Items.java | 8 +------- .../geyser/registry/ListRegistry.java | 20 +++++++++++++++++++ .../geysermc/geyser/registry/Registries.java | 5 ++++- .../populator/BlockRegistryPopulator.java | 3 +-- 4 files changed, 26 insertions(+), 10 deletions(-) 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 8c271a7bb..03f044068 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -30,8 +30,6 @@ import org.geysermc.geyser.item.type.*; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.registry.Registries; -import java.util.Collections; - import static org.geysermc.geyser.item.type.Item.builder; /** @@ -1378,11 +1376,7 @@ public final class Items { public static T register(T item, int id) { item.setJavaId(id); - // This makes sure that the array is large enough to put the java item at the correct location - if (Registries.JAVA_ITEMS.get().size() <= id) { - Registries.JAVA_ITEMS.get().addAll(Collections.nCopies(id - Registries.JAVA_ITEMS.get().size() + 1, AIR)); - } - Registries.JAVA_ITEMS.get().set(id, item); + Registries.JAVA_ITEMS.registerWithAnyIndex(id, item, AIR); Registries.JAVA_ITEM_IDENTIFIERS.register(item.javaIdentifier(), item); return item; } diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java index 34a78c370..2070d67ae 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.registry.loader.RegistryLoader; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.function.Supplier; @@ -94,6 +95,25 @@ public class ListRegistry extends Registry> { return this.mappings.set(index, value); } + /** + * Registers a new value into this registry with the given index, even if this value would normally be outside + * the range of a list. + * + * @param index the index + * @param value the value + * @param defaultValue the default value to fill empty spaces in the registry with. + * @return a new value into this registry with the given index. + */ + public M registerWithAnyIndex(int index, M value, M defaultValue) { + if (this.frozen) { + throw new IllegalStateException("Registry should not be modified after frozen!"); + } + if (this.mappings.size() <= index) { + this.mappings.addAll(Collections.nCopies(index - this.mappings.size() + 1, defaultValue)); + } + return this.mappings.set(index, value); + } + /** * Mark this registry as unsuitable for new additions. The backing list will then be optimized for storage. */ 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 54d013140..b509d6ac0 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -127,7 +127,10 @@ public final class Registries { */ public static final PacketTranslatorRegistry JAVA_PACKET_TRANSLATORS = PacketTranslatorRegistry.create(); - public static final SimpleRegistry> JAVA_ITEMS = SimpleRegistry.create(RegistryLoaders.empty(ArrayList::new)); + /** + * A registry containing all Java items ordered by their network ID. + */ + public static final ListRegistry JAVA_ITEMS = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); public static final SimpleMappedRegistry JAVA_ITEM_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 6b856c509..a8fb0001d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -213,7 +213,6 @@ public final class BlockRegistryPopulator { GeyserBedrockBlock[] javaToBedrockBlocks = new GeyserBedrockBlock[JAVA_BLOCKS_SIZE]; GeyserBedrockBlock[] javaToVanillaBedrockBlocks = new GeyserBedrockBlock[JAVA_BLOCKS_SIZE]; - //List javaToBedrockIdentifiers = new ArrayList<>(BlockRegistries.JAVA_BLOCKS.get().size()); var javaToBedrockIdentifiers = new Int2ObjectOpenHashMap(); Block lastBlockSeen = null; @@ -456,7 +455,7 @@ public final class BlockRegistryPopulator { }; block.setJavaId(javaBlockState.stateGroupId()); - BlockRegistries.JAVA_BLOCKS.get().add(javaBlockState.stateGroupId(), block); //TODO don't allow duplicates, allow blanks + BlockRegistries.JAVA_BLOCKS.registerWithAnyIndex(javaBlockState.stateGroupId(), block, Blocks.AIR); BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, stateRuntimeId); BlockRegistries.BLOCK_STATES.register(stateRuntimeId, new BlockState(block, stateRuntimeId)); } From e9e364636a8774cdbe1244b46a81eec52e6700ee Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 9 Jun 2024 15:44:29 -0400 Subject: [PATCH 198/897] New potion effects --- .../geyser/registry/loader/PotionMixRegistryLoader.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java index 0eec7cdb6..eae4e2bea 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.registry.loader; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; @@ -75,6 +74,11 @@ public class PotionMixRegistryLoader implements RegistryLoader inputs = List.of( getNonNull(mappings, Items.POTION), From ae6059bdc3c467f39d7c8a7094d897c0e08a1263 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 9 Jun 2024 16:57:51 -0400 Subject: [PATCH 199/897] Implement wind charges --- .../geyser/entity/EntityDefinitions.java | 16 ++++++ .../entity/type/AbstractWindChargeEntity.java | 53 ++++++++++++++++++ .../geyser/session/GeyserSession.java | 1 + .../java/level/JavaExplodeTranslator.java | 56 ++++++++++++------- .../level/JavaLevelParticlesTranslator.java | 5 +- 5 files changed, 108 insertions(+), 23 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/AbstractWindChargeEntity.java 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 76c65e9c8..a7c2d6ca6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.entity; +import org.geysermc.geyser.entity.type.AbstractWindChargeEntity; +import org.geysermc.geyser.entity.factory.EntityFactory; import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -64,6 +66,7 @@ public final class EntityDefinitions { public static final EntityDefinition BLAZE; public static final EntityDefinition BOAT; public static final EntityDefinition BOGGED; + public static final EntityDefinition BREEZE_WIND_CHARGE; public static final EntityDefinition CAMEL; public static final EntityDefinition CAT; public static final EntityDefinition CAVE_SPIDER; @@ -166,6 +169,7 @@ public final class EntityDefinitions { public static final EntityDefinition VINDICATOR; public static final EntityDefinition WANDERING_TRADER; public static final EntityDefinition WARDEN; + public static final EntityDefinition WIND_CHARGE; public static final EntityDefinition WITCH; public static final EntityDefinition WITHER; public static final EntityDefinition WITHER_SKELETON; @@ -376,6 +380,18 @@ public final class EntityDefinitions { .heightAndWidth(0.25f) .build(); + EntityFactory windChargeSupplier = AbstractWindChargeEntity::new; + BREEZE_WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase) + .type(EntityType.BREEZE_WIND_CHARGE) + .identifier("minecraft:breeze_wind_charge_projectile") + .heightAndWidth(0.3125f) + .build(); + WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase) + .type(EntityType.WIND_CHARGE) + .identifier("minecraft:wind_charge_projectile") + .heightAndWidth(0.3125f) + .build(); + EntityDefinition abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase) .addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags) .addTranslator(null) // "Piercing level" diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AbstractWindChargeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractWindChargeEntity.java new file mode 100644 index 000000000..5678c3af4 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractWindChargeEntity.java @@ -0,0 +1,53 @@ +/* + * 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; + +import org.cloudburstmc.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.UUID; + +/** + * Note that, as of 1.21, a wind charge entity does not actually implement the thrown item. We're just reusing + * the "hide until far away" aspect. + */ +public class AbstractWindChargeEntity extends ThrowableItemEntity { + public AbstractWindChargeEntity(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 void tick() { + super.tick(); + } + + @Override + protected float getDrag() { + // Always, even in water. As of 1.21. + return 1f; + } +} 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 ae5e1d338..b8e617fbb 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1047,6 +1047,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public void packetReceived(Session session, Packet packet) { + System.out.println(packet); Registries.JAVA_PACKET_TRANSLATORS.translate(packet.getClass(), packet, GeyserSession.this); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java index 496f5982d..85107d637 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java @@ -25,22 +25,24 @@ package org.geysermc.geyser.translator.protocol.java.level; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; -import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; 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.ChunkUtils; +import org.geysermc.geyser.util.SoundUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.ExplosionInteraction; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket; + +import java.util.concurrent.ThreadLocalRandom; @Translator(packet = ClientboundExplodePacket.class) public class JavaExplodeTranslator extends PacketTranslator { @@ -56,27 +58,39 @@ public class JavaExplodeTranslator extends PacketTranslator createParticle(GeyserSession session, Particle particle) { + public static @Nullable Function createParticle(GeyserSession session, Particle particle) { switch (particle.getType()) { case BLOCK -> { int blockState = session.getBlockMappings().getBedrockBlockId(((BlockParticleData) particle.getData()).getBlockState()); @@ -177,6 +177,7 @@ public class JavaLevelParticlesTranslator extends PacketTranslator { ParticleMapping particleMapping = Registries.PARTICLES.get(particle.getType()); + System.out.println(particle.getType() + " " + particleMapping); if (particleMapping == null) { //TODO ensure no particle can be null return null; } @@ -205,7 +206,7 @@ public class JavaLevelParticlesTranslator extends PacketTranslator Date: Sun, 9 Jun 2024 16:58:26 -0400 Subject: [PATCH 200/897] oooops --- .../src/main/java/org/geysermc/geyser/session/GeyserSession.java | 1 - 1 file changed, 1 deletion(-) 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 b8e617fbb..ae5e1d338 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1047,7 +1047,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public void packetReceived(Session session, Packet packet) { - System.out.println(packet); Registries.JAVA_PACKET_TRANSLATORS.translate(packet.getClass(), packet, GeyserSession.this); } From edee5e7a8e61b818c506428f6f9e2da942285fa5 Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Mon, 10 Jun 2024 01:43:10 +0200 Subject: [PATCH 201/897] Add builtin server transfer support for ViaProxy (#4723) --- .../viaproxy/GeyserViaProxyPlugin.java | 5 +- .../GeyserServerTransferListener.java | 62 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/listener/GeyserServerTransferListener.java diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java index 30404e705..bdc80335a 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java @@ -37,6 +37,7 @@ import org.apache.logging.log4j.LogManager; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.command.GeyserCommandManager; @@ -44,6 +45,7 @@ import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.geysermc.geyser.platform.viaproxy.listener.GeyserServerTransferListener; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; @@ -57,7 +59,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.UUID; -public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootstrap { +public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootstrap, EventRegistrar { public static final File ROOT_FOLDER = new File(PluginManager.PLUGINS_DIR, "Geyser"); @@ -120,6 +122,7 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst } this.geyser = GeyserImpl.load(PlatformType.VIAPROXY, this); + this.geyser.eventBus().register(this, new GeyserServerTransferListener()); LoopbackUtil.checkAndApplyLoopback(this.logger); } diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/listener/GeyserServerTransferListener.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/listener/GeyserServerTransferListener.java new file mode 100644 index 000000000..64b3cc56e --- /dev/null +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/listener/GeyserServerTransferListener.java @@ -0,0 +1,62 @@ +/* + * 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.platform.viaproxy.listener; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.net.HostAndPort; +import org.geysermc.event.PostOrder; +import org.geysermc.event.subscribe.Subscribe; +import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent; +import org.geysermc.geyser.api.event.java.ServerTransferEvent; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class GeyserServerTransferListener { + + private final Cache> cookieStorages = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build(); + + @Subscribe(postOrder = PostOrder.FIRST) + private void onServerTransfer(final ServerTransferEvent event) { + this.cookieStorages.put(event.connection().xuid(), event.cookies()); + final GeyserSession geyserSession = (GeyserSession) event.connection(); + final HostAndPort hostAndPort = HostAndPort.fromString(geyserSession.getClientData().getServerAddress()).withDefaultPort(19132); + event.bedrockHost(hostAndPort.getHost()); + event.bedrockPort(hostAndPort.getPort()); + } + + @Subscribe(postOrder = PostOrder.FIRST) + private void onSessionLogin(final SessionLoginEvent event) { + final Map cookies = this.cookieStorages.asMap().remove(event.connection().xuid()); + if (cookies != null) { + event.cookies(cookies); + event.transferring(true); + } + } + +} From 02179a798f12eaf5791e6d89cc95cfa0bf68d99a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:53:14 -0400 Subject: [PATCH 202/897] You shall compile! --- .../translator/protocol/java/level/JavaExplodeTranslator.java | 2 +- .../protocol/java/level/JavaLevelEventTranslator.java | 1 - .../protocol/java/level/JavaLevelParticlesTranslator.java | 1 - core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 4 ++-- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java index 85107d637..f840b8143 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java @@ -74,7 +74,7 @@ public class JavaExplodeTranslator extends PacketTranslator { ParticleMapping particleMapping = Registries.PARTICLES.get(particle.getType()); - System.out.println(particle.getType() + " " + particleMapping); if (particleMapping == null) { //TODO ensure no particle can be null return null; } diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 1f1d5ce8c..54705bcd2 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 1f1d5ce8c482dac142f13e95e19368e3f36de144 +Subproject commit 54705bcd2bcba830267efbb1fbfd4e52972c40f7 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 089cab44f..afd001220 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ websocket = "1.5.1" protocol = "3.0.0.Beta2-20240606.172607-7" raknet = "1.0.0.CR3-20240416.144209-1" mcauthlib = "e5b0bcc" -mcprotocollib = "1.21-SNAPSHOT" +mcprotocollib = "784e91c" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" @@ -107,7 +107,7 @@ guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } -mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" } +mcprotocollib = { group = "com.github.GeyserMC", name = "mcprotocollib", version.ref = "mcprotocollib" } raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } From 538e9f4dd6bb2d7d9e00fae73e834f9a93b572c1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 10 Jun 2024 17:04:43 -0400 Subject: [PATCH 203/897] Properly remove SnowCollision --- .../translator/collision/BlockCollision.java | 2 +- .../translator/collision/SnowCollision.java | 89 ------------------- 2 files changed, 1 insertion(+), 90 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java index a2615deb1..2481028a4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java @@ -61,7 +61,7 @@ public class BlockCollision { } /** - * Overridden in classes like SnowCollision and GrassPathCollision when correction code needs to be run before the + * Overridden in classes like GrassPathCollision when correction code needs to be run before the * main correction */ public void beforeCorrectPosition(int x, int y, int z, BoundingBox playerCollision) {} diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java deleted file mode 100644 index af2bcb7ea..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java +++ /dev/null @@ -1,89 +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.collision; - -import lombok.EqualsAndHashCode; -import org.geysermc.geyser.level.physics.BoundingBox; -import org.geysermc.geyser.session.GeyserSession; - -@EqualsAndHashCode(callSuper = true) -//@CollisionRemapper(regex = "^snow$", passDefaultBoxes = true, usesParams = true) TODO remove if no bugs are found. Seems fine with Bedrock 1.20.80 and 1.20.5 -public class SnowCollision extends BlockCollision { - private final int layers; - - public SnowCollision(String params, BoundingBox[] defaultBoxes) { - super(defaultBoxes); - int layerCharIndex = params.indexOf("=") + 1; - layers = Integer.parseInt(params.substring(layerCharIndex, layerCharIndex + 1)); - - pushUpTolerance = 0.125; - } - - // Needs to run before the main correction code or it can move the player into blocks - // This is counteracted by the main collision code pushing them out - @Override - public void beforeCorrectPosition(int x, int y, int z, BoundingBox playerCollision) { - // In Bedrock, snow layers round down to half blocks but you can't sink into them at all - // This means the collision each half block reaches above where it should be on Java so the player has to be - // pushed down - if (layers == 4 || layers == 8) { - double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2); - double boxMaxY = (boundingBoxes[0].getMiddleY() + y) + (boundingBoxes[0].getSizeY() / 2); - // If the player is in the buggy area, push them down - if (playerMinY > boxMaxY && - playerMinY <= (boxMaxY + 0.125)) { - playerCollision.translate(0, boxMaxY - playerMinY, 0); - } - } - } - - @Override - public boolean correctPosition(GeyserSession session, int x, int y, int z, BoundingBox playerCollision) { - if (layers == 1) { - // 1 layer of snow does not have collision - return true; - } - // Hack to prevent false positives - playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001); - playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001); - playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001); - - if (this.checkIntersection(x, y, z, playerCollision)) { - double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2); - double boxMaxY = (boundingBoxes[0].getMiddleY() + y) + (boundingBoxes[0].getSizeY() / 2); - // If the player actually can't step onto it (they can step onto it from other snow layers) - if ((boxMaxY - playerMinY) > 0.5) { - // Cancel the movement - return false; - } - } - - playerCollision.setSizeX(playerCollision.getSizeX() + 0.0001); - playerCollision.setSizeY(playerCollision.getSizeY() + 0.0001); - playerCollision.setSizeZ(playerCollision.getSizeZ() + 0.0001); - return super.correctPosition(session, x, y, z, playerCollision); - } -} From 9a310f248b265460c14fe944ac42696f056343ff Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:59:03 -0400 Subject: [PATCH 204/897] 1.21-pre4 updated block tags --- .../java/org/geysermc/geyser/session/cache/tags/BlockTag.java | 1 + 1 file changed, 1 insertion(+) 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 32d708eca..5a85efc84 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 @@ -42,6 +42,7 @@ public final class BlockTag implements Ordered { 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"); From d19807170df1b95a8856df4a86e7fc1d7f72b88f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:40:14 -0400 Subject: [PATCH 205/897] Properly show dyed wolf armor --- .../living/animal/tameable/WolfEntity.java | 2 +- .../java/org/geysermc/geyser/item/Items.java | 4 +- .../geyser/item/type/DyeableArmorItem.java | 7 +-- .../org/geysermc/geyser/item/type/Item.java | 8 ++++ .../geyser/item/type/WolfArmorItem.java | 46 +++++++++++++++++++ .../org/geysermc/geyser/util/ItemUtils.java | 7 ++- 6 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java 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 9c6c5e08d..e7fde2be8 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 @@ -123,7 +123,7 @@ public class WolfEntity extends TameableEntity { @Override public void setChestplate(ItemStack stack) { super.setChestplate(stack); - isCurseOfBinding = ItemUtils.hasEffect(session, stack.getDataComponents(), EnchantmentComponent.PREVENT_ARMOR_CHANGE); // TODO test + isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); // TODO test } @Override 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 82bef33dc..5ae69fa4e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -834,7 +834,7 @@ public final class Items { 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())); - public static final Item WOLF_ARMOR = register(new ArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder().stackSize(1).maxDamage(64))); + public static final Item WOLF_ARMOR = register(new WolfArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder().stackSize(1).maxDamage(64))); public static final Item FLINT_AND_STEEL = register(new Item("flint_and_steel", builder().stackSize(1).maxDamage(64))); public static final Item BOWL = register(new Item("bowl", builder())); public static final Item APPLE = register(new Item("apple", builder())); @@ -1042,7 +1042,7 @@ public final class Items { 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.LAVA_CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON)); + public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.LAVA_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())); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index b2dbb95e5..8c63eaeb0 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -29,9 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -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.DyedItemColor; public class DyeableArmorItem extends ArmorItem { public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) { @@ -44,9 +42,6 @@ public class DyeableArmorItem extends ArmorItem { // Note that this is handled as of 1.20.5 in the ItemColors class. // But horse leather armor and body leather armor are now both armor items. So it works! - DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR); - if (dyedItemColor != null) { - builder.putInt("customColor", dyedItemColor.getRgb()); - } + translateDyedColor(components, builder); } } 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 8c67d7d5f..2caa65dac 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 @@ -48,6 +48,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.Identifier; 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.DyedItemColor; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; import java.util.ArrayList; @@ -253,6 +254,13 @@ public class Item { builder.getOrCreateLore().add(0, ChatColor.RESET + ChatColor.GRAY + enchantmentName + " " + lvlTranslation); } + protected final void translateDyedColor(DataComponents components, BedrockItemBuilder builder) { + DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR); + if (dyedItemColor != null) { + builder.putInt("customColor", dyedItemColor.getRgb()); + } + } + /* Translation methods end */ public GeyserItemStack newItemStack(int count, DataComponents components) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java new file mode 100644 index 000000000..bd97a6a7d --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java @@ -0,0 +1,46 @@ +/* + * 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.item.type; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.ArmorMaterial; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; + +public class WolfArmorItem extends ArmorItem { + public WolfArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) { + super(javaIdentifier, material, builder); + } + + @Override + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); + + // Note that this is handled as of 1.21 in the ItemColors class. + translateDyedColor(components, builder); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index bbb64a41e..eec0d173d 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -34,6 +34,7 @@ import org.geysermc.geyser.item.enchantment.EnchantmentComponent; import org.geysermc.geyser.item.type.FishingRodItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +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.item.component.ItemEnchantments; @@ -65,7 +66,11 @@ public final class ItemUtils { return 0; } - public static boolean hasEffect(GeyserSession session, @Nullable DataComponents components, EnchantmentComponent component) { + public static boolean hasEffect(GeyserSession session, @Nullable ItemStack itemStack, EnchantmentComponent component) { + if (itemStack == null) { + return false; + } + DataComponents components = itemStack.getDataComponents(); if (components == null) { return false; } From 956a84a3fbbcc04bade20448e3d5009a07ea086e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:47:26 -0400 Subject: [PATCH 206/897] Enchantment tag can be null --- .../java/org/geysermc/geyser/session/cache/TagCache.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 335e940f4..933b57db7 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,6 +26,7 @@ package org.geysermc.geyser.session.cache; import it.unimi.dsi.fastutil.ints.IntArrays; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -83,8 +84,12 @@ public final class TagCache { loadTags("Enchantment", enchantmentTags, ALL_ENCHANTMENT_TAGS, this.enchantments); } - private void loadTags(String type, Map packetTags, Map allTags, int[][] localValues) { + private void loadTags(String type, @Nullable Map packetTags, Map allTags, int[][] localValues) { Arrays.fill(localValues, IntArrays.EMPTY_ARRAY); + if (packetTags == null) { + 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) { From b78c7b2bd3dd94dc45c91e2a4cabfb4b77cabe7c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:54:57 -0400 Subject: [PATCH 207/897] Fix #4729 --- .../level/block/entity/DoubleChestBlockEntityTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index 102f4a0e6..988d94073 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -38,7 +38,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType * Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockChunkWantsBlockEntityTag */ @BlockEntity(type = { BlockEntityType.CHEST, BlockEntityType.TRAPPED_CHEST }) -public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator { +public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { From 29dacd2397e9e3688141dbf61874daab9776c343 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 11 Jun 2024 14:26:53 -0400 Subject: [PATCH 208/897] Properly remap coral blocks on 1.20.80 --- .../registry/populator/Conversion685_671.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java index 250fd9d9f..0b0731707 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java @@ -51,16 +51,16 @@ public class Conversion685_671 { if (NEW_CORAL_BLOCKS.contains(identifer)) { switch (identifer) { - case "minecraft:tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(0); } - case "minecraft:brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(1); } - case "minecraft:bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(2); } - case "minecraft:fire_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(3); } - case "minecraft:horn_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(4); } - case "minecraft:dead_tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(8); } - case "minecraft:dead_brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(9); } - case "minecraft:dead_bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(10); } - case "minecraft:dead_fire_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(11); } - case "minecraft:dead_horn_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:red_flower").withBedrockData(12); } + case "minecraft:tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(0); } + case "minecraft:brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(1); } + case "minecraft:bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(2); } + case "minecraft:fire_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(3); } + case "minecraft:horn_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(4); } + case "minecraft:dead_tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(8); } + case "minecraft:dead_brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(9); } + case "minecraft:dead_bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(10); } + case "minecraft:dead_fire_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(11); } + case "minecraft:dead_horn_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(12); } } } From a42c979abb0a9b20588f60e7b0d6be254021f9f2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 12 Jun 2024 00:12:15 -0400 Subject: [PATCH 209/897] This variant of tag loading should be slightly more efficient --- .../java/org/geysermc/geyser/session/cache/TagCache.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 933b57db7..656a16cf4 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 @@ -85,8 +85,8 @@ public final class TagCache { } private void loadTags(String type, @Nullable Map packetTags, Map allTags, int[][] localValues) { - Arrays.fill(localValues, IntArrays.EMPTY_ARRAY); if (packetTags == null) { + Arrays.fill(localValues, IntArrays.EMPTY_ARRAY); GeyserImpl.getInstance().getLogger().debug("Not loading " + type + " tags; they do not exist here."); return; } @@ -95,8 +95,11 @@ public final class TagCache { 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); } }); From 82d68bfe9bee47dcd90723044d22841c5ca9f60f Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 13 Jun 2024 00:14:10 +0200 Subject: [PATCH 210/897] Bump fabric/neoforge dependencies to 1.21, update README.md, bump Geyser version to 2.4.0 --- README.md | 2 +- .../src/main/resources/META-INF/neoforge.mods.toml | 2 +- .../main/kotlin/geyser.modded-conventions.gradle.kts | 11 ++++++++--- gradle.properties | 2 +- gradle/libs.versions.toml | 8 ++++---- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index dd2d096ec..c45af73ed 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.0 and Minecraft Java 1.20.5/1.20.6 +### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.0 and Minecraft Java 1.21 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml index ff2823aa2..3a25f6119 100644 --- a/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -20,6 +20,6 @@ config = "geyser.mixins.json" [[dependencies.geyser_neoforge]] modId="minecraft" type="required" - versionRange="[1.20.5,1.21)" + versionRange="[1.20.5,)" ordering="NONE" side="BOTH" \ No newline at end of file diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index b75e9c5be..6472e4312 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -110,18 +110,23 @@ afterEvaluate { } dependencies { - minecraft("com.mojang:minecraft:1.20.5") + minecraft("com.mojang:minecraft:1.21-rc1") mappings(loom.officialMojangMappings()) } repositories { // mavenLocal() - maven("https://repo.opencollab.dev/maven-releases/") - maven("https://repo.opencollab.dev/maven-snapshots/") + maven("https://repo.opencollab.dev/main") maven("https://jitpack.io") maven("https://oss.sonatype.org/content/repositories/snapshots/") maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") maven("https://maven.neoforged.net/releases") + maven("https://prmaven.neoforged.net/NeoForge/pr1076") { + name = "Maven for 1.21 PR" + content { + includeModule("net.neoforged", "neoforge") + } + } } modrinth { diff --git a/gradle.properties b/gradle.properties index ea473906a..a222b1d99 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.3.2-SNAPSHOT +version=2.4.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 afd001220..11851a5cd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,11 +28,11 @@ commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" viaproxy = "3.2.1" -fabric-minecraft = "1.20.5" -fabric-loader = "0.15.10" -fabric-api = "0.97.6+1.20.5" +fabric-minecraft = "1.21-rc1" +fabric-loader = "0.15.11" +fabric-api = "0.100.1+1.21" fabric-permissions = "0.2-SNAPSHOT" -neoforge-minecraft = "20.5.0-beta" +neoforge-minecraft = "21.0.0-alpha.1.21-rc1.20240611.001314" mixin = "0.8.5" # plugin versions From ecffb564ed568babe1e73af2f7b3c806a2f3f49b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:34:42 -0400 Subject: [PATCH 211/897] Refactor static recipe loading The only recipes added should be the ones that are sent on Bedrock, so it appears in the recipe book. Every other recipe will be handled through our fallback system. --- .../geyser/inventory/recipe/GeyserRecipe.java | 6 + .../geysermc/geyser/item/type/BannerItem.java | 15 +- .../geyser/item/type/EnchantedBookItem.java | 16 +- .../geyser/item/type/FireworkRocketItem.java | 4 +- .../geyser/item/type/FireworkStarItem.java | 4 +- .../org/geysermc/geyser/item/type/Item.java | 37 +-- .../geysermc/geyser/registry/Registries.java | 13 +- .../registry/loader/RecipeRegistryLoader.java | 149 ++++++++++ .../populator/RecipeRegistryPopulator.java | 233 --------------- .../geyser/session/GeyserSession.java | 3 +- .../inventory/PlayerInventoryTranslator.java | 2 +- .../translator/item/ItemTranslator.java | 13 +- .../java/JavaUpdateRecipesTranslator.java | 270 +++++++++++------- core/src/main/resources/mappings | 2 +- 14 files changed, 360 insertions(+), 407 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java 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 9d98e9fb3..8b7fa9522 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,6 +25,9 @@ package org.geysermc.geyser.inventory.recipe; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; + /** * A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}. */ @@ -33,4 +36,7 @@ public interface GeyserRecipe { * Whether the recipe is flexible or not in which items can be placed where. */ boolean isShaped(); + + @Nullable + ItemStack result(); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index cf0105622..4af2b4630 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -60,9 +60,6 @@ public class BannerItem extends BlockItem { */ private static final List> OMINOUS_BANNER_PATTERN; - // TODO fix - we somehow need to be able to get the sessions banner pattern registry, which we don't have where we need this :/ - private static final int[] ominousBannerPattern = new int[] { 21, 29, 30, 1, 34, 15, 3, 1 }; - static { // Construct what an ominous banner is supposed to look like OMINOUS_BANNER_PATTERN = List.of( @@ -215,20 +212,22 @@ public class BannerItem extends BlockItem { } @Override - public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { - super.translateNbtToJava(bedrockTag, components, mapping); + public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + super.translateNbtToJava(session, bedrockTag, components, mapping); if (bedrockTag.getInt("Type") == 1) { // Ominous banner pattern List patternLayers = new ArrayList<>(); - for (int i = 0; i < ominousBannerPattern.length; i++) { - patternLayers.add(new BannerPatternLayer(Holder.ofId(ominousBannerPattern[i]), OMINOUS_BANNER_PATTERN.get(i).right().ordinal())); + for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) { + var pair = OMINOUS_BANNER_PATTERN.get(i); + patternLayers.add(new BannerPatternLayer(Holder.ofId(session.getRegistryCache().bannerPatterns().byValue(pair.left())), + pair.right().ordinal())); } components.put(DataComponentType.BANNER_PATTERNS, patternLayers); components.put(DataComponentType.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE); components.put(DataComponentType.ITEM_NAME, Component - .translatable("block.minecraft.ominous_banner") // thank god this works + .translatable("block.minecraft.ominous_banner") .style(Style.style(TextColor.color(16755200))) ); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index 540270555..8b0f3e22e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.BedrockEnchantment; +import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -69,8 +70,8 @@ public class EnchantedBookItem extends Item { } @Override - public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { - super.translateNbtToJava(bedrockTag, components, mapping); + public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + super.translateNbtToJava(session, bedrockTag, components, mapping); List enchantmentTag = bedrockTag.getList("ench", NbtType.COMPOUND); if (enchantmentTag != null) { @@ -80,9 +81,14 @@ public class EnchantedBookItem extends Item { BedrockEnchantment enchantment = BedrockEnchantment.getByBedrockId(bedrockId); if (enchantment != null) { - int level = bedrockEnchantment.getShort("lvl", (short) 1); - // TODO - //javaEnchantments.put(BedrockEnchantment.JavaEnchantment.valueOf(enchantment.name()).ordinal(), level); + List enchantments = session.getRegistryCache().enchantments().values(); + for (int i = 0; i < enchantments.size(); i++) { + if (enchantments.get(i).bedrockEnchantment() == enchantment) { + int level = bedrockEnchantment.getShort("lvl", (short) 1); + javaEnchantments.put(i, level); + break; + } + } } else { GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index c70467b4c..9c637afde 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -70,8 +70,8 @@ public class FireworkRocketItem extends Item { } @Override - public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { - super.translateNbtToJava(bedrockTag, components, mapping); + public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + super.translateNbtToJava(session, bedrockTag, components, mapping); NbtMap fireworksTag = bedrockTag.getCompound("Fireworks"); if (!fireworksTag.isEmpty()) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 18234975d..2ba9b4258 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -78,8 +78,8 @@ public class FireworkStarItem extends Item { } @Override - public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { - super.translateNbtToJava(bedrockTag, components, mapping); + public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + super.translateNbtToJava(session, bedrockTag, components, mapping); NbtMap explosion = bedrockTag.getCompound("FireworksItem"); if (!explosion.isEmpty()) { 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 2caa65dac..1ebf85065 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 @@ -172,7 +172,7 @@ public class Item { * * Therefore, if translation cannot be achieved for a certain item, it is not necessarily bad. */ - public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { + public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) { // TODO see if any items from the creative menu need this // CompoundTag displayTag = tag.get("display"); // if (displayTag != null) { @@ -190,41 +190,6 @@ public class Item { // } // displayTag.put(new ListTag("Lore", lore)); // } -// } - - // TODO no creative item should have enchantments *except* enchanted books -// List enchantmentTag = bedrockTag.getList("ench", NbtType.COMPOUND); -// if (enchantmentTag != null) { -// List enchantments = new ArrayList<>(); -// for (Tag value : enchantmentTag.getValue()) { -// if (!(value instanceof CompoundTag tagValue)) -// continue; -// -// ShortTag bedrockId = tagValue.get("id"); -// if (bedrockId == null) continue; -// -// BedrockEnchantment enchantment = BedrockEnchantment.getByBedrockId(bedrockId.getValue()); -// if (enchantment != null) { -// CompoundTag javaTag = new CompoundTag(""); -// Map javaValue = javaTag.getValue(); -// javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier())); -// ShortTag levelTag = tagValue.get("lvl"); -// javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1)); -// javaTag.setValue(javaValue); -// -// enchantments.add(javaTag); -// } else { -// GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId); -// } -// } -// if (!enchantments.isEmpty()) { -// if ((this instanceof EnchantedBookItem)) { -// bedrockTag.put(new ListTag("StoredEnchantments", enchantments)); -// components.put(DataComponentType.STORED_ENCHANTMENTS, enchantments); -// } else { -// components.put(DataComponentType.ENCHANTMENTS, enchantments); -// } -// } // } } 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 7815768ef..deafbdf7e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -25,14 +25,12 @@ package org.geysermc.geyser.registry; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; -import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.pack.ResourcePack; @@ -42,7 +40,7 @@ import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.loader.*; import org.geysermc.geyser.registry.populator.ItemRegistryPopulator; import org.geysermc.geyser.registry.populator.PacketRegistryPopulator; -import org.geysermc.geyser.registry.populator.RecipeRegistryPopulator; +import org.geysermc.geyser.registry.loader.RecipeRegistryLoader; import org.geysermc.geyser.registry.provider.ProviderSupplier; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ParticleMapping; @@ -95,11 +93,6 @@ public final class Registries { */ public static final SimpleMappedRegistry BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new); - /** - * A versioned registry which holds a {@link RecipeType} to a corresponding list of {@link RecipeData}. - */ - public static final VersionedRegistry>> CRAFTING_DATA = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); - /** * A map containing all entity types and their respective Geyser definitions */ @@ -147,7 +140,7 @@ 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 VersionedRegistry> RECIPES = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + public static final SimpleMappedRegistry> RECIPES = SimpleMappedRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new); /** * A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys. @@ -176,7 +169,7 @@ public final class Registries { static { PacketRegistryPopulator.populate(); ItemRegistryPopulator.populate(); - RecipeRegistryPopulator.populate(); + System.out.println(RECIPES.get()); // Create registries that require other registries to load first POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); 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 new file mode 100644 index 000000000..5d1236581 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java @@ -0,0 +1,149 @@ +/* + * 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.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; +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>> { + + @Override + public Map> load(String input) { + 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; + } + + 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()); + for (NbtMap recipe : recipes) { + ItemStack output = toItemStack(recipe.getCompound("output"), helper); + List 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)}); + } + deserializedRecipes.add(new GeyserShapelessRecipe(javaInputs, output)); + } + return deserializedRecipes; + } + + private static List getShapedRecipes(List recipes, MinecraftCodecHelper helper) { + List deserializedRecipes = new ObjectArrayList<>(recipes.size()); + for (NbtMap recipe : recipes) { + ItemStack output = toItemStack(recipe.getCompound("output"), helper); + List shape = recipe.getList("shape", NbtType.INT_ARRAY); + + // In the recipes mapping, each recipe is mapped by a number + List letterToRecipe = new ArrayList<>(); + for (NbtMap rawInput : recipe.getList("inputs", NbtType.COMPOUND)) { + letterToRecipe.add(toItemStack(rawInput, helper)); + } + + Ingredient[] inputs = new Ingredient[shape.size() * shape.get(0).length]; + int i = 0; + // Create a linear array of items from the "cube" of the shape + for (int j = 0; i < shape.size() * shape.get(0).length; j++) { + for (int index : shape.get(j)) { + ItemStack stack = letterToRecipe.get(index); + inputs[i++] = new Ingredient(new ItemStack[] {stack}); + } + } + deserializedRecipes.add(new GeyserShapedRecipe(shape.size(), shape.get(0).length, inputs, output)); + } + return deserializedRecipes; + } + + /** + * Converts our serialized NBT into an ItemStack. + * id is the Java item ID as an integer, components is an optional String of the data components serialized + * as bytes in Base64 (so MCProtocolLib can parse the data). + */ + private static ItemStack toItemStack(NbtMap nbt, MinecraftCodecHelper helper) { + int id = nbt.getInt("id"); + int count = nbt.getInt("count"); + String componentsRaw = nbt.getString("components", null); + if (componentsRaw != null) { + byte[] bytes = Base64.getDecoder().decode(componentsRaw); + ByteBuf buf = Unpooled.wrappedBuffer(bytes); + DataComponents components = helper.readDataComponentPatch(buf); + return new ItemStack(id, count, components); + } + return new ItemStack(id, count); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java deleted file mode 100644 index 4c6d53518..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ /dev/null @@ -1,233 +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.registry.populator; - -import com.fasterxml.jackson.databind.JsonNode; -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.RecipeType; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtUtils; -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.MultiRecipeData; -import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData; -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.descriptor.ItemDescriptorWithCount; -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.registry.Registries; -import org.geysermc.geyser.registry.type.ItemMapping; -import org.geysermc.geyser.registry.type.ItemMappings; -import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.translator.item.ItemTranslator; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; - -import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; - -/** - * Populates the recipe registry. - */ -public class RecipeRegistryPopulator { - - public static void populate() { - JsonNode items; - try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/recipes.json")) { - items = GeyserImpl.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e); - } - - int currentRecipeId = LAST_RECIPE_NET_ID; - for (Int2ObjectMap.Entry version : Registries.ITEMS.get().int2ObjectEntrySet()) { - // Make a bit of an assumption here that the last recipe net ID will be equivalent between all versions - LAST_RECIPE_NET_ID = currentRecipeId; - Map> craftingData = new EnumMap<>(RecipeType.class); - Int2ObjectMap recipes = new Int2ObjectOpenHashMap<>(); - - craftingData.put(RecipeType.CRAFTING_SPECIAL_BOOKCLONING, - Collections.singletonList(MultiRecipeData.of(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), ++LAST_RECIPE_NET_ID))); - craftingData.put(RecipeType.CRAFTING_SPECIAL_REPAIRITEM, - Collections.singletonList(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000001"), ++LAST_RECIPE_NET_ID))); - craftingData.put(RecipeType.CRAFTING_SPECIAL_MAPEXTENDING, - Collections.singletonList(MultiRecipeData.of(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), ++LAST_RECIPE_NET_ID))); - craftingData.put(RecipeType.CRAFTING_SPECIAL_MAPCLONING, - Collections.singletonList(MultiRecipeData.of(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), ++LAST_RECIPE_NET_ID))); - - // https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/inventory/MultiRecipe.php - - for (JsonNode entry : items.get("leather_armor")) { - // This won't be perfect, as we can't possibly send every leather input for every kind of color - // But it does display the correct output from a base leather armor, and besides visuals everything works fine - craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_ARMORDYE, - c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); - } - for (JsonNode entry : items.get("firework_rockets")) { - craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_FIREWORK_ROCKET, - c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); - } - for (JsonNode entry : items.get("firework_stars")) { - craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_FIREWORK_STAR, - c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); - } - for (JsonNode entry : items.get("shulker_boxes")) { - craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_SHULKERBOXCOLORING, - c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); - } - for (JsonNode entry : items.get("suspicious_stew")) { - craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_SUSPICIOUSSTEW, - c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); - } - for (JsonNode entry : items.get("tipped_arrows")) { - craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_TIPPEDARROW, - c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); - } - - Registries.CRAFTING_DATA.register(version.getIntKey(), craftingData); - Registries.RECIPES.register(version.getIntKey(), recipes); - } - } - - /** - * Computes a Bedrock crafting recipe from the given JSON data. - * @param node the JSON data to compute - * @param recipes a list of all the recipes - * @return the {@link RecipeData} to send to the Bedrock client. - */ - private static RecipeData getCraftingDataFromJsonNode(JsonNode node, Int2ObjectMap recipes, ItemMappings mappings) { - int netId = ++LAST_RECIPE_NET_ID; - int type = node.get("bedrockRecipeType").asInt(); - JsonNode outputNode = node.get("output"); - ItemMapping outputEntry = mappings.getMapping(outputNode.get("identifier").asText()); - ItemData output = getBedrockItemFromIdentifierJson(outputEntry, outputNode); - UUID uuid = UUID.randomUUID(); - if (type == 1) { - // Shaped recipe - List shape = new ArrayList<>(); - // Get the shape of the recipe - for (JsonNode chars : node.get("shape")) { - shape.add(chars.asText()); - } - - // In recipes.json each recipe is mapped by a letter - Map letterToRecipe = new HashMap<>(); - Iterator> iterator = node.get("inputs").fields(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - JsonNode inputNode = entry.getValue(); - ItemMapping inputEntry = mappings.getMapping(inputNode.get("identifier").asText()); - letterToRecipe.put(entry.getKey(), getBedrockItemFromIdentifierJson(inputEntry, inputNode)); - } - - List inputs = new ArrayList<>(shape.size() * shape.get(0).length()); - int i = 0; - // Create a linear array of items from the "cube" of the shape - for (int j = 0; i < shape.size() * shape.get(0).length(); j++) { - for (char c : shape.get(j).toCharArray()) { - ItemData data = letterToRecipe.getOrDefault(String.valueOf(c), ItemData.AIR); - inputs.add(data); - i++; - } - } - - /* Convert into a Java recipe class for autocrafting */ - List ingredients = new ArrayList<>(); - for (ItemData input : inputs) { - ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input, mappings)})); - } - GeyserRecipe recipe = new GeyserShapedRecipe(shape.get(0).length(), shape.size(), - ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings)); - recipes.put(netId, recipe); - /* Convert end */ - - return ShapedRecipeData.shaped(uuid.toString(), shape.get(0).length(), shape.size(), - inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId, false, RecipeUnlockingRequirement.INVALID); - } - List inputs = new ObjectArrayList<>(); - for (JsonNode entry : node.get("inputs")) { - ItemMapping inputEntry = mappings.getMapping(entry.get("identifier").asText()); - inputs.add(getBedrockItemFromIdentifierJson(inputEntry, entry)); - } - - /* Convert into a Java Recipe class for autocrafting */ - List ingredients = new ArrayList<>(); - for (ItemData input : inputs) { - ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input, mappings)})); - } - GeyserRecipe recipe = new GeyserShapelessRecipe(ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings)); - recipes.put(netId, recipe); - /* Convert end */ - - if (type == 5) { - // Shulker box - return ShapelessRecipeData.shulkerBox(uuid.toString(), - inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); - } - return ShapelessRecipeData.shapeless(uuid.toString(), - inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId, RecipeUnlockingRequirement.INVALID); - } - - private static ItemData getBedrockItemFromIdentifierJson(ItemMapping mapping, JsonNode itemNode) { - int count = 1; - short damage = 0; - NbtMap tag = null; - JsonNode damageNode = itemNode.get("bedrockDamage"); - if (damageNode != null) { - damage = damageNode.numberValue().shortValue(); - } - JsonNode countNode = itemNode.get("count"); - if (countNode != null) { - count = countNode.asInt(); - } - JsonNode nbtNode = itemNode.get("bedrockNbt"); - if (nbtNode != null) { - byte[] bytes = Base64.getDecoder().decode(nbtNode.asText()); - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - try { - tag = (NbtMap) NbtUtils.createReaderLE(bais).readTag(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return ItemData.builder() - .definition(mapping.getBedrockDefinition()) - .damage(damage) - .count(count) - .blockDefinition(mapping.getBedrockBlockDefinition()) - .tag(tag) - .build(); - } -} 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 ae5e1d338..836c77379 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -356,8 +356,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * 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. */ - @Setter - private Map> javaToBedrockRecipeIds; + private final Map> javaToBedrockRecipeIds; @Setter private Int2ObjectMap craftingRecipes; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 18d6a22eb..bc6ff2adf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -423,7 +423,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } // Reference the creative items list we send to the client to know what it's asking of us ItemData creativeItem = creativeItems[creativeId]; - javaCreativeItem = ItemTranslator.translateToJava(creativeItem, session.getItemMappings()); + javaCreativeItem = ItemTranslator.translateToJava(session, creativeItem); break; } case CRAFT_RESULTS_DEPRECATED: { 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 251aacba8..8b61e435a 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 @@ -47,7 +47,6 @@ import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.CustomSkull; import org.geysermc.geyser.registry.type.ItemMapping; -import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; @@ -83,25 +82,21 @@ public final class ItemTranslator { private ItemTranslator() { } - /** - * @param mappings item mappings to use while translating. This can't just be a Geyser session as this method is used - * when loading recipes. - */ - public static ItemStack translateToJava(ItemData data, ItemMappings mappings) { + public static ItemStack translateToJava(GeyserSession session, ItemData data) { if (data == null) { return new ItemStack(Items.AIR_ID); } - ItemMapping bedrockItem = mappings.getMapping(data); + ItemMapping bedrockItem = session.getItemMappings().getMapping(data); Item javaItem = bedrockItem.getJavaItem(); - GeyserItemStack itemStack = javaItem.translateToJava(data, bedrockItem, mappings); + GeyserItemStack itemStack = javaItem.translateToJava(data, bedrockItem, session.getItemMappings()); NbtMap nbt = data.getTag(); if (nbt != null && !nbt.isEmpty()) { // translateToJava may have added components DataComponents components = itemStack.getComponents() == null ? new DataComponents(new HashMap<>()) : itemStack.getComponents(); - javaItem.translateNbtToJava(nbt, components, bedrockItem); + javaItem.translateNbtToJava(session, nbt, components, bedrockItem); if (!components.getDataComponents().isEmpty()) { itemStack.setComponents(components); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 2a0c38221..886b31e09 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -103,66 +103,31 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator> recipeTypes = Registries.CRAFTING_DATA.forVersion(session.getUpstream().getProtocolVersion()); - // Get the last known network ID (first used for the pregenerated recipes) and increment from there. - int netId = InventoryUtils.LAST_RECIPE_NET_ID + 1; boolean sendTrimRecipes = false; Map> recipeIDs = session.getJavaToBedrockRecipeIds(); - Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(Registries.RECIPES.forVersion(session.getUpstream().getProtocolVersion())); + recipeIDs.clear(); + Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(); Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); 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(); - ItemData output = ItemTranslator.translateToBedrock(session, shapelessRecipeData.getResult()); - if (!output.isValid()) { - // Likely modded item that Bedrock will complain about if it persists - continue; + List bedrockRecipeIDs = context.translateShapelessRecipe(new GeyserShapelessRecipe(shapelessRecipeData)); + if (bedrockRecipeIDs != null) { + context.addRecipeIdentifier(session, recipe.getIdentifier(), bedrockRecipeIDs); } - // Strip NBT - tools won't appear in the recipe book otherwise - output = output.toBuilder().tag(null).build(); - ItemDescriptorWithCount[][] inputCombinations = combinations(session, shapelessRecipeData.getIngredients()); - if (inputCombinations == null) { - continue; - } - - List bedrockRecipeIDs = new ArrayList<>(); - for (ItemDescriptorWithCount[] inputs : inputCombinations) { - UUID uuid = UUID.randomUUID(); - bedrockRecipeIDs.add(uuid.toString()); - craftingDataPacket.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++, new GeyserShapelessRecipe(shapelessRecipeData)); - } - addRecipeIdentifier(session, recipe.getIdentifier(), bedrockRecipeIDs); } case CRAFTING_SHAPED -> { ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData(); - ItemData output = ItemTranslator.translateToBedrock(session, shapedRecipeData.getResult()); - if (!output.isValid()) { - // Likely modded item that Bedrock will complain about if it persists - continue; + List bedrockRecipeIDs = context.translateShapedRecipe(new GeyserShapedRecipe(shapedRecipeData)); + if (bedrockRecipeIDs != null) { + context.addRecipeIdentifier(session, recipe.getIdentifier(), bedrockRecipeIDs); } - // See above - output = output.toBuilder().tag(null).build(); - ItemDescriptorWithCount[][] inputCombinations = combinations(session, shapedRecipeData.getIngredients()); - if (inputCombinations == null) { - continue; - } - - List bedrockRecipeIDs = new ArrayList<>(); - for (ItemDescriptorWithCount[] inputs : inputCombinations) { - UUID uuid = UUID.randomUUID(); - bedrockRecipeIDs.add(uuid.toString()); - craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData.shaped(uuid.toString(), - shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), Arrays.asList(inputs), - Collections.singletonList(output), uuid, "crafting_table", 0, netId, false, RecipeUnlockingRequirement.INVALID)); - recipeMap.put(netId++, new GeyserShapedRecipe(shapedRecipeData)); - } - addRecipeIdentifier(session, recipe.getIdentifier(), bedrockRecipeIDs); } case STONECUTTING -> { StoneCuttingRecipeData stoneCuttingData = (StoneCuttingRecipeData) recipe.getData(); @@ -198,7 +163,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator(Collections.singletonList(id))); } @@ -212,13 +177,48 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator { // 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"), netId++)); + 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())); } default -> { - List craftingData = recipeTypes.get(recipe.getType()); - if (craftingData != null) { - addSpecialRecipesIdentifiers(session, recipe, craftingData); - craftingDataPacket.getCraftingData().addAll(craftingData); + 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); } } } @@ -250,17 +250,17 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator craftingData) { - String javaRecipeID = recipe.getIdentifier(); - - switch (recipe.getType()) { - case CRAFTING_SPECIAL_BOOKCLONING, CRAFTING_SPECIAL_REPAIRITEM, CRAFTING_SPECIAL_MAPEXTENDING, CRAFTING_SPECIAL_MAPCLONING: - // We do not want to (un)lock these, since BDS does not do it for MultiRecipes - return; - case CRAFTING_SPECIAL_SHULKERBOXCOLORING: - // BDS (un)locks the dyeing with the shulker box recipe, Java never - we want BDS behavior for ease of use - javaRecipeID = "minecraft:shulker_box"; - break; - case CRAFTING_SPECIAL_TIPPEDARROW: - // similar as above - javaRecipeID = "minecraft:arrow"; - break; - } - List bedrockRecipeIDs = new ArrayList<>(); - - // defined in the recipes.json mappings file: Only tipped arrows use shaped recipes, we need the cast for the identifier - if (recipe.getType() == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) { - for (RecipeData data : craftingData) { - bedrockRecipeIDs.add(((org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData) data).getId()); - } - } else { - for (RecipeData data : craftingData) { - bedrockRecipeIDs.add(((org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData) data).getId()); - } - } - addRecipeIdentifier(session, javaRecipeID, bedrockRecipeIDs); + System.out.println(craftingDataPacket); } //TODO: rewrite @@ -323,7 +292,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator, IntSet> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { @@ -407,17 +376,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator bedrockIdentifiers) { - session.getJavaToBedrockRecipeIds().computeIfAbsent(javaIdentifier, k -> new ArrayList<>()).addAll(bedrockIdentifiers); - } - - @EqualsAndHashCode - @AllArgsConstructor - private static class GroupedItem { - ItemDefinition id; - int count; - } - private List getSmithingTransformRecipes(GeyserSession session) { List recipes = new ArrayList<>(); ItemMapping template = session.getItemMappings().getStoredItems().upgradeTemplate(); @@ -442,4 +400,120 @@ 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) { + ItemData output = ItemTranslator.translateToBedrock(session, recipe.result()); + if (!output.isValid()) { + // Likely modded item that Bedrock will complain about if it persists + return null; + } + // 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) { + ItemData output = ItemTranslator.translateToBedrock(session, recipe.result()); + if (!output.isValid()) { + // Likely modded item that Bedrock will complain about if it persists + return null; + } + // 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) { + ItemData output = ItemTranslator.translateToBedrock(session, recipe.result()); + if (!output.isValid()) { + // Likely modded item that Bedrock will complain about if it persists + return null; + } + // See above + 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(); + }; + + 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/resources/mappings b/core/src/main/resources/mappings index 54705bcd2..8795baeb1 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 54705bcd2bcba830267efbb1fbfd4e52972c40f7 +Subproject commit 8795baeb170f7c9832da2def8625f0c5702abd91 From 2ecc4cd841e9902cb0b2ff3128b4d6592b41fb30 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:42:29 -0400 Subject: [PATCH 212/897] Point to right mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 8795baeb1..396ea5ff5 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 8795baeb170f7c9832da2def8625f0c5702abd91 +Subproject commit 396ea5ff50d8c976fde4e7423e682d21aa0ee350 From 82d0a87020aa9e5621f4d78fbda5a9bb4b0863a0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:45:47 -0400 Subject: [PATCH 213/897] Remove debug code --- core/src/main/java/org/geysermc/geyser/registry/Registries.java | 1 - .../translator/protocol/java/JavaUpdateRecipesTranslator.java | 1 - 2 files changed, 2 deletions(-) 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 deafbdf7e..30d3c0763 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -169,7 +169,6 @@ public final class Registries { static { PacketRegistryPopulator.populate(); ItemRegistryPopulator.populate(); - System.out.println(RECIPES.get()); // Create registries that require other registries to load first POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 886b31e09..4d207153b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -282,7 +282,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Date: Wed, 12 Jun 2024 20:56:06 -0400 Subject: [PATCH 214/897] Fix some water plants not being waterlogged --- .../geyser/registry/populator/BlockRegistryPopulator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index a8fb0001d..272522429 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -290,7 +290,8 @@ public final class BlockRegistryPopulator { } boolean waterlogged = blockState.getValue(Properties.WATERLOGGED, false) - || block == Blocks.BUBBLE_COLUMN || block == Blocks.KELP || block == Blocks.SEAGRASS; + || block == Blocks.BUBBLE_COLUMN || block == Blocks.KELP || block == Blocks.KELP_PLANT + || block == Blocks.SEAGRASS || block == Blocks.TALL_SEAGRASS; if (waterlogged) { BlockRegistries.WATERLOGGED.get().set(javaRuntimeId); From 52a93ecc187cd1fdc2bcc0ab66d6c86734ccbbaa Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:16:14 -0400 Subject: [PATCH 215/897] Implement breeze --- .../java/org/geysermc/geyser/entity/EntityDefinitions.java | 5 +++++ .../geyser/entity/type/living/monster/BreezeEntity.java | 4 ++++ 2 files changed, 9 insertions(+) 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 a7c2d6ca6..1496f8a82 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -66,6 +66,7 @@ public final class EntityDefinitions { 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; @@ -530,6 +531,10 @@ public final class EntityDefinitions { .height(1.8f).width(0.6f) .addTranslator(MetadataType.BYTE, BlazeEntity::setBlazeFlags) .build(); + BREEZE = EntityDefinition.inherited(BreezeEntity::new, mobEntityBase) + .type(EntityType.BREEZE) + .height(1.77f).width(0.6f) + .build(); CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase) .type(EntityType.CREEPER) .height(1.7f).width(0.6f) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java index 25d466aaf..251a77fb9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.monster; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; @@ -39,6 +40,9 @@ public class BreezeEntity extends MonsterEntity { @Override public void setPose(Pose pose) { + // TODO Test + setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, pose == Pose.SHOOTING); + setFlag(EntityFlag.JUMP_GOAL_JUMP, pose == Pose.INHALING); super.setPose(pose); } } From 3528b1d692b8c19cf8bca187dbc086647f5399ed Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:47:47 -0400 Subject: [PATCH 216/897] Allow recipes to default count as 1 --- .../geysermc/geyser/registry/loader/RecipeRegistryLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5d1236581..f1d0c456f 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 @@ -136,7 +136,7 @@ public final class RecipeRegistryLoader implements RegistryLoader Date: Wed, 12 Jun 2024 23:48:40 -0400 Subject: [PATCH 217/897] Update to latest MCProtocolLib --- .../type/player/SessionPlayerEntity.java | 2 +- .../geyser/inventory/item/BannerPattern.java | 10 +++-- .../geyser/inventory/recipe/TrimRecipe.java | 17 +------- .../geyser/item/enchantment/Enchantment.java | 7 ++-- .../geysermc/geyser/item/type/BannerItem.java | 7 ++-- .../org/geysermc/geyser/item/type/Item.java | 4 +- .../geysermc/geyser/level/PaintingType.java | 8 +++- .../mappings/versions/MappingsReader_v1.java | 20 ++-------- .../geyser/session/GeyserSession.java | 3 +- .../geyser/session/cache/LodestoneCache.java | 9 +++-- .../geyser/session/cache/RegistryCache.java | 16 ++++---- .../geyser/session/cache/TagCache.java | 14 ++++--- .../geyser/session/cache/tags/BlockTag.java | 5 ++- .../session/cache/tags/EnchantmentTag.java | 6 ++- .../geyser/session/cache/tags/ItemTag.java | 6 ++- .../translator/level/BiomeTranslator.java | 2 +- .../BedrockBlockEntityDataTranslator.java | 4 +- ...tionTrackingDBClientRequestTranslator.java | 2 +- .../JavaClientboundRecipesTranslator.java | 1 + .../protocol/java/JavaCommandsTranslator.java | 15 +++---- .../java/JavaCustomPayloadTranslator.java | 4 +- .../java/JavaGameProfileTranslator.java | 3 +- .../protocol/java/JavaLoginTranslator.java | 10 +++-- .../java/JavaUpdateRecipesTranslator.java | 8 ++-- .../player/JavaStoreCookieTranslator.java | 2 +- .../java/level/JavaStopSoundTranslator.java | 2 +- .../geysermc/geyser/util/MinecraftKey.java | 39 +++++++++++++++++++ .../geyser/util/PluginMessageUtils.java | 3 +- gradle/libs.versions.toml | 2 +- 29 files changed, 135 insertions(+), 96 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/util/MinecraftKey.java 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 ad6729c42..31eb02984 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 @@ -220,7 +220,7 @@ public class SessionPlayerEntity extends PlayerEntity { public void setLastDeathPosition(@Nullable GlobalPos pos) { if (pos != null) { dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition()); - dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension())); + dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension().asString())); dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, true); } else { dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java index b6cc2c206..743fbdc7e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java @@ -26,7 +26,9 @@ package org.geysermc.geyser.inventory.item; import lombok.Getter; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.util.MinecraftKey; import java.util.Locale; @@ -78,17 +80,17 @@ public enum BannerPattern { private static final BannerPattern[] VALUES = values(); - private final String javaIdentifier; + private final Key javaIdentifier; private final String bedrockIdentifier; BannerPattern(String bedrockIdentifier) { - this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT); + this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ROOT)); this.bedrockIdentifier = bedrockIdentifier; } - public static @Nullable BannerPattern getByJavaIdentifier(String javaIdentifier) { + public static @Nullable BannerPattern getByJavaIdentifier(Key key) { for (BannerPattern bannerPattern : VALUES) { - if (bannerPattern.javaIdentifier.equals(javaIdentifier)) { + if (bannerPattern.javaIdentifier.equals(key)) { return bannerPattern; } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java index 9d9dbe0db..8289813a4 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java @@ -47,7 +47,7 @@ public final class TrimRecipe { public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates"); public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) { - String key = stripMinecraftNamespace(entry.getId()); + String key = entry.getId().asMinimalString(); // Color is used when hovering over the item // Find the nearest legacy color from the RGB Java gives us to work with @@ -67,7 +67,7 @@ public final class TrimRecipe { } public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) { - String key = stripMinecraftNamespace(entry.getId()); + String key = entry.getId().asMinimalString(); String itemIdentifier = entry.getData().getString("template_item"); ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier); @@ -78,19 +78,6 @@ public final class TrimRecipe { return new TrimPattern(itemMapping.getBedrockIdentifier(), key); } - // TODO find a good place for a stripNamespace util method - private static String stripMinecraftNamespace(String identifier) { - int i = identifier.indexOf(':'); - if (i >= 0) { - String namespace = identifier.substring(0, i); - // Only strip minecraft namespace - if (namespace.equals("minecraft")) { - return identifier.substring(i + 1); - } - } - return identifier; - } - private TrimRecipe() { //no-op } 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 468b88e87..c5c0d2611 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 @@ -31,6 +31,7 @@ import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.session.cache.tags.EnchantmentTag; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import java.util.HashSet; @@ -59,11 +60,11 @@ public record Enchantment(String identifier, int maxLevel = data.getInt("max_level"); int anvilCost = data.getInt("anvil_cost"); String exclusiveSet = data.getString("exclusive_set", null); - EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(exclusiveSet.substring(1)); - BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId()); + EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(MinecraftKey.key(exclusiveSet.substring(1))); + BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId().asString()); String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(data) : null; - return new Enchantment(entry.getId(), effects, ItemTag.ALL_ITEM_TAGS.get(supportedItems), maxLevel, + return new Enchantment(entry.getId().asString(), effects, ItemTag.ALL_ITEM_TAGS.get(MinecraftKey.key(supportedItems)), maxLevel, description, anvilCost, exclusiveSetTag, bedrockEnchantment); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 4af2b4630..6ec0da8ed 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.type; import it.unimi.dsi.fastutil.Pair; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; @@ -40,8 +41,8 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.registry.JavaRegistry; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.Holder; -import org.geysermc.mcprotocollib.protocol.data.game.Identifier; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -106,7 +107,7 @@ public class BannerItem extends BlockItem { if (color != pair.right()) { return false; } - String id = Identifier.formalize(patternLayer.getString("pattern")); // Ouch + Key id = MinecraftKey.key(patternLayer.getString("pattern")); // Ouch BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(id); if (bannerPattern != pair.left()) { return false; @@ -166,7 +167,7 @@ public class BannerItem extends BlockItem { */ private static NbtMap getBedrockBannerPattern(NbtMap pattern) { // ViaVersion 1.20.4 -> 1.20.5 can send without the namespace - BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(Identifier.formalize(pattern.getString("pattern"))); + BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(MinecraftKey.key(pattern.getString("pattern"))); DyeColor dyeColor = DyeColor.getByJavaIdentifier(pattern.getString("color")); if (bannerPattern == null || dyeColor == null) { return null; 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 1ebf85065..3014e8116 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 @@ -45,7 +45,7 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.mcprotocollib.protocol.data.game.Identifier; +import org.geysermc.geyser.util.MinecraftKey; 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.DyedItemColor; @@ -65,7 +65,7 @@ public class Item { private final int maxDamage; public Item(String javaIdentifier, Builder builder) { - this.javaIdentifier = Identifier.formalize(javaIdentifier).intern(); + this.javaIdentifier = MinecraftKey.key(javaIdentifier).asString().intern(); this.stackSize = builder.stackSize; this.maxDamage = builder.maxDamage; this.attackDamage = builder.attackDamage; diff --git a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java index de35d97f1..f829b481c 100644 --- a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java +++ b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.level; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; +import net.kyori.adventure.key.Key; import java.util.Locale; @@ -90,9 +91,12 @@ public enum PaintingType { private final int width; private final int height; - public static PaintingType getByName(String javaName) { + public static PaintingType getByName(Key key) { + if (!key.namespace().equals("minecraft")) { + return null; + } for (PaintingType paintingName : VALUES) { - if (("minecraft:" + paintingName.name().toLowerCase(Locale.ROOT)).equals(javaName)) return paintingName; + if (paintingName.name().toLowerCase(Locale.ROOT).equals(key.value())) return paintingName; } return null; } diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java index d32d5bc09..b5e25a4ba 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.registry.mappings.versions; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; -import org.geysermc.mcprotocollib.protocol.data.game.Identifier; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.checkerframework.checker.nullness.qual.Nullable; @@ -35,14 +34,9 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockPermutation; import org.geysermc.geyser.api.block.custom.CustomBlockState; -import org.geysermc.geyser.api.block.custom.component.BoxComponent; -import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents; -import org.geysermc.geyser.api.block.custom.component.GeometryComponent; -import org.geysermc.geyser.api.block.custom.component.MaterialInstance; -import org.geysermc.geyser.api.block.custom.component.PlacementConditions; +import org.geysermc.geyser.api.block.custom.component.*; import org.geysermc.geyser.api.block.custom.component.PlacementConditions.BlockFilterType; import org.geysermc.geyser.api.block.custom.component.PlacementConditions.Face; -import org.geysermc.geyser.api.block.custom.component.TransformationComponent; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.util.CreativeCategory; @@ -60,16 +54,10 @@ import org.geysermc.geyser.registry.mappings.util.CustomBlockStateMapping; import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.geyser.util.MinecraftKey; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Predicate; @@ -131,7 +119,7 @@ public class MappingsReader_v1 extends MappingsReader { blocksNode.fields().forEachRemaining(entry -> { if (entry.getValue().isObject()) { try { - String identifier = Identifier.formalize(entry.getKey()); + String identifier = MinecraftKey.key(entry.getKey()).asString(); CustomBlockMapping customBlockMapping = this.readBlockMappingEntry(identifier, entry.getValue()); consumer.accept(identifier, customBlockMapping); } catch (Exception e) { 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 836c77379..e228fc02f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -40,6 +40,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; @@ -290,7 +291,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Keeps track of the world name for respawning. */ @Setter - private String worldName = null; + private Key worldName = null; /** * As of Java 1.19.3, the client only uses these for commands. */ diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java index f66daf027..ee8ebb13f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.session.cache; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos; @@ -64,7 +65,7 @@ public final class LodestoneCache { int x = position.getX(); int y = position.getY(); int z = position.getZ(); - String dim = position.getDimension(); + Key dim = position.getDimension(); for (LodestonePos pos : this.activeLodestones.values()) { if (pos.equals(x, y, z, dim)) { @@ -98,7 +99,7 @@ public final class LodestoneCache { int x = position.getX(); int y = position.getY(); int z = position.getZ(); - String dim = position.getDimension(); + Key dim = position.getDimension(); for (LodestonePos pos : this.activeLodestones.values()) { if (pos.equals(x, y, z, dim)) { @@ -138,8 +139,8 @@ public final class LodestoneCache { this.lodestones.clear(); } - public record LodestonePos(int id, int x, int y, int z, String dimension) { - boolean equals(int x, int y, int z, String dimension) { + public record LodestonePos(int id, int x, int y, int z, Key dimension) { + boolean equals(int x, int y, int z, Key dimension) { return this.x == x && this.y == y && this.z == z && this.dimension.equals(dimension); } } 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 266a0a418..02c43939d 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 @@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import lombok.AccessLevel; import lombok.Getter; import lombok.experimental.Accessors; +import net.kyori.adventure.key.Key; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; @@ -47,6 +48,7 @@ import org.geysermc.geyser.session.cache.registry.JavaRegistry; import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType; @@ -70,8 +72,8 @@ import java.util.function.ToIntFunction; @Accessors(fluent = true) @Getter public final class RegistryCache { - private static final Map> DEFAULTS; - private static final Map>> REGISTRIES = new HashMap<>(); + private static final Map> DEFAULTS; + private static final Map>> REGISTRIES = new HashMap<>(); static { register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry)); @@ -83,14 +85,14 @@ public final class RegistryCache { register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); - register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(entry.getId())); + register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(entry.getId().asString())); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); - Map> defaults = new HashMap<>(); + 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) + List rawValues = tag.getCompound(key.asString()) .getList("value", NbtType.COMPOUND); Map values = new HashMap<>(); for (NbtMap value : rawValues) { @@ -148,7 +150,7 @@ public final class RegistryCache { * @param the class that represents these entries. */ private static void register(String registry, Function> localCacheFunction, BiFunction reader) { - String key = "minecraft:" + registry; + Key key = MinecraftKey.key(registry); REGISTRIES.put(key, (registryCache, entries) -> { Map localRegistry = null; JavaRegistry localCache = localCacheFunction.apply(registryCache); @@ -176,7 +178,7 @@ public final class RegistryCache { * @param localCacheFunction the int array to set the final values to. */ private static void register(String registry, BiConsumer localCacheFunction, ToIntFunction reader) { - REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> { + REGISTRIES.put(MinecraftKey.key(registry), (registryCache, entries) -> { Int2IntMap temp = new Int2IntOpenHashMap(); int greatestId = 0; for (int i = 0; i < entries.size(); i++) { 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 656a16cf4..c8bfc7eed 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,6 +26,7 @@ package org.geysermc.geyser.session.cache; import it.unimi.dsi.fastutil.ints.IntArrays; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; @@ -36,6 +37,7 @@ 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.util.MinecraftKey; import org.geysermc.geyser.util.Ordered; import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; @@ -58,33 +60,33 @@ public final class TagCache { private final int[][] enchantments = new int[ALL_ENCHANTMENT_TAGS.size()][]; public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) { - Map blockTags = packet.getTags().get("minecraft:block"); + Map blockTags = packet.getTags().get(MinecraftKey.key("block")); loadTags("Block", blockTags, ALL_BLOCK_TAGS, this.blocks); // Hack btw GeyserLogger logger = session.getGeyser().getLogger(); - int[] convertableToMud = blockTags.get("minecraft:convertable_to_mud"); + 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("minecraft:item"); + Map itemTags = packet.getTags().get(MinecraftKey.key("item")); loadTags("Item", itemTags, ALL_ITEM_TAGS, this.items); // Hack btw - boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1; + 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("minecraft:enchantment"); + 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) { + 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."); 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 5a85efc84..1dca7843a 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,6 +25,7 @@ package org.geysermc.geyser.session.cache.tags; +import net.kyori.adventure.key.Key; import org.geysermc.geyser.util.Ordered; import java.util.HashMap; @@ -32,7 +33,7 @@ import java.util.Map; @SuppressWarnings("unused") public final class BlockTag implements Ordered { - public static final Map ALL_BLOCK_TAGS = new HashMap<>(); + public static final Map ALL_BLOCK_TAGS = new HashMap<>(); public static final BlockTag WOOL = new BlockTag("wool"); public static final BlockTag PLANKS = new BlockTag("planks"); @@ -232,6 +233,6 @@ public final class BlockTag implements Ordered { } private static void register(String name, BlockTag tag) { - ALL_BLOCK_TAGS.put(("minecraft:" + name).intern(), tag); + ALL_BLOCK_TAGS.put(Key.key(name), tag); } } 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 3c5446adc..0af690abd 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,6 +25,8 @@ package org.geysermc.geyser.session.cache.tags; +import net.kyori.adventure.key.Key; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.geyser.util.Ordered; import java.util.HashMap; @@ -32,7 +34,7 @@ import java.util.Map; @SuppressWarnings("unused") public final class EnchantmentTag implements Ordered { - public static final Map ALL_ENCHANTMENT_TAGS = new HashMap<>(); + public static final Map ALL_ENCHANTMENT_TAGS = new HashMap<>(); public static final EnchantmentTag TOOLTIP_ORDER = new EnchantmentTag("tooltip_order"); public static final EnchantmentTag EXCLUSIVE_SET_ARMOR = new EnchantmentTag("exclusive_set/armor"); @@ -84,6 +86,6 @@ public final class EnchantmentTag implements Ordered { } private static void register(String name, EnchantmentTag tag) { - ALL_ENCHANTMENT_TAGS.put(("minecraft:" + name).intern(), tag); + ALL_ENCHANTMENT_TAGS.put(MinecraftKey.key(name), tag); } } 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 e1fbf4634..a2e861dd6 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,6 +25,8 @@ package org.geysermc.geyser.session.cache.tags; +import net.kyori.adventure.key.Key; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.geyser.util.Ordered; import java.util.HashMap; @@ -32,7 +34,7 @@ import java.util.Map; @SuppressWarnings("unused") public final class ItemTag implements Ordered { - public static final Map ALL_ITEM_TAGS = new HashMap<>(); + public static final Map ALL_ITEM_TAGS = new HashMap<>(); public static final ItemTag WOOL = new ItemTag("wool"); public static final ItemTag PLANKS = new ItemTag("planks"); @@ -195,6 +197,6 @@ public final class ItemTag implements Ordered { } private static void register(String name, ItemTag tag) { - ALL_ITEM_TAGS.put(("minecraft:" + name).intern(), tag); + ALL_ITEM_TAGS.put(MinecraftKey.key(name), tag); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index d70f53e2c..166089b6b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -45,7 +45,7 @@ import org.geysermc.geyser.session.GeyserSession; public class BiomeTranslator { public static int loadServerBiome(RegistryEntry entry) { - String javaIdentifier = entry.getId(); + String javaIdentifier = entry.getId().asString(); return Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java index b5e923ee6..a7e4bc656 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetJigsawBlockPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket; import org.cloudburstmc.math.vector.Vector3i; @@ -119,7 +120,8 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 1ecc5bf82..ecfb2d220 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -34,6 +34,7 @@ import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; import lombok.Getter; import lombok.ToString; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.cloudburstmc.protocol.bedrock.data.command.*; @@ -66,7 +67,7 @@ public class JavaCommandsTranslator extends PacketTranslator ALL_BLOCK_NAMES = Suppliers.memoize(() -> BlockRegistries.JAVA_BLOCKS.get().stream().map(block -> block.javaIdentifier().toString()).toArray(String[]::new)); private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers(); - private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(AttributeType::getIdentifier).toList().toArray(new String[0]); + private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(type -> type.getIdentifier().asString()).toList().toArray(new String[0]); private static final String[] ENUM_BOOLEAN = {"true", "false"}; private static final String[] VALID_COLORS; private static final String[] VALID_SCOREBOARD_SLOTS; @@ -264,8 +265,8 @@ public class JavaCommandsTranslator extends PacketTranslator ATTRIBUTES; case "minecraft:enchantment" -> context.getEnchantments(); case "minecraft:entity_type" -> context.getEntityTypes(); @@ -476,12 +477,8 @@ public class JavaCommandsTranslator extends PacketTranslator { @@ -98,7 +101,7 @@ public class JavaLoginTranslator extends PacketTranslator bedrockRecipeIDs = context.translateShapelessRecipe(new GeyserShapelessRecipe(shapelessRecipeData)); if (bedrockRecipeIDs != null) { - context.addRecipeIdentifier(session, recipe.getIdentifier(), bedrockRecipeIDs); + 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(), bedrockRecipeIDs); + context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs); } } case STONECUTTING -> { @@ -160,7 +160,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator // similar as above "minecraft:arrow"; - default -> recipe.getIdentifier(); + default -> recipe.getIdentifier().asString(); }; addRecipeIdentifier(session, javaRecipeID, identifiers); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java index 342618ff8..7c8374500 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaStoreCookieTranslator.java @@ -35,6 +35,6 @@ public class JavaStoreCookieTranslator extends PacketTranslator Date: Wed, 12 Jun 2024 23:53:02 -0400 Subject: [PATCH 218/897] Fix compilation for modded --- .../geyser/platform/mod/world/GeyserModWorldManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 5543dbcee..ef8c3ec0a 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 @@ -47,6 +47,7 @@ import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.platform.mod.GeyserModBootstrap; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; @@ -173,7 +174,7 @@ public class GeyserModWorldManager extends GeyserWorldManager { return patternLayers.layers().stream() .map(layer -> { BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern( - layer.pattern().value().assetId().toString(), layer.pattern().value().translationKey() + MinecraftKey.key(layer.pattern().value().assetId().toString()), layer.pattern().value().translationKey() ); return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId()); }) From d00cab18fdc0eeb15381cc17c384fd2f5a6faa88 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 13 Jun 2024 14:14:57 +0200 Subject: [PATCH 219/897] Only translate double chest tags if we are dealing with a double chest (#4736) --- .../block/entity/DoubleChestBlockEntityTranslator.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index 988d94073..9f111788b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -42,9 +42,11 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { - int x = (int) bedrockNbt.get("x"); - int z = (int) bedrockNbt.get("z"); - translateChestValue(bedrockNbt, blockState, x, z); + if (blockState.getValue(Properties.CHEST_TYPE) != ChestType.SINGLE) { + int x = (int) bedrockNbt.get("x"); + int z = (int) bedrockNbt.get("z"); + translateChestValue(bedrockNbt, blockState, x, z); + } } /** From db5a5289659d8b07abdcca83e5549672ddc0e272 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 13 Jun 2024 16:53:01 +0200 Subject: [PATCH 220/897] Fix: Improper detection of virtual double chests (#4738) --- .../inventory/chest/DoubleChestInventoryTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index 06531eff2..856cc1876 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -64,7 +64,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition()); if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) { - if (state.block() == Blocks.CHEST || state.block() == Blocks.TRAPPED_CHEST + if ((state.block() == Blocks.CHEST || state.block() == Blocks.TRAPPED_CHEST) && state.getValue(Properties.CHEST_TYPE) != ChestType.SINGLE) { inventory.setHolderPosition(session.getLastInteractionBlockPosition()); ((Container) inventory).setUsingRealBlock(true, state.block()); From ce3083b9b83b65ffc041326e45f14aa040c9dd7b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:24:16 -0400 Subject: [PATCH 221/897] Fix key regression with pre-built registries --- .../geysermc/geyser/session/cache/RegistryCache.java | 10 +++++----- .../java/JavaClientboundRecipesTranslator.java | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) 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 02c43939d..3121af369 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 @@ -72,7 +72,7 @@ import java.util.function.ToIntFunction; @Accessors(fluent = true) @Getter public final class RegistryCache { - private static final Map> DEFAULTS; + private static final Map> DEFAULTS; private static final Map>> REGISTRIES = new HashMap<>(); static { @@ -89,14 +89,14 @@ public final class RegistryCache { // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); - Map> defaults = new HashMap<>(); + 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); - Map values = new HashMap<>(); + Map values = new HashMap<>(); for (NbtMap value : rawValues) { - String name = value.getString("name"); + Key name = MinecraftKey.key(value.getString("name")); values.put(name, value.getCompound("element")); } // Can make these maps immutable and as efficient as possible after initialization @@ -152,7 +152,7 @@ public final class RegistryCache { private static void register(String registry, Function> localCacheFunction, BiFunction reader) { Key key = MinecraftKey.key(registry); REGISTRIES.put(key, (registryCache, entries) -> { - Map localRegistry = null; + Map localRegistry = null; JavaRegistry localCache = localCacheFunction.apply(registryCache); // Clear each local cache every time a new registry entry is given to us // (e.g. proxy server switches) 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/JavaClientboundRecipesTranslator.java index 06abbbac0..9eb69183d 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/JavaClientboundRecipesTranslator.java @@ -39,7 +39,6 @@ public class JavaClientboundRecipesTranslator extends PacketTranslator { From 746be566a2a341498b27ace99a079f6db4adb5d5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:53:20 -0400 Subject: [PATCH 222/897] Sanity check for BlockState being chest --- .../level/block/entity/DoubleChestBlockEntityTranslator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index 9f111788b..6fea10e2e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.ChestType; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; @@ -42,6 +43,9 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { + if (!(blockState.is(Blocks.CHEST) || blockState.is(Blocks.TRAPPED_CHEST))) { + return; + } if (blockState.getValue(Properties.CHEST_TYPE) != ChestType.SINGLE) { int x = (int) bedrockNbt.get("x"); int z = (int) bedrockNbt.get("z"); From b6653acc294e21778d09bfa155528bf116eea70c Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 13 Jun 2024 19:53:47 +0200 Subject: [PATCH 223/897] Catch Throwable when trying to load world adapter --- .../org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index d138ad074..fdef77bbe 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -265,7 +265,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, isPaper); } geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName()); - } catch (Exception e) { + } catch (Throwable e) { if (geyserConfig.isDebugMode()) { geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)"); e.printStackTrace(); From a5ecee73ef0f4382420ffd252eb2097ba70d4e3b Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 13 Jun 2024 20:12:45 +0200 Subject: [PATCH 224/897] Update Bungee warning for outdated proxy checks --- .../geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 062ef6f76..cd6b59f64 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -81,7 +81,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { // Copied from ViaVersion. // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 try { - ProtocolConstants.class.getField("MINECRAFT_1_20_5"); + ProtocolConstants.class.getField("MINECRAFT_1_21"); } catch (NoSuchFieldException e) { geyserLogger.error(" / \\"); geyserLogger.error(" / \\"); From 4a334a2c8d7068c84fc9d41ada97a86f77c85c1f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:58:39 -0400 Subject: [PATCH 225/897] Bed block sanity check for villagers --- .../type/living/merchant/VillagerEntity.java | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java index fb07572e6..d7efa9f1d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java @@ -34,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BedBlock; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; @@ -125,22 +126,24 @@ public class VillagerEntity extends AbstractMerchantEntity { int bedRotation = 0; float xOffset = 0; float zOffset = 0; - switch (state.getValue(Properties.HORIZONTAL_FACING)) { - case SOUTH -> { - bedRotation = 180; - zOffset = -.5f; - } - case EAST -> { - bedRotation = 90; - xOffset = -.5f; - } - case WEST -> { - bedRotation = 270; - xOffset = .5f; - } - case NORTH -> { - // rotation does not change because north is 0 - zOffset = .5f; + if (state.block() instanceof BedBlock) { + switch (state.getValue(Properties.HORIZONTAL_FACING)) { + case SOUTH -> { + bedRotation = 180; + zOffset = -.5f; + } + case EAST -> { + bedRotation = 90; + xOffset = -.5f; + } + case WEST -> { + bedRotation = 270; + xOffset = .5f; + } + case NORTH -> { + // rotation does not change because north is 0 + zOffset = .5f; + } } } From 6a715770e21d0569d00e50b8ab4eea7a9c8518be Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 13 Jun 2024 23:20:43 +0200 Subject: [PATCH 226/897] Update mod dependencies to their official 1.21 releases --- .../mod/fabric/src/main/resources/fabric.mod.json | 4 ++-- .../src/main/resources/META-INF/neoforge.mods.toml | 4 ++-- .../main/kotlin/geyser.modded-conventions.gradle.kts | 10 ++-------- gradle/libs.versions.toml | 4 ++-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json index 93f48b73c..262f9833a 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.10", + "fabricloader": ">=0.15.11", "fabric": "*", - "minecraft": ">=1.20.5" + "minecraft": ">=1.21" } } diff --git a/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml index 3a25f6119..fa01bb6ec 100644 --- a/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -14,12 +14,12 @@ config = "geyser.mixins.json" [[dependencies.geyser_neoforge]] modId="neoforge" type="required" - versionRange="[20.5.0-beta,)" + versionRange="[21.0.0-beta,)" ordering="NONE" side="BOTH" [[dependencies.geyser_neoforge]] modId="minecraft" type="required" - versionRange="[1.20.5,)" + versionRange="[1.21,)" ordering="NONE" side="BOTH" \ No newline at end of file diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index 6472e4312..86c2a2f6a 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -110,7 +110,7 @@ afterEvaluate { } dependencies { - minecraft("com.mojang:minecraft:1.21-rc1") + minecraft("com.mojang:minecraft:1.21") mappings(loom.officialMojangMappings()) } @@ -121,12 +121,6 @@ repositories { maven("https://oss.sonatype.org/content/repositories/snapshots/") maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") maven("https://maven.neoforged.net/releases") - maven("https://prmaven.neoforged.net/NeoForge/pr1076") { - name = "Maven for 1.21 PR" - content { - includeModule("net.neoforged", "neoforge") - } - } } modrinth { @@ -139,6 +133,6 @@ modrinth { syncBodyFrom.set(rootProject.file("README.md").readText()) uploadFile.set(tasks.getByPath("remapModrinthJar")) - gameVersions.addAll("1.20.5", "1.20.6") + gameVersions.addAll("1.21") failSilently.set(true) } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 10a94c3db..5e55aa117 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,11 +28,11 @@ commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" viaproxy = "3.2.1" -fabric-minecraft = "1.21-rc1" +fabric-minecraft = "1.21" fabric-loader = "0.15.11" fabric-api = "0.100.1+1.21" fabric-permissions = "0.2-SNAPSHOT" -neoforge-minecraft = "21.0.0-alpha.1.21-rc1.20240611.001314" +neoforge-minecraft = "21.0.0-beta" mixin = "0.8.5" # plugin versions From 09c0ada50216e1a163b22cccdce5b0657085ebd6 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 13 Jun 2024 19:53:47 +0200 Subject: [PATCH 227/897] Catch Throwable when trying to load world adapter --- .../org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index d138ad074..fdef77bbe 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -265,7 +265,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, isPaper); } geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName()); - } catch (Exception e) { + } catch (Throwable e) { if (geyserConfig.isDebugMode()) { geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)"); e.printStackTrace(); From 138c7b4eee97670d36ec36f5bc0dc6cfcbab56fa Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 14 Jun 2024 17:27:30 +0200 Subject: [PATCH 228/897] Catch EOFExceptions while pinging Java servers when it is misconfigured/not online (#4746) * Catch EOFExceptions when the remote server is misconfigured/not online --- .../geysermc/geyser/ping/GeyserLegacyPingPassthrough.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java index 320334ee5..27b405348 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java +++ b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java @@ -35,10 +35,7 @@ import org.cloudburstmc.nbt.util.VarInts; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.network.GameProtocol; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; +import java.io.*; import java.net.*; import java.util.concurrent.TimeUnit; @@ -139,6 +136,9 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn this.geyser.getLogger().debug("Connection timeout for ping passthrough."); } catch (JsonParseException | JsonMappingException ex) { this.geyser.getLogger().error("Failed to parse json when pinging server!", ex); + } catch (EOFException e) { + this.pingInfo = null; + this.geyser.getLogger().warning("Failed to ping the remote Java server! Is it online and configured in Geyser's config?"); } catch (UnknownHostException ex) { // Don't reset pingInfo, as we want to keep the last known value this.geyser.getLogger().warning("Unable to resolve remote host! Is the remote server down or invalid?"); From 28e4661fcf68f572c8ea5a60c7acb152f13b2ca4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:02:11 -0400 Subject: [PATCH 229/897] Fix incoming player chat --- .../main/java/org/geysermc/geyser/text/TextDecoration.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java index cf2071173..ab9e2b5ed 100644 --- a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -50,13 +50,13 @@ public record TextDecoration(String translationKey, List parameters, NbtMap tag = entry.getData(); NbtMap chat = tag.getCompound("chat", null); if (chat != null) { - String translationKey = tag.getString("translation_key"); + String translationKey = chat.getString("translation_key"); - NbtMap styleTag = tag.getCompound("style"); + NbtMap styleTag = chat.getCompound("style"); Style style = deserializeStyle(styleTag); List parameters = new ArrayList<>(); - List parametersNbt = tag.getList("parameters", NbtType.STRING); + List parametersNbt = chat.getList("parameters", NbtType.STRING); for (String parameter : parametersNbt) { parameters.add(ChatTypeDecoration.Parameter.valueOf(parameter.toUpperCase(Locale.ROOT))); } From a9ba1ad603d819695c2aca7c6c83f2912d03ec98 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:44:00 -0400 Subject: [PATCH 230/897] Properly translate ominous items --- .../java/org/geysermc/geyser/item/Items.java | 2 +- .../geysermc/geyser/item/type/ArrowItem.java | 5 ++ .../geyser/item/type/FireworkStarItem.java | 5 ++ .../geyser/item/type/GoatHornItem.java | 5 ++ .../org/geysermc/geyser/item/type/Item.java | 8 +++ .../geyser/item/type/OminousBottleItem.java | 72 +++++++++++++++++++ .../geysermc/geyser/item/type/PotionItem.java | 5 ++ .../registry/populator/Conversion685_671.java | 6 ++ .../geyser/registry/type/ItemMappings.java | 9 +-- core/src/main/resources/mappings | 2 +- 10 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/type/OminousBottleItem.java 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 5ae69fa4e..1ddd14982 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -1368,7 +1368,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 Item("ominous_bottle", builder())); + 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 int AIR_ID = AIR.javaId(); 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 c06a143ac..4e4f1830e 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 @@ -51,4 +51,9 @@ public class ArrowItem extends Item { } return itemStack; } + + @Override + public boolean ignoreDamage() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 2ba9b4258..5ac0f475c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -90,4 +90,9 @@ public class FireworkStarItem extends Item { components.put(DataComponentType.FIREWORK_EXPLOSION, newExplosion); } } + + @Override + public boolean ignoreDamage() { + return true; + } } 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 cd21c0b6e..d0e85ec52 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 @@ -62,4 +62,9 @@ public class GoatHornItem extends Item { return itemStack; } + + @Override + public boolean ignoreDamage() { + return true; + } } 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 3014e8116..0b2521a3e 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 @@ -226,6 +226,14 @@ public class Item { } } + /** + * Override if the Bedrock equivalent of an item uses damage for extra data, and should not be tracked + * when translating an item. + */ + public boolean ignoreDamage() { + return false; + } + /* Translation methods end */ public GeyserItemStack newItemStack(int count, DataComponents components) { 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 new file mode 100644 index 000000000..815f71419 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/type/OminousBottleItem.java @@ -0,0 +1,72 @@ +/* + * 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.item.type; + +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.inventory.GeyserItemStack; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; + +public class OminousBottleItem extends Item { + public OminousBottleItem(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public ItemData.Builder translateToBedrock(int count, @Nullable DataComponents components, ItemMapping mapping, ItemMappings mappings) { + var builder = super.translateToBedrock(count, components, mapping, mappings); + if (components == null) { + // Level 1 ominous bottle is null components - Java 1.21. + return builder; + } + Integer amplifier = components.get(DataComponentType.OMINOUS_BOTTLE_AMPLIFIER); + if (amplifier != null) { + builder.damage(amplifier); + } + return builder; + } + + @Override + public @NonNull GeyserItemStack translateToJava(@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); + int damage = itemData.getDamage(); + if (damage == 0) { + return itemStack; + } + itemStack.getOrCreateComponents().put(DataComponentType.OMINOUS_BOTTLE_AMPLIFIER, damage); + return itemStack; + } + + @Override + public boolean ignoreDamage() { + return true; + } +} 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 e9889c882..f8fe2b4ee 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 @@ -76,4 +76,9 @@ public class PotionItem extends Item { } return itemStack; } + + @Override + public boolean ignoreDamage() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java index 41a8af826..58886ca57 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java @@ -50,6 +50,12 @@ public class Conversion685_671 { if (NEW_MUSIC_DISCS.contains(item)) { return mapping.withBedrockIdentifier("minecraft:music_disc_otherside"); } + if (item == Items.OMINOUS_TRIAL_KEY) { + return mapping.withBedrockIdentifier("minecraft:trial_key"); + } + if (item == Items.OMINOUS_BOTTLE) { + return mapping.withBedrockIdentifier("minecraft:glass_bottle"); + } if (!NEW_BLOCKS.contains(identifer)) { return mapping; diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index 94c863660..189474238 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.registry.type; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Builder; @@ -41,7 +40,7 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.item.type.PotionItem; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.List; import java.util.Map; @@ -148,10 +147,8 @@ public class ItemMappings implements DefinitionRegistry { } } else { if (!(mapping.getBedrockData() == data.getDamage() || - // Make exceptions for potions, tipped arrows, firework stars, goat horns, and suspicious stews, whose damage values can vary - (mapping.getJavaItem() instanceof PotionItem || mapping.getJavaItem() == Items.ARROW - || mapping.getJavaItem() == Items.FIREWORK_STAR || mapping.getJavaItem() == Items.GOAT_HORN - || mapping.getJavaItem() == Items.SUSPICIOUS_STEW))) { + // Make exceptions for items whose damage values can vary + (mapping.getJavaItem().ignoreDamage() || mapping.getJavaItem() == Items.SUSPICIOUS_STEW))) { continue; } } diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 396ea5ff5..5f892d04d 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 396ea5ff50d8c976fde4e7423e682d21aa0ee350 +Subproject commit 5f892d04d2212a13fad3f517b3f516d6526833f2 From 7e87af718bab6e858fa8a6793a400c407edea9cf Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:48:46 -0400 Subject: [PATCH 231/897] Fix item attribute modifiers --- .../org/geysermc/geyser/translator/item/ItemTranslator.java | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 8b61e435a..672d2d7a5 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 @@ -247,7 +247,7 @@ public final class ItemTranslator { return null; } - String name = modifier.getName().replace("minecraft:", ""); + String name = modifier.getId().asMinimalString(); // the namespace does not need to be present, but if it is, the java client ignores it as of pre-1.20.5 ModifierOperation operation = modifier.getOperation(); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5e55aa117..1677d46fa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ websocket = "1.5.1" protocol = "3.0.0.Beta2-20240606.172607-7" raknet = "1.0.0.CR3-20240416.144209-1" mcauthlib = "e5b0bcc" -mcprotocollib = "f9cc9ee6" +mcprotocollib = "dcf9d02" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From be83fe7220f6679d0c558a3c0db78a4dabd54c7d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 14 Jun 2024 19:36:10 -0400 Subject: [PATCH 232/897] Re-enable crafter inventory --- .../geysermc/geyser/inventory/Container.java | 2 +- .../geyser/inventory/CrafterContainer.java | 40 ++++++++++++++++++- .../inventory/InventoryTranslator.java | 2 +- .../JavaContainerSetContentTranslator.java | 3 +- core/src/main/resources/mappings | 2 +- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Container.java index 81818613f..e78a4d2c6 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Container.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Container.java @@ -38,7 +38,7 @@ import org.jetbrains.annotations.Range; */ @Getter public class Container extends Inventory { - private final PlayerInventory playerInventory; + protected final PlayerInventory playerInventory; private final int containerSize; /** diff --git a/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java index 41452bed6..fb118252d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java @@ -25,13 +25,19 @@ package org.geysermc.geyser.inventory; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.CrafterInventoryTranslator; +import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.GeyserImpl; +import org.jetbrains.annotations.Range; @Getter public class CrafterContainer extends Container { + private GeyserItemStack resultItem = GeyserItemStack.EMPTY; @Setter private boolean triggered = false; @@ -46,8 +52,36 @@ public class CrafterContainer extends Container { super(title, id, size, containerType, playerInventory); } + @Override + public GeyserItemStack getItem(int slot) { + if (slot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) { + return this.resultItem; + } else if (isCraftingGrid(slot)) { + return super.getItem(slot); + } else { + return playerInventory.getItem(slot - CrafterInventoryTranslator.GRID_SIZE + InventoryTranslator.PLAYER_INVENTORY_OFFSET); + } + } + + @Override + public int getOffsetForHotbar(@Range(from = 0, to = 8) int slot) { + return playerInventory.getOffsetForHotbar(slot) - InventoryTranslator.PLAYER_INVENTORY_OFFSET + CrafterInventoryTranslator.GRID_SIZE; + } + + @Override + public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { + if (slot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) { + // Result item probably won't be an item that needs to worry about net ID or lodestone compasses + this.resultItem = newItem; + } else if (isCraftingGrid(slot)) { + super.setItem(slot, newItem, session); + } else { + playerInventory.setItem(slot - CrafterInventoryTranslator.GRID_SIZE + InventoryTranslator.PLAYER_INVENTORY_OFFSET, newItem, session); + } + } + public void setSlot(int slot, boolean enabled) { - if (slot < 0 || slot > 8) { + if (!isCraftingGrid(slot)) { GeyserImpl.getInstance().getLogger().warning("Crafter slot out of bounds: " + slot); return; } @@ -58,4 +92,8 @@ public class CrafterContainer extends Container { disabledSlotsMask = (short) (disabledSlotsMask | (1 << slot)); } } + + private static boolean isCraftingGrid(int slot) { + return slot >= 0 && slot <= 8; + } } 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 5e4ffcafd..4c426b410 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 @@ -86,7 +86,7 @@ public abstract class InventoryTranslator { put(ContainerType.BEACON, new BeaconInventoryTranslator()); put(ContainerType.BREWING_STAND, new BrewingInventoryTranslator()); put(ContainerType.CARTOGRAPHY, new CartographyInventoryTranslator()); - //put(ContainerType.CRAFTER_3x3, new CrafterInventoryTranslator()); todo Output slot is currently broken + put(ContainerType.CRAFTER_3x3, new CrafterInventoryTranslator()); put(ContainerType.CRAFTING, new CraftingInventoryTranslator()); put(ContainerType.ENCHANTMENT, new EnchantingInventoryTranslator()); put(ContainerType.HOPPER, new HopperInventoryTranslator()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java index 44bd7171f..36d382d69 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetContentPacket; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; @@ -36,6 +34,7 @@ import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator; 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.packet.ingame.clientbound.inventory.ClientboundContainerSetContentPacket; @Translator(packet = ClientboundContainerSetContentPacket.class) public class JavaContainerSetContentTranslator extends PacketTranslator { diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 5f892d04d..2ac0c1415 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 5f892d04d2212a13fad3f517b3f516d6526833f2 +Subproject commit 2ac0c1415cb9063c405dbd7e14f2d426a0ba1180 From b1d319bb7eb394c208b91ffbf91d3a20198fa271 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sat, 15 Jun 2024 18:39:09 +0200 Subject: [PATCH 233/897] Add Spigot 1.21 world adapter --- .../org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java | 1 + gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index fdef77bbe..2d13155f2 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -251,6 +251,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { SpigotAdapters.registerWorldAdapter(nmsVersion); geyserLogger.debug("Using spigot NMS adapter for nms version: " + nmsVersion); } catch (Exception e) { // Likely running on Paper 1.20.5+ + geyserLogger.debug("Unable to find spigot world manager: " + e.getMessage()); //noinspection deprecation int protocolVersion = Bukkit.getUnsafe().getProtocolVersion(); PaperAdapters.registerClosestWorldAdapter(protocolVersion); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1677d46fa..648d5eb03 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ jline = "3.21.0" terminalconsoleappender = "1.2.0" folia = "1.19.4-R0.1-SNAPSHOT" viaversion = "4.9.2" -adapters = "1.12-SNAPSHOT" +adapters = "1.13-SNAPSHOT" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" From 851ed36244b733dcf1c24374a4a747740f2251aa Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 15 Jun 2024 16:52:09 -0400 Subject: [PATCH 234/897] Translate vault block entity --- .../entity/VaultBlockEntityTranslator.java | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java new file mode 100644 index 000000000..5f39451ac --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java @@ -0,0 +1,95 @@ +/* + * 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.level.block.entity; + +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongList; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; + +import java.util.List; +import java.util.UUID; + +@BlockEntity(type = BlockEntityType.VAULT) +public class VaultBlockEntityTranslator extends BlockEntityTranslator { + // Bedrock 1.21 does not send the position nor ID in the tag. + @Override + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) { + NbtMapBuilder builder = NbtMap.builder(); + if (javaNbt != null) { + translateTag(session, builder, javaNbt, blockState); + } + return builder.build(); + } + + @Override + public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { + NbtMap sharedData = javaNbt.getCompound("shared_data"); + + NbtMap item = sharedData.getCompound("display_item"); + ItemMapping mapping = session.getItemMappings().getMapping(item.getString("id")); + if (mapping == null) { + bedrockNbt.putCompound("display_item", NbtMap.builder() + .putByte("Count", (byte) 0) + .putShort("Damage", (short) 0) + .putString("Name", "") + .putByte("WasPickedUp", (byte) 0).build()); + } else { + int count = item.getInt("count"); + NbtMapBuilder bedrockItem = BedrockItemBuilder.createItemNbt(mapping, count, mapping.getBedrockData()); + // TODO handle components... + bedrockNbt.putCompound("display_item", bedrockItem.build()); + } + + List connectedPlayers = sharedData.getList("connected_players", NbtType.INT_ARRAY); + LongList bedrockPlayers = new LongArrayList(connectedPlayers.size()); + for (int[] player : connectedPlayers) { + UUID uuid = uuidFromIntArray(player); + PlayerEntity playerEntity = session.getEntityCache().getPlayerEntity(uuid); + if (playerEntity != null) { + bedrockPlayers.add(playerEntity.getGeyserId()); + } + } + bedrockNbt.putList("connected_players", NbtType.LONG, bedrockPlayers); + + // Fill this in, since as of Java 1.21, Bedrock always seems to include it, but Java assumes the default + // if it is not sent over the network + bedrockNbt.putFloat("connected_particle_range", (float) sharedData.getDouble("connected_particles_range", 4.5d)); + } + + // From ViaVersion! thank u!! + private static UUID uuidFromIntArray(int[] parts) { + return new UUID((long) parts[0] << 32 | (parts[1] & 0xFFFFFFFFL), (long) parts[2] << 32 | (parts[3] & 0xFFFFFFFFL)); + } +} From 6025931c7d7728f104676f3bacfd898f3d64fcb2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 15 Jun 2024 22:40:29 -0400 Subject: [PATCH 235/897] Properly translate player entity UUID for vaults --- .../level/block/entity/VaultBlockEntityTranslator.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java index 5f39451ac..50fd64202 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java @@ -76,9 +76,13 @@ public class VaultBlockEntityTranslator extends BlockEntityTranslator { LongList bedrockPlayers = new LongArrayList(connectedPlayers.size()); for (int[] player : connectedPlayers) { UUID uuid = uuidFromIntArray(player); - PlayerEntity playerEntity = session.getEntityCache().getPlayerEntity(uuid); - if (playerEntity != null) { - bedrockPlayers.add(playerEntity.getGeyserId()); + if (uuid.equals(session.getPlayerEntity().getUuid())) { + bedrockPlayers.add(session.getPlayerEntity().getGeyserId()); + } else { + PlayerEntity playerEntity = session.getEntityCache().getPlayerEntity(uuid); + if (playerEntity != null) { + bedrockPlayers.add(playerEntity.getGeyserId()); + } } } bedrockNbt.putList("connected_players", NbtType.LONG, bedrockPlayers); From bd30b34600938f7dbea91ce36889a6605959543c Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 16 Jun 2024 01:06:17 -0400 Subject: [PATCH 236/897] Bump MCPL --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 648d5eb03..6beae8f8d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ websocket = "1.5.1" protocol = "3.0.0.Beta2-20240606.172607-7" raknet = "1.0.0.CR3-20240416.144209-1" mcauthlib = "e5b0bcc" -mcprotocollib = "dcf9d02" +mcprotocollib = "4f5f650" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From d9f9fcf39a784b1ccb642712668acec5741e729b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 16 Jun 2024 12:26:31 -0400 Subject: [PATCH 237/897] Bump Protocol --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6beae8f8d..1456a7e34 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "3.0.0.Beta2-20240606.172607-7" +protocol = "3.0.0.Beta2-20240616.144648-10" raknet = "1.0.0.CR3-20240416.144209-1" mcauthlib = "e5b0bcc" mcprotocollib = "4f5f650" From 6cda7c2202716525f525dff7f8efa00b5e0949ea Mon Sep 17 00:00:00 2001 From: YHDiamond <47502993+YHDiamond@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:01:21 -0400 Subject: [PATCH 238/897] Partially implement handling of "hide_tooltip" and fix attribute modifiers in "Armor" category not showing (#4731) * Skip lore creation if hide tooltips exists * Fix not showing attributes for "Armor" category * Minor refactor --------- Co-authored-by: chris --- .../org/geysermc/geyser/item/type/Item.java | 2 +- .../translator/item/ItemTranslator.java | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) 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 0b2521a3e..362b760c7 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 @@ -125,7 +125,7 @@ public class Item { */ public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { List loreComponents = components.get(DataComponentType.LORE); - if (loreComponents != null) { + if (loreComponents != null && components.get(DataComponentType.HIDE_TOOLTIP) == null) { List lore = builder.getOrCreateLore(); for (Component loreComponent : loreComponents) { lore.add(MessageTranslator.convertMessage(loreComponent, session.locale())); 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 672d2d7a5..7572f5e61 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 @@ -65,6 +65,12 @@ public final class ItemTranslator { * The order of these slots is their display order on Java Edition clients */ private static final EnumMap SLOT_NAMES; + private static final ItemAttributeModifiers.EquipmentSlotGroup[] ARMOR_SLOT_NAMES = new ItemAttributeModifiers.EquipmentSlotGroup[] { + ItemAttributeModifiers.EquipmentSlotGroup.HEAD, + ItemAttributeModifiers.EquipmentSlotGroup.CHEST, + ItemAttributeModifiers.EquipmentSlotGroup.LEGS, + ItemAttributeModifiers.EquipmentSlotGroup.FEET + }; private static final DecimalFormat ATTRIBUTE_FORMAT = new DecimalFormat("0.#####"); static { @@ -132,8 +138,10 @@ public final class ItemTranslator { private static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents components) { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); + boolean hideTooltips = false; if (components != null) { javaItem.translateComponentsToBedrock(session, components, nbtBuilder); + if (components.get(DataComponentType.HIDE_TOOLTIP) != null) hideTooltips = true; } String customName = getCustomName(session, components, bedrockItem); @@ -143,13 +151,13 @@ public final class ItemTranslator { if (components != null) { ItemAttributeModifiers attributeModifiers = components.get(DataComponentType.ATTRIBUTE_MODIFIERS); - if (attributeModifiers != null && attributeModifiers.isShowInTooltip()) { + if (attributeModifiers != null && attributeModifiers.isShowInTooltip() && !hideTooltips) { // only add if attribute modifiers do not indicate to hide them addAttributeLore(attributeModifiers, nbtBuilder, session.locale()); } } - if (session.isAdvancedTooltips()) { + if (session.isAdvancedTooltips() && !hideTooltips) { addAdvancedTooltips(components, nbtBuilder, javaItem, session.locale()); } @@ -207,7 +215,12 @@ public final class ItemTranslator { } ItemAttributeModifiers.EquipmentSlotGroup slotGroup = entry.getSlot(); - if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ANY) { + if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ARMOR) { + // modifier applies to all armor slots + for (ItemAttributeModifiers.EquipmentSlotGroup slot : ARMOR_SLOT_NAMES) { + slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreEntry); + } + } else if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ANY) { // modifier applies to all slots implicitly for (var slot : SLOT_NAMES.keySet()) { slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreEntry); From 1efb633723f601ce4130df8a0ca9dc3a4fe321e6 Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Sun, 16 Jun 2024 22:05:28 +0100 Subject: [PATCH 239/897] Bump MCPL (#4756) --- .../java/level/JavaLevelEventTranslator.java | 52 +++++++++---------- core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 4 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index 2d3bca0d4..d4e317af4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -57,7 +57,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { + case PARTICLES_AND_SOUND_BRUSH_BLOCK_COMPLETE -> { effectPacket.setType(ParticleType.BRUSH_DUST); session.playSoundEvent(SoundEvent.BRUSH_COMPLETED, pos); // todo 1.20.2 verify this } - case COMPOSTER -> { + case COMPOSTER_FILL -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_CROP_GROWTH); ComposterEventData composterEventData = (ComposterEventData) packet.getData(); @@ -146,7 +146,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { + case LAVA_FIZZ -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EVAPORATE); effectPacket.setPosition(pos.add(-0.5f, 0.7f, -0.5f)); @@ -159,7 +159,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { + case REDSTONE_TORCH_BURNOUT -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EVAPORATE); effectPacket.setPosition(pos.add(-0.5f, 0, -0.5f)); @@ -172,7 +172,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { + case END_PORTAL_FRAME_FILL -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EVAPORATE); effectPacket.setPosition(pos.add(-0.5f, 0.3125f, -0.5f)); @@ -185,8 +185,8 @@ public class JavaLevelEventTranslator extends PacketTranslator { - if (levelEvent == LevelEventType.SMOKE) { + case PARTICLES_SHOOT_SMOKE, PARTICLES_SHOOT_WHITE_SMOKE -> { + if (levelEvent == LevelEventType.PARTICLES_SHOOT_SMOKE) { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_SHOOT); } else { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_SHOOT_WHITE_SMOKE); @@ -225,13 +225,13 @@ public class JavaLevelEventTranslator extends PacketTranslator { + case PARTICLES_DESTROY_BLOCK -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_DESTROY_BLOCK); BreakBlockEventData breakBlockEventData = (BreakBlockEventData) packet.getData(); effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakBlockEventData.getBlockState())); } - case BREAK_SPLASH_POTION, BREAK_SPLASH_POTION2 -> { + case PARTICLES_SPELL_POTION_SPLASH, PARTICLES_INSTANT_POTION_SPLASH -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_POTION_SPLASH); effectPacket.setPosition(pos.add(0, -0.5f, 0)); @@ -247,16 +247,16 @@ public class JavaLevelEventTranslator extends PacketTranslator effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EYE_OF_ENDER_DEATH); - case MOB_SPAWN -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_MOB_BLOCK_SPAWN); // TODO: Check, but I don't think I really verified this ever went into effect on Java - case BONEMEAL_GROW_WITH_SOUND, BONEMEAL_GROW -> { - effectPacket.setType(levelEvent == LevelEventType.BONEMEAL_GROW ? org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_TURTLE_EGG : org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_CROP_GROWTH); + case PARTICLES_EYE_OF_ENDER_DEATH -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EYE_OF_ENDER_DEATH); + case PARTICLES_MOBBLOCK_SPAWN -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_MOB_BLOCK_SPAWN); // TODO: Check, but I don't think I really verified this ever went into effect on Java + case PARTICLES_AND_SOUND_PLANT_GROWTH -> { + effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_CROP_GROWTH); BonemealGrowEventData growEventData = (BonemealGrowEventData) packet.getData(); effectPacket.setData(growEventData.getParticleCount()); } - case EGG_CRACK -> effectPacket.setType(ParticleType.VILLAGER_HAPPY); // both the lil green sparkle - case ENDERDRAGON_FIREBALL_EXPLODE -> { + case PARTICLES_EGG_CRACK -> effectPacket.setType(ParticleType.VILLAGER_HAPPY); // both the lil green sparkle + case PARTICLES_DRAGON_FIREBALL_SPLASH -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EYE_OF_ENDER_DEATH); // TODO DragonFireballEventData fireballEventData = (DragonFireballEventData) packet.getData(); @@ -271,15 +271,15 @@ public class JavaLevelEventTranslator extends PacketTranslator { + case PARTICLES_DRAGON_BLOCK_BREAK -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_GENERIC_SPAWN); effectPacket.setData(61); } - case EVAPORATE -> { + case PARTICLES_WATER_EVAPORATING -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EVAPORATE_WATER); effectPacket.setPosition(pos.add(-0.5f, 0.5f, -0.5f)); } - case END_GATEWAY_SPAWN -> { + case ANIMATION_END_GATEWAY_SPAWN -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EXPLOSION); LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); @@ -292,11 +292,11 @@ public class JavaLevelEventTranslator extends PacketTranslator effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_DRIPSTONE_DRIP); - case ELECTRIC_SPARK -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_ELECTRIC_SPARK); // Matches with a Bedrock server but doesn't seem to match up with Java - case WAX_ON -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_WAX_ON); - case WAX_OFF -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_WAX_OFF); - case SCRAPE -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_SCRAPE); - case SCULK_BLOCK_CHARGE -> { + case PARTICLES_ELECTRIC_SPARK -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_ELECTRIC_SPARK); // Matches with a Bedrock server but doesn't seem to match up with Java + case PARTICLES_AND_SOUND_WAX_ON -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_WAX_ON); + case PARTICLES_WAX_OFF -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_WAX_OFF); + case PARTICLES_SCRAPE -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_SCRAPE); + case PARTICLES_SCULK_CHARGE -> { SculkBlockChargeEventData eventData = (SculkBlockChargeEventData) packet.getData(); LevelEventGenericPacket levelEventPacket = new LevelEventGenericPacket(); // TODO add SCULK_BLOCK_CHARGE sound @@ -324,7 +324,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { + case PARTICLES_SCULK_SHRIEK -> { LevelEventGenericPacket levelEventPacket = new LevelEventGenericPacket(); levelEventPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_SCULK_SHRIEK); levelEventPacket.setTag( @@ -346,7 +346,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { + case SOUND_STOP_JUKEBOX_SONG -> { String bedrockSound = session.getWorldCache().removeActiveRecord(origin); if (bedrockSound == null) { // Vanilla record diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 2ac0c1415..420cbe173 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 2ac0c1415cb9063c405dbd7e14f2d426a0ba1180 +Subproject commit 420cbe173ffa0667d4607715f9e3d43402e1ab77 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1456a7e34..23cd00a97 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ websocket = "1.5.1" protocol = "3.0.0.Beta2-20240616.144648-10" raknet = "1.0.0.CR3-20240416.144209-1" mcauthlib = "e5b0bcc" -mcprotocollib = "4f5f650" +mcprotocollib = "1.21-20240616.154144-5" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" @@ -107,7 +107,7 @@ guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } -mcprotocollib = { group = "com.github.GeyserMC", name = "mcprotocollib", version.ref = "mcprotocollib" } +mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" } raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } From 63a3da7c564de2786cafedc60dd13e13d8ae6c92 Mon Sep 17 00:00:00 2001 From: Eclipse <116838833+eclipseisoffline@users.noreply.github.com> Date: Sun, 16 Jun 2024 23:35:18 +0000 Subject: [PATCH 240/897] Fix reading custom jukebox songs (#4757) * Read sound event objects properly in jukebox song * Add debug log for unexpected sound event type --- .../java/org/geysermc/geyser/level/JukeboxSong.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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 fd6ce693d..156a62cd1 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java +++ b/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.level; import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; @@ -33,7 +34,16 @@ public record JukeboxSong(String soundEvent, String description) { public static JukeboxSong read(RegistryEntry entry) { NbtMap data = entry.getData(); - String soundEvent = data.getString("sound_event"); + 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 " + entry.getId() + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject); + } String description = MessageTranslator.deserializeDescription(data); return new JukeboxSong(soundEvent, description); } From deb25d7147360285f2753825fb6f8765a406327c Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:17:57 +0100 Subject: [PATCH 241/897] Bump mappings to fix effects error on startup (#4760) --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 420cbe173..ff44a3257 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 420cbe173ffa0667d4607715f9e3d43402e1ab77 +Subproject commit ff44a32574d0cac242aa99d8f97af0b5c636c0cf From 29928c2d830838cba51a8ba1f6e2d11fff218cd9 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 17 Jun 2024 18:46:57 +0200 Subject: [PATCH 242/897] Sanity check for shulker boxes (#4762) --- .../org/geysermc/geyser/level/block/type/BlockState.java | 9 +++++++++ .../block/entity/ShulkerBoxBlockEntityTranslator.java | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 36c31f32e..2a4b1774d 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -73,6 +73,15 @@ public final class BlockState { return (Boolean) value; } + public > T getValue(Property property, T def) { + var value = get(property); + if (value == null) { + return def; + } + //noinspection unchecked + return (T) value; + } + @Nullable private Comparable get(Property property) { Property[] keys = this.block.propertyKeys(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java index e6d19e492..cac40b350 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -30,6 +30,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.ShulkerInventoryTranslator; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -42,6 +43,6 @@ public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator imple */ @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) { - bedrockNbt.putByte("facing", (byte) blockState.getValue(Properties.FACING).ordinal()); + bedrockNbt.putByte("facing", (byte) blockState.getValue(Properties.FACING, Direction.UP).ordinal()); } } From 77fa37ff828cf31fc09710a5f4c9e57ab2c88944 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 17 Jun 2024 21:31:54 +0200 Subject: [PATCH 243/897] Fix: readme not being synched to modrinth, publish spigot/bungee/velocity variants to modrinth (#4761) * Fix: readme not being synched to modrinth * use new build_number system env var * also upload bungee/spigot/velocity * change name * undo debug mode, oops --- .github/workflows/build.yml | 11 ++------ bootstrap/bungeecord/build.gradle.kts | 5 ++++ bootstrap/mod/build.gradle.kts | 7 +++++ bootstrap/mod/fabric/build.gradle.kts | 1 + bootstrap/mod/neoforge/build.gradle.kts | 1 + bootstrap/spigot/build.gradle.kts | 5 ++++ bootstrap/velocity/build.gradle.kts | 5 ++++ build-logic/build.gradle.kts | 3 +++ build-logic/src/main/kotlin/LibsAccessor.kt | 6 +++++ .../geyser.modded-conventions.gradle.kts | 27 +++++-------------- ....modrinth-uploading-conventions.gradle.kts | 18 +++++++++++++ build.gradle.kts | 14 ++++++++++ gradle/libs.versions.toml | 5 ++-- 13 files changed, 76 insertions(+), 32 deletions(-) create mode 100644 build-logic/src/main/kotlin/LibsAccessor.kt create mode 100644 build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0e94ce965..ccc4dd79c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -103,19 +103,12 @@ jobs: bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar changelog: ${{ steps.metadata.outputs.body }} - - name: Publish to Modrinth (Fabric) + - name: Publish to Modrinth if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} env: BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} - run: ./gradlew fabric:modrinth - - - name: Publish to Modrinth (NeoForge) - if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} - env: - BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} - MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} - run: ./gradlew neoforge:modrinth + run: ./gradlew modrinth - name: Notify Discord if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }} diff --git a/bootstrap/bungeecord/build.gradle.kts b/bootstrap/bungeecord/build.gradle.kts index e93c096a1..910e50723 100644 --- a/bootstrap/bungeecord/build.gradle.kts +++ b/bootstrap/bungeecord/build.gradle.kts @@ -34,3 +34,8 @@ tasks.withType { exclude(dependency("io.netty:netty-resolver-dns:.*")) } } + +modrinth { + uploadFile.set(tasks.getByPath("shadowJar")) + loaders.add("bungeecord") +} diff --git a/bootstrap/mod/build.gradle.kts b/bootstrap/mod/build.gradle.kts index 7651a2df2..32224d00b 100644 --- a/bootstrap/mod/build.gradle.kts +++ b/bootstrap/mod/build.gradle.kts @@ -6,6 +6,13 @@ loom { mixin.defaultRefmapName.set("geyser-refmap.json") } +afterEvaluate { + // We don't need these + tasks.named("remapModrinthJar").configure { + enabled = false + } +} + dependencies { api(projects.core) compileOnly(libs.mixin) diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index cd513c1e4..25bd0af9d 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -63,6 +63,7 @@ tasks { modrinth { loaders.add("fabric") + uploadFile.set(tasks.getByPath("remapModrinthJar")) dependencies { required.project("fabric-api") } diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts index 92ffae7e5..e0e7c2dfa 100644 --- a/bootstrap/mod/neoforge/build.gradle.kts +++ b/bootstrap/mod/neoforge/build.gradle.kts @@ -55,4 +55,5 @@ tasks { modrinth { loaders.add("neoforge") + uploadFile.set(tasks.getByPath("remapModrinthJar")) } \ No newline at end of file diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 7ccb50484..fcb85f100 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -76,3 +76,8 @@ tasks.withType { exclude(dependency("com.mojang:.*")) } } + +modrinth { + uploadFile.set(tasks.getByPath("shadowJar")) + loaders.addAll("spigot", "paper") +} diff --git a/bootstrap/velocity/build.gradle.kts b/bootstrap/velocity/build.gradle.kts index da826803c..4daad9784 100644 --- a/bootstrap/velocity/build.gradle.kts +++ b/bootstrap/velocity/build.gradle.kts @@ -69,4 +69,9 @@ tasks.withType { exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*")) exclude(dependency("net.kyori:adventure-nbt:.*")) } +} + +modrinth { + uploadFile.set(tasks.getByPath("shadowJar")) + loaders.addAll("velocity") } \ No newline at end of file diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index b7aab2bf0..190386667 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -12,6 +12,9 @@ repositories { } dependencies { + // this is OK as long as the same version catalog is used in the main build and build-logic + // see https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 + implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) implementation(libs.indra) implementation(libs.shadow) implementation(libs.architectury.plugin) diff --git a/build-logic/src/main/kotlin/LibsAccessor.kt b/build-logic/src/main/kotlin/LibsAccessor.kt new file mode 100644 index 000000000..2a0c09eb6 --- /dev/null +++ b/build-logic/src/main/kotlin/LibsAccessor.kt @@ -0,0 +1,6 @@ +import org.gradle.accessors.dm.LibrariesForLibs +import org.gradle.api.Project +import org.gradle.kotlin.dsl.getByType + +val Project.libs: LibrariesForLibs + get() = rootProject.extensions.getByType() \ No newline at end of file diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index 86c2a2f6a..7952bcf14 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -8,7 +8,6 @@ plugins { id("geyser.publish-conventions") id("architectury-plugin") id("dev.architectury.loom") - id("com.modrinth.minotaur") } // These are provided by Minecraft/modded platforms already, no need to include them @@ -39,7 +38,7 @@ provided("io.netty", "netty-resolver-dns-native-macos") provided("org.ow2.asm", "asm") architectury { - minecraft = "1.20.5" + minecraft = libs.minecraft.get().version as String } loom { @@ -83,7 +82,7 @@ tasks { register("remapModrinthJar", RemapJarTask::class) { dependsOn(shadowJar) inputFile.set(shadowJar.get().archiveFile) - archiveVersion.set(project.version.toString() + "+build." + System.getenv("GITHUB_RUN_NUMBER")) + archiveVersion.set(project.version.toString() + "+build." + System.getenv("BUILD_NUMBER")) archiveClassifier.set("") } } @@ -93,7 +92,7 @@ afterEvaluate { // These are shaded, no need to JiJ them configurations["shadow"].dependencies.forEach {shadowed -> - println("Not including shadowed dependency: ${shadowed.group}:${shadowed.name}") + //println("Not including shadowed dependency: ${shadowed.group}:${shadowed.name}") providedDependencies.add("${shadowed.group}:${shadowed.name}") } @@ -101,16 +100,16 @@ afterEvaluate { configurations["includeTransitive"].resolvedConfiguration.resolvedArtifacts.forEach { dep -> if (!providedDependencies.contains("${dep.moduleVersion.id.group}:${dep.moduleVersion.id.name}") and !providedDependencies.contains("${dep.moduleVersion.id.group}:.*")) { - println("Including dependency via JiJ: ${dep.id}") + //println("Including dependency via JiJ: ${dep.id}") dependencies.add("include", dep.moduleVersion.id.toString()) } else { - println("Not including ${dep.id} for ${project.name}!") + //println("Not including ${dep.id} for ${project.name}!") } } } dependencies { - minecraft("com.mojang:minecraft:1.21") + minecraft(libs.minecraft) mappings(loom.officialMojangMappings()) } @@ -121,18 +120,4 @@ repositories { maven("https://oss.sonatype.org/content/repositories/snapshots/") maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") maven("https://maven.neoforged.net/releases") -} - -modrinth { - token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token? - projectId.set("wKkoqHrH") - versionNumber.set(project.version as String + "-" + System.getenv("GITHUB_RUN_NUMBER")) - versionType.set("beta") - changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits") - - syncBodyFrom.set(rootProject.file("README.md").readText()) - - uploadFile.set(tasks.getByPath("remapModrinthJar")) - gameVersions.addAll("1.21") - failSilently.set(true) } \ No newline at end of file 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 new file mode 100644 index 000000000..a4a8cd7d6 --- /dev/null +++ b/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("com.modrinth.minotaur") +} + +// Ensure that the readme is synched +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? + projectId.set("geyser") + versionNumber.set(project.version as String + "-" + System.getenv("BUILD_NUMBER")) + versionType.set("beta") + changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits") + gameVersions.add(libs.minecraft.get().version as String) + failSilently.set(true) + + syncBodyFrom.set(rootProject.file("README.md").readText()) +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index dfdff2187..dfbf9837f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -26,6 +26,14 @@ val moddedPlatforms = setOf( projects.mod ).map { it.dependencyProject } +val modrinthPlatforms = setOf( + projects.bungeecord, + projects.fabric, + projects.neoforge, + projects.spigot, + projects.velocity +).map { it.dependencyProject } + subprojects { apply { plugin("java-library") @@ -38,4 +46,10 @@ subprojects { in moddedPlatforms -> plugins.apply("geyser.modded-conventions") else -> plugins.apply("geyser.base-conventions") } + + // Not combined with platform-conventions as that also contains + // platforms which we cant publish to modrinth + if (modrinthPlatforms.contains(this)) { + plugins.apply("geyser.modrinth-uploading-conventions") + } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 23cd00a97..784f30053 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,12 +28,12 @@ commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" viaproxy = "3.2.1" -fabric-minecraft = "1.21" fabric-loader = "0.15.11" fabric-api = "0.100.1+1.21" fabric-permissions = "0.2-SNAPSHOT" neoforge-minecraft = "21.0.0-beta" mixin = "0.8.5" +minecraft = "1.21" # plugin versions indra = "3.1.3" @@ -90,8 +90,9 @@ paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", versio mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" } +minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" } + # Check these on https://modmuss50.me/fabric.html -fabric-minecraft = { group = "com.mojang", name = "minecraft", version.ref = "fabric-minecraft" } 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" } fabric-permissions = { group = "me.lucko", name = "fabric-permissions-api", version.ref = "fabric-permissions" } From a9300fb1ab0a0cf281be6a777eeab16354520f95 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:30:19 -0400 Subject: [PATCH 244/897] Vault: show some components in block entity (enchantments, potion types) --- .../geyser/inventory/item/Potion.java | 9 +++ .../translator/item/ItemTranslator.java | 2 +- .../entity/VaultBlockEntityTranslator.java | 57 ++++++++++++++++++- 3 files changed, 64 insertions(+), 4 deletions(-) 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 c4d20c623..129c365a9 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 @@ -102,6 +102,15 @@ public enum Potion { return new PotionContents(this.ordinal(), -1, Collections.emptyList()); } + public static Potion getByJavaIdentifier(String javaIdentifier) { + for (Potion potion : VALUES) { + if (potion.javaIdentifier.equals(javaIdentifier)) { + return potion; + } + } + return null; + } + public static @Nullable Potion getByJavaId(int javaId) { if (javaId >= 0 && javaId < VALUES.length) { return VALUES[javaId]; 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 7572f5e61..a8d29c465 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 @@ -135,7 +135,7 @@ public final class ItemTranslator { .build(); } - private static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents components) { + public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents components) { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); boolean hideTooltips = false; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java index 50fd64202..81be5b33a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java @@ -25,20 +25,32 @@ package org.geysermc.geyser.translator.level.block.entity; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongList; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.cloudburstmc.protocol.common.util.TriConsumer; import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.inventory.item.Potion; +import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.geyser.translator.item.ItemTranslator; +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.ItemEnchantments; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; @BlockEntity(type = BlockEntityType.VAULT) @@ -67,9 +79,25 @@ public class VaultBlockEntityTranslator extends BlockEntityTranslator { .putByte("WasPickedUp", (byte) 0).build()); } else { int count = item.getInt("count"); - NbtMapBuilder bedrockItem = BedrockItemBuilder.createItemNbt(mapping, count, mapping.getBedrockData()); - // TODO handle components... - bedrockNbt.putCompound("display_item", bedrockItem.build()); + NbtMap componentsTag = item.getCompound("components"); + NbtMapBuilder itemAsNbt; + if (!componentsTag.isEmpty()) { + DataComponents components = new DataComponents(new HashMap<>()); + for (Map.Entry entry : componentsTag.entrySet()) { + var consumer = DATA_COMPONENT_DECODERS.get(entry.getKey()); + if (consumer != null) { + consumer.accept(session, (NbtMap) entry.getValue(), components); + } + } + ItemData bedrockItem = ItemTranslator.translateToBedrock(session, mapping.getJavaItem(), mapping, count, components).build(); + itemAsNbt = BedrockItemBuilder.createItemNbt(mapping, bedrockItem.getCount(), bedrockItem.getDamage()); + if (bedrockItem.getTag() != null) { + itemAsNbt.putCompound("tag", bedrockItem.getTag()); + } + } else { + itemAsNbt = BedrockItemBuilder.createItemNbt(mapping, count, mapping.getBedrockData()); + } + bedrockNbt.putCompound("display_item", itemAsNbt.build()); } List connectedPlayers = sharedData.getList("connected_players", NbtType.INT_ARRAY); @@ -96,4 +124,27 @@ public class VaultBlockEntityTranslator extends BlockEntityTranslator { private static UUID uuidFromIntArray(int[] parts) { return new UUID((long) parts[0] << 32 | (parts[1] & 0xFFFFFFFFL), (long) parts[2] << 32 | (parts[3] & 0xFFFFFFFFL)); } + + // This might be easier to maintain in the long run so items don't have two translate methods. + // Also, it's not out of the question that block entities get the data component treatment, likely rendering this useless. + // The goal is to just translate the basics so clients know what potion is roughly present, and that any enchantment even exists. + private static final Map> DATA_COMPONENT_DECODERS = Map.of( + "minecraft:potion_contents", (session, tag, components) -> { + String potionId = tag.getString("potion"); + Potion potion = Potion.getByJavaIdentifier(potionId); + components.put(DataComponentType.POTION_CONTENTS, potion.toComponent()); + }, + "minecraft:enchantments", (session, tag, components) -> { // Enchanted books already have glint. Translating them doesn't matter. + NbtMap levels = tag.getCompound("levels"); + List enchantmentRegistry = session.getRegistryCache().enchantments().values(); + Int2ObjectMap enchantments = new Int2ObjectOpenHashMap<>(levels.size()); + for (Map.Entry entry : levels.entrySet()) { + for (int i = 0; i < enchantmentRegistry.size(); i++) { + if (enchantmentRegistry.get(i).identifier().equals(entry.getKey())) { + enchantments.put(i, (Integer) entry.getValue()); + } + } + } + components.put(DataComponentType.ENCHANTMENTS, new ItemEnchantments(enchantments, true)); + }); } From 6884a0f7db8a0edd078f1367cda0600402aac198 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 19 Jun 2024 02:37:34 +0200 Subject: [PATCH 245/897] Fix: norwegian locale handling (#4716) --- .../main/java/org/geysermc/geyser/text/GeyserLocale.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java index cfe950409..28fd6f9a4 100644 --- a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java @@ -259,6 +259,13 @@ public class GeyserLocale { // Invalid locale return locale; } + + // See https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes - covers the special case that is norwegian + String lowerCaseLocale = locale.toLowerCase(Locale.ROOT); + if (lowerCaseLocale.equals("nn_no") || lowerCaseLocale.equals("no_no")) { + locale = "nb_NO"; + } + String language = locale.substring(0, 2); String country = locale.substring(3); return language.toLowerCase(Locale.ENGLISH) + "_" + country.toUpperCase(Locale.ENGLISH); From 2c47330509bfa11101786a29046b0e3c26f9fd03 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:52:54 -0400 Subject: [PATCH 246/897] Use integrated world managers for decorated pot animation --- .../mod/world/GeyserModWorldManager.java | 25 +++++++++++++++++++ .../manager/GeyserSpigotWorldManager.java | 20 +++++++++++++++ .../geysermc/geyser/level/WorldManager.java | 9 +++++++ .../java/level/JavaBlockEventTranslator.java | 21 ++++++++++++++++ 4 files changed, 75 insertions(+) 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 ef8c3ec0a..db1768737 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 @@ -30,6 +30,7 @@ import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; import net.minecraft.core.RegistryAccess; 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.ServerPlayer; @@ -39,10 +40,12 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BannerBlockEntity; import net.minecraft.world.level.block.entity.BannerPatternLayers; 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; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.platform.mod.GeyserModBootstrap; @@ -56,6 +59,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen import java.util.HashMap; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; public class GeyserModWorldManager extends GeyserWorldManager { @@ -161,6 +165,27 @@ public class GeyserModWorldManager extends GeyserWorldManager { return future; } + @Override + public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer> apply) { + server.execute(() -> { + ServerPlayer player = getPlayer(session); + if (player == null) { + return; + } + + BlockPos blockPos = new BlockPos(pos.getX(), pos.getY(), pos.getZ()); + // Don't create a new block entity if invalid + //noinspection resource - level() is just a getter + BlockEntity blockEntity = player.level().getChunkAt(blockPos).getBlockEntity(blockPos); + if (blockEntity instanceof DecoratedPotBlockEntity pot) { + List sherds = pot.getDecorations().ordered() + .stream().map(item -> BuiltInRegistries.ITEM.getKey(item).toString()) + .toList(); + apply.accept(sherds); + } + }); + } + private ServerPlayer getPlayer(GeyserSession session) { return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid()); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index e247a72c7..73356c4e7 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -29,10 +29,13 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.DecoratedPot; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.erosion.bukkit.BukkitUtils; import org.geysermc.erosion.bukkit.PickBlockUtils; import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.GeyserImpl; @@ -43,8 +46,10 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; /** * The base world manager to use when there is no supported NMS revision @@ -146,6 +151,21 @@ public class GeyserSpigotWorldManager extends WorldManager { return future.thenApply(RAW_TRANSFORMER); } + public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer> apply) { + Player bukkitPlayer; + if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { + return; + } + Block block = bukkitPlayer.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); + SchedulerUtils.runTask(this.plugin, () -> { + var state = BukkitUtils.getBlockState(block); + if (!(state instanceof DecoratedPot pot)) { + return; + } + apply.accept(pot.getShards().stream().map(material -> material.getKey().toString()).toList()); + }, block); + } + /** * This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id * to the current one. diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index 3670b6b73..4a20771f2 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -43,9 +43,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemCodecHel import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; import java.util.function.Function; /** @@ -209,6 +211,13 @@ public abstract class WorldManager { return CompletableFuture.completedFuture(null); } + /** + * Retrieves decorated pot sherds from the server. Used to ensure the data is not erased on animation sent + * through the BlockEntityDataPacket. + */ + public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer> apply) { + } + protected static final Function, DataComponents> RAW_TRANSFORMER = map -> { try { Map, DataComponent> components = new HashMap<>(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java index d6e45adc3..f56750d12 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.protocol.java.level; import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEventPacket; import org.geysermc.geyser.api.util.PlatformType; @@ -126,6 +127,26 @@ public class JavaBlockEventTranslator extends PacketTranslator { + BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket(); + blockEntityPacket.setBlockPosition(position); + + NbtMapBuilder builder = BlockEntityTranslator.getConstantBedrockTag("DecoratedPot", position); + builder.putList("sherds", NbtType.STRING, sherds); + builder.putByte("animation", switch (potValue.getWobbleStyle()) { + case POSITIVE -> (byte) 2; + case NEGATIVE -> (byte) 1; + }); + + blockEntityPacket.setData(builder.build()); + session.sendUpstreamPacket(blockEntityPacket); + }); + } else if (session.getGeyser().getLogger().isDebug()) { + session.getGeyser().getLogger().debug("Unhandled block event packet: " + packet); } } } From 34158f946331b5c1c3db13d64e33dcae10c34a63 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 19 Jun 2024 22:27:14 +0200 Subject: [PATCH 247/897] Feat: Add changelog to modrinth releases (#4770) * Feat: Add changelog to modrinth releases * oops --- .github/workflows/build.yml | 1 + .../kotlin/geyser.modrinth-uploading-conventions.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ccc4dd79c..2bcf25e8e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -106,6 +106,7 @@ jobs: - name: Publish to Modrinth if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} env: + CHANGELOG: ${{ steps.metadata.outputs.body }} BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }} MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} run: ./gradlew modrinth 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 a4a8cd7d6..d710ae1a2 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 @@ -10,7 +10,7 @@ modrinth { projectId.set("geyser") versionNumber.set(project.version as String + "-" + System.getenv("BUILD_NUMBER")) versionType.set("beta") - changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits") + changelog.set(System.getenv("CHANGELOG") ?: "") gameVersions.add(libs.minecraft.get().version as String) failSilently.set(true) From 126d56d144db6e105f9de49a8fbe384e320b18de Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 19 Jun 2024 23:48:55 +0200 Subject: [PATCH 248/897] Fix: Ignore invalid block entity data sent by Java server (#4766) * Proper block entity checks; ignore invalid block entity data sent by Java server * fix intelliJ warning about potentially null block state * Use auto-generated block entity types instead of hardcoding them * undo some diff * Update BlockRegistryPopulator.java * Access block entity type of state by getting the block first * deprecate JavaBlockState#hasBlockEntity * Simplify check * Add type check in JavaBlockEntityDataTranslator, ensure deprecated setBlockEntity() method still sets piston behavior * nullability annotations * yeet duplicate check --- .../custom/nonvanilla/JavaBlockState.java | 8 + .../geysermc/geyser/level/block/Blocks.java | 333 +++++++++--------- .../level/block/GeyserJavaBlockState.java | 12 +- .../geyser/level/block/type/Block.java | 19 +- .../geyser/level/block/type/BlockState.java | 8 - .../populator/BlockRegistryPopulator.java | 3 - .../BrushableBlockEntityTranslator.java | 1 - .../DecoratedPotBlockEntityTranslator.java | 1 - .../DoubleChestBlockEntityTranslator.java | 5 - .../ShulkerBoxBlockEntityTranslator.java | 3 +- .../entity/SkullBlockEntityTranslator.java | 1 - .../entity/SpawnerBlockEntityTranslator.java | 1 - .../StructureBlockBlockEntityTranslator.java | 1 - .../TrialSpawnerBlockEntityTranslator.java | 1 - .../level/JavaBlockEntityDataTranslator.java | 12 +- .../JavaLevelChunkWithLightTranslator.java | 40 ++- 16 files changed, 225 insertions(+), 224 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockState.java b/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockState.java index f7da4b932..0dd0d3b33 100644 --- a/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockState.java +++ b/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockState.java @@ -73,7 +73,10 @@ public interface JavaBlockState { * Gets whether the block state has block entity * * @return whether the block state has block entity + * @deprecated Does not have an effect. If you were using this to + * set piston behavior, use {@link #pistonBehavior()} instead. */ + @Deprecated(forRemoval = true) boolean hasBlockEntity(); /** @@ -104,6 +107,11 @@ public interface JavaBlockState { Builder pistonBehavior(@Nullable String pistonBehavior); + /** + * @deprecated Does not have an effect. If you were using this to + * * set piston behavior, use {@link #pistonBehavior(String)} instead. + */ + @Deprecated(forRemoval = true) Builder hasBlockEntity(boolean hasBlockEntity); JavaBlockState build(); 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 857a3fc13..735c1f6c4 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 @@ -33,6 +33,7 @@ import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import static org.geysermc.geyser.level.block.property.Properties.*; import static org.geysermc.geyser.level.block.type.Block.builder; @@ -89,11 +90,11 @@ public final class Blocks { public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) + public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder().setBlockEntity(BlockEntityType.BRUSHABLE_BLOCK).destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) .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().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) + public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder().setBlockEntity(BlockEntityType.BRUSHABLE_BLOCK).destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) .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))); @@ -220,7 +221,7 @@ public final class Blocks { public static final Block LAPIS_ORE = register(new Block("lapis_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); 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().requiresCorrectToolForDrops().destroyTime(3.5f) + 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))); public static final Block SANDSTONE = register(new Block("sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); @@ -230,67 +231,67 @@ public final class Blocks { .enumState(NOTEBLOCK_INSTRUMENT) .intState(NOTE) .booleanState(POWERED))); - public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + 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))); @@ -335,7 +336,7 @@ public final class Blocks { public static final Block GREEN_WOOL = register(new Block("green_wool", builder().destroyTime(0.8f))); 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().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) + 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))); public static final Block DANDELION = register(new Block("dandelion", builder().pushReaction(PistonBehavior.DESTROY))); @@ -360,7 +361,7 @@ public final class Blocks { public static final Block TNT = register(new Block("tnt", builder() .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().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) @@ -381,13 +382,13 @@ public final class Blocks { .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().requiresCorrectToolForDrops().destroyTime(5.0f))); + public static final Block SPAWNER = register(new SpawnerBlock("spawner", builder().setBlockEntity(BlockEntityType.MOB_SPAWNER).requiresCorrectToolForDrops().destroyTime(5.0f))); 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))); - public static final Block CHEST = register(new ChestBlock("chest", builder().setBlockEntity().destroyTime(2.5f) + 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))); @@ -405,34 +406,34 @@ public final class Blocks { .intState(AGE_7))); public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f) .intState(MOISTURE))); - public static final Block FURNACE = register(new FurnaceBlock("furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) + 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))); - public static final Block OAK_SIGN = register(new Block("oak_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block OAK_SIGN = register(new Block("oak_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_SIGN = register(new Block("dark_oak_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); public static final Block OAK_DOOR = register(new DoorBlock("oak_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) @@ -452,108 +453,108 @@ public final class Blocks { .enumState(HALF) .enumState(STAIRS_SHAPE) .booleanState(WATERLOGGED))); - public static final Block OAK_WALL_SIGN = register(new Block("oak_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block SPRUCE_WALL_SIGN = register(new Block("spruce_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BIRCH_WALL_SIGN = register(new Block("birch_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block ACACIA_WALL_SIGN = register(new Block("acacia_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block CHERRY_WALL_SIGN = register(new Block("cherry_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block JUNGLE_WALL_SIGN = register(new Block("jungle_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block DARK_OAK_WALL_SIGN = register(new Block("dark_oak_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block MANGROVE_WALL_SIGN = register(new Block("mangrove_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BAMBOO_WALL_SIGN = register(new Block("bamboo_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block OAK_HANGING_SIGN = register(new Block("oak_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block SPRUCE_HANGING_SIGN = register(new Block("spruce_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BIRCH_HANGING_SIGN = register(new Block("birch_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block ACACIA_HANGING_SIGN = register(new Block("acacia_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block CHERRY_HANGING_SIGN = register(new Block("cherry_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block JUNGLE_HANGING_SIGN = register(new Block("jungle_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block DARK_OAK_HANGING_SIGN = register(new Block("dark_oak_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block CRIMSON_HANGING_SIGN = register(new Block("crimson_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block WARPED_HANGING_SIGN = register(new Block("warped_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block MANGROVE_HANGING_SIGN = register(new Block("mangrove_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BAMBOO_HANGING_SIGN = register(new Block("bamboo_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block OAK_WALL_HANGING_SIGN = register(new Block("oak_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block SPRUCE_WALL_HANGING_SIGN = register(new Block("spruce_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BIRCH_WALL_HANGING_SIGN = register(new Block("birch_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block ACACIA_WALL_HANGING_SIGN = register(new Block("acacia_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block CHERRY_WALL_HANGING_SIGN = register(new Block("cherry_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block JUNGLE_WALL_HANGING_SIGN = register(new Block("jungle_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block DARK_OAK_WALL_HANGING_SIGN = register(new Block("dark_oak_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block MANGROVE_WALL_HANGING_SIGN = register(new Block("mangrove_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block CRIMSON_WALL_HANGING_SIGN = register(new Block("crimson_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block WARPED_WALL_HANGING_SIGN = register(new Block("warped_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BAMBOO_WALL_HANGING_SIGN = register(new Block("bamboo_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); public static final Block LEVER = register(new Block("lever", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) @@ -608,7 +609,7 @@ public final class Blocks { 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))); - public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity().destroyTime(2.0f) + public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity(BlockEntityType.JUKEBOX).destroyTime(2.0f) .booleanState(HAS_RECORD))); public static final Block OAK_FENCE = register(new Block("oak_fence", builder().destroyTime(2.0f) .booleanState(EAST) @@ -819,8 +820,8 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block NETHER_WART = register(new Block("nether_wart", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_3))); - public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); - public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(0.5f) + 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))); @@ -830,7 +831,7 @@ public final class Blocks { 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))); - public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); + 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))); @@ -848,7 +849,7 @@ public final class Blocks { .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().requiresCorrectToolForDrops().destroyTime(22.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))); public static final Block TRIPWIRE_HOOK = register(new Block("tripwire_hook", builder().pushReaction(PistonBehavior.DESTROY) @@ -879,10 +880,10 @@ public final class Blocks { .enumState(HALF) .enumState(STAIRS_SHAPE) .booleanState(WATERLOGGED))); - public static final Block COMMAND_BLOCK = register(new Block("command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) + 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))); - public static final Block BEACON = register(new Block("beacon", builder().setBlockEntity().destroyTime(3.0f))); + 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) @@ -965,46 +966,46 @@ public final class Blocks { .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().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block SKELETON_WALL_SKULL = register(new WallSkullBlock("skeleton_wall_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block WITHER_SKELETON_SKULL = register(new SkullBlock("wither_skeleton_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block WITHER_SKELETON_WALL_SKULL = register(new WallSkullBlock("wither_skeleton_wall_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block ZOMBIE_HEAD = register(new SkullBlock("zombie_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block ZOMBIE_WALL_HEAD = register(new WallSkullBlock("zombie_wall_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PLAYER_HEAD = register(new SkullBlock("player_head", SkullBlock.Type.PLAYER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PLAYER_WALL_HEAD = register(new WallSkullBlock("player_wall_head", SkullBlock.Type.PLAYER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block CREEPER_HEAD = register(new SkullBlock("creeper_head", SkullBlock.Type.CREEPER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block CREEPER_WALL_HEAD = register(new WallSkullBlock("creeper_wall_head", SkullBlock.Type.CREEPER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block DRAGON_HEAD = register(new SkullBlock("dragon_head", SkullBlock.Type.DRAGON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block DRAGON_WALL_HEAD = register(new WallSkullBlock("dragon_wall_head", SkullBlock.Type.DRAGON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PIGLIN_HEAD = register(new SkullBlock("piglin_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PIGLIN_WALL_HEAD = register(new WallSkullBlock("piglin_wall_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) + 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))); public static final Block ANVIL = register(new Block("anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK) @@ -1013,7 +1014,7 @@ public final class Blocks { .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))); - public static final Block TRAPPED_CHEST = register(new ChestBlock("trapped_chest", builder().setBlockEntity().destroyTime(2.5f) + 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))); @@ -1021,16 +1022,16 @@ public final class Blocks { .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))); - public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity().pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder().setBlockEntity().destroyTime(0.2f) + public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder().setBlockEntity(BlockEntityType.DAYLIGHT_DETECTOR).destroyTime(0.2f) .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().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))); public static final Block QUARTZ_BLOCK = register(new Block("quartz_block", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); @@ -1046,7 +1047,7 @@ public final class Blocks { .booleanState(POWERED) .enumState(RAIL_SHAPE_STRAIGHT) .booleanState(WATERLOGGED))); - public static final Block DROPPER = register(new Block("dropper", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) + 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))); public static final Block WHITE_TERRACOTTA = register(new Block("white_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); @@ -1264,69 +1265,69 @@ public final class Blocks { .enumState(DOUBLE_BLOCK_HALF))); public static final Block LARGE_FERN = register(new Block("large_fern", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF))); - public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity().destroyTime(1.0f) + public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder().setBlockEntity().destroyTime(1.0f) + public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder().setBlockEntity().destroyTime(1.0f) + public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder().setBlockEntity().destroyTime(1.0f) + public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder().setBlockEntity().destroyTime(1.0f) + public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder().setBlockEntity().destroyTime(1.0f) + public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder().setBlockEntity().destroyTime(1.0f) + public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder().setBlockEntity().destroyTime(1.0f) + public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder().setBlockEntity().destroyTime(1.0f) + public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder().setBlockEntity().destroyTime(1.0f) + public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder().setBlockEntity().destroyTime(1.0f) + public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder().setBlockEntity().destroyTime(1.0f) + public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder().setBlockEntity().destroyTime(1.0f) + public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder().setBlockEntity().destroyTime(1.0f) + public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder().setBlockEntity().destroyTime(1.0f) + public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder().setBlockEntity().destroyTime(1.0f) + public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) .intState(ROTATION_16))); - public static final Block WHITE_WALL_BANNER = register(new BannerBlock("white_wall_banner", 0, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block ORANGE_WALL_BANNER = register(new BannerBlock("orange_wall_banner", 1, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block MAGENTA_WALL_BANNER = register(new BannerBlock("magenta_wall_banner", 2, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block LIGHT_BLUE_WALL_BANNER = register(new BannerBlock("light_blue_wall_banner", 3, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block YELLOW_WALL_BANNER = register(new BannerBlock("yellow_wall_banner", 4, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block LIME_WALL_BANNER = register(new BannerBlock("lime_wall_banner", 5, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block PINK_WALL_BANNER = register(new BannerBlock("pink_wall_banner", 6, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block GRAY_WALL_BANNER = register(new BannerBlock("gray_wall_banner", 7, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block LIGHT_GRAY_WALL_BANNER = register(new BannerBlock("light_gray_wall_banner", 8, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block CYAN_WALL_BANNER = register(new BannerBlock("cyan_wall_banner", 9, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block PURPLE_WALL_BANNER = register(new BannerBlock("purple_wall_banner", 10, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BLUE_WALL_BANNER = register(new BannerBlock("blue_wall_banner", 11, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BROWN_WALL_BANNER = register(new BannerBlock("brown_wall_banner", 12, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block GREEN_WALL_BANNER = register(new BannerBlock("green_wall_banner", 13, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block RED_WALL_BANNER = register(new BannerBlock("red_wall_banner", 14, builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block BLACK_WALL_BANNER = register(new BannerBlock("black_wall_banner", 15, builder().setBlockEntity().destroyTime(1.0f) + 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))); 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))); @@ -1578,11 +1579,11 @@ public final class Blocks { public static final Block BEETROOTS = register(new Block("beetroots", builder().pushReaction(PistonBehavior.DESTROY) .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().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); - public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) + 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))); - public static final Block CHAIN_COMMAND_BLOCK = register(new Block("chain_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) + 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))); public static final Block FROSTED_ICE = register(new Block("frosted_ice", builder().destroyTime(0.5f) @@ -1596,39 +1597,39 @@ public final class Blocks { 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))); - public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block WHITE_SHULKER_BOX = register(new Block("white_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block ORANGE_SHULKER_BOX = register(new Block("orange_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block MAGENTA_SHULKER_BOX = register(new Block("magenta_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIGHT_BLUE_SHULKER_BOX = register(new Block("light_blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block YELLOW_SHULKER_BOX = register(new Block("yellow_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIME_SHULKER_BOX = register(new Block("lime_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PINK_SHULKER_BOX = register(new Block("pink_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block GRAY_SHULKER_BOX = register(new Block("gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block LIGHT_GRAY_SHULKER_BOX = register(new Block("light_gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block CYAN_SHULKER_BOX = register(new Block("cyan_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PURPLE_SHULKER_BOX = register(new Block("purple_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BLUE_SHULKER_BOX = register(new Block("blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BROWN_SHULKER_BOX = register(new Block("brown_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block GREEN_SHULKER_BOX = register(new Block("green_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block RED_SHULKER_BOX = register(new Block("red_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BLACK_SHULKER_BOX = register(new Block("black_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) + 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))); 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))); @@ -1787,7 +1788,7 @@ public final class Blocks { .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().destroyTime(3.0f) + public static final Block CONDUIT = register(new Block("conduit", builder().setBlockEntity(BlockEntityType.CONDUIT).destroyTime(3.0f) .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) @@ -2005,13 +2006,13 @@ public final class Blocks { .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))); - public static final Block BARREL = register(new Block("barrel", builder().setBlockEntity().destroyTime(2.5f) + 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))); - public static final Block SMOKER = register(new Block("smoker", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) + 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))); - public static final Block BLAST_FURNACE = register(new Block("blast_furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f) + 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))); public static final Block CARTOGRAPHY_TABLE = register(new Block("cartography_table", builder().destroyTime(2.5f))); @@ -2019,14 +2020,14 @@ public final class Blocks { 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))); - public static final Block LECTERN = register(new LecternBlock("lectern", builder().setBlockEntity().destroyTime(2.5f) + 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))); 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))); - public static final Block BELL = register(new Block("bell", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) + 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))); @@ -2036,12 +2037,12 @@ public final class Blocks { public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(HANGING) .booleanState(WATERLOGGED))); - public static final Block CAMPFIRE = register(new Block("campfire", builder().setBlockEntity().destroyTime(2.0f) + 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))); - public static final Block SOUL_CAMPFIRE = register(new Block("soul_campfire", builder().setBlockEntity().destroyTime(2.0f) + 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) @@ -2155,30 +2156,30 @@ public final class Blocks { .enumState(DOOR_HINGE) .booleanState(OPEN) .booleanState(POWERED))); - public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block WARPED_SIGN = register(new Block("warped_sign", builder().setBlockEntity().destroyTime(1.0f) + public static final Block WARPED_SIGN = register(new Block("warped_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) .intState(ROTATION_16) .booleanState(WATERLOGGED))); - public static final Block CRIMSON_WALL_SIGN = register(new Block("crimson_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block WARPED_WALL_SIGN = register(new Block("warped_wall_sign", builder().setBlockEntity().destroyTime(1.0f) + 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))); - public static final Block STRUCTURE_BLOCK = register(new Block("structure_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) + public static final Block STRUCTURE_BLOCK = register(new Block("structure_block", builder().setBlockEntity(BlockEntityType.STRUCTURE_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f) .enumState(STRUCTUREBLOCK_MODE))); - public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) + public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity(BlockEntityType.JIGSAW).requiresCorrectToolForDrops().destroyTime(-1.0f) .enumState(ORIENTATION, FrontAndTop.VALUES))); public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f) .intState(LEVEL_COMPOSTER))); public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f) .intState(POWER))); - public static final Block BEE_NEST = register(new Block("bee_nest", builder().setBlockEntity().destroyTime(0.3f) + 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))); - public static final Block BEEHIVE = register(new Block("beehive", builder().setBlockEntity().destroyTime(0.6f) + 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))); public static final Block HONEY_BLOCK = register(new HoneyBlock("honey_block", builder())); @@ -2422,11 +2423,11 @@ public final class Blocks { 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().destroyTime(1.5f) + 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))); - public static final Block CALIBRATED_SCULK_SENSOR = register(new Block("calibrated_sculk_sensor", builder().setBlockEntity().destroyTime(1.5f) + 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) @@ -2440,9 +2441,9 @@ public final class Blocks { .booleanState(UP) .booleanState(WATERLOGGED) .booleanState(WEST))); - public static final Block SCULK_CATALYST = register(new Block("sculk_catalyst", builder().setBlockEntity().destroyTime(3.0f) + public static final Block SCULK_CATALYST = register(new Block("sculk_catalyst", builder().setBlockEntity(BlockEntityType.SCULK_CATALYST).destroyTime(3.0f) .booleanState(BLOOM))); - public static final Block SCULK_SHRIEKER = register(new Block("sculk_shrieker", builder().setBlockEntity().destroyTime(3.0f) + 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))); @@ -2794,18 +2795,18 @@ public final class Blocks { .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().pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block CRAFTER = register(new Block("crafter", builder().setBlockEntity().destroyTime(1.5f) + public static final Block CRAFTER = register(new Block("crafter", builder().setBlockEntity(BlockEntityType.CRAFTER).destroyTime(1.5f) .booleanState(CRAFTING) .enumState(ORIENTATION, FrontAndTop.VALUES) .booleanState(TRIGGERED))); - public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f) + 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))); - public static final Block VAULT = register(new Block("vault", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f) + 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))); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/GeyserJavaBlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/GeyserJavaBlockState.java index 8028a4355..782f664fc 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/GeyserJavaBlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/GeyserJavaBlockState.java @@ -16,7 +16,6 @@ public class GeyserJavaBlockState implements JavaBlockState { boolean canBreakWithHand; String pickItem; String pistonBehavior; - boolean hasBlockEntity; private GeyserJavaBlockState(Builder builder) { this.identifier = builder.identifier; @@ -28,7 +27,6 @@ public class GeyserJavaBlockState implements JavaBlockState { this.canBreakWithHand = builder.canBreakWithHand; this.pickItem = builder.pickItem; this.pistonBehavior = builder.pistonBehavior; - this.hasBlockEntity = builder.hasBlockEntity; } @Override @@ -76,9 +74,10 @@ public class GeyserJavaBlockState implements JavaBlockState { return pistonBehavior; } + @SuppressWarnings("removal") @Override public boolean hasBlockEntity() { - return hasBlockEntity; + return false; } public static class Builder implements JavaBlockState.Builder { @@ -91,7 +90,6 @@ public class GeyserJavaBlockState implements JavaBlockState { private boolean canBreakWithHand; private String pickItem; private String pistonBehavior; - private boolean hasBlockEntity; @Override public Builder identifier(@NonNull String identifier) { @@ -147,9 +145,13 @@ public class GeyserJavaBlockState implements JavaBlockState { return this; } + @SuppressWarnings("removal") @Override public Builder hasBlockEntity(boolean hasBlockEntity) { - this.hasBlockEntity = hasBlockEntity; + // keep the current behavior + if (this.pistonBehavior == null && hasBlockEntity) { + this.pistonBehavior = "BLOCK"; + } return this; } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index ee99b652a..a005fc103 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; 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.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; @@ -41,6 +42,7 @@ import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.intellij.lang.annotations.Subst; import java.util.*; @@ -55,7 +57,7 @@ public class Block { * Can you harvest this with your hand. */ private final boolean requiresCorrectToolForDrops; - private final boolean hasBlockEntity; + private final @Nullable BlockEntityType blockEntityType; private final float destroyTime; private final @NonNull PistonBehavior pushReaction; /** @@ -75,7 +77,7 @@ public class Block { public Block(@Subst("empty") String javaIdentifier, Builder builder) { this.javaIdentifier = Key.key(javaIdentifier); this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops; - this.hasBlockEntity = builder.hasBlockEntity; + this.blockEntityType = builder.blockEntityType; this.destroyTime = builder.destroyTime; this.pushReaction = builder.pushReaction; this.pickItem = builder.pickItem; @@ -181,7 +183,12 @@ public class Block { } public boolean hasBlockEntity() { - return hasBlockEntity; + return blockEntityType != null; + } + + @Nullable + public BlockEntityType blockEntityType() { + return blockEntityType; } public float destroyTime() { @@ -227,7 +234,7 @@ public class Block { public static final class Builder { private final Map, List>> states = new LinkedHashMap<>(); private boolean requiresCorrectToolForDrops = false; - private boolean hasBlockEntity = false; + private BlockEntityType blockEntityType = null; private PistonBehavior pushReaction = PistonBehavior.NORMAL; private float destroyTime; private Supplier pickItem; @@ -271,8 +278,8 @@ public class Block { return this; } - public Builder setBlockEntity() { - this.hasBlockEntity = true; + public Builder setBlockEntity(BlockEntityType blockEntityType) { + this.blockEntityType = blockEntityType; return this; } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 2a4b1774d..7229e9e50 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -65,14 +65,6 @@ public final class BlockState { return (T) get(property); } - public boolean getValue(Property property, boolean def) { - var value = get(property); - if (value == null) { - return def; - } - return (Boolean) value; - } - public > T getValue(Property property, T def) { var value = get(property); if (value == null) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 272522429..d7dc989da 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -435,9 +435,6 @@ public final class BlockRegistryPopulator { if (!javaBlockState.canBreakWithHand()) { builder.requiresCorrectToolForDrops(); } - if (javaBlockState.hasBlockEntity()) { - builder.setBlockEntity(); - } String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier()); String pickItem = javaBlockState.pickItem(); Block block = new Block(cleanJavaIdentifier, builder) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java index f0d632041..de0ce62b3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java @@ -37,7 +37,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType @BlockEntity(type = BlockEntityType.BRUSHABLE_BLOCK) public class BrushableBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { - @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java index 33c884c55..c22d906cf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java @@ -34,7 +34,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType @BlockEntity(type = BlockEntityType.DECORATED_POT) public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator { - @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index 6fea10e2e..9cbd5f433 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.ChestType; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; @@ -40,12 +39,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType */ @BlockEntity(type = { BlockEntityType.CHEST, BlockEntityType.TRAPPED_CHEST }) public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { - @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { - if (!(blockState.is(Blocks.CHEST) || blockState.is(Blocks.TRAPPED_CHEST))) { - return; - } if (blockState.getValue(Properties.CHEST_TYPE) != ChestType.SINGLE) { int x = (int) bedrockNbt.get("x"); int z = (int) bedrockNbt.get("z"); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java index cac40b350..e6d19e492 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -30,7 +30,6 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; -import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.ShulkerInventoryTranslator; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -43,6 +42,6 @@ public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator imple */ @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) { - bedrockNbt.putByte("facing", (byte) blockState.getValue(Properties.FACING, Direction.UP).ordinal()); + bedrockNbt.putByte("facing", (byte) blockState.getValue(Properties.FACING).ordinal()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index cdbb20c44..c2d457202 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -50,7 +50,6 @@ import java.util.concurrent.ExecutionException; @BlockEntity(type = BlockEntityType.SKULL) public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { - @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { Integer rotation = blockState.getValue(Properties.ROTATION_16); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index 4b6a630ba..6b26f2b2c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -39,7 +39,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType @BlockEntity(type = BlockEntityType.MOB_SPAWNER) public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { - @Override public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java index 79fb3da6b..dcf4f85ff 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/StructureBlockBlockEntityTranslator.java @@ -39,7 +39,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType @BlockEntity(type = BlockEntityType.STRUCTURE_BLOCK) public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { - @Override public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java index a4c158a15..dd58bfa6f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java @@ -33,7 +33,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType @BlockEntity(type = BlockEntityType.TRIAL_SPAWNER) public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator { - @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java index 4210a8fe0..24d419c24 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java @@ -33,11 +33,11 @@ import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror; import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.level.block.Blocks; 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.level.block.entity.BlockEntityTranslator; -import org.geysermc.geyser.translator.level.block.entity.RequiresBlockState; import org.geysermc.geyser.translator.level.block.entity.SkullBlockEntityTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -59,11 +59,11 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator> 4) - yOffset]; - BlockState blockState = BlockRegistries.BLOCK_STATES.get(section.get(x, y & 0xF, z)); + BlockState blockState = BlockRegistries.BLOCK_STATES.getOrDefault(section.get(x, y & 0xF, z), Blocks.AIR.defaultBlockState()); // Note that, since 1.20.5, tags can be null, but Bedrock still needs a default tag to render the item // Also, some properties - like banner base colors - are part of the tag and is processed here. BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(type); - bedrockBlockEntities.add(blockEntityTranslator.getBlockEntityTag(session, type, x + chunkBlockX, y, z + chunkBlockZ, tag, blockState)); - // Check for custom skulls - if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.containsKey("profile")) { - BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState); - if (blockDefinition != null) { - int bedrockSectionY = (y >> 4) - (bedrockDimension.minY() >> 4); - int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4); - if (0 <= bedrockSectionY && bedrockSectionY < maxBedrockSectionY) { - // Custom skull is in a section accepted by Bedrock - GeyserChunkSection bedrockSection = sections[bedrockSectionY]; - IntList palette = bedrockSection.getBlockStorageArray()[0].getPalette(); - if (palette instanceof IntImmutableList || palette instanceof IntLists.Singleton) { - // TODO there has to be a better way to expand the palette .-. - bedrockSection = bedrockSection.copy(subChunkIndex); - sections[bedrockSectionY] = bedrockSection; + // The Java server can send block entity data for blocks that aren't actually those blocks. + // A Java client ignores these + if (type == blockState.block().blockEntityType()) { + bedrockBlockEntities.add(blockEntityTranslator.getBlockEntityTag(session, type, x + chunkBlockX, y, z + chunkBlockZ, tag, blockState)); + + // Check for custom skulls + if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.containsKey("profile")) { + BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState); + if (blockDefinition != null) { + int bedrockSectionY = (y >> 4) - (bedrockDimension.minY() >> 4); + int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4); + if (0 <= bedrockSectionY && bedrockSectionY < maxBedrockSectionY) { + // Custom skull is in a section accepted by Bedrock + GeyserChunkSection bedrockSection = sections[bedrockSectionY]; + IntList palette = bedrockSection.getBlockStorageArray()[0].getPalette(); + if (palette instanceof IntImmutableList || palette instanceof IntLists.Singleton) { + // TODO there has to be a better way to expand the palette .-. + bedrockSection = bedrockSection.copy(subChunkIndex); + sections[bedrockSectionY] = bedrockSection; + } + bedrockSection.setFullBlock(x, y & 0xF, z, 0, blockDefinition.getRuntimeId()); } - bedrockSection.setFullBlock(x, y & 0xF, z, 0, blockDefinition.getRuntimeId()); } } } From 57cb8549ec5c6952e2593ee0a41a29290cbc34f9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:56:33 -0400 Subject: [PATCH 249/897] Update Floodgate download location --- core/src/main/java/org/geysermc/geyser/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/Constants.java b/core/src/main/java/org/geysermc/geyser/Constants.java index 5de8e6e6b..588b25172 100644 --- a/core/src/main/java/org/geysermc/geyser/Constants.java +++ b/core/src/main/java/org/geysermc/geyser/Constants.java @@ -34,7 +34,7 @@ public final class Constants { public static final String NEWS_OVERVIEW_URL = "https://api.geysermc.org/v2/news/"; public static final String NEWS_PROJECT_NAME = "geyser"; - public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"; + public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://geysermc.org/download#floodgate"; public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download"; public static final String UPDATE_PERMISSION = "geyser.update"; From 2e6cf2f4caac13b2f51606862852560cc1b17203 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 19 Jun 2024 22:43:47 -0400 Subject: [PATCH 250/897] Update mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index ff44a3257..23cb22f9c 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit ff44a32574d0cac242aa99d8f97af0b5c636c0cf +Subproject commit 23cb22f9ceeb7f24b896a69a711944d7f3e756ed From ded6f6bb7cc36b6a4e2ba2bca07c72b85cba1732 Mon Sep 17 00:00:00 2001 From: Eclipse <116838833+eclipseisoffline@users.noreply.github.com> Date: Thu, 20 Jun 2024 14:46:54 +0000 Subject: [PATCH 251/897] Fix NPEs caused by custom head blocks from Polymer (#4764) * Add null checks to fix NPEs caused by custom head blocks from Polymer * Make sure block state is never null, remove now unnecessary null checks * Remove unnecessary default fallback in skull block entity translator --- .../geyser/entity/type/player/SkullPlayerEntity.java | 2 +- .../geysermc/geyser/level/block/type/BlockState.java | 10 +++++++++- .../bedrock/entity/player/BedrockActionTranslator.java | 4 ++-- .../java/level/JavaBlockDestructionTranslator.java | 4 +--- .../java/level/JavaBlockEntityDataTranslator.java | 5 +---- .../java/level/JavaLevelChunkWithLightTranslator.java | 3 +-- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java index f2f93b266..1c5060de0 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java @@ -152,7 +152,7 @@ public class SkullPlayerEntity extends PlayerEntity { case EAST -> x -= 0.24f; } } else { - rotation = (180f + (blockState.getValue(Properties.ROTATION_16) * 22.5f)) % 360; + rotation = (180f + blockState.getValue(Properties.ROTATION_16, 0) * 22.5f) % 360; } moveAbsolute(Vector3f.from(x, y, z), rotation, 0, rotation, true, true); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 7229e9e50..2513e3ceb 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.level.block.type; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.level.block.property.Property; import org.geysermc.geyser.registry.BlockRegistries; @@ -184,7 +185,14 @@ public final class BlockState { return builder.toString(); } + /** + * Null-safe method that looks up a Java block state ID in the BLOCK_STATES registry, and defaults to air if not found. + * + * @param javaId the Java block state ID to look up. + * @return the corresponding block state, or air if the given ID wasn't registered and returned null. + */ + @NonNull public static BlockState of(int javaId) { - return BlockRegistries.BLOCK_STATES.get(javaId); + return BlockRegistries.BLOCK_STATES.getOrDefault(javaId, BlockRegistries.BLOCK_STATES.get(Block.JAVA_AIR_ID)); } } 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 index 959797d41..6834d3190 100644 --- 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 @@ -160,7 +160,7 @@ public class BedrockActionTranslator extends PacketTranslator> 4) - yOffset]; - BlockState blockState = BlockRegistries.BLOCK_STATES.getOrDefault(section.get(x, y & 0xF, z), Blocks.AIR.defaultBlockState()); + BlockState blockState = BlockState.of(section.get(x, y & 0xF, z)); // Note that, since 1.20.5, tags can be null, but Bedrock still needs a default tag to render the item // Also, some properties - like banner base colors - are part of the tag and is processed here. From fc529a661cc85655ef95e72cc96caa20d5f08218 Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Thu, 20 Jun 2024 19:29:42 +0200 Subject: [PATCH 252/897] Fix build errors reporting to the wrong directory by updating blossom (#4771) * Fix build errors reporting to the wrong directory by updating blossom * Add info comment --- core/build.gradle.kts | 28 ++++++++------ .../org/geysermc/geyser/BuildData.java | 37 +++++++++++++++++++ .../java/org/geysermc/geyser/GeyserImpl.java | 12 +++--- gradle/libs.versions.toml | 2 +- 4 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 core/src/main/java-templates/org/geysermc/geyser/BuildData.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index a27c4fc89..e7b63ff56 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,6 +1,6 @@ -import net.kyori.blossom.BlossomExtension - plugins { + // Allow blossom to mark sources root of templates + idea alias(libs.plugins.blossom) id("geyser.publish-conventions") } @@ -84,16 +84,20 @@ tasks.processResources { } } -configure { - val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java" - val info = GitInfo() - - replaceToken("\${version}", "${project.version} (${info.gitVersion})", mainFile) - replaceToken("\${gitVersion}", info.gitVersion, mainFile) - replaceToken("\${buildNumber}", info.buildNumber, mainFile) - replaceToken("\${branch}", info.branch, mainFile) - replaceToken("\${commit}", info.commit, mainFile) - replaceToken("\${repository}", info.repository, mainFile) +sourceSets { + main { + blossom { + val info = GitInfo() + javaSources { + property("version", "${project.version} (${info.gitVersion})") + property("gitVersion", info.gitVersion) + property("buildNumber", info.buildNumber.toString()) + property("branch", info.branch) + property("commit", info.commit) + property("repository", info.repository) + } + } + } } fun Project.buildNumber(): Int = diff --git a/core/src/main/java-templates/org/geysermc/geyser/BuildData.java b/core/src/main/java-templates/org/geysermc/geyser/BuildData.java new file mode 100644 index 000000000..d489d8d17 --- /dev/null +++ b/core/src/main/java-templates/org/geysermc/geyser/BuildData.java @@ -0,0 +1,37 @@ +/* + * 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; + +// The constants are replaced before compilation +public class BuildData { + public static final String GIT_VERSION = "{{ gitVersion }}"; + public static final String VERSION = "{{ version }}"; + + public static final String BUILD_NUMBER = "{{ buildNumber }}"; + public static final String BRANCH = "{{ branch }}"; + public static final String COMMIT = "{{ commit }}"; + public static final String REPOSITORY = "{{ repository }}"; +} diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index cc5f7ea33..0975ea5a9 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -115,13 +115,13 @@ public class GeyserImpl implements GeyserApi { .enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); public static final String NAME = "Geyser"; - public static final String GIT_VERSION = "${gitVersion}"; - public static final String VERSION = "${version}"; + public static final String GIT_VERSION = BuildData.GIT_VERSION; + public static final String VERSION = BuildData.VERSION; - public static final String BUILD_NUMBER = "${buildNumber}"; - public static final String BRANCH = "${branch}"; - public static final String COMMIT = "${commit}"; - public static final String REPOSITORY = "${repository}"; + public static final String BUILD_NUMBER = BuildData.BUILD_NUMBER; + public static final String BRANCH = BuildData.BRANCH; + public static final String COMMIT = BuildData.COMMIT; + public static final String REPOSITORY = BuildData.REPOSITORY; /** * Oauth client ID for Microsoft authentication diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 784f30053..5a9b7888e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,7 +42,7 @@ architectury-plugin = "3.4-SNAPSHOT" architectury-loom = "1.6-SNAPSHOT" minotaur = "2.8.7" lombok = "8.4" -blossom = "1.2.0" +blossom = "2.1.0" [libraries] base-api = { group = "org.geysermc.api", name = "base-api", version.ref = "base-api" } From f49acb2f7c2281137837259af86e7db18845165d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:08:49 -0400 Subject: [PATCH 253/897] Indicate support for Bedrock 1.21.1 --- README.md | 2 +- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c45af73ed..e3b5a496a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.0 and Minecraft Java 1.21 +### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.1 and Minecraft Java 1.21 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 773f0ae32..de995301a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -48,7 +48,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v685.CODEC.toBuilder() - .minecraftVersion("1.21.0") + .minecraftVersion("1.21.1") .build()); /** @@ -67,7 +67,7 @@ public final class GameProtocol { .minecraftVersion("1.20.80/1.20.81") .build())); SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.0") + .minecraftVersion("1.21.0/1.20.1") .build())); } From dd9d5f321bfa878d1559ed6ef4ba39511d644e72 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:24:39 -0400 Subject: [PATCH 254/897] Work around Bedrock players looking like Steve --- .../java/org/geysermc/geyser/skin/SkinManager.java | 11 +++++++++++ .../java/org/geysermc/geyser/skin/SkinProvider.java | 7 +++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java index 7b126c136..4c3db7504 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java @@ -309,6 +309,15 @@ public class SkinManager { return null; } + if (DEFAULT_FLOODGATE_STEVE.equals(skinUrl)) { + // https://github.com/GeyserMC/Floodgate/commit/00b8b1b6364116ff4bc9b00e2015ce35bae8abb1 ensures that + // Bedrock players on online-mode servers will always have a textures property. However, this skin is + // also sent our way, and isn't overwritten. It's very likely that this skin is *only* a placeholder, + // and no one should ever be using it outside of Floodgate, and therefore no one wants to see this + // specific Steve skin. + return null; + } + boolean isAlex = skinTexture.has("metadata"); String capeUrl = null; @@ -322,5 +331,7 @@ public class SkinManager { return new GameProfileData(skinUrl, capeUrl, isAlex); } + + private static final String DEFAULT_FLOODGATE_STEVE = "https://textures.minecraft.net/texture/31f477eb1a7beee631c2ca64d06f8f68fa93a3386d04452ab27f43acdf1b60cb"; } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index 5b16bc3a3..aec1fa4de 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java @@ -29,9 +29,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import it.unimi.dsi.fastutil.bytes.ByteArrays; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; @@ -56,7 +53,9 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.*; import java.util.function.Predicate; From 78642db3ad05f4f64c24f586c615c749b92871a6 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 20 Jun 2024 19:15:05 -0400 Subject: [PATCH 255/897] Ensure players get disconnected with no Java disconnect packet --- .../org/geysermc/geyser/session/GeyserSession.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) 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 e228fc02f..7f015a05e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -996,7 +996,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public void disconnected(DisconnectedEvent event) { loggingIn = false; - loggedIn = false; String disconnectMessage; Throwable cause = event.getCause(); @@ -1036,13 +1035,19 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } else { GeyserImpl.getInstance().getLogger().error("An exception occurred: ", cause); } - // GeyserSession is disconnected via session.disconnect() called indirectly be the server - // This only needs to be "initiated" here when there is an exception, hence the cause clause - GeyserSession.this.disconnect(disconnectMessage); if (geyser.getConfig().isDebugMode()) { cause.printStackTrace(); } } + if ((!GeyserSession.this.closed && GeyserSession.this.loggedIn) || cause != null) { + // GeyserSession is disconnected via session.disconnect() called indirectly be the server + // This needs to be "initiated" here when there is an exception, but also when the Netty connection + // is closed without a disconnect packet - in this case, closed will still be false, but loggedIn + // will also be true as GeyserSession#disconnect will not have been called. + GeyserSession.this.disconnect(disconnectMessage); + } + + loggedIn = false; } @Override From c00a02e5eae445f16f97043156fe7fcd0203e02d Mon Sep 17 00:00:00 2001 From: basaigh <53559772+basaigh@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:36:55 +0100 Subject: [PATCH 256/897] Add trial chambers map icon (#4783) --- .../main/java/org/geysermc/geyser/level/BedrockMapIcon.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java b/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java index c55a74cd2..eacf6bd1b 100644 --- a/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java +++ b/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java @@ -63,7 +63,8 @@ public enum BedrockMapIcon { ICON_SNOWY_VILLAGE(MapIconType.SNOWY_VILLAGE, 20), ICON_TAIGA_VILLAGE(MapIconType.TAIGA_VILLAGE, 21), ICON_JUNGLE_TEMPLE(MapIconType.JUNGLE_TEMPLE, 22), - ICON_SWAMP_HUT(MapIconType.SWAMP_HUT, 23); + ICON_SWAMP_HUT(MapIconType.SWAMP_HUT, 23), + ICON_TRIAL_CHAMBERS(MapIconType.TRIAL_CHAMBERS, 24); private static final BedrockMapIcon[] VALUES = values(); From 110470726a301f2d5f7162c3fe4804757f01bd11 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 21 Jun 2024 18:28:05 +0200 Subject: [PATCH 257/897] Fix: Bedrock players dying of fall damage, instead of falling in the void (#4704) * fix https://github.com/GeyserMC/Geyser/issues/4649 * add javadoc --- .../type/player/SessionPlayerEntity.java | 74 +++++++++++++++++++ .../player/BedrockMovePlayerTranslator.java | 59 ++++++++------- 2 files changed, 106 insertions(+), 27 deletions(-) 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 31eb02984..45fea4d48 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 @@ -27,15 +27,18 @@ package org.geysermc.geyser.entity.type.player; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; +import lombok.Setter; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +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.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.DimensionUtils; @@ -69,6 +72,15 @@ public class SessionPlayerEntity extends PlayerEntity { private int lastAirSupply = getMaxAir(); + /** + * Determines if our position is currently out-of-sync with the Java server + * due to our workaround for the void floor + *

+ * Must be reset when dying, switching worlds, or being teleported out of the void + */ + @Getter @Setter + private boolean voidPositionDesynched; + public SessionPlayerEntity(GeyserSession session) { super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null); @@ -87,10 +99,25 @@ public class SessionPlayerEntity extends PlayerEntity { @Override public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) { + if (voidPositionDesynched) { + if (!isBelowVoidFloor()) { + voidPositionDesynched = false; // No need to fix our offset; we've been moved + } + } super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround); session.getCollisionManager().updatePlayerBoundingBox(this.position.down(definition.offset())); } + @Override + public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) { + if (voidPositionDesynched) { + if (!isBelowVoidFloor()) { + voidPositionDesynched = false; // No need to fix our offset; we've been moved + } + } + super.moveAbsolute(position, yaw, pitch, headYaw, isOnGround, teleported); + } + @Override public void setPosition(Vector3f position) { if (valid) { // Don't update during session init @@ -225,6 +252,9 @@ public class SessionPlayerEntity extends PlayerEntity { } else { dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false); } + + // We're either respawning or switching worlds, either way, we are no longer desynched + this.setVoidPositionDesynched(false); } @Override @@ -276,4 +306,48 @@ public class SessionPlayerEntity extends PlayerEntity { public void resetAir() { this.setAirSupply(getMaxAir()); } + + private boolean isBelowVoidFloor() { + return position.getY() < voidFloorPosition(); + } + + public int voidFloorPosition() { + // The void floor is offset about 40 blocks below the bottom of the world + BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + return bedrockDimension.minY() - 40; + } + + /** + * This method handles teleporting the player below or above the Bedrock void floor. + * The Java server should never see this desync as we adjust the position that we send to it + * + * @param up in which direction to teleport - true to resync our position, or false to be + * teleported below the void floor. + */ + public void teleportVoidFloorFix(boolean up) { + // Safety to avoid double teleports + if ((voidPositionDesynched && !up) || (!voidPositionDesynched && up)) { + return; + } + + // Work around there being a floor at the bottom of the world and teleport the player below it + // Moving from below to above the void floor works fine + Vector3f newPosition = this.getPosition(); + if (up) { + newPosition = newPosition.up(4f); + voidPositionDesynched = false; + } else { + newPosition = newPosition.down(4f); + voidPositionDesynched = true; + } + + this.setPositionManual(newPosition); + MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); + movePlayerPacket.setRuntimeEntityId(geyserId); + movePlayerPacket.setPosition(newPosition); + movePlayerPacket.setRotation(getBedrockRotation()); + movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT); + movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR); + session.sendUpstreamPacketImmediately(movePlayerPacket); + } } 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/BedrockMovePlayerTranslator.java index cae12170d..3d612c481 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/BedrockMovePlayerTranslator.java @@ -25,20 +25,19 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -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.network.packet.Packet; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; -import org.geysermc.geyser.level.BedrockDimension; 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; @Translator(packet = MovePlayerPacket.class) public class BedrockMovePlayerTranslator extends PacketTranslator { @@ -93,29 +92,42 @@ public class BedrockMovePlayerTranslator extends PacketTranslator= packet.getPosition().getY()) { + if (entity.getPosition().getY() >= packet.getPosition().getY() && !isBelowVoid) { int floorY = position.getFloorY(); - // The void floor is offset about 40 blocks below the bottom of the world - BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); - int voidFloorLocation = bedrockDimension.minY() - 40; - teleportThroughVoidFloor = floorY <= (voidFloorLocation + 2) && floorY >= voidFloorLocation; - if (teleportThroughVoidFloor) { - // https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground. - onGround = false; - } + int voidFloorLocation = entity.voidFloorPosition(); + teleportThroughVoidFloor = floorY <= (voidFloorLocation + 1) && floorY >= voidFloorLocation; } else { teleportThroughVoidFloor = false; } + if (teleportThroughVoidFloor || isBelowVoid) { + // https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground. + onGround = false; + } + + if (isBelowVoid) { + int floorY = position.getFloorY(); + int voidFloorLocation = entity.voidFloorPosition(); + mustResyncPosition = floorY < voidFloorLocation && floorY >= voidFloorLocation - 1; + } else { + mustResyncPosition = false; + } + + double yPosition = position.getY(); + if (entity.isVoidPositionDesynched()) { // not using the cached variable on purpose + yPosition += 4; // We are de-synched since we had to teleport below the void floor. + } + Packet movePacket; if (rotationChanged) { // Send rotation updates as well movePacket = new ServerboundMovePlayerPosRotPacket( onGround, - position.getX(), position.getY(), position.getZ(), + position.getX(), yPosition, position.getZ(), yaw, pitch ); entity.setYaw(yaw); @@ -123,7 +135,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator Date: Fri, 21 Jun 2024 13:50:10 -0400 Subject: [PATCH 258/897] Show trial chamber map item texture --- .../main/java/org/geysermc/geyser/item/type/FilledMapItem.java | 1 + 1 file changed, 1 insertion(+) 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 70a04b863..e571a796a 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 @@ -51,6 +51,7 @@ public class FilledMapItem extends MapItem { switch (mapColor) { case 3830373 -> builder.damage(3); // Ocean Monument case 5393476 -> builder.damage(4); // Woodland explorer + case 12741452 -> builder.damage(14); // Trial Chamber } } } From 21ccafc40c3d389b734ade256b7bd8acafab1f2c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:53:38 -0400 Subject: [PATCH 259/897] DataComponentType.ITEM_NAME should remove italics --- .../geyser/translator/item/ItemTranslator.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 a8d29c465..85b4c6264 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 @@ -418,13 +418,15 @@ public final class ItemTranslator { if (components != null) { // ItemStack#getHoverName as of 1.20.5 Component customName = components.get(DataComponentType.CUSTOM_NAME); - if (customName == null) { - customName = components.get(DataComponentType.ITEM_NAME); - } if (customName != null) { - // Get the translated name and prefix it with a reset char return MessageTranslator.convertMessage(customName, session.locale()); } + customName = components.get(DataComponentType.ITEM_NAME); + if (customName != null) { + // Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition + // behavior as of 1.21 + return ChatColor.RESET + ChatColor.ESCAPE + translationColor + MessageTranslator.convertMessage(customName, session.locale()); + } } if (mapping.hasTranslation()) { From e6bf3ffdf04eeecb36ad385da690b4d539c58cae Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:58:23 -0400 Subject: [PATCH 260/897] Proper trial spawner block entity data --- .../geyser/entity/EntityDefinition.java | 1 + .../entity/SpawnerBlockEntityTranslator.java | 2 +- .../TrialSpawnerBlockEntityTranslator.java | 19 ++++++++++++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java index 31aa7cc73..f9b65a545 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java @@ -47,6 +47,7 @@ import java.util.function.BiConsumer; * metadata translators needed to translate the properties sent from the server. The translators are structured in such * a way that inserting a new one (for example in version updates) is convenient. * + * @param identifier the Bedrock identifier of this entity * @param the entity type this definition represents */ public record EntityDefinition(EntityFactory factory, EntityType entityType, String identifier, diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index 6b26f2b2c..14f706f27 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -107,7 +107,7 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { bedrockNbt.put("isMovable", (byte) 1); } - static void translateSpawnData(@NonNull NbtMapBuilder builder, @Nullable NbtMap spawnData) { + private static void translateSpawnData(@NonNull NbtMapBuilder builder, @Nullable NbtMap spawnData) { if (spawnData == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java index dd58bfa6f..25925a89b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java @@ -27,22 +27,31 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @BlockEntity(type = BlockEntityType.TRIAL_SPAWNER) public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator { + // Note that it would appear block entity updates don't include the NBT, but we do need it on chunk load. @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { if (javaNbt == null) { return; } - // trial spawners have "spawn_data" instead of "SpawnData" - SpawnerBlockEntityTranslator.translateSpawnData(bedrockNbt, javaNbt.getCompound("spawn_data", null)); - - // Because trial spawners don't exist on bedrock yet - bedrockNbt.put("id", "MobSpawner"); + NbtMap entityData = javaNbt.getCompound("spawn_data").getCompound("entity"); + if (entityData.isEmpty()) { + return; + } + NbtMapBuilder spawnData = NbtMap.builder(); + EntityDefinition definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityData.getString("id")); + if (definition != null) { + spawnData.putString("TypeId", definition.identifier()); + } + spawnData.putInt("Weight", entityData.getInt("Size", 1)); // ??? presumably since these are the only other two extra attributes + bedrockNbt.putCompound("spawn_data", spawnData.build()); } } From 55e90b6f576877ab24f65ab874de90c2da803cca Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 22 Jun 2024 20:32:29 +0200 Subject: [PATCH 261/897] Show build number in startup log, fix Geyser version command(#4336) * Version check command/startup log shows build number * Add development build warning * Fix `/geyser version` command * Hack around outdated language module --- core/build.gradle.kts | 24 ++++++--- .../org/geysermc/geyser/BuildData.java | 5 ++ .../java/org/geysermc/geyser/GeyserImpl.java | 8 +++ .../command/defaults/VersionCommand.java | 54 +++++++++++-------- 4 files changed, 60 insertions(+), 31 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index e7b63ff56..fe2576462 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -75,7 +75,7 @@ tasks.processResources { expand( "branch" to info.branch, "buildNumber" to info.buildNumber, - "projectVersion" to project.version, + "projectVersion" to info.version, "commit" to info.commit, "commitAbbrev" to info.commitAbbrev, "commitMessage" to info.commitMessage, @@ -89,20 +89,25 @@ sourceSets { blossom { val info = GitInfo() javaSources { - property("version", "${project.version} (${info.gitVersion})") + property("version", "${info.version} (${info.gitVersion})") property("gitVersion", info.gitVersion) property("buildNumber", info.buildNumber.toString()) property("branch", info.branch) property("commit", info.commit) property("repository", info.repository) + property("devVersion", info.isDev.toString()) } } } } -fun Project.buildNumber(): Int = +fun buildNumber(): Int = (System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1 +fun isDevBuild(branch: String, repository: String): Boolean { + return branch != "master" || repository.equals("https://github.com/GeyserMC/Geyser", ignoreCase = true).not() +} + inner class GitInfo { val branch: String val commit: String @@ -115,22 +120,25 @@ inner class GitInfo { val commitMessage: String val repository: String + val isDev: Boolean + init { - // On Jenkins, a detached head is checked out, so indra cannot determine the branch. - // Fortunately, this environment variable is available. - branch = indraGit.branchName() ?: System.getenv("BRANCH_NAME") ?: "DEV" + branch = indraGit.branchName() ?: "DEV" val commit = indraGit.commit() this.commit = commit?.name ?: "0".repeat(40) commitAbbrev = commit?.name?.substring(0, 7) ?: "0".repeat(7) gitVersion = "git-${branch}-${commitAbbrev}" - version = "${project.version} ($gitVersion)" - buildNumber = buildNumber() val git = indraGit.git() commitMessage = git?.commit()?.message ?: "" repository = git?.repository?.config?.getString("remote", "origin", "url") ?: "" + + buildNumber = buildNumber() + isDev = isDevBuild(branch, repository) + val projectVersion = if (isDev) project.version else project.version.toString().replace("SNAPSHOT", "b${buildNumber}") + version = "$projectVersion ($gitVersion)" } } diff --git a/core/src/main/java-templates/org/geysermc/geyser/BuildData.java b/core/src/main/java-templates/org/geysermc/geyser/BuildData.java index d489d8d17..0e4d08bfe 100644 --- a/core/src/main/java-templates/org/geysermc/geyser/BuildData.java +++ b/core/src/main/java-templates/org/geysermc/geyser/BuildData.java @@ -34,4 +34,9 @@ public class BuildData { public static final String BRANCH = "{{ branch }}"; public static final String COMMIT = "{{ commit }}"; public static final String REPOSITORY = "{{ repository }}"; + private static final String DEV = "{{ devVersion }}"; + + public static boolean isDevBuild() { + return Boolean.parseBoolean(DEV); + } } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 0975ea5a9..a3eeca6a5 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -122,6 +122,7 @@ public class GeyserImpl implements GeyserApi { public static final String BRANCH = BuildData.BRANCH; public static final String COMMIT = BuildData.COMMIT; public static final String REPOSITORY = BuildData.REPOSITORY; + public static final boolean IS_DEV = BuildData.isDevBuild(); /** * Oauth client ID for Microsoft authentication @@ -207,6 +208,12 @@ public class GeyserImpl implements GeyserApi { logger.info(""); logger.info(GeyserLocale.getLocaleStringLog("geyser.core.load", NAME, VERSION)); logger.info(""); + if (IS_DEV) { + // TODO cloud use language string + //logger.info(GeyserLocale.getLocaleStringLog("geyser.core.dev_build", "https://discord.gg/geysermc")); + logger.info("You are running a development build of Geyser! Please report any bugs you find on our Discord server: %s".formatted("https://discord.gg/geysermc")); + logger.info(""); + } logger.info("******************************************"); /* Initialize registries */ @@ -684,6 +691,7 @@ public class GeyserImpl implements GeyserApi { * * @return true if the version number is not 'DEV'. */ + @SuppressWarnings("BooleanMethodIsAlwaysInverted") public boolean isProductionEnvironment() { // First is if Blossom runs, second is if Blossom doesn't run //noinspection ConstantConditions,MismatchedStringCase - changes in production diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java index eb2e8ff47..c6852d577 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.command.defaults; +import com.fasterxml.jackson.databind.JsonNode; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; -import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.command.GeyserCommand; @@ -37,8 +37,7 @@ import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.WebUtils; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; +import java.io.IOException; import java.util.List; public class VersionCommand extends GeyserCommand { @@ -72,27 +71,36 @@ public class VersionCommand extends GeyserCommand { GeyserImpl.NAME, GeyserImpl.VERSION, javaVersions, bedrockVersions)); // Disable update checking in dev mode and for players in Geyser Standalone - if (GeyserImpl.getInstance().isProductionEnvironment() && !(!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.locale())); - try { - String buildXML = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + - URLEncoder.encode(GeyserImpl.BRANCH, StandardCharsets.UTF_8) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber"); - if (buildXML.startsWith("")) { - int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim()); - int buildNum = this.geyser.buildNumber(); - if (latestBuildNum == buildNum) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.locale())); - } else { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.outdated", - sender.locale(), (latestBuildNum - buildNum), Constants.GEYSER_DOWNLOAD_LOCATION)); - } - } else { - throw new AssertionError("buildNumber missing"); - } - } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.version.failed"), e); - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.version.failed", sender.locale())); + if (!GeyserImpl.getInstance().isProductionEnvironment() || (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) { + return; + } + + if (GeyserImpl.IS_DEV) { + // TODO cloud use language string + sender.sendMessage("You are running a development build of Geyser! Please report any bugs you find on our Discord server: %s" + .formatted("https://discord.gg/geysermc")); + //sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.core.dev_build", sender.locale(), "https://discord.gg/geysermc")); + return; + } + + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.locale())); + try { + int buildNumber = this.geyser.buildNumber(); + JsonNode response = WebUtils.getJson("https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest"); + int latestBuildNumber = response.get("build").asInt(); + + if (latestBuildNumber == buildNumber) { + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.locale())); + return; } + + sender.sendMessage(GeyserLocale.getPlayerLocaleString( + "geyser.commands.version.outdated", + sender.locale(), (latestBuildNumber - buildNumber), "https://geysermc.org/download" + )); + } catch (IOException e) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.version.failed"), e); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.version.failed", sender.locale())); } } From a8bd93a075b17bd7d008465ba47353a086869ce8 Mon Sep 17 00:00:00 2001 From: Ethan <68365423+letsgoawaydev@users.noreply.github.com> Date: Mon, 24 Jun 2024 03:43:09 +0800 Subject: [PATCH 262/897] Add fix (#4792) --- .../org/geysermc/geyser/entity/type/PaintingEntity.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java index 6d0294783..09c055c84 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java @@ -86,7 +86,11 @@ public class PaintingEntity extends Entity { private Vector3f fixOffset(PaintingType paintingName) { Vector3f position = super.position; - position = position.add(0.5, 0.5, 0.5); + // ViaVersion already adds the offset for us on older versions, + // so no need to do it then otherwise it will be spaced + if (session.isEmulatePost1_18Logic()) { + position = position.add(0.5, 0.5, 0.5); + } double widthOffset = paintingName.getWidth() > 1 && paintingName.getWidth() != 3 ? 0.5 : 0; double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0; From ca2312c7f68c54f32314c40c2c1db5d9cda5a0b2 Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Mon, 24 Jun 2024 19:45:30 +0200 Subject: [PATCH 263/897] Create .editorconfig (#4615) --- .editorconfig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..c32bad0c8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +charset = utf-8 +indent_size = 4 +indent_style = space +insert_final_newline = true +tab_width = 4 +max_line_length = off + +[*.java] +ij_java_class_count_to_use_import_on_demand = 9999 +ij_java_doc_align_exception_comments = false +ij_java_doc_align_param_comments = false From 835ba9e24f5904ab5ee84f574a94e6a5a637a3df Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:25:12 -0400 Subject: [PATCH 264/897] Remove casting from block mappings --- .../java/org/geysermc/geyser/registry/type/BlockMappings.java | 4 ++-- .../main/java/org/geysermc/geyser/session/GeyserSession.java | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index 5c4e835e4..be96fec0e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -44,7 +44,7 @@ import java.util.Set; @Builder @Value -public class BlockMappings implements DefinitionRegistry { +public class BlockMappings implements DefinitionRegistry { GeyserBedrockBlock bedrockAir; BlockDefinition bedrockWater; BlockDefinition bedrockMovingBlock; @@ -134,7 +134,7 @@ public class BlockMappings implements DefinitionRegistry { } @Override - public boolean isRegistered(GeyserBedrockBlock bedrockBlock) { + public boolean isRegistered(BlockDefinition bedrockBlock) { return getDefinition(bedrockBlock.getRuntimeId()) == bedrockBlock; } } \ No newline at end of file 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 7f015a05e..25dd21662 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -57,7 +57,6 @@ import org.cloudburstmc.protocol.bedrock.data.command.SoftEnumUpdateType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.*; -import org.cloudburstmc.protocol.common.DefinitionRegistry; import org.cloudburstmc.protocol.common.util.OptionalBoolean; import org.geysermc.api.util.BedrockPlatform; import org.geysermc.api.util.InputMode; @@ -1466,7 +1465,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private void startGame() { this.upstream.getCodecHelper().setItemDefinitions(this.itemMappings); - this.upstream.getCodecHelper().setBlockDefinitions((DefinitionRegistry) this.blockMappings); //FIXME + this.upstream.getCodecHelper().setBlockDefinitions(this.blockMappings); this.upstream.getCodecHelper().setCameraPresetDefinitions(CameraDefinitions.CAMERA_DEFINITIONS); StartGamePacket startGamePacket = new StartGamePacket(); From 130b27203f8b7214c986f13b103e9398f2f7b9ad Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 28 Jun 2024 22:55:36 -0400 Subject: [PATCH 265/897] Limit particle amount in LevelParticlesPacket (#4802) --- .../protocol/java/level/JavaLevelParticlesTranslator.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java index 83b5da219..9ec6ee51e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java @@ -60,6 +60,7 @@ import java.util.function.Function; @Translator(packet = ClientboundLevelParticlesPacket.class) public class JavaLevelParticlesTranslator extends PacketTranslator { + private static final int MAX_PARTICLES = 100; @Override public void translate(GeyserSession session, ClientboundLevelParticlesPacket packet) { @@ -71,7 +72,8 @@ public class JavaLevelParticlesTranslator extends PacketTranslator Date: Sat, 29 Jun 2024 13:32:00 -0400 Subject: [PATCH 266/897] Update license to 2024 --- .github/workflows/build.yml | 1 - LICENSE | 2 +- licenseheader.txt | 24 ------------------------ 3 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 licenseheader.txt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bcf25e8e..59aa89086 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,6 @@ on: - 'LICENSE' - 'Jenkinsfile ' - 'README.md' - - 'licenseheader.txt' jobs: build: diff --git a/LICENSE b/LICENSE index bde252698..ba3a723ff 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2019-2023 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 diff --git a/licenseheader.txt b/licenseheader.txt deleted file mode 100644 index 9bfe117f9..000000000 --- a/licenseheader.txt +++ /dev/null @@ -1,24 +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 - */ \ No newline at end of file From 76126869721457b921ed25c2acf3523a543a6173 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 30 Jun 2024 22:03:30 -0400 Subject: [PATCH 267/897] Don't show git version string twice --- core/build.gradle.kts | 4 ++-- core/src/main/java/org/geysermc/geyser/GeyserImpl.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index fe2576462..1d1794cf7 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -89,7 +89,7 @@ sourceSets { blossom { val info = GitInfo() javaSources { - property("version", "${info.version} (${info.gitVersion})") + property("version", info.version) property("gitVersion", info.gitVersion) property("buildNumber", info.buildNumber.toString()) property("branch", info.branch) @@ -156,4 +156,4 @@ tasks.register("downloadBedrockData") { suffixedFiles = listOf("block_palette.nbt", "creative_items.json", "runtime_item_states.json") destinationDir = "$projectDir/src/main/resources/bedrock" -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index a3eeca6a5..88cc74691 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -694,7 +694,7 @@ public class GeyserImpl implements GeyserApi { @SuppressWarnings("BooleanMethodIsAlwaysInverted") public boolean isProductionEnvironment() { // First is if Blossom runs, second is if Blossom doesn't run - //noinspection ConstantConditions,MismatchedStringCase - changes in production + //noinspection ConstantConditions - changes in production return !("git-local/dev-0000000".equals(GeyserImpl.GIT_VERSION) || "${gitVersion}".equals(GeyserImpl.GIT_VERSION)); } From 48ea81eb9845b621e2bb1434669a2e2a51eded43 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 1 Jul 2024 17:17:52 +0200 Subject: [PATCH 268/897] Update mappings (#4812) Fixes short grass mapping --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 23cb22f9c..69e302bf3 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 23cb22f9ceeb7f24b896a69a711944d7f3e756ed +Subproject commit 69e302bf3a118e5274f86b23a1818c61dba84c64 From ff1e1dd7e38f617454b1b439d3056361072b795b Mon Sep 17 00:00:00 2001 From: Eclipse <116838833+eclipseisoffline@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:17:47 +0000 Subject: [PATCH 269/897] Fix attribute modifier tooltips (#4816) --- .../geysermc/geyser/translator/item/ItemTranslator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 85b4c6264..abe39f177 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 @@ -52,6 +52,7 @@ import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.*; @@ -209,7 +210,7 @@ public final class ItemTranslator { Map> slotsToModifiers = new HashMap<>(); for (ItemAttributeModifiers.Entry entry : modifiers.getModifiers()) { // convert the modifier tag to a lore entry - String loreEntry = attributeToLore(entry.getModifier(), language); + String loreEntry = attributeToLore(entry.getAttribute(), entry.getModifier(), language); if (loreEntry == null) { continue; // invalid or failed } @@ -254,13 +255,13 @@ public final class ItemTranslator { } @Nullable - private static String attributeToLore(ItemAttributeModifiers.AttributeModifier modifier, String language) { + private static String attributeToLore(int attribute, ItemAttributeModifiers.AttributeModifier modifier, String language) { double amount = modifier.getAmount(); if (amount == 0) { return null; } - String name = modifier.getId().asMinimalString(); + String name = AttributeType.Builtin.from(attribute).getIdentifier().asMinimalString(); // the namespace does not need to be present, but if it is, the java client ignores it as of pre-1.20.5 ModifierOperation operation = modifier.getOperation(); From 9f19c0a9f614d9e40141fb490163aa3ca2d66cd2 Mon Sep 17 00:00:00 2001 From: Ethan <68365423+letsgoawaydev@users.noreply.github.com> Date: Sat, 6 Jul 2024 17:58:54 +0800 Subject: [PATCH 270/897] Fix: Trial Spawner Level Events (#4821) * commit every thing i could do, couldnt get it to work with ominous stuff * Fix trial spawner events to work correctly. * Update mappings to latest * fix comment * Workaround for buggy trial chamber particles * Fix positioning and also fix become ominous event * Fix sounds and positioning again * Fix random new line * Update mappings * update cloudburst library to 20240704.153116-14 * Fix accidental random line --- .../java/level/JavaLevelEventTranslator.java | 134 +++++++++++++++--- core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 2 +- 3 files changed, 116 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index d4e317af4..542af1598 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -28,9 +28,16 @@ package org.geysermc.geyser.translator.protocol.java.level; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; -import org.cloudburstmc.protocol.bedrock.packet.*; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket; +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.SpawnParticleEffectPacket; +import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket; +import org.cloudburstmc.protocol.bedrock.packet.TextPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.JukeboxSong; import org.geysermc.geyser.registry.Registries; @@ -40,13 +47,27 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.level.event.LevelEventTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.SoundUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; -import org.geysermc.mcprotocollib.protocol.data.game.level.event.*; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.BonemealGrowEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.BreakBlockEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.BreakPotionEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.ComposterEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.DragonFireballEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEventType; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.RecordEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.SculkBlockChargeEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.SmokeEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.TrialSpawnerDetectEventData; +import org.geysermc.mcprotocollib.protocol.data.game.level.event.UnknownLevelEventData; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import java.util.Collections; +import java.util.Optional; +import java.util.Random; import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; @Translator(packet = ClientboundLevelEventPacket.class) public class JavaLevelEventTranslator extends PacketTranslator { @@ -291,6 +312,20 @@ public class JavaLevelEventTranslator extends PacketTranslator effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.ANIMATION_SPAWN_COBWEB); + case ANIMATION_VAULT_ACTIVATE -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.ANIMATION_VAULT_ACTIVATE); + case ANIMATION_VAULT_DEACTIVATE -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.ANIMATION_VAULT_DEACTIVATE); + case ANIMATION_VAULT_EJECT_ITEM -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.ANIMATION_VAULT_EJECT_ITEM); + case ANIMATION_TRIAL_SPAWNER_EJECT_ITEM -> { + Random random = ThreadLocalRandom.current(); + PlaySoundPacket playSoundPacket = new PlaySoundPacket(); + playSoundPacket.setSound("trial_spawner.eject_item"); + playSoundPacket.setPosition(pos); + playSoundPacket.setVolume(1.0f); + playSoundPacket.setPitch(0.8f + random.nextFloat() * 0.3f); + session.sendUpstreamPacket(playSoundPacket); + return; + } case DRIPSTONE_DRIP -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_DRIPSTONE_DRIP); case PARTICLES_ELECTRIC_SPARK -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_ELECTRIC_SPARK); // Matches with a Bedrock server but doesn't seem to match up with Java case PARTICLES_AND_SOUND_WAX_ON -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_WAX_ON); @@ -303,22 +338,22 @@ public class JavaLevelEventTranslator extends PacketTranslator 0) { levelEventPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.SCULK_CHARGE); levelEventPacket.setTag( - NbtMap.builder() - .putInt("x", packet.getPosition().getX()) - .putInt("y", packet.getPosition().getY()) - .putInt("z", packet.getPosition().getZ()) - .putShort("charge", (short) eventData.getCharge()) - .putShort("facing", encodeFacing(eventData.getBlockFaces())) // TODO check if this is actually correct - .build() + NbtMap.builder() + .putInt("x", packet.getPosition().getX()) + .putInt("y", packet.getPosition().getY()) + .putInt("z", packet.getPosition().getZ()) + .putShort("charge", (short) eventData.getCharge()) + .putShort("facing", encodeFacing(eventData.getBlockFaces())) // TODO check if this is actually correct + .build() ); } else { levelEventPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.SCULK_CHARGE_POP); levelEventPacket.setTag( - NbtMap.builder() - .putInt("x", packet.getPosition().getX()) - .putInt("y", packet.getPosition().getY()) - .putInt("z", packet.getPosition().getZ()) - .build() + NbtMap.builder() + .putInt("x", packet.getPosition().getX()) + .putInt("y", packet.getPosition().getY()) + .putInt("z", packet.getPosition().getZ()) + .build() ); } session.sendUpstreamPacket(levelEventPacket); @@ -328,11 +363,11 @@ public class JavaLevelEventTranslator extends PacketTranslator { + // Particles spawn here + TrialSpawnerDetectEventData eventData = (TrialSpawnerDetectEventData) packet.getData(); + effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_TRIAL_SPAWNER_DETECTION); + // 0.75 is used here for Y instead of 0.5 to match Java Positioning. + // 0.5 is what the BDS uses for positioning. + effectPacket.setPosition(pos.sub(0.5f, 0.75f, 0.5f)); + effectPacket.setData(eventData.getDetectedPlayers()); + } + case PARTICLES_TRIAL_SPAWNER_DETECT_PLAYER_OMINOUS -> { + effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_TRIAL_SPAWNER_DETECTION_CHARGED); + effectPacket.setPosition(pos.sub(0.5f, 0.75f, 0.5f)); + /* + Particles don't spawn here for some reason, only sound plays + This seems to be a bug in v1.21.0 and v1.21.1: see https://bugs.mojang.com/browse/MCPE-181465 + If this gets fixed, the spawnOminousTrialSpawnerParticles function can be removed. + The positioning should be the same as normal activation. + */ + spawnOminousTrialSpawnerParticles(session, pos); + } + case PARTICLES_TRIAL_SPAWNER_BECOME_OMINOUS -> { + effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_TRIAL_SPAWNER_BECOME_CHARGED); + effectPacket.setPosition(pos.sub(0.5f, 0.5f, 0.5f)); + // Same issue as above here + spawnOminousTrialSpawnerParticles(session, pos); + } + case PARTICLES_TRIAL_SPAWNER_SPAWN_MOB_AT -> { + // This should be its own class in MCProtocolLib. + // if 0, use Orange Flames, + // if 1, use Blue Flames for ominous spawners + UnknownLevelEventData eventData = (UnknownLevelEventData) packet.getData(); + effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_TRIAL_SPAWNER_SPAWNING); + effectPacket.setData(eventData.getData()); + } + case PARTICLES_TRIAL_SPAWNER_SPAWN -> { + UnknownLevelEventData eventData = (UnknownLevelEventData) packet.getData(); + effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_TRIAL_SPAWNER_SPAWNING); + effectPacket.setData(eventData.getData()); + + Random random = ThreadLocalRandom.current(); + PlaySoundPacket playSoundPacket = new PlaySoundPacket(); + playSoundPacket.setSound("trial_spawner.spawn_mob"); + playSoundPacket.setPosition(pos); + playSoundPacket.setVolume(1.0f); + playSoundPacket.setPitch(0.8f + random.nextFloat() * 0.3f); + session.sendUpstreamPacket(playSoundPacket); + } + case PARTICLES_TRIAL_SPAWNER_SPAWN_ITEM -> effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_TRIAL_SPAWNER_EJECTING); case SOUND_STOP_JUKEBOX_SONG -> { String bedrockSound = session.getWorldCache().removeActiveRecord(origin); if (bedrockSound == null) { @@ -396,4 +479,15 @@ public class JavaLevelEventTranslator extends PacketTranslator Date: Sat, 6 Jul 2024 21:50:19 +0800 Subject: [PATCH 271/897] Fix toggleable block opening sounds (doors, trapdoors, fence gates) (#4815) * Initial Commit * Fix minor copy and paste comment mistake * Remove debug log Co-authored-by: chris * Remove iron check on fence gate sound translator iron fence gates dont exist lol * Remove iron check from fence gate sound translator. Iron fence gates dont exist (yet) * Remove unnecessary curly braces * Rewrite the code, now functioning correctly with the runtime id * Update mappings * Better formatting Co-authored-by: chris * fix comment because it is referring to code that has been changed * Hopefully fix double closing * Seems like the double closing issue isnt from my code and from somewhere else * Fix issue where doors would update twice when opening/closing them using the upper half * change weird variable name --------- Co-authored-by: chris --- .../geyser/level/block/type/DoorBlock.java | 15 +++++++- .../java/level/JavaBlockUpdateTranslator.java | 4 +-- .../BlockSoundInteractionTranslator.java | 12 +++---- .../BucketSoundInteractionTranslator.java | 4 ++- .../ComparatorSoundInteractionTranslator.java | 4 ++- .../FlintAndSteelInteractionTranslator.java | 3 +- .../block/GrassPathInteractionTranslator.java | 4 ++- .../sound/block/HoeInteractionTranslator.java | 4 ++- .../LeverSoundInteractionTranslator.java | 4 ++- ...> OpenableSoundInteractionTranslator.java} | 35 +++++++++++++++---- .../org/geysermc/geyser/util/SoundUtils.java | 4 +-- 11 files changed, 69 insertions(+), 24 deletions(-) rename core/src/main/java/org/geysermc/geyser/translator/sound/block/{DoorSoundInteractionTranslator.java => OpenableSoundInteractionTranslator.java} (55%) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java index bfde51a79..2efbdb523 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java @@ -37,9 +37,22 @@ public class DoorBlock extends Block { @Override public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + // Needed to check whether we must force the client to update the door state. + String doubleBlockHalf = state.getValue(Properties.DOUBLE_BLOCK_HALF); + + if (doubleBlockHalf.equals("lower")) { + BlockState oldBlockState = session.getGeyser().getWorldManager().blockAt(session, position); + // If these are the same, it means that we already updated the lower door block (manually in the workaround below), + // and we do not need to update the block in the cache/on the client side using the super.updateBlock() method again. + // Otherwise, we send the door updates twice which will cause visual glitches on the client side + if (oldBlockState == state) { + return; + } + } + super.updateBlock(session, state, position); - if (state.getValue(Properties.DOUBLE_BLOCK_HALF).equals("upper")) { + if (doubleBlockHalf.equals("upper")) { // Update the lower door block as Bedrock client doesn't like door to be closed from the top // See https://github.com/GeyserMC/Geyser/issues/4358 Vector3i belowDoorPosition = position.sub(0, 1, 0); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java index 74b961996..d89775662 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java @@ -100,8 +100,8 @@ public class JavaBlockUpdateTranslator extends PacketTranslator { - +public interface BlockSoundInteractionTranslator extends SoundInteractionTranslator { /** * Handles the block interaction when a player * right-clicks a block. * * @param session the session interacting with the block * @param position the position of the block - * @param identifier the identifier of the block + * @param state the state of the block */ - static void handleBlockInteraction(GeyserSession session, Vector3f position, String identifier) { + static void handleBlockInteraction(GeyserSession session, Vector3f position, BlockState state) { // If we need to get the hand identifier, only get it once and save it to a variable String handIdentifier = null; @@ -58,7 +58,7 @@ public interface BlockSoundInteractionTranslator extends SoundInteractionTransla if (interactionEntry.getKey().blocks().length != 0) { boolean contains = false; for (String blockIdentifier : interactionEntry.getKey().blocks()) { - if (identifier.contains(blockIdentifier)) { + if (state.toString().contains(blockIdentifier)) { contains = true; break; } @@ -87,7 +87,7 @@ public interface BlockSoundInteractionTranslator extends SoundInteractionTransla continue; } } - ((BlockSoundInteractionTranslator) interactionEntry.getValue()).translate(session, position, identifier); + ((BlockSoundInteractionTranslator) interactionEntry.getValue()).translate(session, position, state); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/BucketSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/BucketSoundInteractionTranslator.java index 7a5e86af7..45800e1ab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/BucketSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/BucketSoundInteractionTranslator.java @@ -29,6 +29,7 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; @@ -37,7 +38,8 @@ import org.geysermc.geyser.translator.sound.SoundTranslator; public class BucketSoundInteractionTranslator implements BlockSoundInteractionTranslator { @Override - public void translate(GeyserSession session, Vector3f position, String identifier) { + public void translate(GeyserSession session, Vector3f position, BlockState state) { + String identifier = state.toString(); if (!session.isPlacedBucket()) { return; // No bucket was really interacted with } 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 e77539e6e..9d5d3cd59 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.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; @@ -36,7 +37,8 @@ import org.geysermc.geyser.translator.sound.SoundTranslator; public class ComparatorSoundInteractionTranslator implements BlockSoundInteractionTranslator { @Override - public void translate(GeyserSession session, Vector3f position, String identifier) { + 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); diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/FlintAndSteelInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/FlintAndSteelInteractionTranslator.java index a822f3520..e8225a336 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/FlintAndSteelInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/FlintAndSteelInteractionTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.sound.block; 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.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; @@ -36,7 +37,7 @@ import org.geysermc.geyser.translator.sound.SoundTranslator; public class FlintAndSteelInteractionTranslator implements BlockSoundInteractionTranslator { @Override - public void translate(GeyserSession session, Vector3f position, String identifier) { + public void translate(GeyserSession session, Vector3f position, BlockState state) { LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); levelSoundEventPacket.setPosition(position); levelSoundEventPacket.setBabySound(false); 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 0a91f8896..a25beaa50 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 @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.sound.block; 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; @@ -37,7 +38,8 @@ import org.geysermc.geyser.translator.sound.SoundTranslator; public class GrassPathInteractionTranslator implements BlockSoundInteractionTranslator { @Override - public void translate(GeyserSession session, Vector3f position, String identifier) { + public void translate(GeyserSession session, Vector3f position, BlockState state) { + String identifier = state.toString(); LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); levelSoundEventPacket.setPosition(position); levelSoundEventPacket.setBabySound(false); 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 410422b4a..1a583ab8a 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 @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.sound.block; 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; @@ -37,7 +38,8 @@ import org.geysermc.geyser.translator.sound.SoundTranslator; public class HoeInteractionTranslator implements BlockSoundInteractionTranslator { @Override - public void translate(GeyserSession session, Vector3f position, String identifier) { + public void translate(GeyserSession session, Vector3f position, BlockState state) { + String identifier = state.toString(); LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); levelSoundEventPacket.setPosition(position); levelSoundEventPacket.setBabySound(false); 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 17b8768bc..fd045739c 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.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; @@ -36,7 +37,8 @@ import org.geysermc.geyser.translator.sound.SoundTranslator; public class LeverSoundInteractionTranslator implements BlockSoundInteractionTranslator { @Override - public void translate(GeyserSession session, Vector3f position, String identifier) { + 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); diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/DoorSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/OpenableSoundInteractionTranslator.java similarity index 55% rename from core/src/main/java/org/geysermc/geyser/translator/sound/block/DoorSoundInteractionTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/sound/block/OpenableSoundInteractionTranslator.java index 8f8ab8bf6..93d55ca33 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/DoorSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/OpenableSoundInteractionTranslator.java @@ -27,21 +27,42 @@ 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.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; @SoundTranslator(blocks = {"door", "fence_gate"}) -public class DoorSoundInteractionTranslator implements BlockSoundInteractionTranslator { +public class OpenableSoundInteractionTranslator implements BlockSoundInteractionTranslator { @Override - public void translate(GeyserSession session, Vector3f position, String identifier) { + public void translate(GeyserSession session, Vector3f position, BlockState state) { + String identifier = state.toString(); if (identifier.contains("iron")) return; - LevelEventPacket levelEventPacket = new LevelEventPacket(); - levelEventPacket.setType(LevelEvent.SOUND_DOOR_OPEN); - levelEventPacket.setPosition(position); - levelEventPacket.setData(0); - session.sendUpstreamPacket(levelEventPacket); + SoundEvent event = getSound(identifier.contains("open=true"), identifier); + LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); + levelSoundEventPacket.setPosition(position.add(0.5, 0.5, 0.5)); + levelSoundEventPacket.setBabySound(false); + levelSoundEventPacket.setRelativeVolumeDisabled(false); + levelSoundEventPacket.setIdentifier(":"); + levelSoundEventPacket.setSound(event); + levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlock(state).getRuntimeId()); + session.sendUpstreamPacket(levelSoundEventPacket); + } + + private SoundEvent getSound(boolean open, String identifier) { + if (identifier.contains("_door")) { + return open ? SoundEvent.DOOR_OPEN : SoundEvent.DOOR_CLOSE; + } + + if (identifier.contains("_trapdoor")) { + return open ? SoundEvent.TRAPDOOR_OPEN : SoundEvent.TRAPDOOR_CLOSE; + } + + // Fence Gate + return open ? SoundEvent.FENCE_GATE_OPEN : SoundEvent.FENCE_GATE_CLOSE; } } 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 524d241db..693ce136a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -133,7 +133,7 @@ public final class SoundUtils { } if (sound == null) { session.getGeyser().getLogger().debug("[Builtin] Sound for original '" + soundIdentifier + "' to mappings '" + soundMapping.getBedrock() - + "' was not a playable level sound, or has yet to be mapped to an enum in SoundEvent."); + + "' was not a playable level sound, or has yet to be mapped to an enum in SoundEvent."); return; } @@ -144,7 +144,7 @@ public final class SoundUtils { // Minecraft Wiki: 2^(x/12) = Java pitch where x is -12 to 12 // Java sends the note value as above starting with -12 and ending at 12 // Bedrock has a number for each type of note, then proceeds up the scale by adding to that number - soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12); + soundPacket.setExtraData(soundMapping.getExtraData() + (int) (Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12); } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { if (!soundMapping.getIdentifier().equals(":")) { int javaId = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(soundMapping.getIdentifier(), Block.JAVA_AIR_ID); From 74cabed67444e1a6b79ba6966df08b7c1e2bf6ca Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 6 Jul 2024 20:47:49 +0200 Subject: [PATCH 272/897] Update to loom 1.7-SNAPSHOT, update gradle wrapper (#4820) --- gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 78601024f..49c02d190 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ minecraft = "1.21" indra = "3.1.3" shadow = "8.1.1" architectury-plugin = "3.4-SNAPSHOT" -architectury-loom = "1.6-SNAPSHOT" +architectury-loom = "1.7-SNAPSHOT" minotaur = "2.8.7" lombok = "8.4" blossom = "2.1.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch delta 34118 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 delta 34176 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 SGW6ptSs!X7{rG*o_g?|vpSEZK diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a4..a4413138c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From cbd59de37b3026e21fd01f71b70df00503ed0d8a Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 6 Jul 2024 23:14:15 +0200 Subject: [PATCH 273/897] Only apply door fix when we can actually access the old blockstate (#4827) --- .../java/org/geysermc/geyser/level/block/type/DoorBlock.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java index 2efbdb523..956d4b771 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java @@ -40,7 +40,7 @@ public class DoorBlock extends Block { // Needed to check whether we must force the client to update the door state. String doubleBlockHalf = state.getValue(Properties.DOUBLE_BLOCK_HALF); - if (doubleBlockHalf.equals("lower")) { + if (!session.getGeyser().getWorldManager().hasOwnChunkCache() && doubleBlockHalf.equals("lower")) { BlockState oldBlockState = session.getGeyser().getWorldManager().blockAt(session, position); // If these are the same, it means that we already updated the lower door block (manually in the workaround below), // and we do not need to update the block in the cache/on the client side using the super.updateBlock() method again. From a807fa6bb5c19f12894d82361372393b4d13c97c Mon Sep 17 00:00:00 2001 From: LetsGoAway <68365423+letsgoawaydev@users.noreply.github.com> Date: Sun, 7 Jul 2024 17:27:49 +0800 Subject: [PATCH 274/897] Fix typo in version command (#4830) --- .../src/main/java/org/geysermc/geyser/network/GameProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index de995301a..1e9e76205 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -67,7 +67,7 @@ public final class GameProtocol { .minecraftVersion("1.20.80/1.20.81") .build())); SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.0/1.20.1") + .minecraftVersion("1.21.0/1.21.1") .build())); } From e0af0a54b78ada10d14c94469c75739ba06b6295 Mon Sep 17 00:00:00 2001 From: strom <167184523+stromsoftware@users.noreply.github.com> Date: Sun, 7 Jul 2024 16:59:18 +0200 Subject: [PATCH 275/897] Fix: Text display passenger offsets (#4676) --- .../geyser/entity/EntityDefinitions.java | 4 +- .../geyser/entity/type/DisplayBaseEntity.java | 77 +++++++++++++++++++ .../geyser/entity/type/TextDisplayEntity.java | 18 +---- .../org/geysermc/geyser/util/EntityUtils.java | 24 ++++-- 4 files changed, 97 insertions(+), 26 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/DisplayBaseEntity.java 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 1496f8a82..11b4a32d1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -307,11 +307,11 @@ public final class EntityDefinitions { .addTranslator(MetadataType.INT, TNTEntity::setFuseLength) .build(); - EntityDefinition displayBase = EntityDefinition.inherited(entityBase.factory(), entityBase) + EntityDefinition displayBase = EntityDefinition.inherited(DisplayBaseEntity::new, entityBase) .addTranslator(null) // Interpolation delay .addTranslator(null) // Transformation interpolation duration .addTranslator(null) // Position/Rotation interpolation duration - .addTranslator(null) // Translation + .addTranslator(MetadataType.VECTOR3, DisplayBaseEntity::setTranslation) // Translation .addTranslator(null) // Scale .addTranslator(null) // Left rotation .addTranslator(null) // Right rotation diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/DisplayBaseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/DisplayBaseEntity.java new file mode 100644 index 000000000..16587d125 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/DisplayBaseEntity.java @@ -0,0 +1,77 @@ +/* + * 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; + +import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; + +import java.util.Optional; +import java.util.UUID; + +public class DisplayBaseEntity extends Entity { + + private @Nullable Vector3f baseTranslation; + + public DisplayBaseEntity(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 void setDisplayNameVisible(BooleanEntityMetadata entityMetadata) { + // Don't allow the display name to be hidden - messes with our armor stand. + // On JE: Hiding the display name still shows the display entity text. + } + + @Override + public void setDisplayName(EntityMetadata, ?> entityMetadata) { + // This would usually set EntityDataTypes.NAME, but we are instead using NAME for the text display. + // On JE: custom name does not override text display. + } + + public void setTranslation(EntityMetadata translationMeta){ + this.baseTranslation = translationMeta.getValue(); + if (this.baseTranslation == null) { + return; + } + if (this.vehicle == null) { + this.setRiderSeatPosition(this.baseTranslation); + this.moveRelative(this.baseTranslation.getX(), this.baseTranslation.getY(), this.baseTranslation.getZ(), yaw, pitch, headYaw, false); + } else { + EntityUtils.updateMountOffset(this, this.vehicle, true, true, false); + this.updateBedrockMetadata(); + } + } + + public Vector3f getTranslation() { + return baseTranslation; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java index 28f38f919..ff5604c19 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.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 @@ -32,13 +32,11 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import java.util.Optional; import java.util.UUID; // Note: 1.19.4 requires that the billboard is set to something in order to show, on Java Edition -public class TextDisplayEntity extends Entity { +public class TextDisplayEntity extends DisplayBaseEntity { public TextDisplayEntity(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); } @@ -51,18 +49,6 @@ public class TextDisplayEntity extends Entity { this.dirtyMetadata.put(EntityDataTypes.NAMETAG_ALWAYS_SHOW, (byte) 1); } - @Override - public void setDisplayNameVisible(BooleanEntityMetadata entityMetadata) { - // Don't allow the display name to be hidden - messes with our armor stand. - // On JE: Hiding the display name still shows the display entity text. - } - - @Override - public void setDisplayName(EntityMetadata, ?> entityMetadata) { - // This would usually set EntityDataTypes.NAME, but we are instead using NAME for the text display. - // On JE: custom name does not override text display. - } - public void setText(EntityMetadata entityMetadata) { this.dirtyMetadata.put(EntityDataTypes.NAME, MessageTranslator.convertMessage(entityMetadata.getValue())); } 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 bfb70a4ed..53aefde1e 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.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 @@ -32,6 +32,7 @@ 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.Entity; +import org.geysermc.geyser.entity.type.TextDisplayEntity; import org.geysermc.geyser.entity.type.living.ArmorStandEntity; import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.entity.type.living.animal.horse.CamelEntity; @@ -172,11 +173,7 @@ public final class EntityUtils { case BOAT -> { // Without the X offset, more than one entity on a boat is stacked on top of each other if (moreThanOneEntity) { - if (rider) { - xOffset = 0.2f; - } else { - xOffset = -0.6f; - } + xOffset = rider ? 0.2f : -0.6f; if (passenger instanceof AnimalEntity) { xOffset += 0.2f; } @@ -203,6 +200,18 @@ 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 -> { + if (passenger instanceof TextDisplayEntity textDisplay) { + Vector3f displayTranslation = textDisplay.getTranslation(); + if (displayTranslation == null) { + return; + } + + xOffset = displayTranslation.getX(); + yOffset = displayTranslation.getY() + 0.2f; + zOffset = displayTranslation.getZ(); + } + } } /* * Bedrock Differences @@ -228,8 +237,7 @@ public final class EntityUtils { if (mount instanceof ArmorStandEntity armorStand) { yOffset -= armorStand.getYOffset(); } - Vector3f offset = Vector3f.from(xOffset, yOffset, zOffset); - passenger.setRiderSeatPosition(offset); + passenger.setRiderSeatPosition(Vector3f.from(xOffset, yOffset, zOffset)); } } From 0a928c41b01de14ef428b348f91d0226f2236968 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 8 Jul 2024 00:41:00 +0200 Subject: [PATCH 276/897] Show potions & custom items in the shulker box tooltip (#4822) * Fix: Potions/Custom items showing up improperly in shulker box previews * oops --- .../geyser/item/type/ShulkerBoxItem.java | 31 +++++++++++++++++-- .../translator/item/BedrockItemBuilder.java | 9 +++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index a539fa739..c3b739adc 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -29,15 +29,19 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; +import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.geyser.translator.item.CustomItemTranslator; 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.item.component.PotionContents; import java.util.ArrayList; import java.util.List; @@ -64,12 +68,35 @@ public class ShulkerBoxItem extends BlockItem { } ItemMapping boxMapping = session.getItemMappings().getMapping(item.getId()); - NbtMapBuilder boxItemNbt = BedrockItemBuilder.createItemNbt(boxMapping, item.getAmount(), boxMapping.getBedrockData()); // Final item tag to add to the list + int bedrockData = boxMapping.getBedrockData(); + String bedrockIdentifier = boxMapping.getBedrockIdentifier(); + DataComponents boxComponents = item.getDataComponents(); + + if (boxComponents != null) { + // Check for custom items + ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(boxComponents, boxMapping); + if (customItemDefinition != null) { + bedrockIdentifier = customItemDefinition.getIdentifier(); + bedrockData = 0; + } else { + // Manual checks for potions/tipped arrows + if (boxMapping.getJavaItem() instanceof PotionItem || boxMapping.getJavaItem() instanceof ArrowItem) { + PotionContents potionContents = boxComponents.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + Potion potion = Potion.getByJavaId(potionContents.getPotionId()); + if (potion != null) { + bedrockData = potion.getBedrockId(); + } + } + } + } + } + + NbtMapBuilder boxItemNbt = BedrockItemBuilder.createItemNbt(bedrockIdentifier, item.getAmount(), bedrockData); // Final item tag to add to the list boxItemNbt.putByte("Slot", (byte) slot); boxItemNbt.putByte("WasPickedUp", (byte) 0); // ??? TODO might not be needed // Only the display name is what we have interest in, so just translate that if relevant - DataComponents boxComponents = item.getDataComponents(); if (boxComponents != null) { String customName = ItemTranslator.getCustomName(session, boxComponents, boxMapping, '7'); if (customName != null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java index 52d5b7e31..e989288c2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java @@ -145,8 +145,15 @@ public final class BedrockItemBuilder { * Creates item NBT to nest within NBT with name, count, and damage set. */ public static NbtMapBuilder createItemNbt(ItemMapping mapping, int count, int damage) { + return createItemNbt(mapping.getBedrockIdentifier(), count, damage); + } + + /** + * Creates item NBT to nest within NBT with name, count, and damage set. + */ + public static NbtMapBuilder createItemNbt(String bedrockIdentifier, int count, int damage) { NbtMapBuilder builder = NbtMap.builder(); - builder.putString("Name", mapping.getBedrockIdentifier()); + builder.putString("Name", bedrockIdentifier); builder.putByte("Count", (byte) count); builder.putShort("Damage", (short) damage); return builder; From f825007d9a5e5c3856aa09e05786f4dcb1f4102a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 9 Jul 2024 12:39:43 -0400 Subject: [PATCH 277/897] Support Bedrock 1.21.2 --- .../org/geysermc/geyser/network/GameProtocol.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 1e9e76205..c79ef365d 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -43,13 +43,17 @@ import java.util.StringJoiner; */ public final class GameProtocol { + // Surprise protocol bump WOW + private static final BedrockCodec BEDROCK_V686 = Bedrock_v685.CODEC.toBuilder() + .protocolVersion(686) + .minecraftVersion("1.21.2") + .build(); + /** * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v685.CODEC.toBuilder() - .minecraftVersion("1.21.1") - .build()); + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(BEDROCK_V686); /** * A list of all supported Bedrock versions that can join Geyser @@ -66,9 +70,10 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v671.CODEC.toBuilder() .minecraftVersion("1.20.80/1.20.81") .build())); - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v685.CODEC.toBuilder() .minecraftVersion("1.21.0/1.21.1") .build())); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } /** From a3b1f203ec7d607644195d1630b0077a5fe211b5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 9 Jul 2024 12:59:48 -0400 Subject: [PATCH 278/897] Bump Bedrock version in README --- README.md | 2 +- core/src/main/resources/mappings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e3b5a496a..14bdb17a9 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.1 and Minecraft Java 1.21 +### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.2 and Minecraft Java 1.21 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index aaf53d695..23cb22f9c 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit aaf53d6953c927e5ac1b87fd6627ffbfd4aa7cf5 +Subproject commit 23cb22f9ceeb7f24b896a69a711944d7f3e756ed From 7fdb410d26f8759c906d6673eacce9f60d00ff4b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 9 Jul 2024 13:00:27 -0400 Subject: [PATCH 279/897] Fix mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 23cb22f9c..aaf53d695 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 23cb22f9ceeb7f24b896a69a711944d7f3e756ed +Subproject commit aaf53d6953c927e5ac1b87fd6627ffbfd4aa7cf5 From 2a6025f3fc841f471c92b23fd2ed982eca36ae4f Mon Sep 17 00:00:00 2001 From: Eclipse Date: Wed, 10 Jul 2024 10:02:32 +0000 Subject: [PATCH 280/897] Fix reading enchantments from server (#4836) --- .../geyser/inventory/recipe/TrimRecipe.java | 21 ++++--- .../updater/AnvilInventoryUpdater.java | 27 +++++---- .../geyser/item/enchantment/Enchantment.java | 59 ++++++++++++++----- .../geysermc/geyser/level/JavaDimension.java | 6 +- .../geysermc/geyser/level/JukeboxSong.java | 8 +-- .../geyser/session/cache/RegistryCache.java | 38 ++++++++---- .../geyser/session/cache/TagCache.java | 8 ++- .../cache/registry/RegistryEntryContext.java | 56 ++++++++++++++++++ .../geysermc/geyser/text/TextDecoration.java | 6 +- 9 files changed, 166 insertions(+), 63 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/registry/RegistryEntryContext.java diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java index 8289813a4..b5e76a296 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java @@ -32,9 +32,8 @@ import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescriptor; import org.geysermc.geyser.registry.type.ItemMapping; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; /** * Stores information on trim materials and patterns, including smithing armor hacks for pre-1.20. @@ -46,18 +45,18 @@ public final class TrimRecipe { public static final ItemDescriptorWithCount ADDITION = tagDescriptor("minecraft:trim_materials"); public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates"); - public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) { - String key = entry.getId().asMinimalString(); + public static TrimMaterial readTrimMaterial(RegistryEntryContext context) { + String key = context.id().asMinimalString(); // Color is used when hovering over the item // Find the nearest legacy color from the RGB Java gives us to work with // Also yes this is a COMPLETE hack but it works ok!!!!! - String colorTag = entry.getData().getCompound("description").getString("color"); + String colorTag = context.data().getCompound("description").getString("color"); TextColor color = TextColor.fromHexString(colorTag); String legacy = MessageTranslator.convertMessage(Component.space().color(color)); - String itemIdentifier = entry.getData().getString("ingredient"); - ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier); + String itemIdentifier = context.data().getString("ingredient"); + ItemMapping itemMapping = context.session().getItemMappings().getMapping(itemIdentifier); if (itemMapping == null) { // This should never happen so not sure what to do here. itemMapping = ItemMapping.AIR; @@ -66,11 +65,11 @@ public final class TrimRecipe { return new TrimMaterial(key, legacy.substring(2).trim(), itemMapping.getBedrockIdentifier()); } - public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) { - String key = entry.getId().asMinimalString(); + public static TrimPattern readTrimPattern(RegistryEntryContext context) { + String key = context.id().asMinimalString(); - String itemIdentifier = entry.getData().getString("template_item"); - ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier); + String itemIdentifier = context.data().getString("template_item"); + ItemMapping itemMapping = context.session().getItemMappings().getMapping(itemIdentifier); if (itemMapping == null) { // This should never happen so not sure what to do here. itemMapping = ItemMapping.AIR; 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 c3ac73372..7afd31cc9 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.inventory.updater; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import java.util.stream.IntStream; import net.kyori.adventure.text.Component; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -41,11 +42,14 @@ import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.item.Items; 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; @@ -310,17 +314,18 @@ public class AnvilInventoryUpdater extends InventoryUpdater { for (Object2IntMap.Entry entry : getEnchantments(session, material).object2IntEntrySet()) { Enchantment enchantment = entry.getKey(); - boolean canApply = isEnchantedBook(input) || session.getTagCache().is(enchantment.supportedItems(), input); - var exclusiveSet = enchantment.exclusiveSet(); - if (exclusiveSet != null) { - int[] incompatibleEnchantments = session.getTagCache().get(exclusiveSet); - for (int i : incompatibleEnchantments) { - Enchantment incompatible = session.getRegistryCache().enchantments().byId(i); - if (combinedEnchantments.containsKey(incompatible)) { - canApply = false; - if (!bedrock) { - cost++; - } + 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()); + + 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); + if (combinedEnchantments.containsKey(incompatible)) { + canApply = false; + if (!bedrock) { + cost++; } } } 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 c5c0d2611..3c0caa60c 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,18 +25,21 @@ package org.geysermc.geyser.item.enchantment; +import java.util.List; +import java.util.function.Function; +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.session.cache.tags.EnchantmentTag; -import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; /** * @param description only populated if {@link #bedrockEnchantment()} is not null. @@ -44,28 +47,32 @@ import java.util.Set; */ public record Enchantment(String identifier, Set effects, - ItemTag supportedItems, + HolderSet supportedItems, int maxLevel, String description, int anvilCost, - @Nullable EnchantmentTag exclusiveSet, + HolderSet exclusiveSet, @Nullable BedrockEnchantment bedrockEnchantment) { - // Implementation note: I have a feeling the tags can be a list of items, because in vanilla they're HolderSet classes. - // I'm not sure how that's wired over the network, so we'll put it off. - public static Enchantment read(RegistryEntry entry) { - NbtMap data = entry.getData(); + public static Enchantment read(RegistryEntryContext context) { + NbtMap data = context.data(); Set effects = readEnchantmentComponents(data.getCompound("effects")); - String supportedItems = data.getString("supported_items").substring(1); // Remove '#' at beginning that indicates tag + + HolderSet supportedItems = readHolderSet(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"); - String exclusiveSet = data.getString("exclusive_set", null); - EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(MinecraftKey.key(exclusiveSet.substring(1))); - BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId().asString()); + + HolderSet exclusiveSet = readHolderSet(data.getOrDefault("exclusive_set", null), 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(data) : null; - return new Enchantment(entry.getId().asString(), effects, ItemTag.ALL_ITEM_TAGS.get(MinecraftKey.key(supportedItems)), maxLevel, - description, anvilCost, exclusiveSetTag, bedrockEnchantment); + return new Enchantment(context.id().asString(), effects, supportedItems, maxLevel, + description, anvilCost, exclusiveSet, bedrockEnchantment); } private static Set readEnchantmentComponents(NbtMap effects) { @@ -77,4 +84,24 @@ 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, Function keyIdMapping) { + if (holderSet == null) { + return new HolderSet(new int[]{}); + } + + if (holderSet instanceof String stringTag) { + // Tag + if (stringTag.startsWith("#")) { + return new HolderSet(Key.key(stringTag.substring(1))); // Remove '#' at beginning that indicates tag + } else { + return new HolderSet(new int[]{keyIdMapping.apply(Key.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).map(keyIdMapping).mapToInt(Integer::intValue).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/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 6112dc6cf..dd0f4215e 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.level; import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; /** * Represents the information we store from the current Java dimension @@ -35,8 +35,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; */ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale) { - public static JavaDimension read(RegistryEntry entry) { - NbtMap dimension = entry.getData(); + public static JavaDimension read(RegistryEntryContext entry) { + NbtMap dimension = entry.data(); int minY = dimension.getInt("min_y"); int maxY = dimension.getInt("height"); // Logical height can be ignored probably - seems to be for artificial limits like the Nether. 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 156a62cd1..b00dc9f98 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java +++ b/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java @@ -27,13 +27,13 @@ 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.mcprotocollib.protocol.data.game.RegistryEntry; public record JukeboxSong(String soundEvent, String description) { - public static JukeboxSong read(RegistryEntry entry) { - NbtMap data = entry.getData(); + public static JukeboxSong read(RegistryEntryContext context) { + NbtMap data = context.data(); Object soundEventObject = data.get("sound_event"); String soundEvent; if (soundEventObject instanceof NbtMap map) { @@ -42,7 +42,7 @@ public record JukeboxSong(String soundEvent, String description) { soundEvent = string; } else { soundEvent = ""; - GeyserImpl.getInstance().getLogger().debug("Sound event for " + entry.getId() + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject); + GeyserImpl.getInstance().getLogger().debug("Sound event for " + context.id() + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject); } String description = MessageTranslator.deserializeDescription(data); return new JukeboxSong(soundEvent, description); 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 3121af369..a393d461d 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 @@ -27,6 +27,8 @@ package org.geysermc.geyser.session.cache; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.AccessLevel; import lombok.Getter; import lombok.experimental.Accessors; @@ -45,6 +47,7 @@ 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.JavaRegistry; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; @@ -59,7 +62,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; -import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.ToIntFunction; @@ -76,16 +78,16 @@ public final class RegistryCache { private static final Map>> REGISTRIES = new HashMap<>(); static { - register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry)); - register("dimension_type", cache -> cache.dimensions, ($, entry) -> JavaDimension.read(entry)); - register("enchantment", cache -> cache.enchantments, ($, entry) -> Enchantment.read(entry)); - register("jukebox_song", cache -> cache.jukeboxSongs, ($, entry) -> JukeboxSong.read(entry)); - register("painting_variant", cache -> cache.paintings, ($, entry) -> PaintingType.getByName(entry.getId())); + register("chat_type", cache -> cache.chatTypes, TextDecoration::readChatType); + register("dimension_type", cache -> cache.dimensions, JavaDimension::read); + register("enchantment", cache -> cache.enchantments, Enchantment::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); register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); - register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); - register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(entry.getId().asString())); + register("banner_pattern", cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); + register("wolf_variant", cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); @@ -149,25 +151,35 @@ public final class RegistryCache { * @param reader converts the RegistryEntry NBT into a class file * @param the class that represents these entries. */ - private static void register(String registry, Function> localCacheFunction, BiFunction reader) { - Key key = MinecraftKey.key(registry); - REGISTRIES.put(key, (registryCache, entries) -> { + private static void register(String registry, Function> localCacheFunction, Function reader) { + Key registryKey = MinecraftKey.key(registry); + REGISTRIES.put(registryKey, (registryCache, entries) -> { Map localRegistry = null; JavaRegistry localCache = localCacheFunction.apply(registryCache); // Clear each local cache every time a new registry entry is given to us // (e.g. proxy server switches) + + // Store each of the entries resource location IDs and their respective network ID, + // used for the key mapper that's currently only used by the Enchantment class + Object2IntMap entryIdMap = new Object2IntOpenHashMap<>(); + for (int i = 0; i < entries.size(); i++) { + entryIdMap.put(entries.get(i).getId(), i); + } + List builder = new ArrayList<>(entries.size()); for (int i = 0; i < entries.size(); i++) { RegistryEntry entry = entries.get(i); // 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(key); + localRegistry = DEFAULTS.get(registryKey); } entry = new RegistryEntry(entry.getId(), localRegistry.get(entry.getId())); } + + RegistryEntryContext context = new RegistryEntryContext(entry, entryIdMap, registryCache.session); // This is what Geyser wants to keep as a value for this registry. - T cacheEntry = reader.apply(registryCache.session, entry); + T cacheEntry = reader.apply(context); builder.add(i, cacheEntry); } localCache.reset(builder); 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 c8bfc7eed..f4d69dcdb 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 @@ -130,8 +130,12 @@ public final class TagCache { return contains(values, item.javaId()); } - public int[] get(EnchantmentTag tag) { - return this.enchantments[tag.ordinal()]; + public int[] get(ItemTag itemTag) { + return this.items[itemTag.ordinal()]; + } + + public int[] get(EnchantmentTag enchantmentTag) { + return this.enchantments[enchantmentTag.ordinal()]; } private static boolean contains(int[] array, int i) { diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/RegistryEntryContext.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/RegistryEntryContext.java new file mode 100644 index 000000000..415890d95 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/RegistryEntryContext.java @@ -0,0 +1,56 @@ +/* + * 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 it.unimi.dsi.fastutil.objects.Object2IntMap; +import java.util.Map; +import net.kyori.adventure.key.Key; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; + +/** + * Used to store context around a single registry entry when reading said entry's NBT. + * + * @param entry the registry entry being read. + * @param keyIdMap a map for each of the resource location's in the registry and their respective network IDs. + * @param session the Geyser session. + */ +public record RegistryEntryContext(RegistryEntry entry, Object2IntMap keyIdMap, GeyserSession session) { + + public int getNetworkId(Key registryKey) { + return keyIdMap.getOrDefault(registryKey, 0); + } + + public Key id() { + return entry.getId(); + } + + // Not annotated as nullable because data should never be null here + public NbtMap data() { + return entry.getData(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java index ab9e2b5ed..94aec22ef 100644 --- a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -29,7 +29,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; -import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType; import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatTypeDecoration; @@ -43,11 +43,11 @@ public record TextDecoration(String translationKey, List parameters, throw new UnsupportedOperationException(); } - public static ChatType readChatType(RegistryEntry entry) { + public static ChatType readChatType(RegistryEntryContext context) { // Note: The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. // (This note has been passed around through several classes and iterations. It stays as a warning // to anyone that dares to try and hardcode registry IDs.) - NbtMap tag = entry.getData(); + NbtMap tag = context.data(); NbtMap chat = tag.getCompound("chat", null); if (chat != null) { String translationKey = chat.getString("translation_key"); From 93b0a612659d026a293a53f632f89d1c5775eacf Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 12 Jul 2024 20:55:40 +0200 Subject: [PATCH 281/897] Fix: hanging sign recipe not showing up in the recipe book (#4814) --- .../populator/CreativeItemRegistryPopulator.java | 12 +----------- .../registry/populator/ItemRegistryPopulator.java | 7 ++----- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java index c536d739c..2c033edc7 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java @@ -49,8 +49,6 @@ import java.util.function.Consumer; public class CreativeItemRegistryPopulator { private static final List> JAVA_ONLY_ITEM_FILTER = List.of( - // Just shows an empty texture; either way it doesn't exist in the creative menu on Java - (identifier, data) -> identifier.equals("minecraft:debug_stick"), // Bedrock-only as its own item (identifier, data) -> identifier.equals("minecraft:empty_map") && data == 2, // Bedrock-only banner patterns @@ -103,16 +101,8 @@ public class CreativeItemRegistryPopulator { } GeyserBedrockBlock blockDefinition = null; - JsonNode blockRuntimeIdNode = itemNode.get("blockRuntimeId"); JsonNode blockStateNode; - if (blockRuntimeIdNode != null) { - bedrockBlockRuntimeId = blockRuntimeIdNode.asInt(); - if (bedrockBlockRuntimeId == 0 && !identifier.equals("minecraft:blue_candle")) { // FIXME - bedrockBlockRuntimeId = -1; - } - - blockDefinition = bedrockBlockRuntimeId == -1 ? null : blockMappings.getDefinition(bedrockBlockRuntimeId); - } else if ((blockStateNode = itemNode.get("block_state_b64")) != null) { + if ((blockStateNode = itemNode.get("block_state_b64")) != null) { byte[] bytes = Base64.getDecoder().decode(blockStateNode.asText()); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); try { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index e19066462..85207ac3a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -252,10 +252,7 @@ public class ItemRegistryPopulator { } else { // Try to get an example block runtime ID from the creative contents packet, for Bedrock identifier obtaining int aValidBedrockBlockId = blacklistedIdentifiers.getOrDefault(bedrockIdentifier, customBlockItemOverride != null ? customBlockItemOverride.getRuntimeId() : -1); - if (aValidBedrockBlockId == -1 && customBlockItemOverride == null) { - // Fallback - bedrockBlock = blockMappings.getBedrockBlock(firstBlockRuntimeId); - } else { + if (aValidBedrockBlockId != -1 || customBlockItemOverride != null) { // As of 1.16.220, every item requires a block runtime ID attached to it. // This is mostly for identifying different blocks with the same item ID - wool, slabs, some walls. // However, in order for some visuals and crafting to work, we need to send the first matching block state @@ -266,7 +263,7 @@ public class ItemRegistryPopulator { boolean firstPass = true; // Block states are all grouped together. In the mappings, we store the first block runtime ID in order, // and the last, if relevant. We then iterate over all those values and get their Bedrock equivalents - Integer lastBlockRuntimeId = entry.getValue().getLastBlockRuntimeId() == null ? firstBlockRuntimeId : entry.getValue().getLastBlockRuntimeId(); + int lastBlockRuntimeId = entry.getValue().getLastBlockRuntimeId() == null ? firstBlockRuntimeId : entry.getValue().getLastBlockRuntimeId(); for (int i = firstBlockRuntimeId; i <= lastBlockRuntimeId; i++) { GeyserBedrockBlock bedrockBlockRuntimeId = blockMappings.getVanillaBedrockBlock(i); NbtMap blockTag = bedrockBlockRuntimeId.getState(); From b0c7ddb68dbf3141f9710ea970e5f06fd246c2a4 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 13 Jul 2024 18:53:13 +0200 Subject: [PATCH 282/897] Fix: Item color names/glint for rare items (#4763) * debug stick changes * yay light purple item name * Address review * Auto-generate rarity * Add glint generation * Translate all rare items properly * Use putIfAbsent instead of double checks --- .../java/org/geysermc/geyser/item/Items.java | 121 +++++++++--------- .../geyser/item/components/Rarity.java | 51 ++++++++ .../org/geysermc/geyser/item/type/Item.java | 25 ++++ .../populator/ItemRegistryPopulator.java | 4 +- .../translator/item/ItemTranslator.java | 34 +++-- 5 files changed, 163 insertions(+), 72 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/components/Rarity.java 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 1ddd14982..462e98d19 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -25,6 +25,7 @@ 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.level.block.Blocks; @@ -122,7 +123,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(), Blocks.HEAVY_CORE)); + public static final Item HEAVY_CORE = register(new BlockItem(builder().rarity(Rarity.EPIC), 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)); @@ -416,7 +417,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(), Blocks.DRAGON_EGG)); + public static final Item DRAGON_EGG = register(new BlockItem(builder().rarity(Rarity.EPIC), 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)); @@ -432,8 +433,8 @@ public final class Items { 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(), Blocks.COMMAND_BLOCK)); - public static final Item BEACON = register(new BlockItem(builder(), Blocks.BEACON)); + 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 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)); @@ -480,8 +481,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(), Blocks.BARRIER)); - public static final Item LIGHT = register(new BlockItem(builder(), Blocks.LIGHT)); + 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 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)); @@ -551,14 +552,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(), Blocks.REPEATING_COMMAND_BLOCK)); - public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.CHAIN_COMMAND_BLOCK)); + 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 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(), Blocks.STRUCTURE_VOID)); + public static final Item STRUCTURE_VOID = register(new BlockItem(builder().rarity(Rarity.EPIC), 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)); @@ -657,7 +658,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(), Blocks.CONDUIT)); + public static final Item CONDUIT = register(new BlockItem(builder().rarity(Rarity.RARE), 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)); @@ -810,7 +811,7 @@ 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))); + public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432).rarity(Rarity.UNCOMMON))); 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))); @@ -829,8 +830,8 @@ public final class Items { 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(), Blocks.STRUCTURE_BLOCK)); - public static final Item JIGSAW = register(new BlockItem(builder(), Blocks.JIGSAW)); + 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 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())); @@ -921,8 +922,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())); - public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", 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 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)); @@ -1042,7 +1043,7 @@ public final class Items { 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.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON)); + 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 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())); @@ -1125,12 +1126,12 @@ public final class Items { 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())); + public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder().rarity(Rarity.UNCOMMON))); 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))); + public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500).rarity(Rarity.EPIC))); 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)); @@ -1140,18 +1141,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(), 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 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 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))); + public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1).rarity(Rarity.UNCOMMON))); 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())); @@ -1167,7 +1168,7 @@ public final class Items { 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))); + public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1).rarity(Rarity.EPIC))); 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)); @@ -1186,7 +1187,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())); + public static final Item END_CRYSTAL = register(new Item("end_crystal", builder().rarity(Rarity.RARE))); 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)); @@ -1194,52 +1195,52 @@ 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())); + public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder().rarity(Rarity.UNCOMMON))); 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))); + public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1).rarity(Rarity.UNCOMMON))); 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))); - 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 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 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))); + 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 NAUTILUS_SHELL = register(new Item("nautilus_shell", builder())); - public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder())); + public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder().rarity(Rarity.UNCOMMON))); 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))); - 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 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 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))); - 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 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 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)); diff --git a/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java b/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java new file mode 100644 index 000000000..6fa74ea35 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java @@ -0,0 +1,51 @@ +/* + * 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.item.components; + +import lombok.Getter; + +@Getter +public enum Rarity { + COMMON("common", 'f'), + UNCOMMON("uncommon", 'e'), + RARE("rare", 'b'), + EPIC("epic", 'd'); + + private final String name; + private final char color; + + Rarity(final String name, char chatColor) { + this.name = name; + this.color = chatColor; + } + + private static final Rarity[] VALUES = values(); + + public static Rarity fromId(int id) { + return VALUES.length > id ? VALUES[id] : VALUES[0]; + } + +} 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 362b760c7..57538565a 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 @@ -35,6 +35,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; @@ -63,12 +64,16 @@ public class Item { private final int stackSize; private final int attackDamage; private final int maxDamage; + private final Rarity rarity; + private final boolean glint; public Item(String javaIdentifier, Builder builder) { this.javaIdentifier = MinecraftKey.key(javaIdentifier).asString().intern(); this.stackSize = builder.stackSize; this.maxDamage = builder.maxDamage; this.attackDamage = builder.attackDamage; + this.rarity = builder.rarity; + this.glint = builder.glint; } public String javaIdentifier() { @@ -91,6 +96,14 @@ public class Item { return stackSize; } + public Rarity rarity() { + return rarity; + } + + public boolean glint() { + return glint; + } + public boolean isValidRepairItem(Item other) { return false; } @@ -275,6 +288,8 @@ public class Item { private int stackSize = 64; private int maxDamage; private int attackDamage; + private Rarity rarity = Rarity.COMMON; + private boolean glint = false; public Builder stackSize(int stackSize) { this.stackSize = stackSize; @@ -292,6 +307,16 @@ public class Item { return this; } + public Builder rarity(Rarity rarity) { + this.rarity = rarity; + return this; + } + + public Builder glint(boolean glintOverride) { + this.glint = glintOverride; + return this; + } + private Builder() { } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 85207ac3a..2d26d14f8 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -58,6 +58,7 @@ import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -399,8 +400,9 @@ public class ItemRegistryPopulator { } } - if (javaOnlyItems.contains(javaItem)) { + if (javaOnlyItems.contains(javaItem) || javaItem.rarity() != Rarity.COMMON) { // These items don't exist on Bedrock, so set up a variable that indicates they should have custom names + // Or, ensure that we are translating these at all times to account for rarity colouring mappingBuilder = mappingBuilder.translationString((bedrockBlock != null ? "block." : "item.") + entry.getKey().replace(":", ".")); GeyserImpl.getInstance().getLogger().debug("Adding " + entry.getKey() + " as an item that needs to be translated."); } 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 abe39f177..6a781dcb8 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 @@ -33,7 +33,9 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -41,6 +43,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.BlockRegistries; @@ -145,7 +148,20 @@ public final class ItemTranslator { if (components.get(DataComponentType.HIDE_TOOLTIP) != null) hideTooltips = true; } - String customName = getCustomName(session, components, bedrockItem); + Rarity rarity = javaItem.rarity(); + boolean enchantmentGlint = javaItem.glint(); + if (components != null) { + Integer rarityIndex = components.get(DataComponentType.RARITY); + if (rarityIndex != null) { + rarity = Rarity.fromId(rarityIndex); + } + Boolean enchantmentGlintOverride = components.get(DataComponentType.ENCHANTMENT_GLINT_OVERRIDE); + if (enchantmentGlintOverride != null) { + enchantmentGlint = enchantmentGlintOverride; + } + } + + String customName = getCustomName(session, components, bedrockItem, rarity.getColor()); if (customName != null) { nbtBuilder.setCustomName(customName); } @@ -162,6 +178,12 @@ public final class ItemTranslator { addAdvancedTooltips(components, nbtBuilder, javaItem, session.locale()); } + // Add enchantment override. We can't remove it - enchantments would stop showing - but we can add it. + if (enchantmentGlint) { + NbtMapBuilder nbtMapBuilder = nbtBuilder.getOrCreateNbt(); + nbtMapBuilder.putIfAbsent("ench", NbtList.EMPTY); + } + ItemData.Builder builder = javaItem.translateToBedrock(count, components, bedrockItem, session.getItemMappings()); // Finalize the Bedrock NBT builder.tag(nbtBuilder.build()); @@ -401,16 +423,6 @@ public final class ItemTranslator { } } - /** - * Translates the display name of the item - * @param session the Bedrock client's session - * @param components the components to translate - * @param mapping the item entry, in case it requires translation - */ - public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping) { - return getCustomName(session, components, mapping, 'f'); - } - /** * @param translationColor if this item is not available on Java, the color that the new name should be. * Normally, this should just be white, but for shulker boxes this should be gray. From 6e0bad3c40605c4ac2f3cbac7c6af673f679ead5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 13 Jul 2024 15:11:22 -0400 Subject: [PATCH 283/897] Fix #4837 by not hardcoding dimension IDs --- .../living/monster/EnderDragonEntity.java | 8 +- .../geysermc/geyser/level/JavaDimension.java | 22 ++- .../geyser/session/GeyserSession.java | 2 - .../protocol/java/JavaLoginTranslator.java | 17 +- .../protocol/java/JavaRespawnTranslator.java | 11 +- .../java/entity/JavaAnimateTranslator.java | 2 +- .../java/level/JavaLevelEventTranslator.java | 3 +- .../level/JavaLevelParticlesTranslator.java | 2 +- .../java/level/JavaMapItemDataTranslator.java | 2 +- ...JavaSetDefaultSpawnPositionTranslator.java | 2 +- .../org/geysermc/geyser/util/ChunkUtils.java | 5 +- .../geysermc/geyser/util/DimensionUtils.java | 157 ++++++++++-------- 12 files changed, 135 insertions(+), 98 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java index 0162d498e..04044fcb4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java @@ -30,7 +30,11 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.*; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; +import org.cloudburstmc.protocol.bedrock.packet.SpawnParticleEffectPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.living.MobEntity; @@ -260,7 +264,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { // so we need to manually spawn particles for (int i = 0; i < 8; i++) { SpawnParticleEffectPacket spawnParticleEffectPacket = new SpawnParticleEffectPacket(); - spawnParticleEffectPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension())); + spawnParticleEffectPacket.setDimensionId(DimensionUtils.javaToBedrock(session)); spawnParticleEffectPacket.setPosition(head.getPosition().add(random.nextGaussian() / 2f, random.nextGaussian() / 2f, random.nextGaussian() / 2f)); spawnParticleEffectPacket.setIdentifier("minecraft:dragon_breath_fire"); spawnParticleEffectPacket.setMolangVariablesJson(Optional.empty()); diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index dd0f4215e..7462844fc 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -25,15 +25,17 @@ package org.geysermc.geyser.level; +import net.kyori.adventure.key.Key; import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.util.DimensionUtils; /** * Represents the information we store from the current Java dimension * @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension. * This controls if they have the shaking effect applied in the dimension. */ -public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale) { +public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale, int bedrockId, boolean isNetherLike) { public static JavaDimension read(RegistryEntryContext entry) { NbtMap dimension = entry.data(); @@ -46,6 +48,22 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double world // Load world coordinate scale for the world border double coordinateScale = dimension.getDouble("coordinate_scale"); - return new JavaDimension(minY, maxY, piglinSafe, coordinateScale); + boolean isNetherLike; + // Cache the Bedrock version of this dimension, and base it off the ID - THE ID CAN CHANGE!!! + // https://github.com/GeyserMC/Geyser/issues/4837 + int bedrockId; + Key id = entry.id(); + if ("minecraft".equals(id.namespace())) { + String identifier = id.asString(); + bedrockId = DimensionUtils.javaToBedrock(identifier); + isNetherLike = DimensionUtils.NETHER_IDENTIFIER.equals(identifier); + } else { + // Effects should give is a clue on how this (custom) dimension is supposed to look like + String effects = dimension.getString("effects"); + bedrockId = DimensionUtils.javaToBedrock(effects); + isNetherLike = DimensionUtils.NETHER_IDENTIFIER.equals(effects); + } + + return new JavaDimension(minY, maxY, piglinSafe, coordinateScale, bedrockId, isNetherLike); } } 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 25dd21662..3d47956b9 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -312,8 +312,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * The dimension of the player. * As all entities are in the same world, this can be safely applied to all other entities. */ - @Setter - private int dimension = DimensionUtils.OVERWORLD; @MonotonicNonNull @Setter private JavaDimension dimensionType = null; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 6988d6cc8..1e885403b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.protocol.java; import net.kyori.adventure.key.Key; import org.geysermc.erosion.Constants; +import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; @@ -65,12 +66,15 @@ public class JavaLoginTranslator extends PacketTranslator { SpawnParticleEffectPacket stringPacket = new SpawnParticleEffectPacket(); stringPacket.setIdentifier(particleMapping.identifier()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java index 1591b4952..52a08ab29 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java @@ -46,7 +46,7 @@ public class JavaMapItemDataTranslator extends PacketTranslator entityEffects = session.getEffectCache().getEntityEffects(); + for (Effect effect : entityEffects) { + MobEffectPacket mobEffectPacket = new MobEffectPacket(); + mobEffectPacket.setEvent(MobEffectPacket.Event.REMOVE); + mobEffectPacket.setRuntimeEntityId(player.getGeyserId()); + mobEffectPacket.setEffectId(EntityUtils.toBedrockEffectId(effect)); + session.sendUpstreamPacket(mobEffectPacket); + } + // Effects are re-sent from server + entityEffects.clear(); + + finalizeDimensionSwitch(session, player); + + // If the bedrock nether height workaround is enabled, meaning the client is told it's in the end dimension, + // we check if the player is entering the nether and apply the nether fog to fake the fact that the client + // thinks they are in the end dimension. + if (isCustomBedrockNetherId()) { + if (javaDimension.isNetherLike()) { + session.camera().sendFog(BEDROCK_FOG_HELL); + } else if (previousDimension.isNetherLike()) { + session.camera().removeFog(BEDROCK_FOG_HELL); + } + } + } + + /** + * Switch dimensions without clearing internal logic. + */ + public static void fastSwitchDimension(GeyserSession session, int bedrockDimension) { + changeDimension(session, bedrockDimension); + finalizeDimensionSwitch(session, session.getPlayerEntity()); + } + + private static void changeDimension(GeyserSession session, int bedrockDimension) { if (session.getServerRenderDistance() > 32 && !session.isEmulatePost1_13Logic()) { // The server-sided view distance wasn't a thing until Minecraft Java 1.14 // So ViaVersion compensates by sending a "view distance" of 64 @@ -77,7 +116,7 @@ public class DimensionUtils { // To solve this, we cap at 32 unless we know that the render distance actually exceeds 32 // Also, as of 1.19: PS4 crashes with a ChunkRadiusUpdatedPacket too large session.getGeyser().getLogger().debug("Applying dimension switching workaround for Bedrock render distance of " - + session.getServerRenderDistance()); + + session.getServerRenderDistance()); ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); chunkRadiusUpdatedPacket.setRadius(32); session.sendUpstreamPacket(chunkRadiusUpdatedPacket); @@ -92,24 +131,14 @@ public class DimensionUtils { changeDimensionPacket.setPosition(pos); session.sendUpstreamPacket(changeDimensionPacket); - session.setDimension(javaDimension); - setBedrockDimension(session, javaDimension); + setBedrockDimension(session, bedrockDimension); - player.setPosition(pos); + session.getPlayerEntity().setPosition(pos); session.setSpawned(false); session.setLastChunkPosition(null); + } - Set entityEffects = session.getEffectCache().getEntityEffects(); - for (Effect effect : entityEffects) { - MobEffectPacket mobEffectPacket = new MobEffectPacket(); - mobEffectPacket.setEvent(MobEffectPacket.Event.REMOVE); - mobEffectPacket.setRuntimeEntityId(player.getGeyserId()); - mobEffectPacket.setEffectId(EntityUtils.toBedrockEffectId(effect)); - session.sendUpstreamPacket(mobEffectPacket); - } - // Effects are re-sent from server - entityEffects.clear(); - + private static void finalizeDimensionSwitch(GeyserSession session, Entity player) { //let java server handle portal travel sound StopSoundPacket stopSoundPacket = new StopSoundPacket(); stopSoundPacket.setStoppingAllSound(true); @@ -130,23 +159,12 @@ public class DimensionUtils { // TODO - fix this hack of a fix by sending the final dimension switching logic after sections have been sent. // The client wants sections sent to it before it can successfully respawn. ChunkUtils.sendEmptyChunks(session, player.getPosition().toInt(), 3, true); - - // If the bedrock nether height workaround is enabled, meaning the client is told it's in the end dimension, - // we check if the player is entering the nether and apply the nether fog to fake the fact that the client - // thinks they are in the end dimension. - if (isCustomBedrockNetherId()) { - if (NETHER == javaDimension) { - session.camera().sendFog(BEDROCK_FOG_HELL); - } else if (NETHER == previousDimension) { - session.camera().removeFog(BEDROCK_FOG_HELL); - } - } } - public static void setBedrockDimension(GeyserSession session, int javaDimension) { - session.getChunkCache().setBedrockDimension(switch (javaDimension) { - case DimensionUtils.THE_END -> BedrockDimension.THE_END; - case DimensionUtils.NETHER -> DimensionUtils.isCustomBedrockNetherId() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER; + public static void setBedrockDimension(GeyserSession session, int bedrockDimension) { + session.getChunkCache().setBedrockDimension(switch (bedrockDimension) { + case BEDROCK_END_ID -> BedrockDimension.THE_END; + case BEDROCK_DEFAULT_NETHER_ID -> BedrockDimension.THE_NETHER; // JavaDimension *should* be set to BEDROCK_END_ID if the Nether workaround is enabled. default -> BedrockDimension.OVERWORLD; }); } @@ -155,26 +173,12 @@ public class DimensionUtils { if (dimension == BedrockDimension.THE_NETHER) { return BEDROCK_NETHER_ID; } else if (dimension == BedrockDimension.THE_END) { - return 2; + return BEDROCK_END_ID; } else { - return 0; + return BEDROCK_OVERWORLD_ID; } } - /** - * Map the Java edition dimension IDs to Bedrock edition - * - * @param javaDimension Dimension ID to convert - * @return Converted Bedrock edition dimension ID - */ - public static int javaToBedrock(int javaDimension) { - return switch (javaDimension) { - case NETHER -> BEDROCK_NETHER_ID; - case THE_END -> 2; - default -> 0; - }; - } - /** * Map the Java edition dimension IDs to Bedrock edition * @@ -183,12 +187,23 @@ public class DimensionUtils { */ public static int javaToBedrock(String javaDimension) { return switch (javaDimension) { - case "minecraft:the_nether" -> BEDROCK_NETHER_ID; + case NETHER_IDENTIFIER -> BEDROCK_NETHER_ID; case "minecraft:the_end" -> 2; default -> 0; }; } + /** + * Gets the Bedrock dimension ID, with a safety check if a packet is created before the player is logged/spawned in. + */ + public static int javaToBedrock(GeyserSession session) { + JavaDimension dimension = session.getDimensionType(); + if (dimension == null) { + return BEDROCK_OVERWORLD_ID; + } + return dimension.bedrockId(); + } + /** * The Nether dimension in Bedrock does not permit building above Y128 - the Bedrock above the dimension. * This workaround sets the Nether as the End dimension to ignore this limit. @@ -197,28 +212,28 @@ public class DimensionUtils { */ public static void changeBedrockNetherId(boolean isAboveNetherBedrockBuilding) { // Change dimension ID to the End to allow for building above Bedrock - BEDROCK_NETHER_ID = isAboveNetherBedrockBuilding ? 2 : 1; + BEDROCK_NETHER_ID = isAboveNetherBedrockBuilding ? BEDROCK_END_ID : BEDROCK_DEFAULT_NETHER_ID; } /** * Gets the fake, temporary dimension we send clients to so we aren't switching to the same dimension without an additional * dimension switch. * - * @param currentDimension the current dimension of the player - * @param newDimension the new dimension that the player will be transferred to - * @return the fake dimension to transfer to + * @param currentBedrockDimension the current dimension of the player + * @param newBedrockDimension the new dimension that the player will be transferred to + * @return the Bedrock fake dimension to transfer to */ - public static int getTemporaryDimension(int currentDimension, int newDimension) { + public static int getTemporaryDimension(int currentBedrockDimension, int newBedrockDimension) { if (isCustomBedrockNetherId()) { // Prevents rare instances of Bedrock locking up - return javaToBedrock(newDimension) == 2 ? OVERWORLD : NETHER; + return newBedrockDimension == BEDROCK_END_ID ? BEDROCK_OVERWORLD_ID : BEDROCK_END_ID; } // Check current Bedrock dimension and not just the Java dimension. // Fixes rare instances like https://github.com/GeyserMC/Geyser/issues/3161 - return javaToBedrock(currentDimension) == 0 ? NETHER : OVERWORLD; + return currentBedrockDimension == BEDROCK_OVERWORLD_ID ? BEDROCK_DEFAULT_NETHER_ID : BEDROCK_OVERWORLD_ID; } public static boolean isCustomBedrockNetherId() { - return BEDROCK_NETHER_ID == 2; + return BEDROCK_NETHER_ID == BEDROCK_END_ID; } } From 6ab0186fc9e7753fc15620d2a9eba57fc0b76ab0 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 13 Jul 2024 22:00:15 +0200 Subject: [PATCH 284/897] Fix: Manually translated item names for block items not showing up properly (#4857) --- .../geyser/registry/populator/ItemRegistryPopulator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 2d26d14f8..aad5e494d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -59,6 +59,7 @@ import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; +import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -403,7 +404,7 @@ public class ItemRegistryPopulator { if (javaOnlyItems.contains(javaItem) || javaItem.rarity() != Rarity.COMMON) { // These items don't exist on Bedrock, so set up a variable that indicates they should have custom names // Or, ensure that we are translating these at all times to account for rarity colouring - mappingBuilder = mappingBuilder.translationString((bedrockBlock != null ? "block." : "item.") + entry.getKey().replace(":", ".")); + mappingBuilder = mappingBuilder.translationString((javaItem instanceof BlockItem ? "block." : "item.") + entry.getKey().replace(":", ".")); GeyserImpl.getInstance().getLogger().debug("Adding " + entry.getKey() + " as an item that needs to be translated."); } From 49f66c2a022b67a48f300fa652062241046f5eb9 Mon Sep 17 00:00:00 2001 From: LetsGoAway <68365423+letsgoawaydev@users.noreply.github.com> Date: Sun, 14 Jul 2024 16:44:39 +0800 Subject: [PATCH 285/897] Correctly cap scale attribute (#4856) * Fix scale attribute cap * Update LivingEntity.java --- .../geysermc/geyser/entity/attribute/GeyserAttributeType.java | 2 +- .../java/org/geysermc/geyser/entity/type/LivingEntity.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index f19912a8c..a4a0df8b8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -49,7 +49,7 @@ public enum GeyserAttributeType { ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f), ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f), MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f), - SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), // Unused. Do we need this? + SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), // Bedrock Attributes ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f), 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 499084555..2a1bc1188 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 @@ -48,6 +48,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.MathUtils; 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.EntityMetadata; @@ -252,7 +253,7 @@ public class LivingEntity extends Entity { } private void setAttributeScale(float scale) { - this.attributeScale = scale; + this.attributeScale = MathUtils.clamp(scale, GeyserAttributeType.SCALE.getMinimum(), GeyserAttributeType.SCALE.getMaximum()); applyScale(); } From 9cdda707a31d299a24dcff8081fc306c69902e7b Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 14 Jul 2024 20:17:22 +0200 Subject: [PATCH 286/897] Fix: Send a container close packet to Java for containers that could not be opened (#4861) * Close containers if we did not manage to open it * Mark session inventory translator as nonnull --- .../java/org/geysermc/geyser/session/GeyserSession.java | 2 +- .../protocol/java/inventory/JavaOpenBookTranslator.java | 1 + .../main/java/org/geysermc/geyser/util/InventoryUtils.java | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) 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 25dd21662..c2f94b1c6 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -222,7 +222,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private boolean closingInventory; @Setter - private InventoryTranslator inventoryTranslator = InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR; + private @NonNull InventoryTranslator inventoryTranslator = InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR; /** * Use {@link #getNextItemNetId()} instead for consistency diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java index e7cf21a69..172880725 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenBookTranslator.java @@ -70,6 +70,7 @@ public class JavaOpenBookTranslator extends PacketTranslator { Inventory openInv = session.getOpenInventory(); @@ -110,7 +111,11 @@ public class InventoryUtils { inventory.setDisplayed(true); } } else { + // Can occur if we e.g. did not find a spot to put a fake container in + ServerboundContainerClosePacket closePacket = new ServerboundContainerClosePacket(inventory.getJavaId()); + session.sendDownstreamGamePacket(closePacket); session.setOpenInventory(null); + session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR); } } From 06890504a2bfcdbf218a9d2c2874fa1262d91cca Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 14 Jul 2024 21:55:57 +0200 Subject: [PATCH 287/897] Fix: Totem animation when playing totem effects manually (#4860) * Fix: Totem animation for manually played totem effects * Ensure we always reset the offhand correctly --- .../geyser/inventory/PlayerInventory.java | 5 ++++ .../inventory/item/StoredItemMappings.java | 2 ++ .../entity/JavaEntityEventTranslator.java | 27 ++++++++++++++++++- .../geysermc/geyser/util/InventoryUtils.java | 6 +++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java index 9bef4b08e..c3756d663 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java @@ -29,6 +29,7 @@ import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.jetbrains.annotations.Range; @@ -73,6 +74,10 @@ public class PlayerInventory extends Inventory { return items[36 + heldItemSlot]; } + public boolean eitherHandMatchesItem(@NonNull Item item) { + return getItemInHand().asItem() == item || getItemInHand(Hand.OFF_HAND).asItem() == item; + } + public void setItemInHand(@NonNull GeyserItemStack item) { if (36 + heldItemSlot > this.size) { GeyserImpl.getInstance().getLogger().debug("Held item slot was larger than expected!"); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java index 05f6ba6cc..475a3e588 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java @@ -50,6 +50,7 @@ public class StoredItemMappings { private final ItemMapping milkBucket; private final ItemMapping powderSnowBucket; private final ItemMapping shield; + private final ItemMapping totem; private final ItemMapping upgradeTemplate; private final ItemMapping wheat; private final ItemMapping writableBook; @@ -66,6 +67,7 @@ public class StoredItemMappings { this.milkBucket = load(itemMappings, Items.MILK_BUCKET); this.powderSnowBucket = load(itemMappings, Items.POWDER_SNOW_BUCKET); this.shield = load(itemMappings, Items.SHIELD); + this.totem = load(itemMappings, Items.TOTEM_OF_UNDYING); this.upgradeTemplate = load(itemMappings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE); this.wheat = load(itemMappings, Items.WHEAT); this.writableBook = load(itemMappings, Items.WRITABLE_BOOK); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index e119d39ce..6c2e02cd3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -29,7 +29,9 @@ import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; @@ -42,11 +44,15 @@ import org.geysermc.geyser.entity.type.FishingHookEntity; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.living.animal.ArmadilloEntity; import org.geysermc.geyser.entity.type.living.monster.WardenEntity; +import org.geysermc.geyser.item.Items; 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.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket; +import java.util.Collections; import java.util.concurrent.ThreadLocalRandom; @Translator(packet = ClientboundEntityEventPacket.class) @@ -154,6 +160,16 @@ public class JavaEntityEventTranslator extends PacketTranslator getTotemOfUndying() { + return protocolVersion -> ItemData.builder() + .definition(Registries.ITEMS.forVersion(protocolVersion).getStoredItems().totem().getBedrockDefinition()) + .count(1).build(); + } + /** * See {@link #findOrCreateItem(GeyserSession, String)}. This is for finding a specified {@link ItemStack}. * From efc8ba061028a2c67ea7120079fa8ce8c42ea701 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 15 Jul 2024 01:31:03 +0200 Subject: [PATCH 288/897] Fix: Block place sounds on mod platforms (#4859) --- .../mod/mixin/server/BlockPlaceMixin.java | 79 +++++++++++++++++++ .../mod/src/main/resources/geyser.mixins.json | 1 + .../java/level/JavaBlockUpdateTranslator.java | 20 ++--- 3 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java new file mode 100644 index 000000000..98620588e --- /dev/null +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/BlockPlaceMixin.java @@ -0,0 +1,79 @@ +/* + * 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.platform.mod.mixin.server; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockState; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.SoundEvent; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.session.GeyserSession; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(BlockItem.class) +public class BlockPlaceMixin { + + @Inject(method = "place", locals = LocalCapture.CAPTURE_FAILSOFT, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/core/BlockPos;Lnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V")) + private void geyser$hijackPlaySound(BlockPlaceContext blockPlaceContext, CallbackInfoReturnable cir, BlockPlaceContext blockPlaceContext2, BlockState blockState, BlockPos blockPos, Level level, Player player, ItemStack itemStack, BlockState blockState2, SoundType soundType) { + if (player == null) { + return; + } + + GeyserSession session = GeyserImpl.getInstance().connectionByUuid(player.getUUID()); + if (session == null) { + return; + } + + Vector3f position = Vector3f.from( + blockPos.getX(), + blockPos.getY(), + blockPos.getZ() + ); + + LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket(); + placeBlockSoundPacket.setSound(SoundEvent.PLACE); + placeBlockSoundPacket.setPosition(position); + placeBlockSoundPacket.setBabySound(false); + placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(Block.BLOCK_STATE_REGISTRY.getId(blockState2))); + placeBlockSoundPacket.setIdentifier(":"); + session.sendUpstreamPacket(placeBlockSoundPacket); + session.setLastBlockPlacePosition(null); + session.setLastBlockPlaced(null); + } +} diff --git a/bootstrap/mod/src/main/resources/geyser.mixins.json b/bootstrap/mod/src/main/resources/geyser.mixins.json index 47b2f60f3..2576e1ce6 100644 --- a/bootstrap/mod/src/main/resources/geyser.mixins.json +++ b/bootstrap/mod/src/main/resources/geyser.mixins.json @@ -4,6 +4,7 @@ "package": "org.geysermc.geyser.platform.mod.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ + "server.BlockPlaceMixin", "server.ServerConnectionListenerMixin" ], "server": [ diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java index d89775662..6d5fbc113 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java @@ -28,8 +28,8 @@ package org.geysermc.geyser.translator.protocol.java.level; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -43,24 +43,27 @@ public class JavaBlockUpdateTranslator extends PacketTranslator Date: Mon, 15 Jul 2024 15:16:45 -0400 Subject: [PATCH 289/897] Indicate support for Bedrock 1.21.3 --- README.md | 2 +- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 14bdb17a9..9469b1bb6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.2 and Minecraft Java 1.21 +### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.3 and Minecraft Java 1.21 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index c79ef365d..8f3f00021 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -73,7 +73,9 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v685.CODEC.toBuilder() .minecraftVersion("1.21.0/1.21.1") .build())); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.21.2/1.21.3") + .build()); } /** From 677a56cf6c487d7cc74e139e76057fe5ba16b84b Mon Sep 17 00:00:00 2001 From: "masel.io" Date: Tue, 16 Jul 2024 11:23:30 +0200 Subject: [PATCH 290/897] Add Timeout to CompletableFuture in GeyserBungeePingPassthrough to Prevent Memory Leak (#4858) * fix: Add timeout for GeyserBungeePingPassthrough#getPingInformation Signed-off-by: ByteExceptionM * fix: Use Geyser Logger instead of Bungee Logger Signed-off-by: ByteExceptionM * Fix typo Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> * chore: Add ip suppression if configured Signed-off-by: ByteExceptionM * Remove empty line Co-authored-by: chris * Remove empty line Co-authored-by: chris --------- Signed-off-by: ByteExceptionM Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> Co-authored-by: chris --- .../bungeecord/GeyserBungeePingPassthrough.java | 14 +++++++++++++- .../geyser/ping/IGeyserPingPassthrough.java | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java index 3c3853ed8..1193a52b3 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java @@ -36,6 +36,7 @@ import net.md_5.bungee.api.event.ProxyPingEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.protocol.ProtocolConstants; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; @@ -43,6 +44,7 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; @AllArgsConstructor public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener { @@ -59,7 +61,17 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List future.complete(event); } })); - ProxyPingEvent event = future.join(); + + ProxyPingEvent event; + + try { + event = future.get(100, TimeUnit.MILLISECONDS); + } catch (Throwable cause) { + String address = GeyserImpl.getInstance().getConfig().isLogPlayerIpAddresses() ? inetSocketAddress.toString() : ""; + GeyserImpl.getInstance().getLogger().error("Failed to get ping information for " + address, cause); + return null; + } + ServerPing response = event.getResponse(); return new GeyserPingInfo( response.getDescriptionComponent().toLegacyText(), diff --git a/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java b/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java index 69ac974cc..4e60d60e4 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java +++ b/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java @@ -35,10 +35,10 @@ import java.net.InetSocketAddress; public interface IGeyserPingPassthrough { /** - * Get the MOTD of the server displayed on the multiplayer screen + * Gets the ping information, including the MOTD and player count, from the server * * @param inetSocketAddress the ip address of the client pinging the server - * @return string of the MOTD + * @return the ping information */ @Nullable GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress); From 669a76c628f6a99eb3304b3505331e1609373111 Mon Sep 17 00:00:00 2001 From: Valaphee The Meerkat <32491319+valaphee@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:13:34 +0200 Subject: [PATCH 291/897] Empty player list on phase transition, despawn skulls, always reset weather (#4847) * Empty player list on transition, despawn skulls * Always reset weather --- .../geyser/session/cache/EntityCache.java | 4 ++ .../geyser/session/cache/SkullCache.java | 8 +++ ...vaFinishConfigurationPacketTranslator.java | 49 +++++++++++++++++++ .../protocol/java/JavaLoginTranslator.java | 19 ------- .../geysermc/geyser/util/DimensionUtils.java | 15 ++++++ 5 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java index 6524e1ddc..3affa12cf 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java @@ -141,6 +141,10 @@ public class EntityCache { return playerEntities.values(); } + public void removeAllPlayerEntities() { + playerEntities.clear(); + } + public void addBossBar(UUID uuid, BossBar bossBar) { bossBars.put(uuid, bossBar); bossBar.addBossBar(); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java index a40a1156d..0eec39b0b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java @@ -243,8 +243,16 @@ public class SkullCache { } public void clear() { + for (Skull skull : skulls.values()) { + if (skull.entity != null) { + skull.entity.despawnEntity(); + } + } skulls.clear(); inRangeSkulls.clear(); + for (SkullPlayerEntity skull : unusedSkullEntities) { + skull.despawnEntity(); + } unusedSkullEntities.clear(); totalSkullEntities = 0; lastPlayerPosition = null; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java new file mode 100644 index 000000000..8ade4a1f0 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java @@ -0,0 +1,49 @@ +/* + * 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; + +import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +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.configuration.clientbound.ClientboundFinishConfigurationPacket; + +@Translator(packet = ClientboundFinishConfigurationPacket.class) +public class JavaFinishConfigurationPacketTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundFinishConfigurationPacket packet) { + // Clear the player list, as on Java the player list is cleared after transitioning from config to play phase + PlayerListPacket playerListPacket = new PlayerListPacket(); + playerListPacket.setAction(PlayerListPacket.Action.REMOVE); + for (PlayerEntity otherEntity : session.getEntityCache().getAllPlayerEntities()) { + playerListPacket.getEntries().add(new PlayerListPacket.Entry(otherEntity.getTabListUuid())); + } + session.sendUpstreamPacket(playerListPacket); + session.getEntityCache().removeAllPlayerEntities(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 6988d6cc8..6c065a392 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -79,25 +79,6 @@ public class JavaLoginTranslator extends PacketTranslator Date: Wed, 17 Jul 2024 14:21:41 -0400 Subject: [PATCH 292/897] Fix #4870 --- .../level/block/entity/CampfireBlockEntityTranslator.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java index fb71a84cc..703c0954c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java @@ -42,10 +42,9 @@ public class CampfireBlockEntityTranslator extends BlockEntityTranslator { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { List items = javaNbt.getList("Items", NbtType.COMPOUND); if (items != null) { - int i = 1; for (NbtMap itemTag : items) { - bedrockNbt.put("Item" + i, getItem(session, itemTag)); - i++; + int slot = itemTag.getByte("Slot") + 1; + bedrockNbt.put("Item" + slot, getItem(session, itemTag)); } } } @@ -55,8 +54,7 @@ public class CampfireBlockEntityTranslator extends BlockEntityTranslator { if (mapping == null) { mapping = ItemMapping.AIR; } - NbtMapBuilder tagBuilder = BedrockItemBuilder.createItemNbt(mapping, tag.getByte("Count"), mapping.getBedrockData()); - tagBuilder.put("tag", NbtMap.builder().build()); // I don't think this is necessary... - Camo, 1.20.5/1.20.80 + NbtMapBuilder tagBuilder = BedrockItemBuilder.createItemNbt(mapping, tag.getInt("count"), mapping.getBedrockData()); return tagBuilder.build(); } } From 9fe3acc81cb88d613a558111bc6b8f326add300d Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 17 Jul 2024 21:44:53 +0200 Subject: [PATCH 293/897] Properly fix hanging signs (#4872) --- .../populator/CreativeItemRegistryPopulator.java | 1 - .../registry/populator/ItemRegistryPopulator.java | 11 ++++++++++- .../geysermc/geyser/registry/type/ItemMapping.java | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java index 2c033edc7..8e42887ff 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java @@ -80,7 +80,6 @@ public class CreativeItemRegistryPopulator { private static ItemData.@Nullable Builder createItemData(JsonNode itemNode, BlockMappings blockMappings, Map definitions) { int count = 1; int damage = 0; - int bedrockBlockRuntimeId; NbtMap tag = null; String identifier = itemNode.get("id").textValue(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index aad5e494d..2c97fe13c 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -167,6 +167,7 @@ public class ItemRegistryPopulator { Map javaItemToMapping = new Object2ObjectOpenHashMap<>(); List creativeItems = new ArrayList<>(); + Set noBlockDefinitions = new ObjectOpenHashSet<>(); AtomicInteger creativeNetId = new AtomicInteger(); CreativeItemRegistryPopulator.populate(palette, definitions, itemBuilder -> { @@ -187,6 +188,9 @@ public class ItemRegistryPopulator { bedrockBlockIdOverrides.put(identifier, item.getBlockDefinition()); } } + } else { + // Item mappings should also NOT have a block definition for these. + noBlockDefinitions.add(item.getDefinition().getIdentifier()); } }); @@ -254,7 +258,12 @@ public class ItemRegistryPopulator { } else { // Try to get an example block runtime ID from the creative contents packet, for Bedrock identifier obtaining int aValidBedrockBlockId = blacklistedIdentifiers.getOrDefault(bedrockIdentifier, customBlockItemOverride != null ? customBlockItemOverride.getRuntimeId() : -1); - if (aValidBedrockBlockId != -1 || customBlockItemOverride != null) { + if (aValidBedrockBlockId == -1 && customBlockItemOverride == null) { + // Fallback + if (!noBlockDefinitions.contains(entry.getValue().getBedrockIdentifier())) { + bedrockBlock = blockMappings.getBedrockBlock(firstBlockRuntimeId); + } + } else { // As of 1.16.220, every item requires a block runtime ID attached to it. // This is mostly for identifying different blocks with the same item ID - wool, slabs, some walls. // However, in order for some visuals and crafting to work, we need to send the first matching block state diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java index 437b8223a..8a2c77f28 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.registry.type; import it.unimi.dsi.fastutil.Pair; import lombok.Builder; import lombok.EqualsAndHashCode; +import lombok.ToString; import lombok.Value; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; @@ -42,6 +43,7 @@ import java.util.List; @Value @Builder @EqualsAndHashCode +@ToString public class ItemMapping { public static final ItemMapping AIR = new ItemMapping( "minecraft:air", From 8fd99e1e1a01bd5b12ef8a10c4b5778fa2b4de91 Mon Sep 17 00:00:00 2001 From: LetsGoAway <68365423+letsgoawaydev@users.noreply.github.com> Date: Sat, 20 Jul 2024 18:09:22 +0800 Subject: [PATCH 294/897] Use the correct way of sending block breaking particles (#4825) --- .../player/BedrockActionTranslator.java | 197 ++++++++++-------- 1 file changed, 113 insertions(+), 84 deletions(-) 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 index 6834d3190..cd1300a13 100644 --- 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 @@ -32,7 +32,12 @@ 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.*; +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; @@ -52,8 +57,17 @@ 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.*; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.*; +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 { @@ -70,7 +84,7 @@ public class BedrockActionTranslator extends PacketTranslator { // Respawn process is finished and the server and client are both OK with respawning. EntityEventPacket eventPacket = new EntityEventPacket(); eventPacket.setRuntimeEntityId(entity.getGeyserId()); @@ -88,16 +102,16 @@ public class BedrockActionTranslator extends PacketTranslator { if (!entity.getFlag(EntityFlag.SWIMMING)) { ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); session.sendDownstreamGamePacket(startSwimPacket); session.setSwimming(true); } - break; - case STOP_SWIMMING: + } + 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); @@ -105,56 +119,55 @@ public class BedrockActionTranslator extends PacketTranslator { // Otherwise gliding will not work in creative ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false); session.sendDownstreamGamePacket(playerAbilitiesPacket); - case STOP_GLIDE: - ServerboundPlayerCommandPacket glidePacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING); - session.sendDownstreamGamePacket(glidePacket); - break; - case START_SNEAK: + 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(); - break; - case STOP_SNEAK: + } + case STOP_SNEAK -> { ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING); session.sendDownstreamGamePacket(stopSneakPacket); session.stopSneaking(); - break; - case START_SPRINT: + } + case START_SPRINT -> { if (!entity.getFlag(EntityFlag.SWIMMING)) { ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); session.sendDownstreamGamePacket(startSprintPacket); session.setSprinting(true); } - break; - case STOP_SPRINT: + } + case STOP_SPRINT -> { if (!entity.getFlag(EntityFlag.SWIMMING)) { ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); session.sendDownstreamGamePacket(stopSprintPacket); } session.setSprinting(false); - break; - case DROP_ITEM: + } + case DROP_ITEM -> { ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, - vector, Direction.VALUES[packet.getFace()], 0); + vector, Direction.VALUES[packet.getFace()], 0); session.sendDownstreamGamePacket(dropItemPacket); - break; - case STOP_SLEEP: + } + case STOP_SLEEP -> { ServerboundPlayerCommandPacket stopSleepingPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.LEAVE_BED); session.sendDownstreamGamePacket(stopSleepingPacket); - break; - 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) { + } + 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(); @@ -180,18 +193,20 @@ public class BedrockActionTranslator extends PacketTranslator { if (session.getGameMode() == GameMode.CREATIVE) { break; } @@ -201,52 +216,48 @@ public class BedrockActionTranslator extends PacketTranslator= (breakTime+=2) * 50) { + 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.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence()); + 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); - break; - case ABORT_BREAK: + } + 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()); + InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); session.sendDownstreamGamePacket(interactPacket); break; } @@ -260,25 +271,23 @@ public class BedrockActionTranslator extends PacketTranslator { + } + 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); - attributesPacket = new UpdateAttributesPacket(); + UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); attributesPacket.setRuntimeEntityId(entity.getGeyserId()); attributesPacket.getAttributes().addAll(entity.getAttributes().values()); session.sendUpstreamPacket(attributesPacket); - break; - case JUMP: - entity.setOnGround(false); // Increase block break time while jumping - break; - case MISSED_SWING: + } + 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); @@ -294,18 +303,18 @@ public class BedrockActionTranslator extends PacketTranslator { // Since 1.20.30 if (session.isCanFly()) { if (session.getGameMode() == GameMode.SPECTATOR) { - // should already be flying + // 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 + // 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; } @@ -313,9 +322,9 @@ public class BedrockActionTranslator extends PacketTranslator { session.setFlying(false); session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false)); - break; - 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 + } + 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()); + vector, + Direction.DOWN, + Hand.MAIN_HAND, + 0, 0, 0, + false, + session.getWorldCache().nextPredictionSequence()); session.sendDownstreamGamePacket(blockPacket); break; } @@ -349,10 +358,30 @@ public class BedrockActionTranslator extends PacketTranslator 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); + } } From f62cef7acbd8fecab28793cc9649ddba2982bffe Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 21 Jul 2024 02:10:51 +0200 Subject: [PATCH 295/897] Fix: Only shutdown/close handlers in onDisable if they're nonnull (#4882) --- .../java/org/geysermc/geyser/GeyserImpl.java | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 88cc74691..9ee182edd 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -55,7 +55,11 @@ import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.event.EventRegistrar; -import org.geysermc.geyser.api.event.lifecycle.*; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostReloadEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPreReloadEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.RemoteServer; @@ -85,7 +89,13 @@ import org.geysermc.geyser.skin.SkinProvider; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.*; +import org.geysermc.geyser.util.AssetUtils; +import org.geysermc.geyser.util.CooldownUtils; +import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.geyser.util.Metrics; +import org.geysermc.geyser.util.NewsHandler; +import org.geysermc.geyser.util.VersionCheckUtils; +import org.geysermc.geyser.util.WebUtils; import org.geysermc.mcprotocollib.network.tcp.TcpSession; import java.io.File; @@ -97,11 +107,19 @@ import java.net.UnknownHostException; import java.nio.file.Path; import java.security.Key; import java.text.DecimalFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -645,16 +663,11 @@ public class GeyserImpl implements GeyserApi { bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.kick.done")); } - scheduledThread.shutdown(); - geyserServer.shutdown(); - if (skinUploader != null) { - skinUploader.close(); - } - newsHandler.shutdown(); - - if (this.erosionUnixListener != null) { - this.erosionUnixListener.close(); - } + runIfNonNull(scheduledThread, ScheduledExecutorService::shutdown); + runIfNonNull(geyserServer, GeyserServer::shutdown); + runIfNonNull(skinUploader, FloodgateSkinUploader::close); + runIfNonNull(newsHandler, NewsHandler::shutdown); + runIfNonNull(erosionUnixListener, UnixSocketClientListener::close); Registries.RESOURCE_PACKS.get().clear(); @@ -833,6 +846,12 @@ public class GeyserImpl implements GeyserApi { } } + private void runIfNonNull(T nullable, Consumer consumer) { + if (nullable != null) { + consumer.accept(nullable); + } + } + private void scheduleRefreshTokensWrite() { scheduledThread.execute(() -> { // Ensure all writes are handled on the same thread From 96f00981df9f6f180e90349f6e9a711fcce05883 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 21 Jul 2024 02:15:38 +0200 Subject: [PATCH 296/897] Somewhat fix: firework recipe not showing up in recipe book (#4873) * Somewhat fix firework crafting * Use instanceof instead of casting --- .../item/type/BedrockRequiresTagItem.java | 36 +++++++++++++++++++ .../geyser/item/type/FireworkRocketItem.java | 36 ++++++++++++++----- .../translator/item/ItemTranslator.java | 7 ++++ .../java/JavaUpdateRecipesTranslator.java | 33 +++++++++++++---- 4 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java new file mode 100644 index 000000000..c41d14396 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java @@ -0,0 +1,36 @@ +/* + * 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.item.type; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; + +public interface BedrockRequiresTagItem { + + void addRequiredNbt(GeyserSession session, @Nullable DataComponents components, BedrockItemBuilder builder); +} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index 9c637afde..2e7848318 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -27,6 +27,8 @@ package org.geysermc.geyser.item.type; import it.unimi.dsi.fastutil.ints.IntArrays; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; @@ -41,7 +43,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.Fireworks; import java.util.ArrayList; import java.util.List; -public class FireworkRocketItem extends Item { +public class FireworkRocketItem extends Item implements BedrockRequiresTagItem { public FireworkRocketItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } @@ -58,14 +60,16 @@ public class FireworkRocketItem extends Item { fireworksNbt.putByte("Flight", (byte) fireworks.getFlightDuration()); List explosions = fireworks.getExplosions(); - if (explosions.isEmpty()) { - return; + if (!explosions.isEmpty()) { + List explosionNbt = new ArrayList<>(); + for (Fireworks.FireworkExplosion explosion : explosions) { + explosionNbt.add(translateExplosionToBedrock(explosion)); + } + fireworksNbt.putList("Explosions", NbtType.COMPOUND, explosionNbt); + } else { + // This is the default firework + fireworksNbt.put("Explosions", NbtList.EMPTY); } - List explosionNbt = new ArrayList<>(); - for (Fireworks.FireworkExplosion explosion : explosions) { - explosionNbt.add(translateExplosionToBedrock(explosion)); - } - fireworksNbt.putList("Explosions", NbtType.COMPOUND, explosionNbt); builder.putCompound("Fireworks", fireworksNbt.build()); } @@ -138,4 +142,20 @@ public class FireworkRocketItem extends Item { return null; } } + + @Override + public void addRequiredNbt(GeyserSession session, @Nullable DataComponents components, BedrockItemBuilder builder) { + if (components != null) { + Fireworks fireworks = components.get(DataComponentType.FIREWORKS); + if (fireworks != null) { + // Already translated + return; + } + } + + NbtMapBuilder fireworksNbt = NbtMap.builder(); + fireworksNbt.putByte("Flight", (byte) 1); + fireworksNbt.put("Explosions", NbtList.EMPTY); + builder.putCompound("Fireworks", fireworksNbt.build()); + } } 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 6a781dcb8..e9527872a 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 @@ -45,6 +45,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.item.type.BedrockRequiresTagItem; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -148,6 +149,12 @@ public final class ItemTranslator { if (components.get(DataComponentType.HIDE_TOOLTIP) != null) hideTooltips = true; } + // Fixes fireworks crafting recipe: they always contain a tag + // TODO remove once all items have their default components + if (javaItem instanceof BedrockRequiresTagItem requiresTagItem) { + requiresTagItem.addRequiredNbt(session, components, nbtBuilder); + } + Rarity rarity = javaItem.rarity(); boolean enchantmentGlint = javaItem.glint(); if (components != null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index f9b840dd9..fd8981552 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -25,7 +25,11 @@ package org.geysermc.geyser.translator.protocol.java; -import it.unimi.dsi.fastutil.ints.*; +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.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -40,7 +44,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescri import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.recipe.*; +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.GeyserStonecutterData; +import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -58,7 +66,17 @@ import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.SmithingTransfo import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.StoneCuttingRecipeData; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; @@ -191,6 +209,9 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator { 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) { @@ -427,7 +448,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Date: Sat, 20 Jul 2024 23:21:36 -0400 Subject: [PATCH 297/897] Small cleanups --- README.md | 2 +- .../entity/type/living/animal/tameable/ParrotEntity.java | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index 9469b1bb6..07f3df5aa 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ There are a few things Geyser is unable to support due to various differences be 3. Run `gradlew build` and locate to `bootstrap/build` folder. ## Contributing -Any contributions are appreciated. Please feel free to reach out to us on [Discord](http://discord.geysermc.org/) if +Any contributions are appreciated. Please feel free to reach out to us on [Discord](https://discord.gg/geysermc) if you're interested in helping out with Geyser. ## Libraries Used: 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 8baba6f00..69b19b1b9 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 @@ -31,7 +31,6 @@ 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.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; @@ -39,13 +38,9 @@ import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import java.util.Set; import java.util.UUID; public class ParrotEntity extends TameableEntity { - // Note: is the same as chicken. Reuse? - private static final Set TAMING_FOOD = Set.of(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS); - public ParrotEntity(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); } From 7d5c4a38f807c864c2784492b3aba0a7c79ef999 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 20 Jul 2024 23:22:04 -0400 Subject: [PATCH 298/897] Respect block range attribute where we can #4864 --- .../entity/attribute/GeyserAttributeType.java | 1 + .../type/player/SessionPlayerEntity.java | 8 ++ ...BedrockInventoryTransactionTranslator.java | 81 +++++++++---------- 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index a4a0df8b8..3b543a943 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -50,6 +50,7 @@ public enum GeyserAttributeType { ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f), MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f), SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), + BLOCK_INTERACTION_RANGE("minecraft:player.block_interaction_range", null, 0.0f, 64f, 4.5f), // Bedrock Attributes ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f), 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 45fea4d48..dc0545cee 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 @@ -64,6 +64,11 @@ public class SessionPlayerEntity extends PlayerEntity { */ @Getter protected final Map attributes = new Object2ObjectOpenHashMap<>(); + /** + * Java-only attribute + */ + @Getter + private double blockInteractionRange = GeyserAttributeType.BLOCK_INTERACTION_RANGE.getDefaultValue(); /** * Used in PlayerInputTranslator for movement checks. */ @@ -232,6 +237,8 @@ public class SessionPlayerEntity extends PlayerEntity { protected void updateAttribute(Attribute javaAttribute, List newAttributes) { if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) { session.setAttackSpeed(AttributeUtils.calculateValue(javaAttribute)); + } else if (javaAttribute.getType() == AttributeType.Builtin.PLAYER_BLOCK_INTERACTION_RANGE) { + this.blockInteractionRange = AttributeUtils.calculateValue(javaAttribute); } else { super.updateAttribute(javaAttribute, newAttributes); } @@ -295,6 +302,7 @@ public class SessionPlayerEntity extends PlayerEntity { public void resetAttributes() { attributes.clear(); maxHealth = GeyserAttributeType.MAX_HEALTH.getDefaultValue(); + blockInteractionRange = GeyserAttributeType.BLOCK_INTERACTION_RANGE.getDefaultValue(); UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); attributesPacket.setRuntimeEntityId(geyserId); 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 534a89e23..9d78d174b 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 @@ -70,7 +70,11 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator; 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.*; +import org.geysermc.geyser.util.BlockUtils; +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.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; @@ -78,7 +82,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractActio import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.*; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; import java.util.List; import java.util.concurrent.TimeUnit; @@ -90,11 +98,6 @@ import java.util.concurrent.TimeUnit; @Translator(packet = InventoryTransactionPacket.class) public class BedrockInventoryTransactionTranslator extends PacketTranslator { - private static final float MAXIMUM_BLOCK_PLACING_DISTANCE = 64f; - private static final int CREATIVE_EYE_HEIGHT_PLACE_DISTANCE = 49; - private static final int SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE = 36; - private static final float MAXIMUM_BLOCK_DESTROYING_DISTANCE = 36f; - @Override public void translate(GeyserSession session, InventoryTransactionPacket packet) { if (packet.getTransactionType() == InventoryTransactionType.NORMAL && packet.getActions().size() == 3) { @@ -243,17 +246,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator - (creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { + if (!canInteractWithBlock(session, playerPosition, packetBlockPosition)) { restoreCorrectBlock(session, blockPos, packet); return; } @@ -262,26 +261,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator - (creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { - restoreCorrectBlock(session, blockPos, packet); - return; - } - Vector3f blockCenter = Vector3f.from(packetBlockPosition.getX() + 0.5f, packetBlockPosition.getY() + 0.5f, packetBlockPosition.getZ() + 0.5f); - // Vanilla check - if (!(session.getPlayerEntity().getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0) - .distanceSquared(blockCenter) < MAXIMUM_BLOCK_PLACING_DISTANCE)) { - // The client thinks that its blocks have been successfully placed. Restore the server's blocks instead. - restoreCorrectBlock(session, blockPos, packet); - return; - } - // More recent vanilla check (as of 1.18.2) double clickDistanceX = clickPositionFullX - blockCenter.getX(); double clickDistanceY = clickPositionFullY - blockCenter.getY(); double clickDistanceZ = clickPositionFullZ - blockCenter.getZ(); @@ -433,14 +414,10 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator MAXIMUM_BLOCK_DESTROYING_DISTANCE) { + playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight()); + + if (!canInteractWithBlock(session, playerPosition, packet.getBlockPosition())) { restoreCorrectBlock(session, packet.getBlockPosition(), packet); return; } @@ -550,6 +527,28 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator(BlockPos) + float minX = packetBlockPosition.getX(); + float minY = packetBlockPosition.getY(); + float minZ = packetBlockPosition.getZ(); + float maxX = packetBlockPosition.getX() + 1; + float maxY = packetBlockPosition.getY() + 1; + float maxZ = packetBlockPosition.getZ() + 1; + + // AABB#distanceToSqr + float diffX = Math.max(Math.max(minX - playerPosition.getX(), playerPosition.getX() - maxX), 0); + float diffY = Math.max(Math.max(minY - playerPosition.getY(), playerPosition.getY() - maxY), 0); + float diffZ = Math.max(Math.max(minZ - playerPosition.getZ(), playerPosition.getZ() - maxZ), 0); + return ((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) < (additionalRangeCheck * additionalRangeCheck); + } + /** * Restore the correct block state from the server without updating the chunk cache. * @@ -696,4 +695,4 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator Date: Sun, 21 Jul 2024 13:11:27 +0200 Subject: [PATCH 299/897] Fix: Text display offset (#4883) --- .../geysermc/geyser/entity/EntityDefinitions.java | 1 + .../geyser/entity/type/TextDisplayEntity.java | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) 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 11b4a32d1..9063c7421 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -327,6 +327,7 @@ public final class EntityDefinitions { TEXT_DISPLAY = EntityDefinition.inherited(TextDisplayEntity::new, displayBase) .type(EntityType.TEXT_DISPLAY) .identifier("minecraft:armor_stand") + .offset(-0.5f) .addTranslator(MetadataType.CHAT, TextDisplayEntity::setText) .addTranslator(null) // Line width .addTranslator(null) // Background color diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java index ff5604c19..8b47ce1ed 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java @@ -38,7 +38,17 @@ import java.util.UUID; // Note: 1.19.4 requires that the billboard is set to something in order to show, on Java Edition public class TextDisplayEntity extends DisplayBaseEntity { public TextDisplayEntity(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); + super(session, entityId, geyserId, uuid, definition, position.add(0, definition.offset(), 0), motion, yaw, pitch, headYaw); + } + + @Override + public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) { + super.moveRelative(relX, relY + definition.offset(), relZ, yaw, pitch, isOnGround); + } + + @Override + public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) { + super.moveAbsolute(position.add(Vector3f.from(0, definition.offset(), 0)), yaw, pitch, headYaw, isOnGround, teleported); } @Override From 1dd9ba3fb6e20a4df18580b9a4c45548ee2a3898 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 22 Jul 2024 07:24:21 +0200 Subject: [PATCH 300/897] Fix: Allow items to be worn as hats if their Java base items also allow it (#4885) --- .../registry/populator/CustomItemRegistryPopulator.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index a6fa164c1..0a9c93980 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -199,7 +199,13 @@ public class CustomItemRegistryPopulator { computeThrowableProperties(componentBuilder); } - computeRenderOffsets(false, customItemData, componentBuilder); + // Hardcoded on Java, and should extend to the custom item + boolean isHat = (javaItem.equals(Items.SKELETON_SKULL) || javaItem.equals(Items.WITHER_SKELETON_SKULL) + || javaItem.equals(Items.CARVED_PUMPKIN) || javaItem.equals(Items.ZOMBIE_HEAD) + || javaItem.equals(Items.PIGLIN_HEAD) || javaItem.equals(Items.DRAGON_HEAD) + || javaItem.equals(Items.CREEPER_HEAD) || javaItem.equals(Items.PLAYER_HEAD) + ); + computeRenderOffsets(isHat, customItemData, componentBuilder); componentBuilder.putCompound("item_properties", itemProperties.build()); builder.putCompound("components", componentBuilder.build()); From b113a6b185209bdc9718d81bed67c62a81375f2a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:43:57 -0400 Subject: [PATCH 301/897] Mark sequence position when block placing Fixes some instances between 1.19 and 1.20.5 when block ghosting could occur --- .../java/org/geysermc/geyser/session/cache/WorldCache.java | 2 +- .../bedrock/BedrockInventoryTransactionTranslator.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) 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 8eb715560..fb5137b05 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 @@ -201,4 +201,4 @@ public final class WorldCache { public String removeActiveRecord(Vector3i pos) { return this.activeRecords.remove(pos); } -} \ No newline at end of file +} 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 9d78d174b..1e4c82da1 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 @@ -247,8 +247,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator Date: Tue, 23 Jul 2024 23:12:05 +0200 Subject: [PATCH 302/897] Fix: Sticky pistons not retracting on Geyser-Spigot/turning visually into normal pistons on all other platforms (#4891) --- .../java/level/JavaBlockEventTranslator.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java index f56750d12..ff861530a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java @@ -43,7 +43,15 @@ import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.BellValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.BlockValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.ChestValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.DecoratedPotValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.EndGatewayValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.MobSpawnerValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.NoteBlockValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValue; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; @Translator(packet = ClientboundBlockEventPacket.class) @@ -80,7 +88,7 @@ public class JavaBlockEventTranslator extends PacketTranslator { BlockState state = session.getGeyser().getWorldManager().blockAt(session, position); - boolean sticky = state.is(Blocks.STICKY_PISTON); + boolean sticky = isSticky(state); boolean extended = action != PistonValueType.PUSHING; return new PistonBlockEntity(session, pos, direction, sticky, extended); }); @@ -149,4 +157,8 @@ public class JavaBlockEventTranslator extends PacketTranslator Date: Wed, 24 Jul 2024 14:27:05 -0400 Subject: [PATCH 303/897] Map unbreakable item component Fixes #4893 --- core/src/main/java/org/geysermc/geyser/item/type/Item.java | 5 +++++ 1 file changed, 5 insertions(+) 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 57538565a..2417177ce 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 @@ -170,6 +170,11 @@ public class Item { builder.putInt("RepairCost", repairCost); } + // If the tag exists, it's unbreakable; the value is just weather to show the tooltip. As of Java 1.21 + if (components.getDataComponents().containsKey(DataComponentType.UNBREAKABLE)) { + builder.putByte("Unbreakable", (byte) 1); + } + // Prevents the client from trying to stack items with untranslated components // Relies on correct hash code implementation, and some luck builder.putInt("GeyserHash", components.hashCode()); // TODO: don't rely on this From a85b312b40cb7f819d9cba896463ed3bfb38e4c5 Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Wed, 24 Jul 2024 23:06:59 +0200 Subject: [PATCH 304/897] Port to MinecraftAuth (#4779) Co-authored-by: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Co-authored-by: onebeastchris Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- bootstrap/mod/fabric/build.gradle.kts | 2 +- core/build.gradle.kts | 5 +- .../java/org/geysermc/geyser/Constants.java | 4 +- .../java/org/geysermc/geyser/GeyserImpl.java | 91 +++++++-- .../geyser/item/type/PlayerHeadItem.java | 2 +- .../geyser/level/block/type/SkullBlock.java | 2 +- .../geyser/network/UpstreamPacketHandler.java | 6 +- .../geyser/session/GeyserSession.java | 192 +++++++++++------- .../PendingMicrosoftAuthentication.java | 136 +++++-------- .../geyser/skin/FakeHeadProvider.java | 16 +- .../translator/item/ItemTranslator.java | 14 +- ...SetLocalPlayerAsInitializedTranslator.java | 4 +- .../java/JavaGameProfileTranslator.java | 2 +- .../JavaPlayerInfoUpdateTranslator.java | 2 +- .../geyser/util/LoginEncryptionUtils.java | 6 +- .../geyser/util/MinecraftAuthLogger.java | 49 +++++ gradle/libs.versions.toml | 6 +- 17 files changed, 320 insertions(+), 219 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/util/MinecraftAuthLogger.java diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index 25bd0af9d..0d083fcf7 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -25,7 +25,7 @@ dependencies { shadow(libs.protocol.connection) { isTransitive = false } shadow(libs.protocol.common) { isTransitive = false } shadow(libs.protocol.codec) { isTransitive = false } - shadow(libs.mcauthlib) { isTransitive = false } + shadow(libs.minecraftauth) { isTransitive = false } shadow(libs.raknet) { isTransitive = false } // Consequences of shading + relocating mcauthlib: shadow/relocate mcpl! diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1d1794cf7..3b5cc3df9 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -25,11 +25,10 @@ dependencies { api(libs.bundles.protocol) - api(libs.mcauthlib) + api(libs.minecraftauth) api(libs.mcprotocollib) { exclude("io.netty", "netty-all") - exclude("com.github.GeyserMC", "packetlib") - exclude("com.github.GeyserMC", "mcauthlib") + exclude("net.raphimc", "MinecraftAuth") } implementation(libs.raknet) { diff --git a/core/src/main/java/org/geysermc/geyser/Constants.java b/core/src/main/java/org/geysermc/geyser/Constants.java index 588b25172..534cb30ad 100644 --- a/core/src/main/java/org/geysermc/geyser/Constants.java +++ b/core/src/main/java/org/geysermc/geyser/Constants.java @@ -39,7 +39,9 @@ public final class Constants { public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download"; public static final String UPDATE_PERMISSION = "geyser.update"; + @Deprecated static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json"; + static final String SAVED_AUTH_CHAINS_FILE = "saved-auth-chains.json"; public static final String GEYSER_CUSTOM_NAMESPACE = "geyser_custom"; @@ -54,4 +56,4 @@ public final class Constants { } GLOBAL_API_WS_URI = wsUri; } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 9ee182edd..8f88f5b6a 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -29,6 +29,7 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; import io.netty.channel.epoll.Epoll; import io.netty.util.NettyRuntime; import io.netty.util.concurrent.DefaultThreadFactory; @@ -38,6 +39,8 @@ import lombok.Getter; import lombok.Setter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession; +import net.raphimc.minecraftauth.step.msa.StepMsaToken; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -93,6 +96,7 @@ import org.geysermc.geyser.util.AssetUtils; import org.geysermc.geyser.util.CooldownUtils; import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.Metrics; +import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.geyser.util.NewsHandler; import org.geysermc.geyser.util.VersionCheckUtils; import org.geysermc.geyser.util.WebUtils; @@ -179,7 +183,7 @@ public class GeyserImpl implements GeyserApi { private PendingMicrosoftAuthentication pendingMicrosoftAuthentication; @Getter(AccessLevel.NONE) - private Map savedRefreshTokens; + private Map savedAuthChains; @Getter private static GeyserImpl instance; @@ -552,37 +556,84 @@ public class GeyserImpl implements GeyserApi { if (config.getRemote().authType() == AuthType.ONLINE) { // May be written/read to on multiple threads from each GeyserSession as well as writing the config - savedRefreshTokens = new ConcurrentHashMap<>(); + savedAuthChains = new ConcurrentHashMap<>(); - File tokensFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile(); - if (tokensFile.exists()) { + // TODO Remove after a while - just a migration help + //noinspection deprecation + File refreshTokensFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile(); + if (refreshTokensFile.exists()) { + logger.info("Migrating refresh tokens to auth chains..."); + TypeReference> type = new TypeReference<>() { }; + Map refreshTokens = null; + try { + refreshTokens = JSON_MAPPER.readValue(refreshTokensFile, type); + } catch (IOException e) { + // ignored - we'll just delete this file :)) + } + + if (refreshTokens != null) { + List validUsers = config.getSavedUserLogins(); + final Gson gson = new Gson(); + for (Map.Entry entry : refreshTokens.entrySet()) { + String user = entry.getKey(); + if (!validUsers.contains(user)) { + continue; + } + + // Migrate refresh tokens to auth chains + try { + StepFullJavaSession javaSession = PendingMicrosoftAuthentication.AUTH_FLOW.apply(false, 10); + StepFullJavaSession.FullJavaSession fullJavaSession = javaSession.getFromInput( + MinecraftAuthLogger.INSTANCE, + PendingMicrosoftAuthentication.AUTH_CLIENT, + new StepMsaToken.RefreshToken(entry.getValue()) + ); + + String authChain = gson.toJson(javaSession.toJson(fullJavaSession)); + savedAuthChains.put(user, authChain); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().warning("Could not migrate " + entry.getKey() + " to an auth chain! " + + "They will need to sign in the next time they join Geyser."); + } + + // Ensure the new additions are written to the file + scheduleAuthChainsWrite(); + } + } + + // Finally: Delete it. Goodbye! + refreshTokensFile.delete(); + } + + File authChainsFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_AUTH_CHAINS_FILE).toFile(); + if (authChainsFile.exists()) { TypeReference> type = new TypeReference<>() { }; - Map refreshTokenFile = null; + Map authChainFile = null; try { - refreshTokenFile = JSON_MAPPER.readValue(tokensFile, type); + authChainFile = JSON_MAPPER.readValue(authChainsFile, type); } catch (IOException e) { logger.error("Cannot load saved user tokens!", e); } - if (refreshTokenFile != null) { + if (authChainFile != null) { List validUsers = config.getSavedUserLogins(); boolean doWrite = false; - for (Map.Entry entry : refreshTokenFile.entrySet()) { + for (Map.Entry entry : authChainFile.entrySet()) { String user = entry.getKey(); if (!validUsers.contains(user)) { // Perform a write to this file to purge the now-unused name doWrite = true; continue; } - savedRefreshTokens.put(user, entry.getValue()); + savedAuthChains.put(user, entry.getValue()); } if (doWrite) { - scheduleRefreshTokensWrite(); + scheduleAuthChainsWrite(); } } } } else { - savedRefreshTokens = null; + savedAuthChains = null; } newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED); @@ -829,11 +880,11 @@ public class GeyserImpl implements GeyserApi { } @Nullable - public String refreshTokenFor(@NonNull String bedrockName) { - return savedRefreshTokens.get(bedrockName); + public String authChainFor(@NonNull String bedrockName) { + return savedAuthChains.get(bedrockName); } - public void saveRefreshToken(@NonNull String bedrockName, @NonNull String refreshToken) { + public void saveAuthChain(@NonNull String bedrockName, @NonNull String authChain) { if (!getConfig().getSavedUserLogins().contains(bedrockName)) { // Do not save this login return; @@ -841,8 +892,8 @@ public class GeyserImpl implements GeyserApi { // We can safely overwrite old instances because MsaAuthenticationService#getLoginResponseFromRefreshToken // refreshes the token for us - if (!Objects.equals(refreshToken, savedRefreshTokens.put(bedrockName, refreshToken))) { - scheduleRefreshTokensWrite(); + if (!Objects.equals(authChain, savedAuthChains.put(bedrockName, authChain))) { + scheduleAuthChainsWrite(); } } @@ -852,15 +903,15 @@ public class GeyserImpl implements GeyserApi { } } - private void scheduleRefreshTokensWrite() { + private void scheduleAuthChainsWrite() { scheduledThread.execute(() -> { // Ensure all writes are handled on the same thread - File savedTokens = getBootstrap().getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile(); + File savedAuthChains = getBootstrap().getSavedUserLoginsFolder().resolve(Constants.SAVED_AUTH_CHAINS_FILE).toFile(); TypeReference> type = new TypeReference<>() { }; - try (FileWriter writer = new FileWriter(savedTokens)) { + try (FileWriter writer = new FileWriter(savedAuthChains)) { JSON_MAPPER.writerFor(type) .withDefaultPrettyPrinter() - .writeValue(writer, savedRefreshTokens); + .writeValue(writer, this.savedAuthChains); } catch (IOException e) { getLogger().error("Unable to write saved refresh tokens!", e); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index 86572d60c..d4999c80d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.item.type; -import com.github.steveice10.mc.auth.data.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java index c4aae46a2..6e791d674 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.level.block.type; -import com.github.steveice10.mc.auth.data.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; 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 c7aabb806..f56a8a43f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -274,10 +274,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { private boolean couldLoginUserByName(String bedrockUsername) { if (geyser.getConfig().getSavedUserLogins().contains(bedrockUsername)) { - String refreshToken = geyser.refreshTokenFor(bedrockUsername); - if (refreshToken != null) { + String authChain = geyser.authChainFor(bedrockUsername); + if (authChain != null) { geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().name())); - session.authenticateWithRefreshToken(refreshToken); + session.authenticateWithAuthChain(authChain); return true; } } 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 c2f94b1c6..f7e3bd43d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -25,9 +25,8 @@ package org.geysermc.geyser.session; -import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.auth.exception.request.RequestException; -import com.github.steveice10.mc.auth.service.MsaAuthenticationService; +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.ints.Int2ObjectMap; @@ -41,22 +40,60 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; import net.kyori.adventure.key.Key; +import net.raphimc.minecraftauth.step.java.StepMCProfile; +import net.raphimc.minecraftauth.step.java.StepMCToken; +import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession; import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.value.qual.IntRange; -import org.cloudburstmc.math.vector.*; +import org.cloudburstmc.math.vector.Vector2f; +import org.cloudburstmc.math.vector.Vector2i; +import org.cloudburstmc.math.vector.Vector3d; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.BedrockServerSession; -import org.cloudburstmc.protocol.bedrock.data.*; +import org.cloudburstmc.protocol.bedrock.data.Ability; +import org.cloudburstmc.protocol.bedrock.data.AbilityLayer; +import org.cloudburstmc.protocol.bedrock.data.AuthoritativeMovementMode; +import org.cloudburstmc.protocol.bedrock.data.ChatRestrictionLevel; +import org.cloudburstmc.protocol.bedrock.data.ExperimentData; +import org.cloudburstmc.protocol.bedrock.data.GamePublishSetting; +import org.cloudburstmc.protocol.bedrock.data.GameRuleData; +import org.cloudburstmc.protocol.bedrock.data.GameType; +import org.cloudburstmc.protocol.bedrock.data.PlayerPermission; +import org.cloudburstmc.protocol.bedrock.data.SoundEvent; +import org.cloudburstmc.protocol.bedrock.data.SpawnBiomeType; import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData; import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; import org.cloudburstmc.protocol.bedrock.data.command.SoftEnumUpdateType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; -import org.cloudburstmc.protocol.bedrock.packet.*; +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.CraftingDataPacket; +import org.cloudburstmc.protocol.bedrock.packet.CreativeContentPacket; +import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket; +import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; +import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; +import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket; +import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket; +import org.cloudburstmc.protocol.bedrock.packet.SyncEntityPropertyPacket; +import org.cloudburstmc.protocol.bedrock.packet.TextPacket; +import org.cloudburstmc.protocol.bedrock.packet.TransferPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateAbilitiesPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateAdventureSettingsPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateClientInputLocksPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateSoftEnumPacket; import org.cloudburstmc.protocol.common.util.OptionalBoolean; import org.geysermc.api.util.BedrockPlatform; import org.geysermc.api.util.InputMode; @@ -106,7 +143,22 @@ import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.BedrockClientData; -import org.geysermc.geyser.session.cache.*; +import org.geysermc.geyser.session.cache.AdvancementsCache; +import org.geysermc.geyser.session.cache.BookEditCache; +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.LodestoneCache; +import org.geysermc.geyser.session.cache.PistonCache; +import org.geysermc.geyser.session.cache.PreferencesCache; +import org.geysermc.geyser.session.cache.RegistryCache; +import org.geysermc.geyser.session.cache.SkullCache; +import org.geysermc.geyser.session.cache.StructureBlockCache; +import org.geysermc.geyser.session.cache.TagCache; +import org.geysermc.geyser.session.cache.TeleportCache; +import org.geysermc.geyser.session.cache.WorldBorder; +import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; @@ -116,9 +168,15 @@ import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.LoginEncryptionUtils; +import org.geysermc.geyser.util.MinecraftAuthLogger; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.network.BuiltinFlags; import org.geysermc.mcprotocollib.network.Session; -import org.geysermc.mcprotocollib.network.event.session.*; +import org.geysermc.mcprotocollib.network.event.session.ConnectedEvent; +import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent; +import org.geysermc.mcprotocollib.network.event.session.PacketErrorEvent; +import org.geysermc.mcprotocollib.network.event.session.PacketSendingEvent; +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; @@ -153,7 +211,16 @@ import java.net.ConnectException; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledFuture; @@ -163,6 +230,8 @@ import java.util.concurrent.atomic.AtomicInteger; @Getter public class GeyserSession implements GeyserConnection, GeyserCommandSource { + private static final Gson GSON = new Gson(); + private final GeyserImpl geyser; private final UpstreamSession upstream; private DownstreamSession downstream; @@ -690,7 +759,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } } - public void authenticateWithRefreshToken(String refreshToken) { + public void authenticateWithAuthChain(String authChain) { if (loggedIn) { geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", getAuthData().name())); return; @@ -699,24 +768,23 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { loggingIn = true; CompletableFuture.supplyAsync(() -> { - MsaAuthenticationService service = new MsaAuthenticationService(GeyserImpl.OAUTH_CLIENT_ID); - service.setRefreshToken(refreshToken); + StepFullJavaSession step = PendingMicrosoftAuthentication.AUTH_FLOW.apply(true, 30); + StepFullJavaSession.FullJavaSession response; try { - service.login(); - } catch (RequestException e) { - geyser.getLogger().error("Error while attempting to use refresh token for " + bedrockUsername() + "!", e); + response = step.refresh(MinecraftAuthLogger.INSTANCE, PendingMicrosoftAuthentication.AUTH_CLIENT, step.fromJson(GSON.fromJson(authChain, JsonObject.class))); + } catch (Exception e) { + geyser.getLogger().error("Error while attempting to use auth chain for " + bedrockUsername() + "!", e); return Boolean.FALSE; } - GameProfile profile = service.getSelectedProfile(); - if (profile == null) { - // Java account is offline - disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode())); - return null; - } + StepMCProfile.MCProfile mcProfile = response.getMcProfile(); + StepMCToken.MCToken mcToken = mcProfile.getMcToken(); - protocol = new MinecraftProtocol(profile, service.getAccessToken()); - geyser.saveRefreshToken(bedrockUsername(), service.getRefreshToken()); + protocol = new MinecraftProtocol( + new GameProfile(mcProfile.getId(), mcProfile.getName()), + mcToken.getAccessToken() + ); + geyser.saveAuthChain(bedrockUsername(), GSON.toJson(step.toJson(response))); return Boolean.TRUE; }).whenComplete((successful, ex) -> { if (this.closed) { @@ -761,25 +829,15 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { final PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getOrCreateTask( getAuthData().xuid() ); - task.setOnline(true); - task.resetTimer(); - - if (task.getAuthentication().isDone()) { + if (task.getAuthentication() != null && task.getAuthentication().isDone()) { onMicrosoftLoginComplete(task); } else { - task.getCode(offlineAccess).whenComplete((response, ex) -> { - boolean connected = !closed; - if (ex != null) { - if (connected) { - geyser.getLogger().error("Failed to get Microsoft auth code", ex); - disconnect(ex.toString()); - } - task.cleanup(); // error getting auth code -> clean up immediately - } else if (connected) { - LoginEncryptionUtils.buildAndShowMicrosoftCodeWindow(this, response); - task.getAuthentication().whenComplete((r, $) -> onMicrosoftLoginComplete(task)); + task.resetRunningFlow(); + task.performLoginAttempt(offlineAccess, code -> { + if (!closed) { + LoginEncryptionUtils.buildAndShowMicrosoftCodeWindow(this, code); } - }); + }).handle((r, e) -> onMicrosoftLoginComplete(task)); } } @@ -791,36 +849,32 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return false; } task.cleanup(); // player is online -> remove pending authentication immediately - Throwable ex = task.getLoginException(); - if (ex != null) { - geyser.getLogger().error("Failed to log in with Microsoft code!", ex); - disconnect(ex.toString()); - } else { - MsaAuthenticationService service = task.getMsaAuthenticationService(); - GameProfile selectedProfile = service.getSelectedProfile(); - if (selectedProfile == null) { - disconnect(GeyserLocale.getPlayerLocaleString( - "geyser.network.remote.invalid_account", - clientData.getLanguageCode() - )); - } else { - this.protocol = new MinecraftProtocol( - selectedProfile, - service.getAccessToken() - ); - try { - connectDownstream(); - } catch (Throwable t) { - t.printStackTrace(); - return false; - } + return task.getAuthentication().handle((result, ex) -> { + if (ex != null) { + geyser.getLogger().error("Failed to log in with Microsoft code!", ex); + disconnect(ex.toString()); + return false; + } - // Save our refresh token for later use - geyser.saveRefreshToken(bedrockUsername(), service.getRefreshToken()); - return true; - } - } - return false; + StepMCProfile.MCProfile mcProfile = result.session().getMcProfile(); + StepMCToken.MCToken mcToken = mcProfile.getMcToken(); + + this.protocol = new MinecraftProtocol( + new GameProfile(mcProfile.getId(), mcProfile.getName()), + mcToken.getAccessToken() + ); + + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + return false; + } + + // Save our auth chain for later use + geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session()))); + return true; + }).getNow(false); } /** @@ -1103,7 +1157,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { if (authData != null) { PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getTask(authData.xuid()); if (task != null) { - task.setOnline(false); + task.resetRunningFlow(); } } } diff --git a/core/src/main/java/org/geysermc/geyser/session/PendingMicrosoftAuthentication.java b/core/src/main/java/org/geysermc/geyser/session/PendingMicrosoftAuthentication.java index 0651039a0..7d0e2fbf9 100644 --- a/core/src/main/java/org/geysermc/geyser/session/PendingMicrosoftAuthentication.java +++ b/core/src/main/java/org/geysermc/geyser/session/PendingMicrosoftAuthentication.java @@ -25,27 +25,44 @@ package org.geysermc.geyser.session; -import com.github.steveice10.mc.auth.exception.request.AuthPendingException; -import com.github.steveice10.mc.auth.exception.request.RequestException; -import com.github.steveice10.mc.auth.service.MsaAuthenticationService; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; +import net.lenni0451.commons.httpclient.HttpClient; +import net.raphimc.minecraftauth.MinecraftAuth; +import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession; +import net.raphimc.minecraftauth.step.msa.StepMsaDeviceCode; +import net.raphimc.minecraftauth.util.MicrosoftConstants; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.util.MinecraftAuthLogger; -import java.io.Serial; -import java.util.concurrent.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.function.BiFunction; +import java.util.function.Consumer; /** * Pending Microsoft authentication task cache. * It permits user to exit the server while they authorize Geyser to access their Microsoft account. */ public class PendingMicrosoftAuthentication { + public static final HttpClient AUTH_CLIENT = MinecraftAuth.createHttpClient(); + public static final BiFunction AUTH_FLOW = (offlineAccess, timeoutSec) -> MinecraftAuth.builder() + .withClientId(GeyserImpl.OAUTH_CLIENT_ID) + .withScope(offlineAccess ? "XboxLive.signin XboxLive.offline_access" : "XboxLive.signin") + .withTimeout(timeoutSec) + .deviceCode() + .withoutDeviceToken() + .regularAuthentication(MicrosoftConstants.JAVA_XSTS_RELYING_PARTY) + .buildMinecraftJavaProfileStep(false); /** * For GeyserConnect usage. */ @@ -57,8 +74,8 @@ public class PendingMicrosoftAuthentication { .build(new CacheLoader<>() { @Override public AuthenticationTask load(@NonNull String userKey) { - return storeServerInformation ? new ProxyAuthenticationTask(userKey, timeoutSeconds * 1000L) - : new AuthenticationTask(userKey, timeoutSeconds * 1000L); + return storeServerInformation ? new ProxyAuthenticationTask(userKey, timeoutSeconds) + : new AuthenticationTask(userKey, timeoutSeconds); } }); } @@ -80,37 +97,23 @@ public class PendingMicrosoftAuthentication { public class AuthenticationTask { private static final Executor DELAYED_BY_ONE_SECOND = CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS); - @Getter - private final MsaAuthenticationService msaAuthenticationService = new MsaAuthenticationService(GeyserImpl.OAUTH_CLIENT_ID); private final String userKey; - private final long timeoutMs; - - private long remainingTimeMs; - - @Setter - private boolean online = true; - + private final int timeoutSec; @Getter - private final CompletableFuture authentication; + private CompletableFuture authentication; - @Getter - private volatile Throwable loginException; - - private AuthenticationTask(String userKey, long timeoutMs) { + private AuthenticationTask(String userKey, int timeoutSec) { this.userKey = userKey; - this.timeoutMs = timeoutMs; - this.remainingTimeMs = timeoutMs; - - this.authentication = new CompletableFuture<>(); - this.authentication.whenComplete((r, ex) -> { - this.loginException = ex; - // avoid memory leak, in case player doesn't connect again - CompletableFuture.delayedExecutor(timeoutMs, TimeUnit.MILLISECONDS).execute(this::cleanup); - }); + this.timeoutSec = timeoutSec; } - public void resetTimer() { - this.remainingTimeMs = this.timeoutMs; + public void resetRunningFlow() { + if (authentication == null) { + return; + } + + // Interrupt the current flow + this.authentication.cancel(true); } public void cleanup() { @@ -121,52 +124,18 @@ public class PendingMicrosoftAuthentication { authentications.invalidate(userKey); } - public CompletableFuture getCode(boolean offlineAccess) { - // Request the code - CompletableFuture code = CompletableFuture.supplyAsync( - () -> tryGetCode(offlineAccess)); - // Once the code is received, continuously try to request the access token, profile, etc - code.thenRun(() -> performLoginAttempt(System.currentTimeMillis())); - return code; - } - - /** - * @param offlineAccess whether we want a refresh token for later use. - */ - private MsaAuthenticationService.MsCodeResponse tryGetCode(boolean offlineAccess) throws CompletionException { - try { - return msaAuthenticationService.getAuthCode(offlineAccess); - } catch (RequestException e) { - throw new CompletionException(e); - } - } - - private void performLoginAttempt(long lastAttempt) { - CompletableFuture.runAsync(() -> { + public CompletableFuture performLoginAttempt(boolean offlineAccess, Consumer deviceCodeConsumer) { + return authentication = CompletableFuture.supplyAsync(() -> { try { - msaAuthenticationService.login(); - } catch (AuthPendingException e) { - long currentAttempt = System.currentTimeMillis(); - if (!online) { - // decrement timer only when player's offline - remainingTimeMs -= currentAttempt - lastAttempt; - if (remainingTimeMs <= 0L) { - // time's up - authentication.completeExceptionally(new TaskTimeoutException()); - cleanup(); - return; - } - } - // try again in 1 second - performLoginAttempt(currentAttempt); - return; + StepFullJavaSession step = AUTH_FLOW.apply(offlineAccess, timeoutSec); + return new StepChainResult(step, step.getFromInput(MinecraftAuthLogger.INSTANCE, AUTH_CLIENT, new StepMsaDeviceCode.MsaDeviceCodeCallback(deviceCodeConsumer))); } catch (Exception e) { - authentication.completeExceptionally(e); - return; + throw new CompletionException(e); } - // login successful - authentication.complete(msaAuthenticationService); - }, DELAYED_BY_ONE_SECOND); + }, DELAYED_BY_ONE_SECOND).whenComplete((r, ex) -> { + // avoid memory leak, in case player doesn't connect again + CompletableFuture.delayedExecutor(timeoutSec, TimeUnit.SECONDS).execute(this::cleanup); + }); } @Override @@ -181,22 +150,11 @@ public class PendingMicrosoftAuthentication { private String server; private int port; - private ProxyAuthenticationTask(String userKey, long timeoutMs) { - super(userKey, timeoutMs); + private ProxyAuthenticationTask(String userKey, int timeoutSec) { + super(userKey, timeoutSec); } } - /** - * @see PendingMicrosoftAuthentication - */ - public static class TaskTimeoutException extends Exception { - - @Serial - private static final long serialVersionUID = 1L; - - TaskTimeoutException() { - super("It took too long to authorize Geyser to access your Microsoft account. " + - "Please request new code and try again."); - } + public record StepChainResult(StepFullJavaSession step, StepFullJavaSession.FullJavaSession session) { } } diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index ef3ff3293..6f6bcb0ae 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java @@ -25,11 +25,10 @@ package org.geysermc.geyser.skin; -import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.auth.data.GameProfile.Texture; -import com.github.steveice10.mc.auth.data.GameProfile.TextureModel; -import com.github.steveice10.mc.auth.data.GameProfile.TextureType; -import com.github.steveice10.mc.auth.exception.property.PropertyException; +import org.geysermc.mcprotocollib.auth.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile.Texture; +import org.geysermc.mcprotocollib.auth.GameProfile.TextureModel; +import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -113,12 +112,7 @@ public class FakeHeadProvider { return; } - Map textures = null; - try { - textures = profile.getTextures(false); - } catch (PropertyException e) { - session.getGeyser().getLogger().debug("Failed to get textures from GameProfile: " + e); - } + Map textures = profile.getTextures(false); if (textures == null || textures.isEmpty()) { loadHead(session, entity, profile.getName()); 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 e9527872a..aa0c3eb43 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 @@ -25,10 +25,9 @@ package org.geysermc.geyser.translator.item; -import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.auth.data.GameProfile.Texture; -import com.github.steveice10.mc.auth.data.GameProfile.TextureType; -import com.github.steveice10.mc.auth.exception.property.PropertyException; +import org.geysermc.mcprotocollib.auth.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile.Texture; +import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; @@ -487,12 +486,7 @@ public final class ItemTranslator { GameProfile profile = components.get(DataComponentType.PROFILE); if (profile != null) { - Map textures = null; - try { - textures = profile.getTextures(false); - } catch (PropertyException e) { - GeyserImpl.getInstance().getLogger().debug("Failed to get textures from GameProfile: " + e); - } + Map textures = profile.getTextures(false); if (textures == null || textures.isEmpty()) { return null; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java index de2df0cb7..47c5bfd35 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java @@ -46,10 +46,10 @@ public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslat if (session.remoteServer().authType() == AuthType.ONLINE) { if (!session.isLoggedIn()) { if (session.getGeyser().getConfig().getSavedUserLogins().contains(session.bedrockUsername())) { - if (session.getGeyser().refreshTokenFor(session.bedrockUsername()) == null) { + if (session.getGeyser().authChainFor(session.bedrockUsername()) == null) { LoginEncryptionUtils.buildAndShowConsentWindow(session); } else { - // If the refresh token is not null and we're here, then the refresh token expired + // If the auth chain is not null and we're here, then it expired // and the expiration form has been cached session.getFormCache().resendAllForms(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java index e7bde6a9d..47d1cff08 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.auth.data.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile; import net.kyori.adventure.key.Key; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.PlayerEntity; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java index f5ea4c08d..19f34db74 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.auth.data.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; diff --git a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java index 478a6ef96..d3024be65 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.util; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.steveice10.mc.auth.service.MsaAuthenticationService; +import net.raphimc.minecraftauth.step.msa.StepMsaDeviceCode; import org.cloudburstmc.protocol.bedrock.packet.LoginPacket; import org.cloudburstmc.protocol.bedrock.packet.ServerToClientHandshakePacket; import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult; @@ -203,7 +203,7 @@ public class LoginEncryptionUtils { /** * Shows the code that a user must input into their browser */ - public static void buildAndShowMicrosoftCodeWindow(GeyserSession session, MsaAuthenticationService.MsCodeResponse msCode) { + public static void buildAndShowMicrosoftCodeWindow(GeyserSession session, StepMsaDeviceCode.MsaDeviceCode msCode) { String locale = session.locale(); StringBuilder message = new StringBuilder("%xbox.signin.website\n") @@ -212,7 +212,7 @@ public class LoginEncryptionUtils { .append(ChatColor.RESET) .append("\n%xbox.signin.enterCode\n") .append(ChatColor.GREEN) - .append(msCode.user_code); + .append(msCode.getUserCode()); int timeout = session.getGeyser().getConfig().getPendingAuthenticationTimeout(); if (timeout != 0) { message.append("\n\n") diff --git a/core/src/main/java/org/geysermc/geyser/util/MinecraftAuthLogger.java b/core/src/main/java/org/geysermc/geyser/util/MinecraftAuthLogger.java new file mode 100644 index 000000000..4e928d47e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/MinecraftAuthLogger.java @@ -0,0 +1,49 @@ +/* + * 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.util; + +import net.raphimc.minecraftauth.util.logging.ILogger; +import org.geysermc.geyser.GeyserImpl; + +public class MinecraftAuthLogger implements ILogger { + + public static final MinecraftAuthLogger INSTANCE = new MinecraftAuthLogger(); + + @Override + public void info(String message) { + GeyserImpl.getInstance().getLogger().debug(message); + } + + @Override + public void warn(String message) { + GeyserImpl.getInstance().getLogger().warning(message); + } + + @Override + public void error(String message) { + GeyserImpl.getInstance().getLogger().error(message); + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 49c02d190..845589585 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,8 +12,8 @@ gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" protocol = "3.0.0.Beta2-20240704.153116-14" raknet = "1.0.0.CR3-20240416.144209-1" -mcauthlib = "e5b0bcc" -mcprotocollib = "1.21-20240616.154144-5" +minecraftauth = "4.1.0" +mcprotocollib = "1.21-20240718.102029-13" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" @@ -107,7 +107,7 @@ commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } -mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } +minecraftauth = { group = "net.raphimc", name = "MinecraftAuth", version.ref = "minecraftauth" } mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" } raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } From 5ebb16a1920e75dd91dec8217ef3f06a1d2a2355 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Thu, 25 Jul 2024 10:38:12 +0000 Subject: [PATCH 305/897] Update MCPL (#4897) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 845589585..58b5310ac 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ websocket = "1.5.1" protocol = "3.0.0.Beta2-20240704.153116-14" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.0" -mcprotocollib = "1.21-20240718.102029-13" +mcprotocollib = "1.21-20240725.013034-16" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From e994d6e1d6929750d63a81c57d0f0d8f3497673d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Jul 2024 16:51:22 -0400 Subject: [PATCH 306/897] Bring in #4847 change --- .../org/geysermc/geyser/util/DimensionUtils.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index cd1a690c3..b1408b817 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -27,9 +27,11 @@ package org.geysermc.geyser.util; 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.packet.ChangeDimensionPacket; import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEffectPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket; @@ -85,6 +87,20 @@ public class DimensionUtils { // Effects are re-sent from server entityEffects.clear(); + // Always reset weather, as it sometimes suddenly starts raining. See https://github.com/GeyserMC/Geyser/issues/3679 + LevelEventPacket stopRainPacket = new LevelEventPacket(); + stopRainPacket.setType(LevelEvent.STOP_RAINING); + stopRainPacket.setData(0); + stopRainPacket.setPosition(Vector3f.ZERO); + session.sendUpstreamPacket(stopRainPacket); + session.setRaining(false); + LevelEventPacket stopThunderPacket = new LevelEventPacket(); + stopThunderPacket.setType(LevelEvent.STOP_THUNDERSTORM); + stopThunderPacket.setData(0); + stopThunderPacket.setPosition(Vector3f.ZERO); + session.sendUpstreamPacket(stopThunderPacket); + session.setThunder(false); + finalizeDimensionSwitch(session, player); // If the bedrock nether height workaround is enabled, meaning the client is told it's in the end dimension, From 663e3af7c8f10e5ae9e4fc5d76ad32b8730b26c9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Jul 2024 17:22:10 -0400 Subject: [PATCH 307/897] Fix non-block items in stonecutters Fixes #4845 --- .../geysermc/geyser/item/type/BlockItem.java | 13 ++++++++++++ .../org/geysermc/geyser/item/type/Item.java | 11 +++++++--- .../java/JavaUpdateRecipesTranslator.java | 3 ++- .../geysermc/geyser/util/StatisticsUtils.java | 20 +++++++------------ 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BlockItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BlockItem.java index 30a31a100..c57e58469 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BlockItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BlockItem.java @@ -28,6 +28,9 @@ package org.geysermc.geyser.item.type; import org.geysermc.geyser.level.block.type.Block; public class BlockItem extends Item { + // If item is instanceof ItemNameBlockItem + private final boolean treatLikeBlock; + public BlockItem(Builder builder, Block block, Block... otherBlocks) { super(block.javaIdentifier().value(), builder); @@ -36,6 +39,7 @@ public class BlockItem extends Item { for (Block otherBlock : otherBlocks) { registerBlock(otherBlock, this); } + treatLikeBlock = true; } // Use this constructor if the item name is not the same as its primary block @@ -46,5 +50,14 @@ public class BlockItem extends Item { for (Block otherBlock : otherBlocks) { registerBlock(otherBlock, this); } + treatLikeBlock = false; + } + + @Override + public String translationKey() { + if (!treatLikeBlock) { + return super.translationKey(); + } + return "block." + this.javaIdentifier.namespace() + "." + this.javaIdentifier.value(); } } 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 2417177ce..a8a477025 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.type; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -59,7 +60,7 @@ import java.util.Map; public class Item { private static final Map BLOCK_TO_ITEM = new HashMap<>(); - private final String javaIdentifier; + protected final Key javaIdentifier; private int javaId = -1; private final int stackSize; private final int attackDamage; @@ -68,7 +69,7 @@ public class Item { private final boolean glint; public Item(String javaIdentifier, Builder builder) { - this.javaIdentifier = MinecraftKey.key(javaIdentifier).asString().intern(); + this.javaIdentifier = MinecraftKey.key(javaIdentifier); this.stackSize = builder.stackSize; this.maxDamage = builder.maxDamage; this.attackDamage = builder.attackDamage; @@ -77,7 +78,7 @@ public class Item { } public String javaIdentifier() { - return javaIdentifier; + return javaIdentifier.asString(); } public int javaId() { @@ -108,6 +109,10 @@ public class Item { return false; } + public String translationKey() { + return "item." + javaIdentifier.namespace() + "." + javaIdentifier.value(); + } + /* Translation methods to Bedrock and back */ public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index fd8981552..7c36c505b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -253,7 +253,8 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Registries.JAVA_ITEMS.get().get(stoneCuttingRecipeData.getResult().getId()) - .javaIdentifier()))); + // See RecipeManager#getRecipesFor as of 1.21 + .translationKey()))); // Now that it's sorted, let's translate these recipes int buttonId = 0; diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index 72fcb4fa6..9847c0cfc 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -107,7 +107,7 @@ public class StatisticsUtils { for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof BreakItemStatistic statistic) { - String item = itemRegistry.get(statistic.getId()).javaIdentifier(); + Item item = itemRegistry.get(statistic.getId()); content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } @@ -117,7 +117,7 @@ public class StatisticsUtils { for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof CraftItemStatistic statistic) { - String item = itemRegistry.get(statistic.getId()).javaIdentifier(); + Item item = itemRegistry.get(statistic.getId()); content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } @@ -127,7 +127,7 @@ public class StatisticsUtils { for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof UseItemStatistic statistic) { - String item = itemRegistry.get(statistic.getId()).javaIdentifier(); + Item item = itemRegistry.get(statistic.getId()); content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } @@ -137,7 +137,7 @@ public class StatisticsUtils { for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof PickupItemStatistic statistic) { - String item = itemRegistry.get(statistic.getId()).javaIdentifier(); + Item item = itemRegistry.get(statistic.getId()); content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } @@ -147,7 +147,7 @@ public class StatisticsUtils { for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof DropItemStatistic statistic) { - String item = itemRegistry.get(statistic.getId()).javaIdentifier(); + Item item = itemRegistry.get(statistic.getId()); content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } @@ -208,14 +208,8 @@ public class StatisticsUtils { * @param language the language to search in * @return the full name of the item */ - private static String getItemTranslateKey(String item, String language) { - item = item.replace("minecraft:", "item.minecraft."); - String translatedItem = MinecraftLocale.getLocaleString(item, language); - if (translatedItem.equals(item)) { - // Didn't translate; must be a block - translatedItem = MinecraftLocale.getLocaleString(item.replace("item.", "block."), language); - } - return translatedItem; + private static String getItemTranslateKey(Item item, String language) { + return MinecraftLocale.getLocaleString(item.translationKey(), language); } private static String translate(String keys, String locale) { From 258d6aadb436c29b0ea969c52564b571983c9c02 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 27 Jul 2024 00:39:45 +0200 Subject: [PATCH 308/897] Fix: Bedrock players being able to always eat food while in peaceful difficulty (#4904) --- .../BedrockServerSettingsRequestTranslator.java | 10 ++++++++++ .../java/JavaChangeDifficultyTranslator.java | 14 +++++++++++--- .../org/geysermc/geyser/util/SettingsUtils.java | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java index aa7a2e40f..c7475e5d0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java @@ -27,12 +27,14 @@ package org.geysermc.geyser.translator.protocol.bedrock; import org.cloudburstmc.protocol.bedrock.packet.ServerSettingsRequestPacket; import org.cloudburstmc.protocol.bedrock.packet.ServerSettingsResponsePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetDifficultyPacket; import org.geysermc.cumulus.form.CustomForm; import org.geysermc.cumulus.form.impl.FormDefinitions; 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.SettingsUtils; +import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import java.util.concurrent.TimeUnit; @@ -47,6 +49,14 @@ public class BedrockServerSettingsRequestTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundChangeDifficultyPacket packet) { + Difficulty difficulty = packet.getDifficulty(); + session.getWorldCache().setDifficulty(difficulty); + + // Peaceful difficulty allows always eating food - hence, we just do not send it to Bedrock. + if (difficulty == Difficulty.PEACEFUL) { + difficulty = Difficulty.EASY; + } + SetDifficultyPacket setDifficultyPacket = new SetDifficultyPacket(); - setDifficultyPacket.setDifficulty(packet.getDifficulty().ordinal()); + setDifficultyPacket.setDifficulty(difficulty.ordinal()); session.sendUpstreamPacket(setDifficultyPacket); - session.getWorldCache().setDifficulty(packet.getDifficulty()); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java index ed97408b9..6f46b191c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.util; +import org.cloudburstmc.protocol.bedrock.packet.SetDifficultyPacket; import org.geysermc.cumulus.component.DropdownComponent; import org.geysermc.cumulus.form.CustomForm; import org.geysermc.geyser.GeyserImpl; @@ -33,6 +34,7 @@ import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; public class SettingsUtils { /** @@ -96,6 +98,7 @@ public class SettingsUtils { } builder.validResultHandler((response) -> { + applyDifficultyFix(session); if (showClientSettings) { // Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config. if (showCoordinates) { @@ -134,9 +137,21 @@ public class SettingsUtils { } }); + builder.closedOrInvalidResultHandler($ -> applyDifficultyFix(session)); + return builder.build(); } + private static void applyDifficultyFix(GeyserSession session) { + // Peaceful difficulty allows always eating food - hence, we just do not send it to Bedrock. + // Since we sent the real difficulty before opening the server settings form, let's restore it to our workaround here + if (session.getWorldCache().getDifficulty() == Difficulty.PEACEFUL) { + SetDifficultyPacket setDifficultyPacket = new SetDifficultyPacket(); + setDifficultyPacket.setDifficulty(Difficulty.EASY.ordinal()); + session.sendUpstreamPacket(setDifficultyPacket); + } + } + private static String translateEntry(String key, String locale) { if (key.startsWith("%")) { // Bedrock will translate From 45f96a03e79b8227f8cd661ad08b423dda237042 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 28 Jul 2024 12:56:41 -0400 Subject: [PATCH 309/897] Fix online mode no auth token dimension setting on login --- .../protocol/java/JavaLoginTranslator.java | 22 +++++++++++-------- .../geysermc/geyser/util/DimensionUtils.java | 5 +++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 641313ee4..cf4b7058b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -26,28 +26,25 @@ package org.geysermc.geyser.translator.protocol.java; import net.kyori.adventure.key.Key; -import org.geysermc.erosion.Constants; -import org.geysermc.geyser.level.JavaDimension; -import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; -import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket; -import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameRuleData; -import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; +import org.geysermc.erosion.Constants; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler; +import org.geysermc.geyser.level.JavaDimension; 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.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.MinecraftKey; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; +import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -83,6 +80,13 @@ public class JavaLoginTranslator extends PacketTranslator Date: Sun, 28 Jul 2024 17:22:36 -0400 Subject: [PATCH 310/897] Fix world manager access stalling for the main thread --- .../geyser/platform/mod/world/GeyserModWorldManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 db1768737..524087e86 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; @@ -89,7 +90,8 @@ public class GeyserModWorldManager extends GeyserWorldManager { 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; } From 3e01c436c9af55e0b40b52efb60c486275031051 Mon Sep 17 00:00:00 2001 From: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Date: Mon, 29 Jul 2024 00:16:15 -0700 Subject: [PATCH 311/897] 1.21.20 Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .../geyser/impl/camera/CameraDefinitions.java | 14 +- .../geyser/network/CodecProcessor.java | 50 +- .../geysermc/geyser/network/GameProtocol.java | 19 +- .../geyser/network/UpstreamPacketHandler.java | 2 +- .../populator/BlockRegistryPopulator.java | 4 +- .../registry/populator/Conversion685_671.java | 12 +- .../registry/populator/Conversion712_685.java | 436 ++ .../populator/ItemRegistryPopulator.java | 4 +- .../inventory/InventoryTranslator.java | 4 +- .../resources/bedrock/biome_definitions.dat | Bin 41676 -> 41832 bytes .../bedrock/block_palette.1_21_20.nbt | Bin 0 -> 178977 bytes .../bedrock/creative_items.1_21_20.json | 6214 +++++++++++++++ .../resources/bedrock/entity_identifiers.dat | Bin 8314 -> 8314 bytes .../bedrock/runtime_item_states.1_21_20.json | 6794 +++++++++++++++++ core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 2 +- 16 files changed, 13521 insertions(+), 36 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java create mode 100644 core/src/main/resources/bedrock/block_palette.1_21_20.nbt create mode 100644 core/src/main/resources/bedrock/creative_items.1_21_20.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_21_20.json diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java b/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java index 80564bdf3..7bb25c9ef 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java @@ -43,13 +43,13 @@ public class CameraDefinitions { static { CAMERA_PRESETS = List.of( - new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, OptionalBoolean.empty()), - new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.of(false)), - new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.of(true)), - new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.of(true))); + new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()), + new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()), + new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()), + new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()), + new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.of(false)), + new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.of(true)), + new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.of(true))); SimpleDefinitionRegistry.Builder builder = SimpleDefinitionRegistry.builder(); for (int i = 0; i < CAMERA_PRESETS.size(); i++) { 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 e7cf81d47..fd18c01ce 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -40,6 +40,9 @@ import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventorySlotSeri 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; +import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventoryContentSerializer_v712; +import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventorySlotSerializer_v712; +import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.MobArmorEquipmentSerializer_v712; import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.cloudburstmc.protocol.bedrock.packet.BossEventPacket; @@ -119,7 +122,17 @@ class CodecProcessor { /** * Serializer that throws an exception when trying to deserialize InventoryContentPacket since server-auth inventory is used. */ - private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER = new InventoryContentSerializer_v407() { + private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V407 = new InventoryContentSerializer_v407() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { + throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!"); + } + }; + + /** + * Serializer that throws an exception when trying to deserialize InventoryContentPacket since server-auth inventory is used. + */ + private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V712 = new InventoryContentSerializer_v712() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!"); @@ -129,7 +142,17 @@ class CodecProcessor { /** * Serializer that throws an exception when trying to deserialize InventorySlotPacket since server-auth inventory is used. */ - private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER = new InventorySlotSerializer_v407() { + private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER_V407 = new InventorySlotSerializer_v407() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { + throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!"); + } + }; + + /* + * Serializer that throws an exception when trying to deserialize InventorySlotPacket since server-auth inventory is used. + */ + private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER_V712 = new InventorySlotSerializer_v712() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!"); @@ -148,7 +171,16 @@ class CodecProcessor { /** * Serializer that does nothing when trying to deserialize MobArmorEquipmentPacket since it is not used from the client. */ - private static final BedrockPacketSerializer MOB_ARMOR_EQUIPMENT_SERIALIZER = new MobArmorEquipmentSerializer_v291() { + private static final BedrockPacketSerializer MOB_ARMOR_EQUIPMENT_SERIALIZER_V291 = new MobArmorEquipmentSerializer_v291() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobArmorEquipmentPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize MobArmorEquipmentPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer MOB_ARMOR_EQUIPMENT_SERIALIZER_V712 = new MobArmorEquipmentSerializer_v712() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobArmorEquipmentPacket packet) { } @@ -193,7 +225,7 @@ class CodecProcessor { /** * Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v662. */ - private static final BedrockPacketSerializer SET_ENTITY_MOTION_SERIALIZER_V662 = new SetEntityMotionSerializer_v662() { + private static final BedrockPacketSerializer SET_ENTITY_MOTION_SERIALIZER = new SetEntityMotionSerializer_v662() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityMotionPacket packet) { } @@ -224,6 +256,8 @@ class CodecProcessor { @SuppressWarnings("unchecked") static BedrockCodec processCodec(BedrockCodec codec) { + boolean isPre712 = codec.getProtocolVersion() < 712; + BedrockCodec.Builder codecBuilder = codec.toBuilder() // Illegal unused serverbound EDU packets .updateSerializer(PhotoTransferPacket.class, ILLEGAL_SERIALIZER) @@ -252,15 +286,15 @@ class CodecProcessor { .updateSerializer(AnvilDamagePacket.class, IGNORED_SERIALIZER) .updateSerializer(RefreshEntitlementsPacket.class, IGNORED_SERIALIZER) // Illegal when serverbound due to Geyser specific setup - .updateSerializer(InventoryContentPacket.class, INVENTORY_CONTENT_SERIALIZER) - .updateSerializer(InventorySlotPacket.class, INVENTORY_SLOT_SERIALIZER) + .updateSerializer(InventoryContentPacket.class, isPre712 ? INVENTORY_CONTENT_SERIALIZER_V407 : INVENTORY_CONTENT_SERIALIZER_V712) + .updateSerializer(InventorySlotPacket.class, isPre712 ? INVENTORY_SLOT_SERIALIZER_V407 : INVENTORY_SLOT_SERIALIZER_V712) // Ignored only when serverbound .updateSerializer(BossEventPacket.class, BOSS_EVENT_SERIALIZER) - .updateSerializer(MobArmorEquipmentPacket.class, MOB_ARMOR_EQUIPMENT_SERIALIZER) + .updateSerializer(MobArmorEquipmentPacket.class, isPre712 ? MOB_ARMOR_EQUIPMENT_SERIALIZER_V291 : MOB_ARMOR_EQUIPMENT_SERIALIZER_V712) .updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER) .updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER) .updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER) - .updateSerializer(SetEntityMotionPacket.class, SET_ENTITY_MOTION_SERIALIZER_V662) + .updateSerializer(SetEntityMotionPacket.class, SET_ENTITY_MOTION_SERIALIZER) .updateSerializer(SetEntityLinkPacket.class, SET_ENTITY_LINK_SERIALIZER) // Valid serverbound packets where reading of some fields can be skipped .updateSerializer(MobEquipmentPacket.class, MOB_EQUIPMENT_SERIALIZER) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 8f3f00021..18dee94e6 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -29,6 +29,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; +import org.cloudburstmc.protocol.bedrock.codec.v686.Bedrock_v686; +import org.cloudburstmc.protocol.bedrock.codec.v712.Bedrock_v712; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; @@ -43,17 +45,13 @@ import java.util.StringJoiner; */ public final class GameProtocol { - // Surprise protocol bump WOW - private static final BedrockCodec BEDROCK_V686 = Bedrock_v685.CODEC.toBuilder() - .protocolVersion(686) - .minecraftVersion("1.21.2") - .build(); - /** * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(BEDROCK_V686); + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder() + .minecraftVersion("1.21.20") + .build()); /** * A list of all supported Bedrock versions that can join Geyser @@ -73,9 +71,10 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v685.CODEC.toBuilder() .minecraftVersion("1.21.0/1.21.1") .build())); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.2/1.21.3") - .build()); + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v686.CODEC.toBuilder() + .minecraftVersion("1.21.2") + .build())); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } /** 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 f56a8a43f..e9c979b0c 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -209,7 +209,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { ResourcePackManifest.Header header = pack.manifest().header(); resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry( header.uuid().toString(), header.version().toString(), codec.size(), pack.contentKey(), - "", header.uuid().toString(), false, false)); + "", header.uuid().toString(), false, false, false)); } resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks()); session.sendUpstreamPacket(resourcePacksInfo); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index d7dc989da..33c2bc97b 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -38,6 +38,7 @@ import it.unimi.dsi.fastutil.objects.*; import org.cloudburstmc.nbt.*; 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.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -108,7 +109,8 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { var blockMappers = ImmutableMap., Remapper>builder() .put(ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), Conversion685_671::remapBlock) - .put(ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), Conversion712_685::remapBlock) + .put(ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), tag -> tag) .build(); // We can keep this strong as nothing should be garbage collected diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java index 58886ca57..0c7f540bf 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java @@ -45,6 +45,8 @@ public class Conversion685_671 { private static final List NEW_MUSIC_DISCS = List.of(Items.MUSIC_DISC_CREATOR, Items.MUSIC_DISC_CREATOR_MUSIC_BOX, Items.MUSIC_DISC_PRECIPICE); static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { + mapping = Conversion712_685.remapItem(item, mapping); + String identifer = mapping.getBedrockIdentifier(); if (NEW_MUSIC_DISCS.contains(item)) { @@ -111,6 +113,8 @@ public class Conversion685_671 { } static NbtMap remapBlock(NbtMap tag) { + tag = Conversion712_685.remapBlock(tag); + final String name = tag.getString("name"); if (!MODIFIED_BLOCKS.contains(name)) { @@ -130,7 +134,7 @@ public class Conversion685_671 { String coralColor; boolean deadBit = name.startsWith("minecraft:dead_"); - switch(name) { + switch (name) { case "minecraft:tube_coral_block", "minecraft:dead_tube_coral_block" -> coralColor = "blue"; case "minecraft:brain_coral_block", "minecraft:dead_brain_coral_block" -> coralColor = "pink"; case "minecraft:bubble_coral_block", "minecraft:dead_bubble_coral_block" -> coralColor = "purple"; @@ -152,7 +156,7 @@ public class Conversion685_671 { replacement = "minecraft:double_plant"; String doublePlantType; - switch(name) { + switch (name) { case "minecraft:sunflower" -> doublePlantType = "sunflower"; case "minecraft:lilac" -> doublePlantType = "syringa"; case "minecraft:tall_grass" -> doublePlantType = "grass"; @@ -174,7 +178,7 @@ public class Conversion685_671 { replacement = "minecraft:stone_block_slab"; String stoneSlabType; - switch(name) { + switch (name) { case "minecraft:smooth_stone_slab" -> stoneSlabType = "smooth_stone"; case "minecraft:sandstone_slab" -> stoneSlabType = "sandstone"; case "minecraft:petrified_oak_slab" -> stoneSlabType = "wood"; @@ -198,7 +202,7 @@ public class Conversion685_671 { replacement = "minecraft:tallgrass"; String tallGrassType; - switch(name) { + switch (name) { case "minecraft:short_grass" -> tallGrassType = "tall"; case "minecraft:fern" -> tallGrassType = "fern"; default -> throw new IllegalStateException("Unexpected value: " + name); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java new file mode 100644 index 000000000..557a38f1f --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java @@ -0,0 +1,436 @@ +package org.geysermc.geyser.registry.populator; + +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.type.GeyserMappingItem; + +import java.util.List; +import java.util.stream.Stream; + +public class Conversion712_685 { + private static final List NEW_STONE_BLOCK_SLABS_2 = List.of("minecraft:prismarine_slab", "minecraft:dark_prismarine_slab", "minecraft:smooth_sandstone_slab", "minecraft:purpur_slab", "minecraft:red_nether_brick_slab", "minecraft:prismarine_brick_slab", "minecraft:mossy_cobblestone_slab", "minecraft:red_sandstone_slab"); + private static final List NEW_STONE_BLOCK_SLABS_3 = List.of("minecraft:smooth_red_sandstone_slab", "minecraft:polished_granite_slab", "minecraft:granite_slab", "minecraft:polished_diorite_slab", "minecraft:andesite_slab", "minecraft:polished_andesite_slab", "minecraft:diorite_slab", "minecraft:end_stone_brick_slab"); + private static final List NEW_STONE_BLOCK_SLABS_4 = List.of("minecraft:smooth_quartz_slab", "minecraft:cut_sandstone_slab", "minecraft:cut_red_sandstone_slab", "minecraft:normal_stone_slab", "minecraft:mossy_stone_brick_slab"); + private static final List NEW_DOUBLE_STONE_BLOCK_SLABS = List.of("minecraft:quartz_double_slab", "minecraft:petrified_oak_double_slab", "minecraft:stone_brick_double_slab", "minecraft:brick_double_slab", "minecraft:sandstone_double_slab", "minecraft:nether_brick_double_slab", "minecraft:cobblestone_double_slab", "minecraft:smooth_stone_double_slab"); + private static final List NEW_DOUBLE_STONE_BLOCK_SLABS_2 = List.of("minecraft:prismarine_double_slab", "minecraft:dark_prismarine_double_slab", "minecraft:smooth_sandstone_double_slab", "minecraft:purpur_double_slab", "minecraft:red_nether_brick_double_slab", "minecraft:prismarine_brick_double_slab", "minecraft:mossy_cobblestone_double_slab", "minecraft:red_sandstone_double_slab"); + private static final List NEW_DOUBLE_STONE_BLOCK_SLABS_3 = List.of("minecraft:smooth_red_sandstone_double_slab", "minecraft:polished_granite_double_slab", "minecraft:granite_double_slab", "minecraft:polished_diorite_double_slab", "minecraft:andesite_double_slab", "minecraft:polished_andesite_double_slab", "minecraft:diorite_double_slab", "minecraft:end_stone_brick_double_slab"); + private static final List NEW_DOUBLE_STONE_BLOCK_SLABS_4 = List.of("minecraft:smooth_quartz_double_slab", "minecraft:cut_sandstone_double_slab", "minecraft:cut_red_sandstone_double_slab", "minecraft:normal_stone_double_slab", "minecraft:mossy_stone_brick_double_slab"); + private static final List NEW_PRISMARINE_BLOCKS = List.of("minecraft:prismarine_bricks", "minecraft:dark_prismarine", "minecraft:prismarine"); + private static final List NEW_CORAL_FAN_HANGS = List.of("minecraft:tube_coral_wall_fan", "minecraft:brain_coral_wall_fan", "minecraft:dead_tube_coral_wall_fan", "minecraft:dead_brain_coral_wall_fan"); + private static final List NEW_CORAL_FAN_HANGS_2 = List.of("minecraft:bubble_coral_wall_fan", "minecraft:fire_coral_wall_fan", "minecraft:dead_bubble_coral_wall_fan", "minecraft:dead_fire_coral_wall_fan"); + private static final List NEW_CORAL_FAN_HANGS_3 = List.of("minecraft:horn_coral_wall_fan", "minecraft:dead_horn_coral_wall_fan"); + private static final List NEW_MONSTER_EGGS = List.of("minecraft:infested_cobblestone", "minecraft:infested_stone_bricks", "minecraft:infested_mossy_stone_bricks", "minecraft:infested_cracked_stone_bricks", "minecraft:infested_chiseled_stone_bricks", "minecraft:infested_stone"); + private static final List NEW_STONEBRICK_BLOCKS = List.of("minecraft:mossy_stone_bricks", "minecraft:cracked_stone_bricks", "minecraft:chiseled_stone_bricks", "minecraft:smooth_stone_bricks", "minecraft:stone_bricks"); + private static final List NEW_LIGHT_BLOCKS = List.of("minecraft:light_block_0", "minecraft:light_block_1", "minecraft:light_block_2", "minecraft:light_block_3", "minecraft:light_block_4", "minecraft:light_block_5", "minecraft:light_block_6", "minecraft:light_block_7", "minecraft:light_block_8", "minecraft:light_block_9", "minecraft:light_block_10", "minecraft:light_block_11", "minecraft:light_block_12", "minecraft:light_block_13", "minecraft:light_block_14", "minecraft:light_block_15"); + private static final List NEW_SANDSTONE_BLOCKS = List.of("minecraft:cut_sandstone", "minecraft:chiseled_sandstone", "minecraft:smooth_sandstone", "minecraft:sandstone"); + private static final List NEW_QUARTZ_BLOCKS = List.of("minecraft:chiseled_quartz_block", "minecraft:quartz_pillar", "minecraft:smooth_quartz", "minecraft:quartz_block"); + private static final List NEW_RED_SANDSTONE_BLOCKS = List.of("minecraft:cut_red_sandstone", "minecraft:chiseled_red_sandstone", "minecraft:smooth_red_sandstone", "minecraft:red_sandstone"); + private static final List NEW_SAND_BLOCKS = List.of("minecraft:red_sand", "minecraft:sand"); + private static final List NEW_DIRT_BLOCKS = List.of("minecraft:coarse_dirt", "minecraft:dirt"); + private static final List NEW_ANVILS = List.of("minecraft:damaged_anvil", "minecraft:chipped_anvil", "minecraft:deprecated_anvil", "minecraft:anvil"); + private static final List NEW_YELLOW_FLOWERS = List.of("minecraft:dandelion"); + private static final List NEW_BLOCKS = Stream.of(NEW_STONE_BLOCK_SLABS_2, NEW_STONE_BLOCK_SLABS_3, NEW_STONE_BLOCK_SLABS_4, NEW_DOUBLE_STONE_BLOCK_SLABS, NEW_DOUBLE_STONE_BLOCK_SLABS_2, NEW_DOUBLE_STONE_BLOCK_SLABS_3, NEW_DOUBLE_STONE_BLOCK_SLABS_4, NEW_PRISMARINE_BLOCKS, NEW_CORAL_FAN_HANGS, NEW_CORAL_FAN_HANGS_2, NEW_CORAL_FAN_HANGS_3, NEW_MONSTER_EGGS, NEW_STONEBRICK_BLOCKS, NEW_LIGHT_BLOCKS, NEW_SANDSTONE_BLOCKS, NEW_QUARTZ_BLOCKS, NEW_RED_SANDSTONE_BLOCKS, NEW_SAND_BLOCKS, NEW_DIRT_BLOCKS, NEW_ANVILS, NEW_YELLOW_FLOWERS).flatMap(List::stream).toList(); + + static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { + String identifer = mapping.getBedrockIdentifier(); + + if (!NEW_BLOCKS.contains(identifer)) { + return mapping; + } + + if (identifer.equals("minecraft:coarse_dirt")) { + return mapping.withBedrockIdentifier("minecraft:dirt").withBedrockData(1); + } + + if (identifer.equals("minecraft:dandelion")) { + return mapping.withBedrockIdentifier("minecraft:yellow_flower").withBedrockData(0); + } + + if (identifer.equals("minecraft:red_sand")) { + return mapping.withBedrockIdentifier("minecraft:sand").withBedrockData(1); + } + + if (NEW_PRISMARINE_BLOCKS.contains(identifer)) { + switch (identifer) { + case "minecraft:prismarine" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(0); } + case "minecraft:dark_prismarine" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(1); } + case "minecraft:prismarine_bricks" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(2); } + } + } + + if (NEW_SANDSTONE_BLOCKS.contains(identifer)) { + switch (identifer) { + case "minecraft:sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(0); } + case "minecraft:chiseled_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(1); } + case "minecraft:cut_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(2); } + case "minecraft:smooth_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(3); } + } + } + + if (NEW_RED_SANDSTONE_BLOCKS.contains(identifer)) { + switch (identifer) { + case "minecraft:red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(0); } + case "minecraft:chiseled_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(1); } + case "minecraft:cut_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(2); } + case "minecraft:smooth_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(3); } + } + } + + if (NEW_QUARTZ_BLOCKS.contains(identifer)) { + switch (identifer) { + case "minecraft:quartz_block" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(0); } + case "minecraft:chiseled_quartz_block" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(1); } + case "minecraft:quartz_pillar" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(2); } + case "minecraft:smooth_quartz" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(3); } + } + } + + if (NEW_STONE_BLOCK_SLABS_2.contains(identifer)) { + switch (identifer) { + case "minecraft:red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(0); } + case "minecraft:purpur_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(1); } + case "minecraft:prismarine_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(2); } + case "minecraft:dark_prismarine_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(3); } + case "minecraft:prismarine_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(4); } + case "minecraft:mossy_cobblestone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(5); } + case "minecraft:smooth_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(6); } + case "minecraft:red_nether_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(7); } + } + } + + if (NEW_STONE_BLOCK_SLABS_3.contains(identifer)) { + switch (identifer) { + case "minecraft:end_stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(0); } + case "minecraft:smooth_red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(1); } + case "minecraft:polished_andesite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(2); } + case "minecraft:andesite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(3); } + case "minecraft:diorite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(4); } + case "minecraft:polished_diorite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(5); } + case "minecraft:granite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(6); } + case "minecraft:polished_granite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(7); } + } + } + + if (NEW_STONE_BLOCK_SLABS_4.contains(identifer)) { + switch (identifer) { + case "minecraft:mossy_stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(0); } + case "minecraft:smooth_quartz_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(1); } + case "minecraft:normal_stone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(2); } + case "minecraft:cut_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(3); } + case "minecraft:cut_red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(4); } + } + } + + if (NEW_MONSTER_EGGS.contains(identifer)) { + switch (identifer) { + case "minecraft:infested_stone" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(0); } + case "minecraft:infested_cobblestone" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(1); } + case "minecraft:infested_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(2); } + case "minecraft:infested_mossy_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(3); } + case "minecraft:infested_cracked_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(4); } + case "minecraft:infested_chiseled_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(5); } + } + } + + if (NEW_STONEBRICK_BLOCKS.contains(identifer)) { + switch (identifer) { + case "minecraft:stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(0); } + case "minecraft:mossy_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(1); } + case "minecraft:cracked_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(2); } + case "minecraft:chiseled_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(3); } + } + } + + if (NEW_ANVILS.contains(identifer)) { + switch (identifer) { + case "minecraft:anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(0); } + case "minecraft:chipped_anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(4); } + case "minecraft:damaged_anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(8); } + } + } + + return mapping; + } + + static NbtMap remapBlock(NbtMap tag) { + final String name = tag.getString("name"); + + if (!NEW_BLOCKS.contains(name)) { + return tag; + } + + String replacement; + + if (NEW_DOUBLE_STONE_BLOCK_SLABS.contains(name)) { + replacement = "minecraft:double_stone_block_slab"; + String stoneSlabType; + + switch (name) { + case "minecraft:quartz_double_slab" -> stoneSlabType = "quartz"; + case "minecraft:petrified_oak_double_slab" -> stoneSlabType = "wood"; + case "minecraft:stone_brick_double_slab" -> stoneSlabType = "stone_brick"; + case "minecraft:brick_double_slab" -> stoneSlabType = "brick"; + case "minecraft:sandstone_double_slab" -> stoneSlabType = "sandstone"; + case "minecraft:nether_brick_double_slab" -> stoneSlabType = "nether_brick"; + case "minecraft:cobblestone_double_slab" -> stoneSlabType = "cobblestone"; + case "minecraft:smooth_stone_double_slab" -> stoneSlabType = "smooth_stone"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("stone_slab_type", stoneSlabType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_STONE_BLOCK_SLABS_2.contains(name) || NEW_DOUBLE_STONE_BLOCK_SLABS_2.contains(name)) { + replacement = NEW_STONE_BLOCK_SLABS_2.contains(name) ? "minecraft:stone_block_slab2" : "minecraft:double_stone_block_slab2"; + String stoneSlabType2; + + switch (name) { + case "minecraft:prismarine_slab", "minecraft:prismarine_double_slab" -> stoneSlabType2 = "prismarine_rough"; + case "minecraft:dark_prismarine_slab", "minecraft:dark_prismarine_double_slab" -> stoneSlabType2 = "prismarine_dark"; + case "minecraft:smooth_sandstone_slab", "minecraft:smooth_sandstone_double_slab" -> stoneSlabType2 = "smooth_sandstone"; + case "minecraft:purpur_slab", "minecraft:purpur_double_slab" -> stoneSlabType2 = "purpur"; + case "minecraft:red_nether_brick_slab", "minecraft:red_nether_brick_double_slab" -> stoneSlabType2 = "red_nether_brick"; + case "minecraft:prismarine_brick_slab", "minecraft:prismarine_brick_double_slab" -> stoneSlabType2 = "prismarine_brick"; + case "minecraft:mossy_cobblestone_slab", "minecraft:mossy_cobblestone_double_slab" -> stoneSlabType2 = "mossy_cobblestone"; + case "minecraft:red_sandstone_slab", "minecraft:red_sandstone_double_slab" -> stoneSlabType2 = "red_sandstone"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("stone_slab_type_2", stoneSlabType2) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_STONE_BLOCK_SLABS_3.contains(name) || NEW_DOUBLE_STONE_BLOCK_SLABS_3.contains(name)) { + replacement = NEW_STONE_BLOCK_SLABS_3.contains(name) ? "minecraft:stone_block_slab3" : "minecraft:double_stone_block_slab3"; + String stoneSlabType3; + + switch (name) { + case "minecraft:smooth_red_sandstone_slab", "minecraft:smooth_red_sandstone_double_slab" -> stoneSlabType3 = "smooth_red_sandstone"; + case "minecraft:polished_granite_slab", "minecraft:polished_granite_double_slab" -> stoneSlabType3 = "polished_granite"; + case "minecraft:granite_slab", "minecraft:granite_double_slab" -> stoneSlabType3 = "granite"; + case "minecraft:polished_diorite_slab", "minecraft:polished_diorite_double_slab" -> stoneSlabType3 = "polished_diorite"; + case "minecraft:andesite_slab", "minecraft:andesite_double_slab" -> stoneSlabType3 = "andesite"; + case "minecraft:polished_andesite_slab", "minecraft:polished_andesite_double_slab" -> stoneSlabType3 = "polished_andesite"; + case "minecraft:diorite_slab", "minecraft:diorite_double_slab" -> stoneSlabType3 = "diorite"; + case "minecraft:end_stone_brick_slab", "minecraft:end_stone_brick_double_slab" -> stoneSlabType3 = "end_stone_brick"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("stone_slab_type_3", stoneSlabType3) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_STONE_BLOCK_SLABS_4.contains(name) || NEW_DOUBLE_STONE_BLOCK_SLABS_4.contains(name)) { + replacement = NEW_STONE_BLOCK_SLABS_4.contains(name) ? "minecraft:stone_block_slab4" : "minecraft:double_stone_block_slab4"; + String stoneSlabType4; + + switch (name) { + case "minecraft:smooth_quartz_slab", "minecraft:smooth_quartz_double_slab" -> stoneSlabType4 = "smooth_quartz"; + case "minecraft:cut_sandstone_slab", "minecraft:cut_sandstone_double_slab" -> stoneSlabType4 = "cut_sandstone"; + case "minecraft:cut_red_sandstone_slab", "minecraft:cut_red_sandstone_double_slab" -> stoneSlabType4 = "cut_red_sandstone"; + case "minecraft:normal_stone_slab", "minecraft:normal_stone_double_slab" -> stoneSlabType4 = "stone"; + case "minecraft:mossy_stone_brick_slab", "minecraft:mossy_stone_brick_double_slab" -> stoneSlabType4 = "mossy_stone_brick"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("stone_slab_type_4", stoneSlabType4) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_PRISMARINE_BLOCKS.contains(name)) { + replacement = "minecraft:prismarine"; + String prismarineBlockType; + + switch (name) { + case "minecraft:prismarine_bricks" -> prismarineBlockType = "bricks"; + case "minecraft:dark_prismarine" -> prismarineBlockType = "dark"; + case "minecraft:prismarine" -> prismarineBlockType = "default"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("prismarine_block_type", prismarineBlockType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_CORAL_FAN_HANGS.contains(name) || NEW_CORAL_FAN_HANGS_2.contains(name) || NEW_CORAL_FAN_HANGS_3.contains(name)) { + replacement = NEW_CORAL_FAN_HANGS.contains(name) ? "minecraft:coral_fan_hang" : NEW_CORAL_FAN_HANGS_2.contains(name) ? "minecraft:coral_fan_hang2" : "minecraft:coral_fan_hang3"; + boolean deadBit = name.startsWith("minecraft:dead_"); + boolean coralHangTypeBit = name.contains("brain") || name.contains("fire"); + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putBoolean("coral_hang_type_bit", coralHangTypeBit) + .putBoolean("dead_bit", deadBit) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_MONSTER_EGGS.contains(name)) { + replacement = "minecraft:monster_egg"; + String monsterEggStoneType; + + switch (name) { + case "minecraft:infested_cobblestone" -> monsterEggStoneType = "cobblestone"; + case "minecraft:infested_stone_bricks" -> monsterEggStoneType = "stone_brick"; + case "minecraft:infested_mossy_stone_bricks" -> monsterEggStoneType = "mossy_stone_brick"; + case "minecraft:infested_cracked_stone_bricks" -> monsterEggStoneType = "cracked_stone_brick"; + case "minecraft:infested_chiseled_stone_bricks" -> monsterEggStoneType = "chiseled_stone_brick"; + case "minecraft:infested_stone" -> monsterEggStoneType = "stone"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("monster_egg_stone_type", monsterEggStoneType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_STONEBRICK_BLOCKS.contains(name)) { + replacement = "minecraft:stonebrick"; + String stoneBrickType; + + switch (name) { + case "minecraft:mossy_stone_bricks" -> stoneBrickType = "mossy"; + case "minecraft:cracked_stone_bricks" -> stoneBrickType = "cracked"; + case "minecraft:chiseled_stone_bricks" -> stoneBrickType = "chiseled"; + case "minecraft:smooth_stone_bricks" -> stoneBrickType = "smooth"; + case "minecraft:stone_bricks" -> stoneBrickType = "default"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("stone_brick_type", stoneBrickType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_LIGHT_BLOCKS.contains(name)) { + replacement = "minecraft:light_block"; + int blockLightLevel = Integer.parseInt(name.split("_")[2]); + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putInt("block_light_level", blockLightLevel) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_SANDSTONE_BLOCKS.contains(name) || NEW_RED_SANDSTONE_BLOCKS.contains(name)) { + replacement = NEW_SANDSTONE_BLOCKS.contains(name) ? "minecraft:sandstone" : "minecraft:red_sandstone"; + String sandStoneType; + + switch (name) { + case "minecraft:cut_sandstone", "minecraft:cut_red_sandstone" -> sandStoneType = "cut"; + case "minecraft:chiseled_sandstone", "minecraft:chiseled_red_sandstone" -> sandStoneType = "heiroglyphs"; + case "minecraft:smooth_sandstone", "minecraft:smooth_red_sandstone" -> sandStoneType = "smooth"; + case "minecraft:sandstone", "minecraft:red_sandstone" -> sandStoneType = "default"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("sand_stone_type", sandStoneType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_QUARTZ_BLOCKS.contains(name)) { + replacement = "minecraft:quartz_block"; + String chiselType; + + switch (name) { + case "minecraft:chiseled_quartz_block" -> chiselType = "chiseled"; + case "minecraft:quartz_pillar" -> chiselType = "lines"; + case "minecraft:smooth_quartz" -> chiselType = "smooth"; + case "minecraft:quartz_block" -> chiselType = "default"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("chisel_type", chiselType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_SAND_BLOCKS.contains(name)) { + replacement = "minecraft:sand"; + String sandType = name.equals("minecraft:red_sand") ? "red" : "normal"; + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("sand_type", sandType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_DIRT_BLOCKS.contains(name)) { + replacement = "minecraft:dirt"; + String dirtType = name.equals("minecraft:coarse_dirt") ? "coarse" : "normal"; + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("dirt_type", dirtType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_ANVILS.contains(name)) { + replacement = "minecraft:anvil"; + String damage; + + switch (name) { + case "minecraft:damaged_anvil" -> damage = "broken"; + case "minecraft:chipped_anvil" -> damage = "slightly_damaged"; + case "minecraft:deprecated_anvil" -> damage = "very_damaged"; + case "minecraft:anvil" -> damage = "undamaged"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("damage", damage) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_YELLOW_FLOWERS.contains(name)) { + replacement = "minecraft:yellow_flower"; + return tag.toBuilder().putString("name", replacement).build(); + } + + return tag; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 2c97fe13c..f11b58bfe 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -41,6 +41,7 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtUtils; 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.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; @@ -90,7 +91,8 @@ public class ItemRegistryPopulator { public static void populate() { 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())); + 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())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); 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 4c426b410..ce1022936 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 @@ -894,11 +894,11 @@ public abstract class InventoryTranslator { List containerEntries = new ArrayList<>(); for (Map.Entry> entry : containerMap.entrySet()) { - containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue())); + containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue(), null)); } ItemStackResponseSlot cursorEntry = makeItemEntry(0, session.getPlayerInventory().getCursor()); - containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry))); + containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry), null)); return containerEntries; } diff --git a/core/src/main/resources/bedrock/biome_definitions.dat b/core/src/main/resources/bedrock/biome_definitions.dat index dfee570e48866c87a60fce4f93041093f7696468..3ae94a5c85c6f13d4de2feb8a5d24d2ab2f11efe 100644 GIT binary patch delta 283 zcmX?elC?gS)l wVXngD*bKkT)0^f?g3Op~DLMIErtsu-bCo7@&ljA`Yb!XJr%`9~mpLVD0G@a}7ytkO diff --git a/core/src/main/resources/bedrock/block_palette.1_21_20.nbt b/core/src/main/resources/bedrock/block_palette.1_21_20.nbt new file mode 100644 index 0000000000000000000000000000000000000000..521ea3cc6fdded8adda60e2a1ad1ff35ab826dc5 GIT binary patch literal 178977 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�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 q0AJ1OG*VR}TG|eCk Date: Mon, 29 Jul 2024 00:17:56 -0700 Subject: [PATCH 312/897] Indicate 1.21.20 support Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07f3df5aa..ecf991cdb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,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! -### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.3 and Minecraft Java 1.21 +### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.20 and Minecraft Java 1.21 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. From efe2736635b523564fa961ebbf3ae17011c3a8a4 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 30 Jul 2024 10:26:02 +0200 Subject: [PATCH 313/897] Fix: Piston listener on Fabric/NeoForge (#4899) * Fix: Sticky pistons not retracting on Geyser-Spigot/turning visually into normal pistons on all other platforms * Initial attempt: Mod piston listener * fix piston retracting --- bootstrap/mod/build.gradle.kts | 3 +- .../mixin/server/PistonBaseBlockMixin.java | 127 ++++++++++++++++++ .../mod/src/main/resources/geyser.mixins.json | 1 + .../populator/BlockRegistryPopulator.java | 2 +- .../level/block/entity/PistonBlockEntity.java | 5 +- .../java/level/JavaBlockEventTranslator.java | 20 ++- gradle/libs.versions.toml | 2 + 7 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/PistonBaseBlockMixin.java diff --git a/bootstrap/mod/build.gradle.kts b/bootstrap/mod/build.gradle.kts index 32224d00b..57f11b2c7 100644 --- a/bootstrap/mod/build.gradle.kts +++ b/bootstrap/mod/build.gradle.kts @@ -16,7 +16,8 @@ afterEvaluate { dependencies { api(projects.core) compileOnly(libs.mixin) + compileOnly(libs.mixinextras) // Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE! compileOnly(libs.fabric.loader) -} \ No newline at end of file +} diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/PistonBaseBlockMixin.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/PistonBaseBlockMixin.java new file mode 100644 index 000000000..6ac51ba52 --- /dev/null +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/PistonBaseBlockMixin.java @@ -0,0 +1,127 @@ +/* + * 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.platform.mod.mixin.server; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.piston.PistonBaseBlock; +import net.minecraft.world.level.block.state.BlockState; +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.PistonCache; +import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Mixin(PistonBaseBlock.class) +public class PistonBaseBlockMixin { + + @Shadow + @Final + private boolean isSticky; + + @ModifyExpressionValue(method = "moveBlocks", + at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;") + ) + private HashMap geyser$onMapCreate(HashMap original, @Share("pushBlocks") LocalRef> localRef) { + localRef.set(original); + return original; + } + + @Inject(method = "moveBlocks", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/piston/PistonStructureResolver;getToDestroy()Ljava/util/List;") + ) + private void geyser$onBlocksMove(Level level, BlockPos blockPos, Direction direction, boolean isExtending, CallbackInfoReturnable cir, @Share("pushBlocks") LocalRef> localRef) { + PistonValueType type = isExtending ? PistonValueType.PUSHING : PistonValueType.PULLING; + boolean sticky = this.isSticky; + + Object2ObjectMap attachedBlocks = new Object2ObjectArrayMap<>(); + boolean blocksFilled = false; + + for (Map.Entry entry : GeyserImpl.getInstance().getSessionManager().getSessions().entrySet()) { + Player player = level.getPlayerByUUID(entry.getKey()); + //noinspection resource + if (player == null || !player.level().equals(level)) { + continue; + } + GeyserSession session = entry.getValue(); + + int dX = Math.abs(blockPos.getX() - player.getBlockX()) >> 4; + int dZ = Math.abs(blockPos.getZ() - player.getBlockZ()) >> 4; + if ((dX * dX + dZ * dZ) > session.getServerRenderDistance() * session.getServerRenderDistance()) { + // Ignore pistons outside the player's render distance + continue; + } + + // Trying to grab the blocks from the world like other platforms would result in the moving piston block + // being returned instead. + if (!blocksFilled) { + Map blocks = localRef.get(); + for (Map.Entry blockStateEntry : blocks.entrySet()) { + int blockStateId = Block.BLOCK_STATE_REGISTRY.getId(blockStateEntry.getValue()); + org.geysermc.geyser.level.block.type.BlockState state = org.geysermc.geyser.level.block.type.BlockState.of(blockStateId); + attachedBlocks.put(geyser$fromBlockPos(blockStateEntry.getKey()), state); + } + blocksFilled = true; + } + + org.geysermc.geyser.level.physics.Direction orientation = org.geysermc.geyser.level.physics.Direction.VALUES[direction.ordinal()]; + + Vector3i position = geyser$fromBlockPos(blockPos); + session.executeInEventLoop(() -> { + PistonCache pistonCache = session.getPistonCache(); + PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> + new PistonBlockEntity(session, position, orientation, sticky, !isExtending)); + blockEntity.setAction(type, attachedBlocks); + }); + } + } + + @Unique + private static Vector3i geyser$fromBlockPos(BlockPos pos) { + return Vector3i.from(pos.getX(), pos.getY(), pos.getZ()); + } + +} diff --git a/bootstrap/mod/src/main/resources/geyser.mixins.json b/bootstrap/mod/src/main/resources/geyser.mixins.json index 2576e1ce6..e820e654d 100644 --- a/bootstrap/mod/src/main/resources/geyser.mixins.json +++ b/bootstrap/mod/src/main/resources/geyser.mixins.json @@ -5,6 +5,7 @@ "compatibilityLevel": "JAVA_17", "mixins": [ "server.BlockPlaceMixin", + "server.PistonBaseBlockMixin", "server.ServerConnectionListenerMixin" ], "server": [ diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index d7dc989da..f539e52ec 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -129,7 +129,7 @@ public final class BlockRegistryPopulator { NbtMapBuilder builder = vanillaBlockStates.get(i).toBuilder(); builder.remove("version"); // Remove all nbt tags which are not needed for differentiating states builder.remove("name_hash"); // Quick workaround - was added in 1.19.20 - builder.remove("network_id"); // Added in 1.19.80 - ???? + builder.remove("network_id"); // Added in 1.19.80 builder.remove("block_id"); // Added in 1.20.60 //noinspection UnstableApiUsage builder.putCompound("states", statesInterner.intern((NbtMap) builder.remove("states"))); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index 350ce8c3e..d1dd24855 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -37,7 +37,6 @@ import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.Properties; @@ -230,8 +229,8 @@ public class PistonBlockEntity { BlockState state = session.getGeyser().getWorldManager().blockAt(session, blockInFront); if (state.is(Blocks.PISTON_HEAD)) { ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront); - } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && state.is(Blocks.AIR)) { - // Spigot removes the piston head from the cache, but we need to send the block update ourselves + } else if ((session.getGeyser().getWorldManager().hasOwnChunkCache() || session.getErosionHandler().isActive()) && state.is(Blocks.AIR)) { + // The platform removes the piston head from the cache, but we need to send the block update ourselves ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java index ff861530a..c94468c17 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java @@ -82,16 +82,22 @@ public class JavaBlockEventTranslator extends PacketTranslator new PistonBlockEntity(session, pos, direction, true, true)); + PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> new PistonBlockEntity(session, pos, direction, isSticky, true)); if (blockEntity.getAction() != action) { blockEntity.setAction(action, Object2ObjectMaps.emptyMap()); } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 58b5310ac..e50756ef1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,6 +33,7 @@ fabric-api = "0.100.1+1.21" fabric-permissions = "0.2-SNAPSHOT" neoforge-minecraft = "21.0.0-beta" mixin = "0.8.5" +mixinextras = "0.3.5" minecraft = "1.21" # plugin versions @@ -89,6 +90,7 @@ folia-api = { group = "dev.folia", name = "folia-api", version.ref = "folia" } paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "folia" } mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" } +mixinextras = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinextras" } minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" } From ca0f3775a22d39617f8d9a32b983c0d187ead8ea Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 30 Jul 2024 13:49:42 +0100 Subject: [PATCH 314/897] Update links in README (#4917) * Update links in README * Update README.md * Update README.md --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 07f3df5aa..8eac49a24 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,15 @@ 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! -### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.3 and Minecraft Java 1.21 +## Supported Versions +Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.3 and Minecraft Java Server 1.21. For more info please see [here](https://geysermc.org/wiki/geyser/supported-versions/). ## Setting Up -Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. - -[![YouTube Video](https://img.youtube.com/vi/U7dZZ8w7Gi4/0.jpg)](https://www.youtube.com/watch?v=U7dZZ8w7Gi4) +Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser. ## Links: - Website: https://geysermc.org -- Docs: https://wiki.geysermc.org/geyser/ +- Docs: https://geysermc.org/wiki/geyser/ - Download: https://geysermc.org/download - Discord: https://discord.gg/geysermc - Donate: https://opencollective.com/geysermc @@ -34,7 +33,7 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge - Some Entity Flags ## What can't be fixed -There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page. +There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://geysermc.org/wiki/geyser/current-limitations/) page. ## Compiling 1. Clone the repo to your computer @@ -47,7 +46,7 @@ you're interested in helping out with Geyser. ## Libraries Used: - [Adventure Text Library](https://github.com/KyoriPowered/adventure) -- [NukkitX Bedrock Protocol Library](https://github.com/NukkitX/Protocol) -- [Steveice10's Java Protocol Library](https://github.com/Steveice10/MCProtocolLib) +- [CloudburstMC Bedrock Protocol Library](https://github.com/CloudburstMC/Protocol) +- [GeyserMC's Java Protocol Library](https://github.com/GeyserMC/MCProtocolLib) - [TerminalConsoleAppender](https://github.com/Minecrell/TerminalConsoleAppender) - [Simple Logging Facade for Java (slf4j)](https://github.com/qos-ch/slf4j) From 13dfc7c173550c49ff6070176f8d0c4f3d270c8a Mon Sep 17 00:00:00 2001 From: rtm516 Date: Wed, 31 Jul 2024 01:06:26 +0100 Subject: [PATCH 315/897] Allow commands with xbox achievements enabled (#4894) * Allow commands with xbox achievements enabled * Don't enable by default * Add null check to paramData * Update comment --- .../translator/protocol/java/JavaCommandsTranslator.java | 6 +++--- core/src/main/resources/config.yml | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index ecfb2d220..c0e3f5716 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -169,8 +169,8 @@ public class JavaCommandsTranslator extends PacketTranslator flags = Set.of(); + // The command flags, set to NOT_CHEAT so known commands can be used while achievements are enabled. + Set flags = Set.of(CommandData.Flag.NOT_CHEAT); // Loop through all the found commands for (Map.Entry> entry : commands.entrySet()) { @@ -449,7 +449,7 @@ public class JavaCommandsTranslator extends PacketTranslator Date: Wed, 31 Jul 2024 19:21:29 +0200 Subject: [PATCH 316/897] Fix: Geyser-NeoForge not booting due to duplicate module (#4922) --- bootstrap/mod/fabric/build.gradle.kts | 5 +---- bootstrap/mod/neoforge/build.gradle.kts | 3 ++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index 0d083fcf7..9215c575e 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -25,10 +25,7 @@ dependencies { shadow(libs.protocol.connection) { isTransitive = false } shadow(libs.protocol.common) { isTransitive = false } shadow(libs.protocol.codec) { isTransitive = false } - shadow(libs.minecraftauth) { isTransitive = false } shadow(libs.raknet) { isTransitive = false } - - // Consequences of shading + relocating mcauthlib: shadow/relocate mcpl! shadow(libs.mcprotocollib) { isTransitive = false } // Since we also relocate cloudburst protocol: shade erosion common @@ -67,4 +64,4 @@ modrinth { dependencies { required.project("fabric-api") } -} \ No newline at end of file +} diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts index e0e7c2dfa..741e2fd11 100644 --- a/bootstrap/mod/neoforge/build.gradle.kts +++ b/bootstrap/mod/neoforge/build.gradle.kts @@ -5,6 +5,7 @@ plugins { // This is provided by "org.cloudburstmc.math.mutable" too, so yeet. // NeoForge's class loader is *really* annoying. provided("org.cloudburstmc.math", "api") +provided("com.google.errorprone", "error_prone_annotations") architectury { platformSetupLoomIde() @@ -56,4 +57,4 @@ tasks { modrinth { loaders.add("neoforge") uploadFile.set(tasks.getByPath("remapModrinthJar")) -} \ No newline at end of file +} From 6002c9c7a167df137fb802bbbe7a38bc84de7fdb Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 31 Jul 2024 21:22:22 +0200 Subject: [PATCH 317/897] Only add a tag to the bedrock item if it is needed (#4925) --- .../java/JavaUpdateRecipesTranslator.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 7c36c505b..689e0448a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -49,6 +49,8 @@ import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.recipe.TrimRecipe; +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; @@ -443,13 +445,18 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator translateShulkerBoxRecipe(GeyserShapelessRecipe recipe) { - ItemData output = ItemTranslator.translateToBedrock(session, recipe.result()); + 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; } - // Strip NBT - tools won't appear in the recipe book otherwise - // output = output.toBuilder().tag(null).build(); // TODO confirm??? + + 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; @@ -467,13 +474,18 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator translateShapelessRecipe(GeyserShapelessRecipe recipe) { - ItemData output = ItemTranslator.translateToBedrock(session, recipe.result()); + 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; } - // Strip NBT - tools won't appear in the recipe book otherwise - //output = output.toBuilder().tag(null).build(); // TODO confirm this is still true??? + + 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; @@ -491,13 +503,18 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator translateShapedRecipe(GeyserShapedRecipe recipe) { - ItemData output = ItemTranslator.translateToBedrock(session, recipe.result()); + 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; } - // See above - //output = output.toBuilder().tag(null).build(); + + 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; From 87ab51cb28f059dc815be0c9804346d4d88535d8 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 11 Jul 2024 23:56:42 -0500 Subject: [PATCH 318/897] Cloud for commands (#3808) Co-authored-by: onebeastchris --- .../geysermc/geyser/api/command/Command.java | 133 ++++--- .../geyser/api/command/CommandSource.java | 15 + .../lifecycle/GeyserDefineCommandsEvent.java | 2 +- ...GeyserRegisterPermissionCheckersEvent.java | 42 +++ .../GeyserRegisterPermissionsEvent.java | 51 +++ .../geyser/api/extension/Extension.java | 9 + .../api/permission/PermissionChecker.java | 49 +++ bootstrap/bungeecord/build.gradle.kts | 8 +- .../bungeecord/GeyserBungeePlugin.java | 56 +-- .../GeyserBungeeUpdateListener.java | 4 +- .../command/BungeeCommandSource.java | 25 +- .../command/GeyserBungeeCommandExecutor.java | 89 ----- bootstrap/mod/fabric/build.gradle.kts | 13 +- .../fabric/GeyserFabricBootstrap.java | 33 +- bootstrap/mod/neoforge/build.gradle.kts | 11 +- .../neoforge/GeyserNeoForgeBootstrap.java | 50 ++- .../GeyserNeoForgeCommandRegistry.java | 101 ++++++ .../GeyserNeoForgePermissionHandler.java | 149 -------- .../platform/neoforge/PermissionUtils.java | 79 +++++ .../neoforge/mixin/PermissionNodeMixin.java | 48 +++ .../resources/META-INF/neoforge.mods.toml | 2 + .../resources/geyser_neoforge.mixins.json | 12 + .../platform/mod/GeyserModBootstrap.java | 75 +--- .../platform/mod/GeyserModUpdateListener.java | 13 +- .../mod/command/GeyserModCommandExecutor.java | 75 ---- ...mmandSender.java => ModCommandSource.java} | 26 +- .../mod/world/GeyserModWorldManager.java | 7 - bootstrap/spigot/build.gradle.kts | 8 +- .../platform/spigot/GeyserSpigotPlugin.java | 172 ++++----- .../spigot/GeyserSpigotUpdateListener.java | 4 +- .../command/GeyserBrigadierSupport.java | 61 ---- .../command/GeyserPaperCommandListener.java | 87 ----- .../command/GeyserSpigotCommandExecutor.java | 88 ----- ...anager.java => SpigotCommandRegistry.java} | 45 ++- .../spigot/command/SpigotCommandSource.java | 26 +- .../manager/GeyserSpigotWorldManager.java | 9 - .../spigot/src/main/resources/plugin.yml | 8 - bootstrap/standalone/build.gradle.kts | 4 + .../standalone/GeyserStandaloneBootstrap.java | 29 +- .../standalone/GeyserStandaloneLogger.java | 4 +- .../standalone/gui/GeyserStandaloneGUI.java | 20 +- bootstrap/velocity/build.gradle.kts | 9 +- .../velocity/GeyserVelocityPlugin.java | 62 ++-- .../GeyserVelocityUpdateListener.java | 4 +- .../GeyserVelocityCommandExecutor.java | 83 ----- .../command/VelocityCommandSource.java | 18 +- bootstrap/viaproxy/build.gradle.kts | 6 +- .../viaproxy/GeyserViaProxyPlugin.java | 35 +- .../geyser.modded-conventions.gradle.kts | 6 +- .../geyser.platform-conventions.gradle.kts | 1 - core/build.gradle.kts | 3 + .../java/org/geysermc/geyser/Constants.java | 2 - .../org/geysermc/geyser/GeyserBootstrap.java | 8 +- .../java/org/geysermc/geyser/GeyserImpl.java | 19 +- .../org/geysermc/geyser/GeyserLogger.java | 6 + .../java/org/geysermc/geyser/Permissions.java | 63 ++++ .../geyser/command/CommandRegistry.java | 300 ++++++++++++++++ .../command/CommandSourceConverter.java | 113 ++++++ .../geyser/command/ExceptionHandlers.java | 129 +++++++ .../geyser/command/GeyserCommand.java | 204 ++++++++--- .../geyser/command/GeyserCommandExecutor.java | 98 ------ .../geyser/command/GeyserCommandManager.java | 330 ------------------ .../geyser/command/GeyserCommandSource.java | 30 ++ .../geyser/command/GeyserPermission.java | 136 ++++++++ .../defaults/AdvancedTooltipsCommand.java | 33 +- .../command/defaults/AdvancementsCommand.java | 24 +- .../defaults/ConnectionTestCommand.java | 117 +++---- .../geyser/command/defaults/DumpCommand.java | 84 +++-- .../command/defaults/ExtensionsCommand.java | 17 +- .../geyser/command/defaults/HelpCommand.java | 76 ++-- .../geyser/command/defaults/ListCommand.java | 20 +- .../command/defaults/OffhandCommand.java | 26 +- .../command/defaults/ReloadCommand.java | 22 +- .../command/defaults/SettingsCommand.java | 27 +- .../command/defaults/StatisticsCommand.java | 27 +- .../geyser/command/defaults/StopCommand.java | 22 +- .../command/defaults/VersionCommand.java | 34 +- .../standalone/PermissionConfiguration.java | 42 +++ .../StandaloneCloudCommandManager.java | 126 +++++++ .../type/GeyserDefineCommandsEventImpl.java | 6 +- .../command/GeyserExtensionCommand.java | 195 ++++++++++- .../geyser/level/GeyserWorldManager.java | 5 - .../geysermc/geyser/level/WorldManager.java | 9 - .../loader/ProviderRegistryLoader.java | 4 +- .../geyser/session/GeyserSession.java | 28 +- .../BedrockCommandRequestTranslator.java | 26 +- .../BedrockSetDefaultGameTypeTranslator.java | 3 +- .../BedrockSetDifficultyTranslator.java | 3 +- .../BedrockSetPlayerGameTypeTranslator.java | 3 +- .../protocol/java/JavaCommandsTranslator.java | 10 +- .../org/geysermc/geyser/util/FileUtils.java | 12 + .../geysermc/geyser/util/SettingsUtils.java | 3 +- core/src/main/resources/languages | 2 +- core/src/main/resources/permissions.yml | 9 + gradle/libs.versions.toml | 13 +- 95 files changed, 2556 insertions(+), 1879 deletions(-) create mode 100644 api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionCheckersEvent.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionsEvent.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/permission/PermissionChecker.java delete mode 100644 bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java create mode 100644 bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeCommandRegistry.java delete mode 100644 bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java create mode 100644 bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/PermissionUtils.java create mode 100644 bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/mixin/PermissionNodeMixin.java create mode 100644 bootstrap/mod/neoforge/src/main/resources/geyser_neoforge.mixins.json delete mode 100644 bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/GeyserModCommandExecutor.java rename bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/{ModCommandSender.java => ModCommandSource.java} (77%) delete mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserBrigadierSupport.java delete mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserPaperCommandListener.java delete mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java rename bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/{GeyserSpigotCommandManager.java => SpigotCommandRegistry.java} (61%) delete mode 100644 bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java create mode 100644 core/src/main/java/org/geysermc/geyser/Permissions.java create mode 100644 core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/command/CommandSourceConverter.java create mode 100644 core/src/main/java/org/geysermc/geyser/command/ExceptionHandlers.java delete mode 100644 core/src/main/java/org/geysermc/geyser/command/GeyserCommandExecutor.java delete mode 100644 core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java create mode 100644 core/src/main/java/org/geysermc/geyser/command/GeyserPermission.java create mode 100644 core/src/main/java/org/geysermc/geyser/command/standalone/PermissionConfiguration.java create mode 100644 core/src/main/java/org/geysermc/geyser/command/standalone/StandaloneCloudCommandManager.java create mode 100644 core/src/main/resources/permissions.yml diff --git a/api/src/main/java/org/geysermc/geyser/api/command/Command.java b/api/src/main/java/org/geysermc/geyser/api/command/Command.java index 2f1f2b24d..29922ae1e 100644 --- a/api/src/main/java/org/geysermc/geyser/api/command/Command.java +++ b/api/src/main/java/org/geysermc/geyser/api/command/Command.java @@ -28,7 +28,9 @@ package org.geysermc.geyser.api.command; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.api.util.TriState; import java.util.Collections; import java.util.List; @@ -58,15 +60,15 @@ public interface Command { * Gets the permission node associated with * this command. * - * @return the permission node for this command + * @return the permission node for this command if defined, otherwise an empty string */ @NonNull String permission(); /** - * Gets the aliases for this command. + * Gets the aliases for this command, as an unmodifiable list * - * @return the aliases for this command + * @return the aliases for this command as an unmodifiable list */ @NonNull List aliases(); @@ -75,35 +77,39 @@ public interface Command { * Gets if this command is designed to be used only by server operators. * * @return if this command is designated to be used only by server operators. + * @deprecated this method is not guaranteed to provide meaningful or expected results. */ - boolean isSuggestedOpOnly(); - - /** - * Gets if this command is executable on console. - * - * @return if this command is executable on console - */ - boolean isExecutableOnConsole(); - - /** - * Gets the subcommands associated with this - * command. Mainly used within the Geyser Standalone - * GUI to know what subcommands are supported. - * - * @return the subcommands associated with this command - */ - @NonNull - default List subCommands() { - return Collections.emptyList(); + @Deprecated(forRemoval = true) + default boolean isSuggestedOpOnly() { + return false; } /** - * Used to send a deny message to Java players if this command can only be used by Bedrock players. - * - * @return true if this command can only be used by Bedrock players. + * @return true if this command is executable on console + * @deprecated use {@link #isPlayerOnly()} instead (inverted) */ - default boolean isBedrockOnly() { - return false; + @Deprecated(forRemoval = true) + default boolean isExecutableOnConsole() { + return !isPlayerOnly(); + } + + /** + * @return true if this command can only be used by players + */ + boolean isPlayerOnly(); + + /** + * @return true if this command can only be used by Bedrock players + */ + boolean isBedrockOnly(); + + /** + * @deprecated this method will always return an empty immutable list + */ + @Deprecated(forRemoval = true) + @NonNull + default List subCommands() { + return Collections.emptyList(); } /** @@ -128,7 +134,7 @@ public interface Command { * is an instance of this source. * * @param sourceType the source type - * @return the builder + * @return this builder */ Builder source(@NonNull Class sourceType); @@ -136,7 +142,7 @@ public interface Command { * Sets the command name. * * @param name the command name - * @return the builder + * @return this builder */ Builder name(@NonNull String name); @@ -144,23 +150,40 @@ public interface Command { * Sets the command description. * * @param description the command description - * @return the builder + * @return this builder */ Builder description(@NonNull String description); /** - * Sets the permission node. + * Sets the permission node required to run this command.
    + * It will not be registered with any permission registries, such as an underlying server, + * or a permissions Extension (unlike {@link #permission(String, TriState)}). * * @param permission the permission node - * @return the builder + * @return this builder */ Builder permission(@NonNull String permission); + /** + * Sets the permission node and its default value. The usage of the default value is platform dependant + * and may or may not be used. For example, it may be registered to an underlying server. + *

    + * Extensions may instead listen for {@link GeyserRegisterPermissionsEvent} to register permissions, + * especially if the same permission is required by multiple commands. Also see this event for TriState meanings. + * + * @param permission the permission node + * @param defaultValue the node's default value + * @return this builder + * @deprecated this method is experimental and may be removed in the future + */ + @Deprecated + Builder permission(@NonNull String permission, @NonNull TriState defaultValue); + /** * Sets the aliases. * * @param aliases the aliases - * @return the builder + * @return this builder */ Builder aliases(@NonNull List aliases); @@ -168,46 +191,62 @@ public interface Command { * Sets if this command is designed to be used only by server operators. * * @param suggestedOpOnly if this command is designed to be used only by server operators - * @return the builder + * @return this builder + * @deprecated this method is not guaranteed to produce meaningful or expected results */ + @Deprecated(forRemoval = true) Builder suggestedOpOnly(boolean suggestedOpOnly); /** * Sets if this command is executable on console. * * @param executableOnConsole if this command is executable on console - * @return the builder + * @return this builder + * @deprecated use {@link #isPlayerOnly()} instead (inverted) */ + @Deprecated(forRemoval = true) Builder executableOnConsole(boolean executableOnConsole); + /** + * Sets if this command can only be executed by players. + * + * @param playerOnly if this command is player only + * @return this builder + */ + Builder playerOnly(boolean playerOnly); + + /** + * Sets if this command can only be executed by bedrock players. + * + * @param bedrockOnly if this command is bedrock only + * @return this builder + */ + Builder bedrockOnly(boolean bedrockOnly); + /** * Sets the subcommands. * * @param subCommands the subcommands - * @return the builder + * @return this builder + * @deprecated this method has no effect */ - Builder subCommands(@NonNull List subCommands); - - /** - * Sets if this command is bedrock only. - * - * @param bedrockOnly if this command is bedrock only - * @return the builder - */ - Builder bedrockOnly(boolean bedrockOnly); + @Deprecated(forRemoval = true) + default Builder subCommands(@NonNull List subCommands) { + return this; + } /** * Sets the {@link CommandExecutor} for this command. * * @param executor the command executor - * @return the builder + * @return this builder */ Builder executor(@NonNull CommandExecutor executor); /** * Builds the command. * - * @return the command + * @return a new command from this builder */ @NonNull Command build(); diff --git a/api/src/main/java/org/geysermc/geyser/api/command/CommandSource.java b/api/src/main/java/org/geysermc/geyser/api/command/CommandSource.java index 45276e2c4..c1453f579 100644 --- a/api/src/main/java/org/geysermc/geyser/api/command/CommandSource.java +++ b/api/src/main/java/org/geysermc/geyser/api/command/CommandSource.java @@ -26,6 +26,10 @@ package org.geysermc.geyser.api.command; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.api.connection.GeyserConnection; + +import java.util.UUID; /** * Represents an instance capable of sending commands. @@ -64,6 +68,17 @@ public interface CommandSource { */ boolean isConsole(); + /** + * @return a Java UUID if this source represents a player, otherwise null + */ + @Nullable UUID playerUuid(); + + /** + * @return a GeyserConnection if this source represents a Bedrock player that is connected + * to this Geyser instance, otherwise null + */ + @Nullable GeyserConnection connection(); + /** * Returns the locale of the command source. * diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java index 994373752..d136202bd 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java @@ -50,7 +50,7 @@ public interface GeyserDefineCommandsEvent extends Event { /** * Gets all the registered built-in {@link Command}s. * - * @return all the registered built-in commands + * @return all the registered built-in commands as an unmodifiable map */ @NonNull Map commands(); diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionCheckersEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionCheckersEvent.java new file mode 100644 index 000000000..43ebc2c50 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionCheckersEvent.java @@ -0,0 +1,42 @@ +/* + * 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.api.event.lifecycle; + +import org.geysermc.event.Event; +import org.geysermc.event.PostOrder; +import org.geysermc.geyser.api.permission.PermissionChecker; + +/** + * Fired by any permission manager implementations that wish to add support for custom permission checking. + * This event is not guaranteed to be fired - it is currently only fired on Geyser-Standalone and ViaProxy. + *

    + * Subscribing to this event with an earlier {@link PostOrder} and registering a {@link PermissionChecker} + * will result in that checker having a higher priority than others. + */ +public interface GeyserRegisterPermissionCheckersEvent extends Event { + + void register(PermissionChecker checker); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionsEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionsEvent.java new file mode 100644 index 000000000..4f06c4e5f --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionsEvent.java @@ -0,0 +1,51 @@ +/* + * 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.api.event.lifecycle; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.Event; +import org.geysermc.geyser.api.util.TriState; + +/** + * Fired by anything that wishes to gather permission nodes and defaults. + *

    + * This event is not guaranteed to be fired, as certain Geyser platforms do not have a native permission system. + * It can be expected to fire on Geyser-Spigot, Geyser-NeoForge, Geyser-Standalone, and Geyser-ViaProxy + * It may be fired by a 3rd party regardless of the platform. + */ +public interface GeyserRegisterPermissionsEvent extends Event { + + /** + * Registers a permission node and its default value with the firer.

    + * {@link TriState#TRUE} corresponds to all players having the permission by default.
    + * {@link TriState#NOT_SET} corresponds to only server operators having the permission by default (if such a concept exists on the platform).
    + * {@link TriState#FALSE} corresponds to no players having the permission by default.
    + * + * @param permission the permission node to register + * @param defaultValue the default value of the node + */ + void register(@NonNull String permission, @NonNull TriState defaultValue); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/extension/Extension.java b/api/src/main/java/org/geysermc/geyser/api/extension/Extension.java index 993bdee44..1eacfea9a 100644 --- a/api/src/main/java/org/geysermc/geyser/api/extension/Extension.java +++ b/api/src/main/java/org/geysermc/geyser/api/extension/Extension.java @@ -107,6 +107,15 @@ public interface Extension extends EventRegistrar { return this.extensionLoader().description(this); } + /** + * @return the root command that all of this extension's commands will stem from. + * By default, this is the extension's id. + */ + @NonNull + default String rootCommand() { + return this.description().id(); + } + /** * Gets the extension's logger * diff --git a/api/src/main/java/org/geysermc/geyser/api/permission/PermissionChecker.java b/api/src/main/java/org/geysermc/geyser/api/permission/PermissionChecker.java new file mode 100644 index 000000000..c0d4af2f4 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/permission/PermissionChecker.java @@ -0,0 +1,49 @@ +/* + * 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.api.permission; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.command.CommandSource; +import org.geysermc.geyser.api.util.TriState; + +/** + * Something capable of checking if a {@link CommandSource} has a permission + */ +@FunctionalInterface +public interface PermissionChecker { + + /** + * Checks if the given source has a permission + * + * @param source the {@link CommandSource} whose permissions should be queried + * @param permission the permission node to check + * @return a {@link TriState} as the value of the node. {@link TriState#NOT_SET} generally means that the permission + * node itself was not found, and the source does not have such permission. + * {@link TriState#TRUE} and {@link TriState#FALSE} represent explicitly set values. + */ + @NonNull + TriState hasPermission(@NonNull CommandSource source, @NonNull String permission); +} diff --git a/bootstrap/bungeecord/build.gradle.kts b/bootstrap/bungeecord/build.gradle.kts index 910e50723..5fe7ea3d1 100644 --- a/bootstrap/bungeecord/build.gradle.kts +++ b/bootstrap/bungeecord/build.gradle.kts @@ -1,5 +1,7 @@ dependencies { api(projects.core) + + implementation(libs.cloud.bungee) implementation(libs.adventure.text.serializer.bungeecord) compileOnlyApi(libs.bungeecord.proxy) } @@ -8,13 +10,15 @@ platformRelocate("net.md_5.bungee.jni") platformRelocate("com.fasterxml.jackson") platformRelocate("io.netty.channel.kqueue") // This is not used because relocating breaks natives, but we must include it or else we get ClassDefNotFound platformRelocate("net.kyori") +platformRelocate("org.incendo") +platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated platformRelocate("org.yaml") // Broken as of 1.20 // These dependencies are already present on the platform provided(libs.bungeecord.proxy) -application { - mainClass.set("org.geysermc.geyser.platform.bungeecord.GeyserBungeeMain") +tasks.withType { + manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.bungeecord.GeyserBungeeMain" } tasks.withType { diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index cd6b59f64..1c0049231 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.platform.bungeecord; import io.netty.channel.Channel; import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.protocol.ProtocolConstants; @@ -34,17 +35,20 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.CommandSourceConverter; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor; +import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSource; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.bungee.BungeeCommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; import java.io.File; import java.io.IOException; @@ -54,21 +58,22 @@ import java.net.SocketAddress; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; -import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { - private GeyserCommandManager geyserCommandManager; + private CommandRegistry commandRegistry; private GeyserBungeeConfiguration geyserConfig; private GeyserBungeeInjector geyserInjector; private final GeyserBungeeLogger geyserLogger = new GeyserBungeeLogger(getLogger()); private IGeyserPingPassthrough geyserBungeePingPassthrough; - private GeyserImpl geyser; + // We can't disable the plugin; hence we need to keep track of it manually + private boolean disabled; + @Override public void onLoad() { onGeyserInitialize(); @@ -93,16 +98,23 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } if (!this.loadConfig()) { + disabled = true; return; } this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this); this.geyserInjector = new GeyserBungeeInjector(this); + + // Registration of listeners occurs only once + this.getProxy().getPluginManager().registerListener(this, new GeyserBungeeUpdateListener()); } @Override public void onEnable() { + if (disabled) { + return; // Config did not load properly! + } // Big hack - Bungee does not provide us an event to listen to, so schedule a repeating // task that waits for a field to be filled which is set after the plugin enable // process is complete @@ -143,10 +155,18 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); } else { - // For consistency with other platforms - create command manager before GeyserImpl#start() - // This ensures the command events are called before the item/block ones are - this.geyserCommandManager = new GeyserCommandManager(geyser); - this.geyserCommandManager.init(); + var sourceConverter = new CommandSourceConverter<>( + CommandSender.class, + id -> getProxy().getPlayer(id), + () -> getProxy().getConsole(), + BungeeCommandSource::new + ); + CommandManager cloud = new BungeeCommandManager<>( + this, + ExecutionCoordinator.simpleCoordinator(), + sourceConverter + ); + this.commandRegistry = new CommandRegistry(geyser, cloud, false); // applying root permission would be a breaking change because we can't register permission defaults } // Force-disable query if enabled, or else Geyser won't enable @@ -181,16 +201,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } this.geyserInjector.initializeLocalChannel(this); - - this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyser", this.geyser, this.geyserCommandManager.getCommands())); - for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { - Map commands = entry.getValue(); - if (commands.isEmpty()) { - continue; - } - - this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(entry.getKey().description().id(), this.geyser, commands)); - } } @Override @@ -226,8 +236,8 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } @Override - public GeyserCommandManager getGeyserCommandManager() { - return this.geyserCommandManager; + public CommandRegistry getCommandRegistry() { + return this.commandRegistry; } @Override diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java index c68839b20..0a89b5421 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java @@ -29,8 +29,8 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; -import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.Permissions; import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSource; import org.geysermc.geyser.util.VersionCheckUtils; @@ -40,7 +40,7 @@ public final class GeyserBungeeUpdateListener implements Listener { public void onPlayerJoin(final PostLoginEvent event) { if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { final ProxiedPlayer player = event.getPlayer(); - if (player.hasPermission(Constants.UPDATE_PERMISSION)) { + if (player.hasPermission(Permissions.CHECK_UPDATE)) { VersionCheckUtils.checkForGeyserUpdate(() -> new BungeeCommandSource(player)); } } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSource.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSource.java index e3099f170..10ccc5bac 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSource.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSource.java @@ -27,19 +27,22 @@ package org.geysermc.geyser.platform.bungeecord.command; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; +import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.text.GeyserLocale; import java.util.Locale; +import java.util.UUID; public class BungeeCommandSource implements GeyserCommandSource { - private final net.md_5.bungee.api.CommandSender handle; + private final CommandSender handle; - public BungeeCommandSource(net.md_5.bungee.api.CommandSender handle) { + public BungeeCommandSource(CommandSender handle) { this.handle = handle; // Ensure even Java players' languages are loaded GeyserLocale.loadGeyserLocale(this.locale()); @@ -72,12 +75,20 @@ public class BungeeCommandSource implements GeyserCommandSource { return !(handle instanceof ProxiedPlayer); } + @Override + public @Nullable UUID playerUuid() { + if (handle instanceof ProxiedPlayer player) { + return player.getUniqueId(); + } + return null; + } + @Override public String locale() { if (handle instanceof ProxiedPlayer player) { Locale locale = player.getLocale(); if (locale != null) { - // Locale can be null early on in the conneciton + // Locale can be null early on in the connection return GeyserLocale.formatLocale(locale.getLanguage() + "_" + locale.getCountry()); } } @@ -86,6 +97,12 @@ public class BungeeCommandSource implements GeyserCommandSource { @Override public boolean hasPermission(String permission) { - return handle.hasPermission(permission); + // Handle blank permissions ourselves, as bungeecord only handles empty ones + return permission.isBlank() || handle.hasPermission(permission); + } + + @Override + public Object handle() { + return handle; } } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java deleted file mode 100644 index 2d02c9950..000000000 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java +++ /dev/null @@ -1,89 +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.platform.bungeecord.command; - -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.plugin.Command; -import net.md_5.bungee.api.plugin.TabExecutor; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.GeyserCommand; -import org.geysermc.geyser.command.GeyserCommandExecutor; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.GeyserLocale; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Map; - -public class GeyserBungeeCommandExecutor extends Command implements TabExecutor { - private final GeyserCommandExecutor commandExecutor; - - public GeyserBungeeCommandExecutor(String name, GeyserImpl geyser, Map commands) { - super(name); - - this.commandExecutor = new GeyserCommandExecutor(geyser, commands); - } - - @Override - public void execute(CommandSender sender, String[] args) { - BungeeCommandSource commandSender = new BungeeCommandSource(sender); - GeyserSession session = this.commandExecutor.getGeyserSession(commandSender); - - if (args.length > 0) { - GeyserCommand command = this.commandExecutor.getCommand(args[0]); - if (command != null) { - if (!sender.hasPermission(command.permission())) { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.locale()); - - commandSender.sendMessage(ChatColor.RED + message); - return; - } - if (command.isBedrockOnly() && session == null) { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", commandSender.locale()); - - commandSender.sendMessage(ChatColor.RED + message); - return; - } - command.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); - } else { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale()); - commandSender.sendMessage(ChatColor.RED + message); - } - } else { - this.commandExecutor.getCommand("help").execute(session, commandSender, new String[0]); - } - } - - @Override - public Iterable onTabComplete(CommandSender sender, String[] args) { - if (args.length == 1) { - return commandExecutor.tabComplete(new BungeeCommandSource(sender)); - } else { - return Collections.emptyList(); - } - } -} diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index 9215c575e..fd9d7e99d 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -1,7 +1,3 @@ -plugins { - application -} - architectury { platformSetupLoomIde() fabric() @@ -35,13 +31,12 @@ dependencies { shadow(projects.api) { isTransitive = false } shadow(projects.common) { isTransitive = false } - // Permissions - modImplementation(libs.fabric.permissions) - include(libs.fabric.permissions) + modImplementation(libs.cloud.fabric) + include(libs.cloud.fabric) } -application { - mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain") +tasks.withType { + manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.fabric.GeyserFabricMain" } relocate("org.cloudburstmc.netty") 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 c363ade8f..149246d59 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.platform.fabric; -import me.lucko.fabric.api.permissions.v0.Permissions; import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; @@ -34,9 +33,16 @@ 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 org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.CommandSourceConverter; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.platform.mod.GeyserModBootstrap; import org.geysermc.geyser.platform.mod.GeyserModUpdateListener; +import org.geysermc.geyser.platform.mod.command.ModCommandSource; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.fabric.FabricServerCommandManager; public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInitializer { @@ -70,20 +76,23 @@ public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInit ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserModUpdateListener.onPlayReady(handler.getPlayer())); this.onGeyserInitialize(); + + var sourceConverter = CommandSourceConverter.layered( + CommandSourceStack.class, + id -> getServer().getPlayerList().getPlayer(id), + Player::createCommandSourceStack, + () -> getServer().createCommandSourceStack(), // NPE if method reference is used, since server is not available yet + ModCommandSource::new + ); + CommandManager cloud = new FabricServerCommandManager<>( + ExecutionCoordinator.simpleCoordinator(), + sourceConverter + ); + this.setCommandRegistry(new CommandRegistry(GeyserImpl.getInstance(), cloud, false)); // applying root permission would be a breaking change because we can't register permission defaults } @Override public boolean isServer() { return FabricLoader.getInstance().getEnvironmentType().equals(EnvType.SERVER); } - - @Override - public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) { - return Permissions.check(source, permissionNode); - } - - @Override - public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) { - return Permissions.check(source, permissionNode, permissionLevel); - } } diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts index 741e2fd11..81a35a58b 100644 --- a/bootstrap/mod/neoforge/build.gradle.kts +++ b/bootstrap/mod/neoforge/build.gradle.kts @@ -1,7 +1,3 @@ -plugins { - application -} - // This is provided by "org.cloudburstmc.math.mutable" too, so yeet. // NeoForge's class loader is *really* annoying. provided("org.cloudburstmc.math", "api") @@ -38,10 +34,13 @@ dependencies { // Include all transitive deps of core via JiJ includeTransitive(projects.core) + + modImplementation(libs.cloud.neoforge) + include(libs.cloud.neoforge) } -application { - mainClass.set("org.geysermc.geyser.platform.forge.GeyserNeoForgeMain") +tasks.withType { + manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.neoforge.GeyserNeoForgeMain" } tasks { 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 b97e42389..7d3b9dc5f 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.platform.neoforge; import net.minecraft.commands.CommandSourceStack; import net.minecraft.world.entity.player.Player; +import net.neoforged.bus.api.EventPriority; import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; import net.neoforged.fml.loading.FMLLoader; @@ -35,15 +36,22 @@ import net.neoforged.neoforge.event.GameShuttingDownEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.server.ServerStartedEvent; import net.neoforged.neoforge.event.server.ServerStoppingEvent; -import org.checkerframework.checker.nullness.qual.NonNull; +import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; +import org.geysermc.geyser.command.CommandSourceConverter; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.platform.mod.GeyserModBootstrap; import org.geysermc.geyser.platform.mod.GeyserModUpdateListener; +import org.geysermc.geyser.platform.mod.command.ModCommandSource; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.neoforge.NeoForgeServerCommandManager; + +import java.util.Objects; @Mod(ModConstants.MOD_ID) public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { - private final GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler(); - public GeyserNeoForgeBootstrap(ModContainer container) { super(new GeyserNeoForgePlatform(container)); @@ -56,9 +64,25 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { NeoForge.EVENT_BUS.addListener(this::onServerStopping); NeoForge.EVENT_BUS.addListener(this::onPlayerJoin); - NeoForge.EVENT_BUS.addListener(this.permissionHandler::onPermissionGather); + + NeoForge.EVENT_BUS.addListener(EventPriority.HIGHEST, this::onPermissionGather); this.onGeyserInitialize(); + + var sourceConverter = CommandSourceConverter.layered( + CommandSourceStack.class, + id -> getServer().getPlayerList().getPlayer(id), + Player::createCommandSourceStack, + () -> getServer().createCommandSourceStack(), + ModCommandSource::new + ); + CommandManager cloud = new NeoForgeServerCommandManager<>( + ExecutionCoordinator.simpleCoordinator(), + sourceConverter + ); + GeyserNeoForgeCommandRegistry registry = new GeyserNeoForgeCommandRegistry(getGeyser(), cloud); + this.setCommandRegistry(registry); + NeoForge.EVENT_BUS.addListener(EventPriority.LOWEST, registry::onPermissionGatherForUndefined); } private void onServerStarted(ServerStartedEvent event) { @@ -87,13 +111,17 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { return FMLLoader.getDist().isDedicatedServer(); } - @Override - public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) { - return this.permissionHandler.hasPermission(source, permissionNode); - } + private void onPermissionGather(PermissionGatherEvent.Nodes event) { + getGeyser().eventBus().fire( + (GeyserRegisterPermissionsEvent) (permission, defaultValue) -> { + Objects.requireNonNull(permission, "permission"); + Objects.requireNonNull(defaultValue, "permission default for " + permission); - @Override - public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) { - return this.permissionHandler.hasPermission(source, permissionNode, permissionLevel); + if (permission.isBlank()) { + return; + } + PermissionUtils.register(permission, defaultValue, event); + } + ); } } diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeCommandRegistry.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeCommandRegistry.java new file mode 100644 index 000000000..a8854d5d9 --- /dev/null +++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeCommandRegistry.java @@ -0,0 +1,101 @@ +/* + * 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.platform.neoforge; + +import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; +import org.geysermc.geyser.api.util.TriState; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.command.GeyserCommandSource; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.neoforge.PermissionNotRegisteredException; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class GeyserNeoForgeCommandRegistry extends CommandRegistry { + + /** + * Permissions with an undefined permission default. Use Set to not register the same fallback more than once. + * NeoForge requires that all permissions are registered, and cloud-neoforge follows that. + * This is unlike most platforms, on which we wouldn't register a permission if no default was provided. + */ + private final Set undefinedPermissions = new HashSet<>(); + + public GeyserNeoForgeCommandRegistry(GeyserImpl geyser, CommandManager cloud) { + super(geyser, cloud); + } + + @Override + protected void register(GeyserCommand command, Map commands) { + super.register(command, commands); + + // FIRST STAGE: Collect all permissions that may have undefined defaults. + if (!command.permission().isBlank() && command.permissionDefault() == null) { + // Permission requirement exists but no default value specified. + undefinedPermissions.add(command.permission()); + } + } + + @Override + protected void onRegisterPermissions(GeyserRegisterPermissionsEvent event) { + super.onRegisterPermissions(event); + + // SECOND STAGE + // Now that we are aware of all commands, we can eliminate some incorrect assumptions. + // Example: two commands may have the same permission, but only of them defines a permission default. + undefinedPermissions.removeAll(permissionDefaults.keySet()); + } + + /** + * Registers permissions with possibly undefined defaults. + * Should be subscribed late to allow extensions and mods to register a desired permission default first. + */ + void onPermissionGatherForUndefined(PermissionGatherEvent.Nodes event) { + // THIRD STAGE + for (String permission : undefinedPermissions) { + if (PermissionUtils.register(permission, TriState.NOT_SET, event)) { + // The permission was not already registered + geyser.getLogger().debug("Registered permission " + permission + " with fallback default value of NOT_SET"); + } + } + } + + @Override + public boolean hasPermission(GeyserCommandSource source, String permission) { + // NeoForgeServerCommandManager will throw this exception if the permission is not registered to the server. + // We can't realistically ensure that every permission is registered (calls by API users), so we catch this. + // This works for our calls, but not for cloud's internal usage. For that case, see above. + try { + return super.hasPermission(source, permission); + } catch (PermissionNotRegisteredException e) { + return false; + } + } +} diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java deleted file mode 100644 index 0a5f8f052..000000000 --- a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.platform.neoforge; - -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.player.Player; -import net.neoforged.neoforge.server.permission.PermissionAPI; -import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent; -import net.neoforged.neoforge.server.permission.nodes.PermissionDynamicContextKey; -import net.neoforged.neoforge.server.permission.nodes.PermissionNode; -import net.neoforged.neoforge.server.permission.nodes.PermissionType; -import net.neoforged.neoforge.server.permission.nodes.PermissionTypes; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.Constants; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.command.GeyserCommandManager; - -import java.lang.reflect.Constructor; -import java.util.HashMap; -import java.util.Map; - -public class GeyserNeoForgePermissionHandler { - - private static final Constructor PERMISSION_NODE_CONSTRUCTOR; - - static { - try { - @SuppressWarnings("rawtypes") - Constructor constructor = PermissionNode.class.getDeclaredConstructor( - String.class, - PermissionType.class, - PermissionNode.PermissionResolver.class, - PermissionDynamicContextKey[].class - ); - constructor.setAccessible(true); - PERMISSION_NODE_CONSTRUCTOR = constructor; - } catch (NoSuchMethodException e) { - throw new RuntimeException("Unable to construct PermissionNode!", e); - } - } - - private final Map> permissionNodes = new HashMap<>(); - - public void onPermissionGather(PermissionGatherEvent.Nodes event) { - this.registerNode(Constants.UPDATE_PERMISSION, event); - - GeyserCommandManager commandManager = GeyserImpl.getInstance().commandManager(); - for (Map.Entry entry : commandManager.commands().entrySet()) { - Command command = entry.getValue(); - - // Don't register aliases - if (!command.name().equals(entry.getKey())) { - continue; - } - - this.registerNode(command.permission(), event); - } - - for (Map commands : commandManager.extensionCommands().values()) { - for (Map.Entry entry : commands.entrySet()) { - Command command = entry.getValue(); - - // Don't register aliases - if (!command.name().equals(entry.getKey())) { - continue; - } - - this.registerNode(command.permission(), event); - } - } - } - - public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) { - PermissionNode node = this.permissionNodes.get(permissionNode); - if (node == null) { - GeyserImpl.getInstance().getLogger().warning("Unable to find permission node " + permissionNode); - return false; - } - - return PermissionAPI.getPermission((ServerPlayer) source, node); - } - - public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) { - if (!source.isPlayer()) { - return true; - } - assert source.getPlayer() != null; - boolean permission = this.hasPermission(source.getPlayer(), permissionNode); - if (!permission) { - return source.getPlayer().hasPermissions(permissionLevel); - } - - return true; - } - - private void registerNode(String node, PermissionGatherEvent.Nodes event) { - PermissionNode permissionNode = this.createNode(node); - - // NeoForge likes to crash if you try and register a duplicate node - if (!event.getNodes().contains(permissionNode)) { - event.addNodes(permissionNode); - this.permissionNodes.put(node, permissionNode); - } - } - - @SuppressWarnings("unchecked") - private PermissionNode createNode(String node) { - // The typical constructors in PermissionNode require a - // mod id, which means our permission nodes end up becoming - // geyser_neoforge. instead of just . We work around - // this by using reflection to access the constructor that - // doesn't require a mod id or ResourceLocation. - try { - return (PermissionNode) PERMISSION_NODE_CONSTRUCTOR.newInstance( - node, - PermissionTypes.BOOLEAN, - (PermissionNode.PermissionResolver) (player, playerUUID, context) -> false, - new PermissionDynamicContextKey[0] - ); - } catch (Exception e) { - throw new RuntimeException("Unable to create permission node " + node, e); - } - } -} diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/PermissionUtils.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/PermissionUtils.java new file mode 100644 index 000000000..c57dc9a6c --- /dev/null +++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/PermissionUtils.java @@ -0,0 +1,79 @@ +/* + * 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.platform.neoforge; + +import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent; +import net.neoforged.neoforge.server.permission.nodes.PermissionNode; +import net.neoforged.neoforge.server.permission.nodes.PermissionTypes; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; +import org.geysermc.geyser.api.util.TriState; +import org.geysermc.geyser.platform.neoforge.mixin.PermissionNodeMixin; + +/** + * Common logic for handling the more complicated way we have to register permission on NeoForge + */ +public class PermissionUtils { + + private PermissionUtils() { + //no + } + + /** + * Registers the given permission and its default value to the event. If the permission has the same name as one + * that has already been registered to the event, it will not be registered. In other words, it will not override. + * + * @param permission the permission to register + * @param permissionDefault the permission's default value. See {@link GeyserRegisterPermissionsEvent#register(String, TriState)} for TriState meanings. + * @param event the registration event + * @return true if the permission was registered + */ + public static boolean register(String permission, TriState permissionDefault, PermissionGatherEvent.Nodes event) { + // NeoForge likes to crash if you try and register a duplicate node + if (event.getNodes().stream().noneMatch(n -> n.getNodeName().equals(permission))) { + PermissionNode node = createNode(permission, permissionDefault); + event.addNodes(node); + return true; + } + return false; + } + + private static PermissionNode createNode(String node, TriState permissionDefault) { + return PermissionNodeMixin.geyser$construct( + node, + PermissionTypes.BOOLEAN, + (player, playerUUID, context) -> switch (permissionDefault) { + case TRUE -> true; + case FALSE -> false; + case NOT_SET -> { + if (player != null) { + yield player.createCommandSourceStack().hasPermission(player.server.getOperatorUserPermissionLevel()); + } + yield false; // NeoForge javadocs say player is null in the case of an offline player. + } + } + ); + } +} diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/mixin/PermissionNodeMixin.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/mixin/PermissionNodeMixin.java new file mode 100644 index 000000000..a43acd58a --- /dev/null +++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/mixin/PermissionNodeMixin.java @@ -0,0 +1,48 @@ +/* + * 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.platform.neoforge.mixin; + +import net.neoforged.neoforge.server.permission.nodes.PermissionDynamicContextKey; +import net.neoforged.neoforge.server.permission.nodes.PermissionNode; +import net.neoforged.neoforge.server.permission.nodes.PermissionType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(value = PermissionNode.class, remap = false) // this is API - do not remap +public interface PermissionNodeMixin { + + /** + * Invokes the matching private constructor in {@link PermissionNode}. + *

    + * The typical constructors in PermissionNode require a mod id, which means our permission nodes + * would end up becoming {@code geyser_neoforge.} instead of just {@code }. + */ + @SuppressWarnings("rawtypes") // the varargs + @Invoker("") + static PermissionNode geyser$construct(String nodeName, PermissionType type, PermissionNode.PermissionResolver defaultResolver, PermissionDynamicContextKey... dynamics) { + throw new IllegalStateException(); + } +} diff --git a/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml index fa01bb6ec..56b7d68e1 100644 --- a/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -11,6 +11,8 @@ authors="GeyserMC" description="${description}" [[mixins]] config = "geyser.mixins.json" +[[mixins]] +config = "geyser_neoforge.mixins.json" [[dependencies.geyser_neoforge]] modId="neoforge" type="required" diff --git a/bootstrap/mod/neoforge/src/main/resources/geyser_neoforge.mixins.json b/bootstrap/mod/neoforge/src/main/resources/geyser_neoforge.mixins.json new file mode 100644 index 000000000..f1653051c --- /dev/null +++ b/bootstrap/mod/neoforge/src/main/resources/geyser_neoforge.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "org.geysermc.geyser.platform.neoforge.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "PermissionNodeMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java index d7373f0a9..f11b5fbd6 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java @@ -25,30 +25,21 @@ package org.geysermc.geyser.platform.mod; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; import net.minecraft.server.MinecraftServer; -import net.minecraft.world.entity.player.Player; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.api.extension.Extension; -import org.geysermc.geyser.command.GeyserCommand; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.platform.mod.command.GeyserModCommandExecutor; import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform; import org.geysermc.geyser.platform.mod.world.GeyserModWorldManager; import org.geysermc.geyser.text.GeyserLocale; @@ -59,7 +50,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.SocketAddress; import java.nio.file.Path; -import java.util.Map; import java.util.UUID; @RequiredArgsConstructor @@ -70,13 +60,15 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { private final GeyserModPlatform platform; + @Getter private GeyserImpl geyser; private Path dataFolder; - @Setter + @Setter @Getter private MinecraftServer server; - private GeyserCommandManager geyserCommandManager; + @Setter + private CommandRegistry commandRegistry; private GeyserModConfiguration geyserConfig; private GeyserModInjector geyserInjector; private final GeyserModLogger geyserLogger = new GeyserModLogger(); @@ -94,10 +86,6 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); this.geyser = GeyserImpl.load(this.platform.platformType(), this); - - // Create command manager here, since the permission handler on neo needs it - this.geyserCommandManager = new GeyserCommandManager(geyser); - this.geyserCommandManager.init(); } public void onGeyserEnable() { @@ -130,50 +118,6 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { if (isServer()) { this.geyserInjector.initializeLocalChannel(this); } - - // Start command building - // Set just "geyser" as the help command - GeyserModCommandExecutor helpExecutor = new GeyserModCommandExecutor(geyser, - (GeyserCommand) geyser.commandManager().getCommands().get("help")); - LiteralArgumentBuilder builder = Commands.literal("geyser").executes(helpExecutor); - - // Register all subcommands as valid - for (Map.Entry command : geyser.commandManager().getCommands().entrySet()) { - GeyserModCommandExecutor executor = new GeyserModCommandExecutor(geyser, (GeyserCommand) command.getValue()); - builder.then(Commands.literal(command.getKey()) - .executes(executor) - // Could also test for Bedrock but depending on when this is called it may backfire - .requires(executor::testPermission) - // Allows parsing of arguments; e.g. for /geyser dump logs or the connectiontest command - .then(Commands.argument("args", StringArgumentType.greedyString()) - .executes(context -> executor.runWithArgs(context, StringArgumentType.getString(context, "args"))) - .requires(executor::testPermission))); - } - server.getCommands().getDispatcher().register(builder); - - // Register extension commands - for (Map.Entry> extensionMapEntry : geyser.commandManager().extensionCommands().entrySet()) { - Map extensionCommands = extensionMapEntry.getValue(); - if (extensionCommands.isEmpty()) { - continue; - } - - // Register help command for just "/" - GeyserModCommandExecutor extensionHelpExecutor = new GeyserModCommandExecutor(geyser, - (GeyserCommand) extensionCommands.get("help")); - LiteralArgumentBuilder extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor); - - for (Map.Entry command : extensionCommands.entrySet()) { - GeyserModCommandExecutor executor = new GeyserModCommandExecutor(geyser, (GeyserCommand) command.getValue()); - extCmdBuilder.then(Commands.literal(command.getKey()) - .executes(executor) - .requires(executor::testPermission) - .then(Commands.argument("args", StringArgumentType.greedyString()) - .executes(context -> executor.runWithArgs(context, StringArgumentType.getString(context, "args"))) - .requires(executor::testPermission))); - } - server.getCommands().getDispatcher().register(extCmdBuilder); - } } @Override @@ -206,8 +150,8 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { } @Override - public GeyserCommandManager getGeyserCommandManager() { - return geyserCommandManager; + public CommandRegistry getCommandRegistry() { + return commandRegistry; } @Override @@ -235,6 +179,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { return this.server.getServerVersion(); } + @SuppressWarnings("ConstantConditions") // Certain IDEA installations think that ip cannot be null @NonNull @Override public String getServerBindAddress() { @@ -270,10 +215,6 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { return this.platform.resolveResource(resource); } - public abstract boolean hasPermission(@NonNull Player source, @NonNull String permissionNode); - - public abstract boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel); - @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean loadConfig() { try { 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 11ca0bc4f..6a724155f 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,17 +25,18 @@ package org.geysermc.geyser.platform.mod; -import net.minecraft.commands.CommandSourceStack; import net.minecraft.world.entity.player.Player; -import org.geysermc.geyser.Constants; -import org.geysermc.geyser.platform.mod.command.ModCommandSender; +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) { - CommandSourceStack stack = player.createCommandSourceStack(); - if (GeyserModBootstrap.getInstance().hasPermission(stack, Constants.UPDATE_PERMISSION, 2)) { - VersionCheckUtils.checkForGeyserUpdate(() -> new ModCommandSender(stack)); + // 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()); + if (source.hasPermission(Permissions.CHECK_UPDATE)) { + VersionCheckUtils.checkForGeyserUpdate(() -> source); } } diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/GeyserModCommandExecutor.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/GeyserModCommandExecutor.java deleted file mode 100644 index 694dc732e..000000000 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/GeyserModCommandExecutor.java +++ /dev/null @@ -1,75 +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.platform.mod.command; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.context.CommandContext; -import net.minecraft.commands.CommandSourceStack; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.GeyserCommand; -import org.geysermc.geyser.command.GeyserCommandExecutor; -import org.geysermc.geyser.platform.mod.GeyserModBootstrap; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatColor; -import org.geysermc.geyser.text.GeyserLocale; - -import java.util.Collections; - -public class GeyserModCommandExecutor extends GeyserCommandExecutor implements Command { - private final GeyserCommand command; - - public GeyserModCommandExecutor(GeyserImpl geyser, GeyserCommand command) { - super(geyser, Collections.singletonMap(command.name(), command)); - this.command = command; - } - - public boolean testPermission(CommandSourceStack source) { - return GeyserModBootstrap.getInstance().hasPermission(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0); - } - - @Override - public int run(CommandContext context) { - return runWithArgs(context, ""); - } - - public int runWithArgs(CommandContext context, String args) { - CommandSourceStack source = context.getSource(); - ModCommandSender sender = new ModCommandSender(source); - GeyserSession session = getGeyserSession(sender); - if (!testPermission(source)) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); - return 0; - } - - if (command.isBedrockOnly() && session == null) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.locale())); - return 0; - } - - command.execute(session, sender, args.split(" ")); - return 0; - } -} diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSource.java similarity index 77% rename from bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSource.java index 5bebfae93..af1f368b3 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSource.java @@ -31,19 +31,21 @@ import net.minecraft.core.RegistryAccess; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommandSource; -import org.geysermc.geyser.platform.mod.GeyserModBootstrap; import org.geysermc.geyser.text.ChatColor; import java.util.Objects; +import java.util.UUID; -public class ModCommandSender implements GeyserCommandSource { +public class ModCommandSource implements GeyserCommandSource { private final CommandSourceStack source; - public ModCommandSender(CommandSourceStack source) { + public ModCommandSource(CommandSourceStack source) { this.source = source; + // todo find locale? } @Override @@ -75,8 +77,24 @@ public class ModCommandSender implements GeyserCommandSource { return !(source.getEntity() instanceof ServerPlayer); } + @Override + public @Nullable UUID playerUuid() { + if (source.getEntity() instanceof ServerPlayer player) { + return player.getUUID(); + } + return null; + } + @Override public boolean hasPermission(String permission) { - return GeyserModBootstrap.getInstance().hasPermission(source, permission, source.getServer().getOperatorUserPermissionLevel()); + // Unlike other bootstraps; we delegate to cloud here too: + // On NeoForge; we'd have to keep track of all PermissionNodes - cloud already does that + // For Fabric, we won't need to include the Fabric Permissions API anymore - cloud already does that too :p + return GeyserImpl.getInstance().commandRegistry().hasPermission(this, permission); + } + + @Override + public Object handle() { + return source; } } 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 db1768737..89452eba3 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 @@ -48,7 +48,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.network.GameProtocol; -import org.geysermc.geyser.platform.mod.GeyserModBootstrap; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.Holder; @@ -111,12 +110,6 @@ public class GeyserModWorldManager extends GeyserWorldManager { return SharedConstants.getCurrentVersion().getProtocolVersion() == GameProtocol.getJavaProtocolVersion(); } - @Override - public boolean hasPermission(GeyserSession session, String permission) { - ServerPlayer player = getPlayer(session); - return GeyserModBootstrap.getInstance().hasPermission(player, permission); - } - @Override public GameMode getDefaultGameMode(GeyserSession session) { return GameMode.byId(server.getDefaultGameType().getId()); diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index fcb85f100..0a1271145 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -17,12 +17,12 @@ dependencies { classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations }) + implementation(libs.cloud.paper) implementation(libs.commodore) implementation(libs.adventure.text.serializer.bungeecord) compileOnly(libs.folia.api) - compileOnly(libs.paper.mojangapi) compileOnlyApi(libs.viaversion) } @@ -33,13 +33,15 @@ platformRelocate("com.fasterxml.jackson") platformRelocate("net.kyori", "net.kyori.adventure.text.logger.slf4j.ComponentLogger") platformRelocate("org.objectweb.asm") platformRelocate("me.lucko.commodore") +platformRelocate("org.incendo") +platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated platformRelocate("org.yaml") // Broken as of 1.20 // These dependencies are already present on the platform provided(libs.viaversion) -application { - mainClass.set("org.geysermc.geyser.platform.spigot.GeyserSpigotMain") +tasks.withType { + manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.spigot.GeyserSpigotMain" } tasks.withType { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 2d13155f2..3bb44a4bc 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -30,37 +30,34 @@ import com.viaversion.viaversion.api.data.MappingData; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import io.netty.buffer.ByteBuf; -import me.lucko.commodore.CommodoreProvider; import org.bukkit.Bukkit; import org.bukkit.block.data.BlockData; -import org.bukkit.command.CommandMap; -import org.bukkit.command.PluginCommand; +import org.bukkit.command.CommandSender; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.server.ServerLoadEvent; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; -import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.adapters.paper.PaperAdapters; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.CommandSourceConverter; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.platform.spigot.command.GeyserBrigadierSupport; -import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor; -import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager; +import org.geysermc.geyser.platform.spigot.command.SpigotCommandRegistry; +import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource; import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener; import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotLegacyNativeWorldManager; @@ -68,21 +65,21 @@ import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotNativeWorld import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.incendo.cloud.bukkit.BukkitCommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.paper.LegacyPaperCommandManager; import java.io.File; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.net.SocketAddress; import java.nio.file.Path; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.UUID; public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { - private GeyserSpigotCommandManager geyserCommandManager; + private CommandRegistry commandRegistry; private GeyserSpigotConfiguration geyserConfig; private GeyserSpigotInjector geyserInjector; private final GeyserSpigotLogger geyserLogger = GeyserPaperLogger.supported() ? @@ -165,31 +162,37 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { @Override public void onEnable() { - this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); - this.geyserCommandManager.init(); - - // Because Bukkit locks its command map upon startup, we need to - // add our plugin commands in onEnable, but populating the executor - // can happen at any time (later in #onGeyserEnable()) - CommandMap commandMap = GeyserSpigotCommandManager.getCommandMap(); - for (Extension extension : this.geyserCommandManager.extensionCommands().keySet()) { - // Thanks again, Bukkit - try { - Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); - constructor.setAccessible(true); - - PluginCommand pluginCommand = constructor.newInstance(extension.description().id(), this); - pluginCommand.setDescription("The main command for the " + extension.name() + " Geyser extension!"); - - commandMap.register(extension.description().id(), "geyserext", pluginCommand); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { - this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.name(), ex); - } + // Create command manager early so we can add Geyser extension commands + var sourceConverter = new CommandSourceConverter<>( + CommandSender.class, + Bukkit::getPlayer, + Bukkit::getConsoleSender, + SpigotCommandSource::new + ); + LegacyPaperCommandManager cloud; + try { + // LegacyPaperCommandManager works for spigot too, see https://cloud.incendo.org/minecraft/paper + cloud = new LegacyPaperCommandManager<>( + this, + ExecutionCoordinator.simpleCoordinator(), + sourceConverter + ); + } catch (Exception e) { + throw new RuntimeException(e); } + try { + // Commodore brigadier on Spigot/Paper 1.13 - 1.18.2 + // Paper-only brigadier on 1.19+ + cloud.registerBrigadier(); + } catch (BukkitCommandManager.BrigadierInitializationException e) { + geyserLogger.debug("Failed to initialize Brigadier support: " + e.getMessage()); + } + + this.commandRegistry = new SpigotCommandRegistry(geyser, cloud); + // Needs to be an anonymous inner class otherwise Bukkit complains about missing classes Bukkit.getPluginManager().registerEvents(new Listener() { - @EventHandler public void onServerLoaded(ServerLoadEvent event) { if (event.getType() == ServerLoadEvent.LoadType.RELOAD) { @@ -227,7 +230,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } geyserLogger.debug("Spigot ping passthrough type: " + (this.geyserSpigotPingPassthrough == null ? null : this.geyserSpigotPingPassthrough.getClass())); - // Don't need to re-create the world manager/re-register commands/reinject when reloading + // Don't need to re-create the world manager/reinject when reloading if (GeyserImpl.getInstance().isReloading()) { return; } @@ -282,79 +285,40 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserLogger.debug("Using default world manager."); } - PluginCommand geyserCommand = this.getCommand("geyser"); - Objects.requireNonNull(geyserCommand, "base command cannot be null"); - geyserCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser, geyserCommandManager.getCommands())); - - for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { - Map commands = entry.getValue(); - if (commands.isEmpty()) { - continue; - } - - PluginCommand command = this.getCommand(entry.getKey().description().id()); - if (command == null) { - continue; - } - - command.setExecutor(new GeyserSpigotCommandExecutor(this.geyser, commands)); - } - // Register permissions so they appear in, for example, LuckPerms' UI - // Re-registering permissions throws an error - for (Map.Entry entry : geyserCommandManager.commands().entrySet()) { - Command command = entry.getValue(); - if (command.aliases().contains(entry.getKey())) { - // Don't register aliases - continue; + // Re-registering permissions without removing it throws an error + PluginManager pluginManager = Bukkit.getPluginManager(); + geyser.eventBus().fire((GeyserRegisterPermissionsEvent) (permission, def) -> { + Objects.requireNonNull(permission, "permission"); + Objects.requireNonNull(def, "permission default for " + permission); + + if (permission.isBlank()) { + return; + } + PermissionDefault permissionDefault = switch (def) { + case TRUE -> PermissionDefault.TRUE; + case FALSE -> PermissionDefault.FALSE; + case NOT_SET -> PermissionDefault.OP; + }; + + Permission existingPermission = pluginManager.getPermission(permission); + if (existingPermission != null) { + geyserLogger.debug("permission " + permission + " with default " + + existingPermission.getDefault() + " is being overridden by " + permissionDefault); + + pluginManager.removePermission(permission); } - Bukkit.getPluginManager().addPermission(new Permission(command.permission(), - GeyserLocale.getLocaleStringLog(command.description()), - command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE)); - } - - // Register permissions for extension commands - for (Map.Entry> commandEntry : this.geyserCommandManager.extensionCommands().entrySet()) { - for (Map.Entry entry : commandEntry.getValue().entrySet()) { - Command command = entry.getValue(); - if (command.aliases().contains(entry.getKey())) { - // Don't register aliases - continue; - } - - if (command.permission().isBlank()) { - continue; - } - - // Avoid registering the same permission twice, e.g. for the extension help commands - if (Bukkit.getPluginManager().getPermission(command.permission()) != null) { - GeyserImpl.getInstance().getLogger().debug("Skipping permission " + command.permission() + " as it is already registered"); - continue; - } - - Bukkit.getPluginManager().addPermission(new Permission(command.permission(), - GeyserLocale.getLocaleStringLog(command.description()), - command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE)); - } - } - - Bukkit.getPluginManager().addPermission(new Permission(Constants.UPDATE_PERMISSION, - "Whether update notifications can be seen", PermissionDefault.OP)); + pluginManager.addPermission(new Permission(permission, permissionDefault)); + }); // Events cannot be unregistered - re-registering results in duplicate firings GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager); - Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); + pluginManager.registerEvents(blockPlaceListener, this); - Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this); + pluginManager.registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this); - Bukkit.getServer().getPluginManager().registerEvents(new GeyserSpigotUpdateListener(), this); - - boolean brigadierSupported = CommodoreProvider.isSupported(); - geyserLogger.debug("Brigadier supported? " + brigadierSupported); - if (brigadierSupported) { - GeyserBrigadierSupport.loadBrigadier(this, geyserCommand); - } + pluginManager.registerEvents(new GeyserSpigotUpdateListener(), this); } @Override @@ -390,8 +354,8 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } @Override - public GeyserCommandManager getGeyserCommandManager() { - return this.geyserCommandManager; + public CommandRegistry getCommandRegistry() { + return this.commandRegistry; } @Override diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java index 5e3c4def8..8a8a43460 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java @@ -29,8 +29,8 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; -import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.Permissions; import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource; import org.geysermc.geyser.util.VersionCheckUtils; @@ -40,7 +40,7 @@ public final class GeyserSpigotUpdateListener implements Listener { public void onPlayerJoin(final PlayerJoinEvent event) { if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { final Player player = event.getPlayer(); - if (player.hasPermission(Constants.UPDATE_PERMISSION)) { + if (player.hasPermission(Permissions.CHECK_UPDATE)) { VersionCheckUtils.checkForGeyserUpdate(() -> new SpigotCommandSource(player)); } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserBrigadierSupport.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserBrigadierSupport.java deleted file mode 100644 index 61900174c..000000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserBrigadierSupport.java +++ /dev/null @@ -1,61 +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.platform.spigot.command; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import me.lucko.commodore.Commodore; -import me.lucko.commodore.CommodoreProvider; -import org.bukkit.Bukkit; -import org.bukkit.command.PluginCommand; -import org.geysermc.geyser.platform.spigot.GeyserSpigotPlugin; - -/** - * Needs to be a separate class so pre-1.13 loads correctly. - */ -public final class GeyserBrigadierSupport { - - public static void loadBrigadier(GeyserSpigotPlugin plugin, PluginCommand pluginCommand) { - // Enable command completions if supported - // This is beneficial because this is sent over the network and Bedrock can see it - Commodore commodore = CommodoreProvider.getCommodore(plugin); - LiteralArgumentBuilder builder = LiteralArgumentBuilder.literal("geyser"); - for (String command : plugin.getGeyserCommandManager().getCommands().keySet()) { - builder.then(LiteralArgumentBuilder.literal(command)); - } - commodore.register(pluginCommand, builder); - - try { - Class.forName("com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent"); - Bukkit.getServer().getPluginManager().registerEvents(new GeyserPaperCommandListener(), plugin); - plugin.getGeyserLogger().debug("Successfully registered AsyncPlayerSendCommandsEvent listener."); - } catch (ClassNotFoundException e) { - plugin.getGeyserLogger().debug("Not registering AsyncPlayerSendCommandsEvent listener."); - } - } - - private GeyserBrigadierSupport() { - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserPaperCommandListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserPaperCommandListener.java deleted file mode 100644 index dcec045ab..000000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserPaperCommandListener.java +++ /dev/null @@ -1,87 +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.platform.spigot.command; - -import com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent; -import com.mojang.brigadier.tree.CommandNode; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.command.Command; - -import java.net.InetSocketAddress; -import java.util.Iterator; -import java.util.Map; - -public final class GeyserPaperCommandListener implements Listener { - - @SuppressWarnings("UnstableApiUsage") - @EventHandler - public void onCommandSend(AsyncPlayerSendCommandsEvent event) { - // Documentation says to check (event.isAsynchronous() || !event.hasFiredAsync()), but as of Paper 1.18.2 - // event.hasFiredAsync is never true - if (event.isAsynchronous()) { - CommandNode geyserBrigadier = event.getCommandNode().getChild("geyser"); - if (geyserBrigadier != null) { - Player player = event.getPlayer(); - boolean isJavaPlayer = isProbablyJavaPlayer(player); - Map commands = GeyserImpl.getInstance().commandManager().getCommands(); - Iterator> it = geyserBrigadier.getChildren().iterator(); - - while (it.hasNext()) { - CommandNode subnode = it.next(); - Command command = commands.get(subnode.getName()); - if (command != null) { - if ((command.isBedrockOnly() && isJavaPlayer) || !player.hasPermission(command.permission())) { - // Remove this from the node as we don't have permission to use it - it.remove(); - } - } - } - } - } - } - - /** - * This early on, there is a rare chance that Geyser has yet to process the connection. We'll try to minimize that - * chance, though. - */ - private boolean isProbablyJavaPlayer(Player player) { - if (GeyserImpl.getInstance().connectionByUuid(player.getUniqueId()) != null) { - // For sure this is a Bedrock player - return false; - } - - if (GeyserImpl.getInstance().getConfig().isUseDirectConnection()) { - InetSocketAddress address = player.getAddress(); - if (address != null) { - return address.getPort() != 0; - } - } - return true; - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java deleted file mode 100644 index 6780bde17..000000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java +++ /dev/null @@ -1,88 +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.platform.spigot.command; - -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.GeyserCommand; -import org.geysermc.geyser.command.GeyserCommandExecutor; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.GeyserLocale; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public class GeyserSpigotCommandExecutor extends GeyserCommandExecutor implements TabExecutor { - - public GeyserSpigotCommandExecutor(GeyserImpl geyser, Map commands) { - super(geyser, commands); - } - - @Override - public boolean onCommand(@NonNull CommandSender sender, @NonNull Command command, @NonNull String label, String[] args) { - SpigotCommandSource commandSender = new SpigotCommandSource(sender); - GeyserSession session = getGeyserSession(commandSender); - - if (args.length > 0) { - GeyserCommand geyserCommand = getCommand(args[0]); - if (geyserCommand != null) { - if (!sender.hasPermission(geyserCommand.permission())) { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.locale()); - - commandSender.sendMessage(ChatColor.RED + message); - return true; - } - if (geyserCommand.isBedrockOnly() && session == null) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", commandSender.locale())); - return true; - } - geyserCommand.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); - return true; - } else { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale()); - commandSender.sendMessage(ChatColor.RED + message); - } - } else { - getCommand("help").execute(session, commandSender, new String[0]); - return true; - } - return true; - } - - @Override - public List onTabComplete(@NonNull CommandSender sender, @NonNull Command command, @NonNull String label, String[] args) { - if (args.length == 1) { - return tabComplete(new SpigotCommandSource(sender)); - } - return Collections.emptyList(); - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandRegistry.java similarity index 61% rename from bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java rename to bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandRegistry.java index 655d3be23..39496d2c6 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * 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 @@ -29,16 +29,21 @@ import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.command.Command; import org.bukkit.command.CommandMap; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.GeyserCommandSource; +import org.incendo.cloud.CommandManager; import java.lang.reflect.Field; -public class GeyserSpigotCommandManager extends GeyserCommandManager { +public class SpigotCommandRegistry extends CommandRegistry { - private static final CommandMap COMMAND_MAP; + private final CommandMap commandMap; + + public SpigotCommandRegistry(GeyserImpl geyser, CommandManager cloud) { + super(geyser, cloud); - static { CommandMap commandMap = null; try { // Paper-only @@ -49,24 +54,28 @@ public class GeyserSpigotCommandManager extends GeyserCommandManager { Field cmdMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap"); cmdMapField.setAccessible(true); commandMap = (CommandMap) cmdMapField.get(Bukkit.getServer()); - } catch (NoSuchFieldException | IllegalAccessException ex) { - ex.printStackTrace(); + } catch (Exception ex) { + geyser.getLogger().error("Failed to get Spigot's CommandMap", ex); } } - COMMAND_MAP = commandMap; - } - - public GeyserSpigotCommandManager(GeyserImpl geyser) { - super(geyser); + this.commandMap = commandMap; } + @NonNull @Override - public String description(String command) { - Command cmd = COMMAND_MAP.getCommand(command.replace("/", "")); - return cmd != null ? cmd.getDescription() : ""; - } + public String description(@NonNull String command, @NonNull String locale) { + // check if the command is /geyser or an extension command so that we can localize the description + String description = super.description(command, locale); + if (!description.isBlank()) { + return description; + } - public static CommandMap getCommandMap() { - return COMMAND_MAP; + if (commandMap != null) { + Command cmd = commandMap.getCommand(command); + if (cmd != null) { + return cmd.getDescription(); + } + } + return ""; } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java index 365e9ad17..c1fb837c2 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java @@ -27,17 +27,21 @@ package org.geysermc.geyser.platform.spigot.command; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; +import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.platform.spigot.PaperAdventure; import org.geysermc.geyser.text.GeyserLocale; -public class SpigotCommandSource implements GeyserCommandSource { - private final org.bukkit.command.CommandSender handle; +import java.util.UUID; - public SpigotCommandSource(org.bukkit.command.CommandSender handle) { +public class SpigotCommandSource implements GeyserCommandSource { + private final CommandSender handle; + + public SpigotCommandSource(CommandSender handle) { this.handle = handle; // Ensure even Java players' languages are loaded GeyserLocale.loadGeyserLocale(locale()); @@ -65,11 +69,24 @@ public class SpigotCommandSource implements GeyserCommandSource { handle.spigot().sendMessage(BungeeComponentSerializer.get().serialize(message)); } + @Override + public Object handle() { + return handle; + } + @Override public boolean isConsole() { return handle instanceof ConsoleCommandSender; } + @Override + public @Nullable UUID playerUuid() { + if (handle instanceof Player player) { + return player.getUniqueId(); + } + return null; + } + @SuppressWarnings("deprecation") @Override public String locale() { @@ -83,6 +100,7 @@ public class SpigotCommandSource implements GeyserCommandSource { @Override public boolean hasPermission(String permission) { - return handle.hasPermission(permission); + // Don't trust Spigot to handle blank permissions + return permission.isBlank() || handle.hasPermission(permission); } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 73356c4e7..6588a22a3 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -128,15 +128,6 @@ public class GeyserSpigotWorldManager extends WorldManager { return GameMode.byId(Bukkit.getDefaultGameMode().ordinal()); } - @Override - public boolean hasPermission(GeyserSession session, String permission) { - Player player = Bukkit.getPlayer(session.javaUuid()); - if (player != null) { - return player.hasPermission(permission); - } - return false; - } - @Override public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { Player bukkitPlayer; diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/spigot/src/main/resources/plugin.yml index 6e81ccdb6..14e98f577 100644 --- a/bootstrap/spigot/src/main/resources/plugin.yml +++ b/bootstrap/spigot/src/main/resources/plugin.yml @@ -6,11 +6,3 @@ version: ${version} softdepend: ["ViaVersion", "floodgate"] api-version: 1.13 folia-supported: true -commands: - geyser: - description: The main command for Geyser. - usage: /geyser - permission: geyser.command -permissions: - geyser.command: - default: true diff --git a/bootstrap/standalone/build.gradle.kts b/bootstrap/standalone/build.gradle.kts index eaf895108..fd81dad63 100644 --- a/bootstrap/standalone/build.gradle.kts +++ b/bootstrap/standalone/build.gradle.kts @@ -1,5 +1,9 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer +plugins { + application +} + val terminalConsoleVersion = "1.2.0" val jlineVersion = "3.21.0" diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index f289fa2ba..87fbbf0aa 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -42,7 +42,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.standalone.StandaloneCloudCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.configuration.GeyserJacksonConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; @@ -69,7 +70,8 @@ import java.util.stream.Collectors; public class GeyserStandaloneBootstrap implements GeyserBootstrap { - private GeyserCommandManager geyserCommandManager; + private StandaloneCloudCommandManager cloud; + private CommandRegistry commandRegistry; private GeyserStandaloneConfiguration geyserConfig; private final GeyserStandaloneLogger geyserLogger = new GeyserStandaloneLogger(); private IGeyserPingPassthrough geyserPingPassthrough; @@ -222,13 +224,24 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { geyser = GeyserImpl.load(PlatformType.STANDALONE, this); - geyserCommandManager = new GeyserCommandManager(geyser); - geyserCommandManager.init(); + boolean reloading = geyser.isReloading(); + if (!reloading) { + // Currently there would be no significant benefit of re-initializing commands. Also, we would have to unsubscribe CommandRegistry. + // Fire GeyserDefineCommandsEvent after PreInitEvent, before PostInitEvent, for consistency with other bootstraps. + cloud = new StandaloneCloudCommandManager(geyser); + commandRegistry = new CommandRegistry(geyser, cloud); + } GeyserImpl.start(); + if (!reloading) { + // Event must be fired after CommandRegistry has subscribed its listener. + // Also, the subscription for the Permissions class is created when Geyser is initialized. + cloud.fireRegisterPermissionsEvent(); + } + if (gui != null) { - gui.enableCommands(geyser.getScheduledThread(), geyserCommandManager); + gui.enableCommands(geyser.getScheduledThread(), commandRegistry); } geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); @@ -255,8 +268,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { @Override public void onGeyserDisable() { - // We can re-register commands on standalone, so why not - GeyserImpl.getInstance().commandManager().getCommands().clear(); geyser.disable(); } @@ -277,8 +288,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { } @Override - public GeyserCommandManager getGeyserCommandManager() { - return geyserCommandManager; + public CommandRegistry getCommandRegistry() { + return commandRegistry; } @Override 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 3a34920ce..21e6a5e82 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 @@ -44,7 +44,9 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey @Override protected void runCommand(String line) { - GeyserImpl.getInstance().commandManager().runCommand(this, line); + // don't block the terminal! + GeyserImpl geyser = GeyserImpl.getInstance(); + geyser.getScheduledThread().execute(() -> geyser.commandRegistry().runCommand(this, line)); } @Override diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java index b82d8cc94..4cbd178af 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.platform.standalone.gui; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -271,15 +271,14 @@ public class GeyserStandaloneGUI { } /** - * Enable the command input box. + * Enables the command input box. * - * @param executor the executor for running commands off the GUI thread - * @param commandManager the command manager to delegate commands to + * @param executor the executor that commands will be run on + * @param registry the command registry containing all current commands */ - public void enableCommands(ScheduledExecutorService executor, GeyserCommandManager commandManager) { + public void enableCommands(ScheduledExecutorService executor, CommandRegistry registry) { // we don't want to block the GUI thread with the command execution - // todo: once cloud is used, an AsynchronousCommandExecutionCoordinator can be used to avoid this scheduler - commandListener.handler = cmd -> executor.schedule(() -> commandManager.runCommand(logger, cmd), 0, TimeUnit.SECONDS); + commandListener.dispatcher = cmd -> executor.execute(() -> registry.runCommand(logger, cmd)); commandInput.setEnabled(true); commandInput.requestFocusInWindow(); } @@ -344,13 +343,14 @@ public class GeyserStandaloneGUI { private class CommandListener implements ActionListener { - private Consumer handler; + private Consumer dispatcher; @Override public void actionPerformed(ActionEvent e) { - String command = commandInput.getText(); + // the headless variant of Standalone strips trailing whitespace for us - we need to manually + String command = commandInput.getText().stripTrailing(); appendConsole(command + "\n"); // show what was run in the console - handler.accept(command); // run the command + dispatcher.accept(command); // run the command commandInput.setText(""); // clear the input } } diff --git a/bootstrap/velocity/build.gradle.kts b/bootstrap/velocity/build.gradle.kts index 4daad9784..93e0c9c93 100644 --- a/bootstrap/velocity/build.gradle.kts +++ b/bootstrap/velocity/build.gradle.kts @@ -3,12 +3,15 @@ dependencies { api(projects.core) compileOnlyApi(libs.velocity.api) + api(libs.cloud.velocity) } platformRelocate("com.fasterxml.jackson") platformRelocate("it.unimi.dsi.fastutil") platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl") platformRelocate("org.yaml") +platformRelocate("org.incendo") +platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated exclude("com.google.*:*") @@ -38,8 +41,8 @@ exclude("net.kyori:adventure-nbt:*") // These dependencies are already present on the platform provided(libs.velocity.api) -application { - mainClass.set("org.geysermc.geyser.platform.velocity.GeyserVelocityMain") +tasks.withType { + manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.velocity.GeyserVelocityMain" } tasks.withType { @@ -74,4 +77,4 @@ tasks.withType { modrinth { uploadFile.set(tasks.getByPath("shadowJar")) loaders.addAll("velocity") -} \ No newline at end of file +} diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 539bdadbf..868cdbf8e 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.platform.velocity; import com.google.inject.Inject; -import com.velocitypowered.api.command.CommandManager; +import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ListenerBoundEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; @@ -34,24 +34,28 @@ import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.network.ListenerType; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.plugin.Plugin; +import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.proxy.ProxyServer; import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.CommandSourceConverter; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandExecutor; +import org.geysermc.geyser.platform.velocity.command.VelocityCommandSource; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.velocity.VelocityCommandManager; import org.slf4j.Logger; import java.io.File; @@ -59,29 +63,28 @@ import java.io.IOException; import java.net.SocketAddress; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Map; import java.util.UUID; @Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC") public class GeyserVelocityPlugin implements GeyserBootstrap { private final ProxyServer proxyServer; - private final CommandManager commandManager; + private final PluginContainer container; private final GeyserVelocityLogger geyserLogger; - private GeyserCommandManager geyserCommandManager; private GeyserVelocityConfiguration geyserConfig; private GeyserVelocityInjector geyserInjector; private IGeyserPingPassthrough geyserPingPassthrough; + private CommandRegistry commandRegistry; private GeyserImpl geyser; @Getter private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/"); @Inject - public GeyserVelocityPlugin(ProxyServer server, Logger logger, CommandManager manager) { - this.geyserLogger = new GeyserVelocityLogger(logger); + public GeyserVelocityPlugin(ProxyServer server, PluginContainer container, Logger logger) { this.proxyServer = server; - this.commandManager = manager; + this.container = container; + this.geyserLogger = new GeyserVelocityLogger(logger); } @Override @@ -117,8 +120,19 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); } else { - this.geyserCommandManager = new GeyserCommandManager(geyser); - this.geyserCommandManager.init(); + var sourceConverter = new CommandSourceConverter<>( + CommandSource.class, + id -> proxyServer.getPlayer(id).orElse(null), + proxyServer::getConsoleCommandSource, + VelocityCommandSource::new + ); + CommandManager cloud = new VelocityCommandManager<>( + container, + proxyServer, + ExecutionCoordinator.simpleCoordinator(), + sourceConverter + ); + this.commandRegistry = new CommandRegistry(geyser, cloud, false); // applying root permission would be a breaking change because we can't register permission defaults } GeyserImpl.start(); @@ -129,22 +143,10 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer); } - // No need to re-register commands when reloading - if (GeyserImpl.getInstance().isReloading()) { - return; + // No need to re-register events + if (!GeyserImpl.getInstance().isReloading()) { + proxyServer.getEventManager().register(this, new GeyserVelocityUpdateListener()); } - - this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(geyser, geyserCommandManager.getCommands())); - for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { - Map commands = entry.getValue(); - if (commands.isEmpty()) { - continue; - } - - this.commandManager.register(entry.getKey().description().id(), new GeyserVelocityCommandExecutor(this.geyser, commands)); - } - - proxyServer.getEventManager().register(this, new GeyserVelocityUpdateListener()); } @Override @@ -175,8 +177,8 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { } @Override - public GeyserCommandManager getGeyserCommandManager() { - return this.geyserCommandManager; + public CommandRegistry getCommandRegistry() { + return this.commandRegistry; } @Override diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java index 31e584612..c1c88b70d 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java @@ -28,8 +28,8 @@ package org.geysermc.geyser.platform.velocity; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.PostLoginEvent; import com.velocitypowered.api.proxy.Player; -import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.Permissions; import org.geysermc.geyser.platform.velocity.command.VelocityCommandSource; import org.geysermc.geyser.util.VersionCheckUtils; @@ -39,7 +39,7 @@ public final class GeyserVelocityUpdateListener { public void onPlayerJoin(PostLoginEvent event) { if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { final Player player = event.getPlayer(); - if (player.hasPermission(Constants.UPDATE_PERMISSION)) { + if (player.hasPermission(Permissions.CHECK_UPDATE)) { VersionCheckUtils.checkForGeyserUpdate(() -> new VelocityCommandSource(player)); } } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java deleted file mode 100644 index c89c35b06..000000000 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java +++ /dev/null @@ -1,83 +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.platform.velocity.command; - -import com.velocitypowered.api.command.SimpleCommand; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.command.GeyserCommand; -import org.geysermc.geyser.command.GeyserCommandExecutor; -import org.geysermc.geyser.command.GeyserCommandSource; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatColor; -import org.geysermc.geyser.text.GeyserLocale; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public class GeyserVelocityCommandExecutor extends GeyserCommandExecutor implements SimpleCommand { - - public GeyserVelocityCommandExecutor(GeyserImpl geyser, Map commands) { - super(geyser, commands); - } - - @Override - public void execute(Invocation invocation) { - GeyserCommandSource sender = new VelocityCommandSource(invocation.source()); - GeyserSession session = getGeyserSession(sender); - - if (invocation.arguments().length > 0) { - GeyserCommand command = getCommand(invocation.arguments()[0]); - if (command != null) { - if (!invocation.source().hasPermission(getCommand(invocation.arguments()[0]).permission())) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); - return; - } - if (command.isBedrockOnly() && session == null) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.locale())); - return; - } - command.execute(session, sender, invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]); - } else { - String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", sender.locale()); - sender.sendMessage(ChatColor.RED + message); - } - } else { - getCommand("help").execute(session, sender, new String[0]); - } - } - - @Override - public List suggest(Invocation invocation) { - // Velocity seems to do the splitting a bit differently. This results in the same behaviour in bungeecord/spigot. - if (invocation.arguments().length == 0 || invocation.arguments().length == 1) { - return tabComplete(new VelocityCommandSource(invocation.source())); - } - return Collections.emptyList(); - } -} diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java index 403e4cb20..2240f9988 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java @@ -31,10 +31,12 @@ import com.velocitypowered.api.proxy.Player; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.text.GeyserLocale; import java.util.Locale; +import java.util.UUID; public class VelocityCommandSource implements GeyserCommandSource { @@ -72,6 +74,14 @@ public class VelocityCommandSource implements GeyserCommandSource { return handle instanceof ConsoleCommandSource; } + @Override + public @Nullable UUID playerUuid() { + if (handle instanceof Player player) { + return player.getUniqueId(); + } + return null; + } + @Override public String locale() { if (handle instanceof Player) { @@ -83,6 +93,12 @@ public class VelocityCommandSource implements GeyserCommandSource { @Override public boolean hasPermission(String permission) { - return handle.hasPermission(permission); + // Handle blank permissions ourselves, as velocity only handles empty ones + return permission.isBlank() || handle.hasPermission(permission); + } + + @Override + public Object handle() { + return handle; } } diff --git a/bootstrap/viaproxy/build.gradle.kts b/bootstrap/viaproxy/build.gradle.kts index 6eadc790f..254787743 100644 --- a/bootstrap/viaproxy/build.gradle.kts +++ b/bootstrap/viaproxy/build.gradle.kts @@ -8,12 +8,14 @@ platformRelocate("net.kyori") platformRelocate("org.yaml") platformRelocate("it.unimi.dsi.fastutil") platformRelocate("org.cloudburstmc.netty") +platformRelocate("org.incendo") +platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated // These dependencies are already present on the platform provided(libs.viaproxy) -application { - mainClass.set("org.geysermc.geyser.platform.viaproxy.GeyserViaProxyMain") +tasks.withType { + manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyMain" } tasks.withType { diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java index bdc80335a..1eed778f2 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java @@ -34,13 +34,15 @@ import net.raphimc.viaproxy.plugins.events.ProxyStartEvent; import net.raphimc.viaproxy.plugins.events.ProxyStopEvent; import net.raphimc.viaproxy.plugins.events.ShouldVerifyOnlineModeEvent; import org.apache.logging.log4j.LogManager; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.standalone.StandaloneCloudCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; @@ -50,7 +52,6 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.LoopbackUtil; -import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; @@ -66,7 +67,8 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst private final GeyserViaProxyLogger logger = new GeyserViaProxyLogger(LogManager.getLogger("Geyser")); private GeyserViaProxyConfiguration config; private GeyserImpl geyser; - private GeyserCommandManager commandManager; + private StandaloneCloudCommandManager cloud; + private CommandRegistry commandRegistry; private IGeyserPingPassthrough pingPassthrough; @Override @@ -87,7 +89,9 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst @EventHandler private void onConsoleCommand(final ConsoleCommandEvent event) { final String command = event.getCommand().startsWith("/") ? event.getCommand().substring(1) : event.getCommand(); - if (this.getGeyserCommandManager().runCommand(this.getGeyserLogger(), command + " " + String.join(" ", event.getArgs()))) { + CommandRegistry registry = this.getCommandRegistry(); + if (registry.rootCommands().contains(command)) { + registry.runCommand(this.getGeyserLogger(), command + " " + String.join(" ", event.getArgs())); event.setCancelled(true); } } @@ -128,17 +132,25 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst @Override public void onGeyserEnable() { - if (GeyserImpl.getInstance().isReloading()) { + boolean reloading = geyser.isReloading(); + if (reloading) { if (!this.loadConfig()) { return; } + } else { + // Only initialized once - documented in the Geyser-Standalone bootstrap + this.cloud = new StandaloneCloudCommandManager(geyser); + this.commandRegistry = new CommandRegistry(geyser, cloud); } - this.commandManager = new GeyserCommandManager(this.geyser); - this.commandManager.init(); - GeyserImpl.start(); + if (!reloading) { + // Event must be fired after CommandRegistry has subscribed its listener. + // Also, the subscription for the Permissions class is created when Geyser is initialized (by GeyserImpl#start) + this.cloud.fireRegisterPermissionsEvent(); + } + if (ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().newerThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) { // Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser); @@ -166,8 +178,8 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst } @Override - public GeyserCommandManager getGeyserCommandManager() { - return this.commandManager; + public CommandRegistry getCommandRegistry() { + return this.commandRegistry; } @Override @@ -185,7 +197,7 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst return new GeyserViaProxyDumpInfo(); } - @NotNull + @NonNull @Override public String getServerBindAddress() { if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) { @@ -209,6 +221,7 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst return false; } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean loadConfig() { try { final File configFile = FileUtils.fileOrCopiedFromResource(new File(ROOT_FOLDER, "config.yml"), "config.yml", s -> s.replaceAll("generateduuid", UUID.randomUUID().toString()), this); diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index 7952bcf14..20d14c443 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -37,6 +37,10 @@ provided("io.netty", "netty-resolver-dns") provided("io.netty", "netty-resolver-dns-native-macos") provided("org.ow2.asm", "asm") +// cloud-fabric/cloud-neoforge jij's all cloud depends already +provided("org.incendo", ".*") +provided("io.leangen.geantyref", "geantyref") + architectury { minecraft = libs.minecraft.get().version as String } @@ -120,4 +124,4 @@ repositories { maven("https://oss.sonatype.org/content/repositories/snapshots/") maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") maven("https://maven.neoforged.net/releases") -} \ No newline at end of file +} diff --git a/build-logic/src/main/kotlin/geyser.platform-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.platform-conventions.gradle.kts index 81d224906..410e67404 100644 --- a/build-logic/src/main/kotlin/geyser.platform-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.platform-conventions.gradle.kts @@ -1,4 +1,3 @@ plugins { - application id("geyser.publish-conventions") } \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 3b5cc3df9..acd6c5147 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -51,6 +51,9 @@ dependencies { // Adventure text serialization api(libs.bundles.adventure) + // command library + api(libs.cloud.core) + api(libs.erosion.common) { isTransitive = false } diff --git a/core/src/main/java/org/geysermc/geyser/Constants.java b/core/src/main/java/org/geysermc/geyser/Constants.java index 534cb30ad..7f00075d8 100644 --- a/core/src/main/java/org/geysermc/geyser/Constants.java +++ b/core/src/main/java/org/geysermc/geyser/Constants.java @@ -35,9 +35,7 @@ public final class Constants { public static final String NEWS_PROJECT_NAME = "geyser"; public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://geysermc.org/download#floodgate"; - public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download"; - public static final String UPDATE_PERMISSION = "geyser.update"; @Deprecated static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json"; diff --git a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java index a9414d9d0..3063fa4f6 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java @@ -27,7 +27,7 @@ package org.geysermc.geyser; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.level.GeyserWorldManager; @@ -82,11 +82,11 @@ public interface GeyserBootstrap { GeyserLogger getGeyserLogger(); /** - * Returns the current CommandManager + * Returns the current CommandRegistry * - * @return The current CommandManager + * @return The current CommandRegistry */ - GeyserCommandManager getGeyserCommandManager(); + CommandRegistry getCommandRegistry(); /** * Returns the current PingPassthrough manager diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 8f88f5b6a..464ebda96 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -68,7 +68,7 @@ import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.RemoteServer; import org.geysermc.geyser.api.util.MinecraftVersion; import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.erosion.UnixSocketClientListener; @@ -128,7 +128,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; @Getter -public class GeyserImpl implements GeyserApi { +public class GeyserImpl implements GeyserApi, EventRegistrar { public static final ObjectMapper JSON_MAPPER = new ObjectMapper() .enable(JsonParser.Feature.IGNORE_UNDEFINED) .enable(JsonParser.Feature.ALLOW_COMMENTS) @@ -231,9 +231,7 @@ public class GeyserImpl implements GeyserApi { logger.info(GeyserLocale.getLocaleStringLog("geyser.core.load", NAME, VERSION)); logger.info(""); if (IS_DEV) { - // TODO cloud use language string - //logger.info(GeyserLocale.getLocaleStringLog("geyser.core.dev_build", "https://discord.gg/geysermc")); - logger.info("You are running a development build of Geyser! Please report any bugs you find on our Discord server: %s".formatted("https://discord.gg/geysermc")); + logger.info(GeyserLocale.getLocaleStringLog("geyser.core.dev_build", "https://discord.gg/geysermc")); logger.info(""); } logger.info("******************************************"); @@ -266,6 +264,9 @@ public class GeyserImpl implements GeyserApi { CompletableFuture.runAsync(AssetUtils::downloadAndRunClientJarTasks); }); + // Register our general permissions when possible + eventBus.subscribe(this, GeyserRegisterPermissionsEvent.class, Permissions::register); + startInstance(); GeyserConfiguration config = bootstrap.getGeyserConfig(); @@ -730,7 +731,6 @@ public class GeyserImpl implements GeyserApi { if (isEnabled) { this.disable(); } - this.commandManager().getCommands().clear(); // Disable extensions, fire the shutdown event this.eventBus.fire(new GeyserShutdownEvent(this.extensionManager, this.eventBus)); @@ -768,9 +768,12 @@ public class GeyserImpl implements GeyserApi { return this.extensionManager; } + /** + * @return the current CommandRegistry in use. The instance may change over the lifecycle of the Geyser runtime. + */ @NonNull - public GeyserCommandManager commandManager() { - return this.bootstrap.getGeyserCommandManager(); + public CommandRegistry commandRegistry() { + return this.bootstrap.getCommandRegistry(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java index aa79e3630..f408de29c 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java @@ -30,6 +30,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.command.GeyserCommandSource; +import java.util.UUID; public interface GeyserLogger extends GeyserCommandSource { @@ -129,6 +130,11 @@ public interface GeyserLogger extends GeyserCommandSource { return true; } + @Override + default @Nullable UUID playerUuid() { + return null; + } + @Override default boolean hasPermission(String permission) { return true; diff --git a/core/src/main/java/org/geysermc/geyser/Permissions.java b/core/src/main/java/org/geysermc/geyser/Permissions.java new file mode 100644 index 000000000..b65a5af7a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/Permissions.java @@ -0,0 +1,63 @@ +/* + * 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; + +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; +import org.geysermc.geyser.api.util.TriState; + +import java.util.HashMap; +import java.util.Map; + +/** + * Permissions related to Geyser + */ +public final class Permissions { + private static final Map PERMISSIONS = new HashMap<>(); + + public static final String CHECK_UPDATE = register("geyser.update"); + public static final String SERVER_SETTINGS = register("geyser.settings.server"); + public static final String SETTINGS_GAMERULES = register("geyser.settings.gamerules"); + + private Permissions() { + //no + } + + private static String register(String permission) { + return register(permission, TriState.NOT_SET); + } + + @SuppressWarnings("SameParameterValue") + private static String register(String permission, TriState permissionDefault) { + PERMISSIONS.put(permission, permissionDefault); + return permission; + } + + public static void register(GeyserRegisterPermissionsEvent event) { + for (Map.Entry permission : PERMISSIONS.entrySet()) { + event.register(permission.getKey(), permission.getValue()); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java new file mode 100644 index 000000000..f07092afd --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java @@ -0,0 +1,300 @@ +/* + * 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.command; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.event.EventRegistrar; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; +import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.api.util.PlatformType; +import org.geysermc.geyser.api.util.TriState; +import org.geysermc.geyser.command.defaults.AdvancedTooltipsCommand; +import org.geysermc.geyser.command.defaults.AdvancementsCommand; +import org.geysermc.geyser.command.defaults.ConnectionTestCommand; +import org.geysermc.geyser.command.defaults.DumpCommand; +import org.geysermc.geyser.command.defaults.ExtensionsCommand; +import org.geysermc.geyser.command.defaults.HelpCommand; +import org.geysermc.geyser.command.defaults.ListCommand; +import org.geysermc.geyser.command.defaults.OffhandCommand; +import org.geysermc.geyser.command.defaults.ReloadCommand; +import org.geysermc.geyser.command.defaults.SettingsCommand; +import org.geysermc.geyser.command.defaults.StatisticsCommand; +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.text.GeyserLocale; +import org.incendo.cloud.Command.Builder; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import static org.geysermc.geyser.command.GeyserCommand.DEFAULT_ROOT_COMMAND; + +/** + * Registers all built-in and extension commands to the given Cloud CommandManager. + *

    + * Fires {@link GeyserDefineCommandsEvent} upon construction. + *

    + * Subscribes to {@link GeyserRegisterPermissionsEvent} upon construction. + * A new instance of this class (that registers the same permissions) shouldn't be created until the previous + * instance is unsubscribed from the event. + */ +public class CommandRegistry implements EventRegistrar { + + private static final String GEYSER_ROOT_PERMISSION = "geyser.command"; + + protected final GeyserImpl geyser; + private final CommandManager cloud; + private final boolean applyRootPermission; + + /** + * Map of Geyser subcommands to their Commands + */ + private final Map commands = new Object2ObjectOpenHashMap<>(13); + + /** + * Map of Extensions to maps of their subcommands + */ + private final Map> extensionCommands = new Object2ObjectOpenHashMap<>(0); + + /** + * Map of root commands (that are for extensions) to Extensions + */ + private final Map extensionRootCommands = new Object2ObjectOpenHashMap<>(0); + + /** + * Map containing only permissions that have been registered with a default value + */ + protected final Map permissionDefaults = new Object2ObjectOpenHashMap<>(13); + + /** + * Creates a new CommandRegistry. Does apply a root permission. If undesired, use the other constructor. + */ + public CommandRegistry(GeyserImpl geyser, CommandManager cloud) { + this(geyser, cloud, true); + } + + /** + * Creates a new CommandRegistry + * + * @param geyser the Geyser instance + * @param cloud the cloud command manager to register commands to + * @param applyRootPermission true if this registry should apply a permission to Geyser and Extension root commands. + * This currently exists because we want to retain the root command permission for Spigot, + * but don't want to add it yet to platforms like Velocity where we cannot natively + * specify a permission default. Doing so will break setups as players would suddenly not + * have the required permission to execute any Geyser commands. + */ + public CommandRegistry(GeyserImpl geyser, CommandManager cloud, boolean applyRootPermission) { + this.geyser = geyser; + this.cloud = cloud; + this.applyRootPermission = applyRootPermission; + + // register our custom exception handlers + ExceptionHandlers.register(cloud); + + // begin command registration + HelpCommand help = new HelpCommand(DEFAULT_ROOT_COMMAND, "help", "geyser.commands.help.desc", "geyser.command.help", this.commands); + registerBuiltInCommand(help); + buildRootCommand(GEYSER_ROOT_PERMISSION, help); // build root and delegate to help + + registerBuiltInCommand(new ListCommand(geyser, "list", "geyser.commands.list.desc", "geyser.command.list")); + registerBuiltInCommand(new ReloadCommand(geyser, "reload", "geyser.commands.reload.desc", "geyser.command.reload")); + registerBuiltInCommand(new OffhandCommand("offhand", "geyser.commands.offhand.desc", "geyser.command.offhand")); + registerBuiltInCommand(new DumpCommand(geyser, "dump", "geyser.commands.dump.desc", "geyser.command.dump")); + registerBuiltInCommand(new VersionCommand(geyser, "version", "geyser.commands.version.desc", "geyser.command.version")); + registerBuiltInCommand(new SettingsCommand("settings", "geyser.commands.settings.desc", "geyser.command.settings")); + registerBuiltInCommand(new StatisticsCommand("statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); + registerBuiltInCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); + registerBuiltInCommand(new AdvancedTooltipsCommand("tooltips", "geyser.commands.advancedtooltips.desc", "geyser.command.tooltips")); + registerBuiltInCommand(new ConnectionTestCommand(geyser, "connectiontest", "geyser.commands.connectiontest.desc", "geyser.command.connectiontest")); + if (this.geyser.getPlatformType() == PlatformType.STANDALONE) { + registerBuiltInCommand(new StopCommand(geyser, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); + } + + if (!this.geyser.extensionManager().extensions().isEmpty()) { + registerBuiltInCommand(new ExtensionsCommand(this.geyser, "extensions", "geyser.commands.extensions.desc", "geyser.command.extensions")); + } + + GeyserDefineCommandsEvent defineCommandsEvent = new GeyserDefineCommandsEventImpl(this.commands) { + + @Override + public void register(@NonNull Command command) { + if (!(command instanceof GeyserExtensionCommand extensionCommand)) { + throw new IllegalArgumentException("Expected GeyserExtensionCommand as part of command registration but got " + command + "! Did you use the Command builder properly?"); + } + + registerExtensionCommand(extensionCommand.extension(), extensionCommand); + } + }; + this.geyser.eventBus().fire(defineCommandsEvent); + + // Stuff that needs to be done on a per-extension basis + for (Map.Entry> entry : this.extensionCommands.entrySet()) { + Extension extension = entry.getKey(); + + // Register this extension's root command + extensionRootCommands.put(extension.rootCommand(), extension); + + // Register help commands for all extensions with commands + String id = extension.description().id(); + HelpCommand extensionHelp = new HelpCommand( + extension.rootCommand(), + "help", + "geyser.commands.exthelp.desc", + "geyser.command.exthelp." + id, + entry.getValue()); // commands it provides help for + + registerExtensionCommand(extension, extensionHelp); + buildRootCommand("geyser.extension." + id + ".command", extensionHelp); + } + + // Wait for the right moment (depends on the platform) to register permissions. + geyser.eventBus().subscribe(this, GeyserRegisterPermissionsEvent.class, this::onRegisterPermissions); + } + + /** + * @return an immutable view of the root commands registered to this command registry + */ + @NonNull + public Collection rootCommands() { + return cloud.rootCommands(); + } + + /** + * For internal Geyser commands + */ + private void registerBuiltInCommand(GeyserCommand command) { + register(command, this.commands); + } + + private void registerExtensionCommand(@NonNull Extension extension, @NonNull GeyserCommand command) { + register(command, this.extensionCommands.computeIfAbsent(extension, e -> new HashMap<>())); + } + + protected void register(GeyserCommand command, Map commands) { + String root = command.rootCommand(); + String name = command.name(); + if (commands.containsKey(name)) { + throw new IllegalArgumentException("Command with root=%s, name=%s already registered".formatted(root, name)); + } + + command.register(cloud); + commands.put(name, command); + geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.commands.registered", root + " " + name)); + + for (String alias : command.aliases()) { + commands.put(alias, command); + } + + String permission = command.permission(); + TriState defaultValue = command.permissionDefault(); + if (!permission.isBlank() && defaultValue != null) { + + TriState existingDefault = permissionDefaults.get(permission); + // Extensions might be using the same permission for two different commands + if (existingDefault != null && existingDefault != defaultValue) { + geyser.getLogger().debug("Overriding permission default %s:%s with %s".formatted(permission, existingDefault, defaultValue)); + } + + permissionDefaults.put(permission, defaultValue); + } + } + + /** + * Registers a root command to cloud that delegates to the given help command. + * The name of this root command is the root of the given help command. + * + * @param permission the permission of the root command. currently, it may or may not be + * applied depending on the platform. see below. + * @param help the help command to delegate to + */ + private void buildRootCommand(String permission, HelpCommand help) { + Builder builder = cloud.commandBuilder(help.rootCommand()); + + if (applyRootPermission) { + builder = builder.permission(permission); + permissionDefaults.put(permission, TriState.TRUE); + } + + cloud.command(builder.handler(context -> { + GeyserCommandSource source = context.sender(); + if (!source.hasPermission(help.permission())) { + // delegate if possible - otherwise we have nothing else to offer the user. + source.sendLocaleString(ExceptionHandlers.PERMISSION_FAIL_LANG_KEY); + return; + } + help.execute(source); + })); + } + + protected void onRegisterPermissions(GeyserRegisterPermissionsEvent event) { + for (Map.Entry permission : permissionDefaults.entrySet()) { + event.register(permission.getKey(), permission.getValue()); + } + } + + public boolean hasPermission(GeyserCommandSource source, String permission) { + // Handle blank permissions ourselves, as cloud only handles empty ones + return permission.isBlank() || cloud.hasPermission(source, permission); + } + + /** + * Returns the description of the given command + * + * @param command the root command node + * @param locale the ideal locale that the description should be in + * @return a description if found, otherwise an empty string. The locale is not guaranteed. + */ + @NonNull + public String description(@NonNull String command, @NonNull String locale) { + if (command.equals(DEFAULT_ROOT_COMMAND)) { + return GeyserLocale.getPlayerLocaleString("geyser.command.root.geyser", locale); + } + + Extension extension = extensionRootCommands.get(command); + if (extension != null) { + return GeyserLocale.getPlayerLocaleString("geyser.command.root.extension", locale, extension.name()); + } + return ""; + } + + /** + * Dispatches a command into cloud and handles any thrown exceptions. + * This method may or may not be blocking, depending on the {@link ExecutionCoordinator} in use by cloud. + */ + public void runCommand(@NonNull GeyserCommandSource source, @NonNull String command) { + cloud.commandExecutor().executeCommand(source, command); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandSourceConverter.java b/core/src/main/java/org/geysermc/geyser/command/CommandSourceConverter.java new file mode 100644 index 000000000..1fa5871e0 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/CommandSourceConverter.java @@ -0,0 +1,113 @@ +/* + * 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.command; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.session.GeyserSession; +import org.incendo.cloud.SenderMapper; + +import java.util.UUID; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Converts {@link GeyserCommandSource}s to the server's command sender type (and back) in a lenient manner. + * + * @param senderType class of the server command sender type + * @param playerLookup function for looking up a player command sender by UUID + * @param consoleProvider supplier of the console command sender + * @param commandSourceLookup supplier of the platform implementation of the {@link GeyserCommandSource} + * @param server command sender type + */ +public record CommandSourceConverter(Class senderType, + Function playerLookup, + Supplier consoleProvider, + Function commandSourceLookup +) implements SenderMapper { + + /** + * Creates a new CommandSourceConverter for a server platform + * in which the player type is not a command sender type, and must be mapped. + * + * @param senderType class of the command sender type + * @param playerLookup function for looking up a player by UUID + * @param senderLookup function for converting a player to a command sender + * @param consoleProvider supplier of the console command sender + * @param commandSourceLookup supplier of the platform implementation of {@link GeyserCommandSource} + * @return a new CommandSourceConverter + * @param

    server player type + * @param server command sender type + */ + public static CommandSourceConverter layered(Class senderType, + Function playerLookup, + Function senderLookup, + Supplier consoleProvider, + Function commandSourceLookup) { + Function lookup = uuid -> { + P player = playerLookup.apply(uuid); + if (player == null) { + return null; + } + return senderLookup.apply(player); + }; + return new CommandSourceConverter<>(senderType, lookup, consoleProvider, commandSourceLookup); + } + + @Override + public @NonNull GeyserCommandSource map(@NonNull S base) { + return commandSourceLookup.apply(base); + } + + @Override + public @NonNull S reverse(GeyserCommandSource source) throws IllegalArgumentException { + Object handle = source.handle(); + if (senderType.isInstance(handle)) { + return senderType.cast(handle); // one of the server platform implementations + } + + if (source.isConsole()) { + return consoleProvider.get(); // one of the loggers + } + + if (!(source instanceof GeyserSession)) { + GeyserLogger logger = GeyserImpl.getInstance().getLogger(); + if (logger.isDebug()) { + logger.debug("Falling back to UUID for command sender lookup for a command source that is not a GeyserSession: " + source); + Thread.dumpStack(); + } + } + + // Ideally lookup should only be necessary for GeyserSession + UUID uuid = source.playerUuid(); + if (uuid != null) { + return playerLookup.apply(uuid); + } + + throw new IllegalArgumentException("failed to find sender for name=%s, uuid=%s".formatted(source.name(), source.playerUuid())); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/command/ExceptionHandlers.java b/core/src/main/java/org/geysermc/geyser/command/ExceptionHandlers.java new file mode 100644 index 000000000..45657a596 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/ExceptionHandlers.java @@ -0,0 +1,129 @@ +/* + * 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.command; + +import io.leangen.geantyref.GenericTypeReflector; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.text.MinecraftLocale; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.exception.ArgumentParseException; +import org.incendo.cloud.exception.CommandExecutionException; +import org.incendo.cloud.exception.InvalidCommandSenderException; +import org.incendo.cloud.exception.InvalidSyntaxException; +import org.incendo.cloud.exception.NoPermissionException; +import org.incendo.cloud.exception.NoSuchCommandException; +import org.incendo.cloud.exception.handling.ExceptionController; + +import java.lang.reflect.Type; +import java.util.function.BiConsumer; + +/** + * Geyser's exception handlers for command execution with Cloud. + * Overrides Cloud's defaults so that messages can be customized to our liking: localization, etc. + */ +final class ExceptionHandlers { + + final static String PERMISSION_FAIL_LANG_KEY = "geyser.command.permission_fail"; + + private final ExceptionController controller; + + private ExceptionHandlers(ExceptionController controller) { + this.controller = controller; + } + + /** + * Clears the existing handlers that are registered to the given command manager, and repopulates them. + * + * @param manager the manager whose exception handlers will be modified + */ + static void register(CommandManager manager) { + new ExceptionHandlers(manager.exceptionController()).register(); + } + + private void register() { + // Yeet the default exception handlers that cloud provides so that we can perform localization. + controller.clearHandlers(); + + registerExceptionHandler(InvalidSyntaxException.class, + (src, e) -> src.sendLocaleString("geyser.command.invalid_syntax", e.correctSyntax())); + + registerExceptionHandler(InvalidCommandSenderException.class, (src, e) -> { + // We currently don't use cloud sender type requirements anywhere. + // This can be implemented better in the future if necessary. + Type type = e.requiredSenderTypes().iterator().next(); // just grab the first + String typeString = GenericTypeReflector.getTypeName(type); + src.sendLocaleString("geyser.command.invalid_sender", e.commandSender().getClass().getSimpleName(), typeString); + }); + + registerExceptionHandler(NoPermissionException.class, ExceptionHandlers::handleNoPermission); + + registerExceptionHandler(NoSuchCommandException.class, + (src, e) -> src.sendLocaleString("geyser.command.not_found")); + + registerExceptionHandler(ArgumentParseException.class, + (src, e) -> src.sendLocaleString("geyser.command.invalid_argument", e.getCause().getMessage())); + + registerExceptionHandler(CommandExecutionException.class, + (src, e) -> handleUnexpectedThrowable(src, e.getCause())); + + registerExceptionHandler(Throwable.class, + (src, e) -> handleUnexpectedThrowable(src, e.getCause())); + } + + private void registerExceptionHandler(Class type, BiConsumer handler) { + controller.registerHandler(type, context -> handler.accept(context.context().sender(), context.exception())); + } + + private static void handleNoPermission(GeyserCommandSource source, NoPermissionException exception) { + // custom handling if the source can't use the command because of additional requirements + if (exception.permissionResult() instanceof GeyserPermission.Result result) { + if (result.meta() == GeyserPermission.Result.Meta.NOT_BEDROCK) { + source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.command.bedrock_only", source.locale())); + return; + } + if (result.meta() == GeyserPermission.Result.Meta.NOT_PLAYER) { + source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.command.player_only", source.locale())); + return; + } + } else { + GeyserLogger logger = GeyserImpl.getInstance().getLogger(); + if (logger.isDebug()) { + logger.debug("Expected a GeyserPermission.Result for %s but instead got %s from %s".formatted(exception.currentChain(), exception.permissionResult(), exception.missingPermission())); + } + } + + // Result.NO_PERMISSION or generic permission failure + source.sendLocaleString(PERMISSION_FAIL_LANG_KEY); + } + + private static void handleUnexpectedThrowable(GeyserCommandSource source, Throwable throwable) { + source.sendMessage(MinecraftLocale.getLocaleString("command.failed", source.locale())); // java edition translation key + GeyserImpl.getInstance().getLogger().error("Exception while executing command handler", throwable); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java index 47d57e73f..3cc05ca0c 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java @@ -25,65 +25,187 @@ package org.geysermc.geyser.command; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.experimental.Accessors; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; +import org.geysermc.geyser.api.util.TriState; +import org.geysermc.geyser.text.GeyserLocale; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.description.CommandDescription; +import org.jetbrains.annotations.Contract; import java.util.Collections; import java.util.List; -@Accessors(fluent = true) -@Getter -@RequiredArgsConstructor -public abstract class GeyserCommand implements Command { +public abstract class GeyserCommand implements org.geysermc.geyser.api.command.Command { + public static final String DEFAULT_ROOT_COMMAND = "geyser"; + + /** + * The second literal of the command. Note: the first literal is {@link #rootCommand()}. + */ + @NonNull + private final String name; - protected final String name; /** * The description of the command - will attempt to be translated. */ - protected final String description; - protected final String permission; - - private List aliases = Collections.emptyList(); - - public abstract void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args); + @NonNull + private final String description; /** - * If false, hides the command from being shown on the Geyser Standalone GUI. - * - * @return true if the command can be run on the server console - */ - @Override - public boolean isExecutableOnConsole() { - return true; - } - - /** - * Used in the GUI to know what subcommands can be run - * - * @return a list of all possible subcommands, or empty if none. + * The permission node required to run the command, or blank if not required. */ @NonNull - @Override - public List subCommands() { - return Collections.emptyList(); + private final String permission; + + /** + * The default value of the permission node. + * A null value indicates that the permission node should not be registered whatsoever. + * See {@link GeyserRegisterPermissionsEvent#register(String, TriState)} for TriState meanings. + */ + @Nullable + private final TriState permissionDefault; + + /** + * True if this command can be executed by players + */ + private final boolean playerOnly; + + /** + * True if this command can only be run by bedrock players + */ + private final boolean bedrockOnly; + + /** + * The aliases of the command {@link #name}. This should not be modified after construction. + */ + protected List aliases = Collections.emptyList(); + + public GeyserCommand(@NonNull String name, @NonNull String description, + @NonNull String permission, @Nullable TriState permissionDefault, + boolean playerOnly, boolean bedrockOnly) { + + if (name.isBlank()) { + throw new IllegalArgumentException("Command cannot be null or blank!"); + } + if (permission.isBlank()) { + // Cloud treats empty permissions as available to everyone, but not blank permissions. + // When registering commands, we must convert ALL whitespace permissions into empty ones, + // because we cannot override permission checks that Cloud itself performs + permission = ""; + permissionDefault = null; + } + + this.name = name; + this.description = description; + this.permission = permission; + this.permissionDefault = permissionDefault; + + if (bedrockOnly && !playerOnly) { + throw new IllegalArgumentException("Command cannot be bedrockOnly if it is not playerOnly"); + } + + this.playerOnly = playerOnly; + this.bedrockOnly = bedrockOnly; } - public void setAliases(List aliases) { - this.aliases = aliases; + public GeyserCommand(@NonNull String name, @NonNull String description, @NonNull String permission, @Nullable TriState permissionDefault) { + this(name, description, permission, permissionDefault, false, false); + } + + @NonNull + @Override + public final String name() { + return name; + } + + @NonNull + @Override + public final String description() { + return description; + } + + @NonNull + @Override + public final String permission() { + return permission; + } + + @Nullable + public final TriState permissionDefault() { + return permissionDefault; + } + + @Override + public final boolean isPlayerOnly() { + return playerOnly; + } + + @Override + public final boolean isBedrockOnly() { + return bedrockOnly; + } + + @NonNull + @Override + public final List aliases() { + return Collections.unmodifiableList(aliases); } /** - * Used for permission defaults on server implementations. - * - * @return if this command is designated to be used only by server operators. + * @return the first (literal) argument of this command, which comes before {@link #name()}. */ - @Override - public boolean isSuggestedOpOnly() { - return false; + public String rootCommand() { + return DEFAULT_ROOT_COMMAND; } -} \ No newline at end of file + + /** + * Returns a {@link org.incendo.cloud.permission.Permission} that handles {@link #isBedrockOnly()}, {@link #isPlayerOnly()}, and {@link #permission()}. + * + * @param manager the manager to be used for permission node checking + * @return a permission that will properly restrict usage of this command + */ + public final GeyserPermission commandPermission(CommandManager manager) { + return new GeyserPermission(bedrockOnly, playerOnly, permission, manager); + } + + /** + * Creates a new command builder with {@link #rootCommand()}, {@link #name()}, and {@link #aliases()} built on it. + * A permission predicate that takes into account {@link #permission()}, {@link #isBedrockOnly()}, and {@link #isPlayerOnly()} + * is applied. The Applicable from {@link #meta()} is also applied to the builder. + */ + @Contract(value = "_ -> new", pure = true) + public final Command.Builder baseBuilder(CommandManager manager) { + return manager.commandBuilder(rootCommand()) + .literal(name, aliases.toArray(new String[0])) + .permission(commandPermission(manager)) + .apply(meta()); + } + + /** + * @return an Applicable that applies this command's description + */ + protected Command.Builder.Applicable meta() { + return builder -> builder + .commandDescription(CommandDescription.commandDescription(GeyserLocale.getLocaleStringLog(description))); // used in cloud-bukkit impl + } + + /** + * Registers this command to the given command manager. + * This method may be overridden to register more than one command. + *

    + * The default implementation is that {@link #baseBuilder(CommandManager)} with {@link #execute(CommandContext)} + * applied as the handler is registered to the manager. + */ + public void register(CommandManager manager) { + manager.command(baseBuilder(manager).handler(this::execute)); + } + + /** + * Executes this command + * @param context the context with which this command should be executed + */ + public abstract void execute(CommandContext context); +} diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandExecutor.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandExecutor.java deleted file mode 100644 index 37d2ef4fb..000000000 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandExecutor.java +++ /dev/null @@ -1,98 +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.command; - -import lombok.AllArgsConstructor; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.session.GeyserSession; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * Represents helper functions for listening to {@code /geyser} or {@code /geyserext} commands. - */ -@AllArgsConstructor -public class GeyserCommandExecutor { - - protected final GeyserImpl geyser; - private final Map commands; - - public GeyserCommand getCommand(String label) { - return (GeyserCommand) commands.get(label); - } - - @Nullable - public GeyserSession getGeyserSession(GeyserCommandSource sender) { - if (sender.isConsole()) { - return null; - } - - for (GeyserSession session : geyser.getSessionManager().getSessions().values()) { - if (sender.name().equals(session.getPlayerEntity().getUsername())) { - return session; - } - } - return null; - } - - /** - * Determine which subcommands to suggest in the tab complete for the main /geyser command by a given command sender. - * - * @param sender The command sender to receive the tab complete suggestions. - * If the command sender is a bedrock player, an empty list will be returned as bedrock players do not get command argument suggestions. - * If the command sender is not a bedrock player, bedrock commands will not be shown. - * If the command sender does not have the permission for a given command, the command will not be shown. - * @return A list of command names to include in the tab complete - */ - public List tabComplete(GeyserCommandSource sender) { - if (getGeyserSession(sender) != null) { - // Bedrock doesn't get tab completions or argument suggestions - return Collections.emptyList(); - } - - List availableCommands = new ArrayList<>(); - - // Only show commands they have permission to use - for (Map.Entry entry : commands.entrySet()) { - Command geyserCommand = entry.getValue(); - if (sender.hasPermission(geyserCommand.permission())) { - if (geyserCommand.isBedrockOnly()) { - // Don't show commands the JE player can't run - continue; - } - - availableCommands.add(entry.getKey()); - } - } - - return availableCommands; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java deleted file mode 100644 index 72ed22381..000000000 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java +++ /dev/null @@ -1,330 +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.command; - -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.api.command.CommandExecutor; -import org.geysermc.geyser.api.command.CommandSource; -import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent; -import org.geysermc.geyser.api.extension.Extension; -import org.geysermc.geyser.command.defaults.AdvancedTooltipsCommand; -import org.geysermc.geyser.command.defaults.AdvancementsCommand; -import org.geysermc.geyser.command.defaults.ConnectionTestCommand; -import org.geysermc.geyser.command.defaults.DumpCommand; -import org.geysermc.geyser.command.defaults.ExtensionsCommand; -import org.geysermc.geyser.command.defaults.HelpCommand; -import org.geysermc.geyser.command.defaults.ListCommand; -import org.geysermc.geyser.command.defaults.OffhandCommand; -import org.geysermc.geyser.command.defaults.ReloadCommand; -import org.geysermc.geyser.command.defaults.SettingsCommand; -import org.geysermc.geyser.command.defaults.StatisticsCommand; -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 java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -@RequiredArgsConstructor -public class GeyserCommandManager { - - @Getter - private final Map commands = new Object2ObjectOpenHashMap<>(12); - private final Map> extensionCommands = new Object2ObjectOpenHashMap<>(0); - - private final GeyserImpl geyser; - - public void init() { - registerBuiltInCommand(new HelpCommand(geyser, "help", "geyser.commands.help.desc", "geyser.command.help", "geyser", this.commands)); - registerBuiltInCommand(new ListCommand(geyser, "list", "geyser.commands.list.desc", "geyser.command.list")); - registerBuiltInCommand(new ReloadCommand(geyser, "reload", "geyser.commands.reload.desc", "geyser.command.reload")); - registerBuiltInCommand(new OffhandCommand(geyser, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand")); - registerBuiltInCommand(new DumpCommand(geyser, "dump", "geyser.commands.dump.desc", "geyser.command.dump")); - registerBuiltInCommand(new VersionCommand(geyser, "version", "geyser.commands.version.desc", "geyser.command.version")); - registerBuiltInCommand(new SettingsCommand(geyser, "settings", "geyser.commands.settings.desc", "geyser.command.settings")); - registerBuiltInCommand(new StatisticsCommand(geyser, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); - registerBuiltInCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); - registerBuiltInCommand(new AdvancedTooltipsCommand("tooltips", "geyser.commands.advancedtooltips.desc", "geyser.command.tooltips")); - registerBuiltInCommand(new ConnectionTestCommand(geyser, "connectiontest", "geyser.commands.connectiontest.desc", "geyser.command.connectiontest")); - if (this.geyser.getPlatformType() == PlatformType.STANDALONE) { - registerBuiltInCommand(new StopCommand(geyser, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); - } - - if (!this.geyser.extensionManager().extensions().isEmpty()) { - registerBuiltInCommand(new ExtensionsCommand(this.geyser, "extensions", "geyser.commands.extensions.desc", "geyser.command.extensions")); - } - - GeyserDefineCommandsEvent defineCommandsEvent = new GeyserDefineCommandsEventImpl(this.commands) { - - @Override - public void register(@NonNull Command command) { - if (!(command instanceof GeyserExtensionCommand extensionCommand)) { - throw new IllegalArgumentException("Expected GeyserExtensionCommand as part of command registration but got " + command + "! Did you use the Command builder properly?"); - } - - registerExtensionCommand(extensionCommand.extension(), extensionCommand); - } - }; - - this.geyser.eventBus().fire(defineCommandsEvent); - - // Register help commands for all extensions with commands - for (Map.Entry> entry : this.extensionCommands.entrySet()) { - String id = entry.getKey().description().id(); - registerExtensionCommand(entry.getKey(), new HelpCommand(this.geyser, "help", "geyser.commands.exthelp.desc", "geyser.command.exthelp." + id, id, entry.getValue())); - } - } - - /** - * For internal Geyser commands - */ - public void registerBuiltInCommand(GeyserCommand command) { - register(command, this.commands); - } - - public void registerExtensionCommand(@NonNull Extension extension, @NonNull Command command) { - register(command, this.extensionCommands.computeIfAbsent(extension, e -> new HashMap<>())); - } - - private void register(Command command, Map commands) { - commands.put(command.name(), command); - geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.commands.registered", command.name())); - - if (command.aliases().isEmpty()) { - return; - } - - for (String alias : command.aliases()) { - commands.put(alias, command); - } - } - - @NonNull - public Map commands() { - return Collections.unmodifiableMap(this.commands); - } - - @NonNull - public Map> extensionCommands() { - return Collections.unmodifiableMap(this.extensionCommands); - } - - public boolean runCommand(GeyserCommandSource sender, String command) { - Extension extension = null; - for (Extension loopedExtension : this.extensionCommands.keySet()) { - if (command.startsWith(loopedExtension.description().id() + " ")) { - extension = loopedExtension; - break; - } - } - - if (!command.startsWith("geyser ") && extension == null) { - return false; - } - - command = command.trim().replace(extension != null ? extension.description().id() + " " : "geyser ", ""); - String label; - String[] args; - - if (!command.contains(" ")) { - label = command.toLowerCase(Locale.ROOT); - args = new String[0]; - } else { - label = command.substring(0, command.indexOf(" ")).toLowerCase(Locale.ROOT); - String argLine = command.substring(command.indexOf(" ") + 1); - args = argLine.contains(" ") ? argLine.split(" ") : new String[] { argLine }; - } - - Command cmd = (extension != null ? this.extensionCommands.getOrDefault(extension, Collections.emptyMap()) : this.commands).get(label); - if (cmd == null) { - sender.sendMessage(GeyserLocale.getLocaleStringLog("geyser.commands.invalid")); - return false; - } - - if (cmd instanceof GeyserCommand) { - if (sender instanceof GeyserSession) { - ((GeyserCommand) cmd).execute((GeyserSession) sender, sender, args); - } else { - if (!cmd.isBedrockOnly()) { - ((GeyserCommand) cmd).execute(null, sender, args); - } else { - geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only")); - } - } - } - - return true; - } - - /** - * Returns the description of the given command - * - * @param command Command to get the description for - * @return Command description - */ - public String description(String command) { - return ""; - } - - @RequiredArgsConstructor - public static class CommandBuilder implements Command.Builder { - private final Extension extension; - private Class sourceType; - private String name; - private String description = ""; - private String permission = ""; - private List aliases; - private boolean suggestedOpOnly = false; - private boolean executableOnConsole = true; - private List subCommands; - private boolean bedrockOnly; - private CommandExecutor executor; - - @Override - public Command.Builder source(@NonNull Class sourceType) { - this.sourceType = sourceType; - return this; - } - - public CommandBuilder name(@NonNull String name) { - this.name = name; - return this; - } - - public CommandBuilder description(@NonNull String description) { - this.description = description; - return this; - } - - public CommandBuilder permission(@NonNull String permission) { - this.permission = permission; - return this; - } - - public CommandBuilder aliases(@NonNull List aliases) { - this.aliases = aliases; - return this; - } - - @Override - public Command.Builder suggestedOpOnly(boolean suggestedOpOnly) { - this.suggestedOpOnly = suggestedOpOnly; - return this; - } - - public CommandBuilder executableOnConsole(boolean executableOnConsole) { - this.executableOnConsole = executableOnConsole; - return this; - } - - public CommandBuilder subCommands(@NonNull List subCommands) { - this.subCommands = subCommands; - return this; - } - - public CommandBuilder bedrockOnly(boolean bedrockOnly) { - this.bedrockOnly = bedrockOnly; - return this; - } - - public CommandBuilder executor(@NonNull CommandExecutor executor) { - this.executor = executor; - return this; - } - - @NonNull - public GeyserExtensionCommand build() { - if (this.name == null || this.name.isBlank()) { - throw new IllegalArgumentException("Command cannot be null or blank!"); - } - - if (this.sourceType == null) { - throw new IllegalArgumentException("Source type was not defined for command " + this.name + " in extension " + this.extension.name()); - } - - return new GeyserExtensionCommand(this.extension, this.name, this.description, this.permission) { - - @SuppressWarnings("unchecked") - @Override - public void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args) { - Class sourceType = CommandBuilder.this.sourceType; - CommandExecutor executor = CommandBuilder.this.executor; - if (sourceType.isInstance(session)) { - executor.execute((T) session, this, args); - return; - } - - if (sourceType.isInstance(sender)) { - executor.execute((T) sender, this, args); - return; - } - - GeyserImpl.getInstance().getLogger().debug("Ignoring command " + this.name + " due to no suitable sender."); - } - - @NonNull - @Override - public List aliases() { - return CommandBuilder.this.aliases == null ? Collections.emptyList() : CommandBuilder.this.aliases; - } - - @Override - public boolean isSuggestedOpOnly() { - return CommandBuilder.this.suggestedOpOnly; - } - - @NonNull - @Override - public List subCommands() { - return CommandBuilder.this.subCommands == null ? Collections.emptyList() : CommandBuilder.this.subCommands; - } - - @Override - public boolean isBedrockOnly() { - return CommandBuilder.this.bedrockOnly; - } - - @Override - public boolean isExecutableOnConsole() { - return CommandBuilder.this.executableOnConsole; - } - }; - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java index 88d148b11..c14767496 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java @@ -25,11 +25,16 @@ package org.geysermc.geyser.command; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.CommandSource; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import java.util.UUID; + /** * Implemented on top of any class that can send a command. * For example, it wraps around Spigot's CommandSender class. @@ -46,4 +51,29 @@ public interface GeyserCommandSource extends CommandSource { default void sendMessage(Component message) { sendMessage(LegacyComponentSerializer.legacySection().serialize(message)); } + + default void sendLocaleString(String key, Object... values) { + sendMessage(GeyserLocale.getPlayerLocaleString(key, locale(), values)); + } + + default void sendLocaleString(String key) { + sendMessage(GeyserLocale.getPlayerLocaleString(key, locale())); + } + + @Override + default @Nullable GeyserSession connection() { + UUID uuid = playerUuid(); + if (uuid == null) { + return null; + } + return GeyserImpl.getInstance().connectionByUuid(uuid); + } + + /** + * @return the underlying platform handle that this source represents. + * If such handle doesn't exist, this itself is returned. + */ + default Object handle() { + return this; + } } diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserPermission.java b/core/src/main/java/org/geysermc/geyser/command/GeyserPermission.java new file mode 100644 index 000000000..1ee677e97 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserPermission.java @@ -0,0 +1,136 @@ +/* + * 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.command; + +import lombok.AllArgsConstructor; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.key.CloudKey; +import org.incendo.cloud.permission.Permission; +import org.incendo.cloud.permission.PermissionResult; +import org.incendo.cloud.permission.PredicatePermission; + +import static org.geysermc.geyser.command.GeyserPermission.Result.Meta; + +@AllArgsConstructor +public class GeyserPermission implements PredicatePermission { + + /** + * True if this permission requires the command source to be a bedrock player + */ + private final boolean bedrockOnly; + + /** + * True if this permission requires the command source to be any player + */ + private final boolean playerOnly; + + /** + * The permission node that the command source must have + */ + private final String permission; + + /** + * The command manager to delegate permission checks to + */ + private final CommandManager manager; + + @Override + public @NonNull Result testPermission(@NonNull GeyserCommandSource source) { + if (bedrockOnly) { + if (source.connection() == null) { + return new Result(Meta.NOT_BEDROCK); + } + // connection is present -> it is a player -> playerOnly is irrelevant + } else if (playerOnly) { + if (source.isConsole()) { + return new Result(Meta.NOT_PLAYER); // must be a player but is console + } + } + + if (permission.isBlank() || manager.hasPermission(source, permission)) { + return new Result(Meta.ALLOWED); + } + return new Result(Meta.NO_PERMISSION); + } + + @Override + public @NonNull CloudKey key() { + return CloudKey.cloudKey(permission); + } + + /** + * Basic implementation of cloud's {@link PermissionResult} that delegates to the more informative {@link Meta}. + */ + public final class Result implements PermissionResult { + + private final Meta meta; + + private Result(Meta meta) { + this.meta = meta; + } + + public Meta meta() { + return meta; + } + + @Override + public boolean allowed() { + return meta == Meta.ALLOWED; + } + + @Override + public @NonNull Permission permission() { + return GeyserPermission.this; + } + + /** + * More detailed explanation of whether the permission check passed. + */ + public enum Meta { + + /** + * The source must be a bedrock player, but is not. + */ + NOT_BEDROCK, + + /** + * The source must be a player, but is not. + */ + NOT_PLAYER, + + /** + * The source does not have a required permission node. + */ + NO_PERMISSION, + + /** + * The source meets all requirements. + */ + ALLOWED + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java index 466515b3f..75b9252da 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java @@ -25,33 +25,32 @@ package org.geysermc.geyser.command.defaults; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; +import org.incendo.cloud.context.CommandContext; + +import java.util.Objects; public class AdvancedTooltipsCommand extends GeyserCommand { + public AdvancedTooltipsCommand(String name, String description, String permission) { - super(name, description, permission); + super(name, description, permission, TriState.TRUE, true, true); } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - if (session != null) { - String onOrOff = session.isAdvancedTooltips() ? "off" : "on"; - session.setAdvancedTooltips(!session.isAdvancedTooltips()); - session.sendMessage("§l§e" + MinecraftLocale.getLocaleString("debug.prefix", session.locale()) + " §r" + MinecraftLocale.getLocaleString("debug.advanced_tooltips." + onOrOff, session.locale())); - session.getInventoryTranslator().updateInventory(session, session.getPlayerInventory()); - } - } + public void execute(CommandContext context) { + GeyserSession session = Objects.requireNonNull(context.sender().connection()); - @Override - public boolean isExecutableOnConsole() { - return false; - } - - @Override - public boolean isBedrockOnly() { - return true; + String onOrOff = session.isAdvancedTooltips() ? "off" : "on"; + session.setAdvancedTooltips(!session.isAdvancedTooltips()); + session.sendMessage(ChatColor.BOLD + ChatColor.YELLOW + + MinecraftLocale.getLocaleString("debug.prefix", session.locale()) + + " " + ChatColor.RESET + + MinecraftLocale.getLocaleString("debug.advanced_tooltips." + onOrOff, session.locale())); + session.getInventoryTranslator().updateInventory(session, session.getPlayerInventory()); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java index 28253433f..0cba28f33 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java @@ -25,29 +25,23 @@ package org.geysermc.geyser.command.defaults; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; +import org.incendo.cloud.context.CommandContext; + +import java.util.Objects; public class AdvancementsCommand extends GeyserCommand { + public AdvancementsCommand(String name, String description, String permission) { - super(name, description, permission); + super(name, description, permission, TriState.TRUE, true, true); } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - if (session != null) { - session.getAdvancementsCache().buildAndShowMenuForm(); - } - } - - @Override - public boolean isExecutableOnConsole() { - return false; - } - - @Override - public boolean isBedrockOnly() { - return true; + public void execute(CommandContext context) { + GeyserSession session = Objects.requireNonNull(context.sender().connection()); + session.getAdvancementsCache().buildAndShowMenuForm(); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java index 981c97595..d2066dba1 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java @@ -26,90 +26,82 @@ package org.geysermc.geyser.command.defaults; import com.fasterxml.jackson.databind.JsonNode; -import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.util.PlatformType; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.GeyserConfiguration; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.LoopbackUtil; import org.geysermc.geyser.util.WebUtils; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Random; import java.util.concurrent.CompletableFuture; +import static org.incendo.cloud.parser.standard.IntegerParser.integerParser; +import static org.incendo.cloud.parser.standard.StringParser.stringParser; + public class ConnectionTestCommand extends GeyserCommand { + /* * The MOTD is temporarily changed during the connection test. * This allows us to check if we are pinging the correct Geyser instance */ public static String CONNECTION_TEST_MOTD = null; - private final GeyserImpl geyser; + private static final String ADDRESS = "address"; + private static final String PORT = "port"; + private final GeyserImpl geyser; private final Random random = new Random(); public ConnectionTestCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); + super(name, description, permission, TriState.NOT_SET); this.geyser = geyser; } @Override - public void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args) { - // Only allow the console to create dumps on Geyser Standalone - if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); - return; - } + public void register(CommandManager manager) { + manager.command(baseBuilder(manager) + .required(ADDRESS, stringParser()) + .optional(PORT, integerParser(0, 65535)) + .handler(this::execute)); + } - if (args.length == 0) { - sender.sendMessage("Provide the server IP and port you are trying to test Bedrock connections for. Example: `test.geysermc.org:19132`"); - return; - } + @Override + public void execute(CommandContext context) { + GeyserCommandSource source = context.sender(); + String ipArgument = context.get(ADDRESS); + Integer portArgument = context.getOrDefault(PORT, null); // null if port was not specified // Replace "<" and ">" symbols if they are present to avoid the common issue of people including them - String[] fullAddress = args[0].replace("<", "").replace(">", "").split(":", 2); - - // Still allow people to not supply a port and fallback to 19132 - int port; - if (fullAddress.length == 2) { - try { - port = Integer.parseInt(fullAddress[1]); - } catch (NumberFormatException e) { - // can occur if e.g. "/geyser connectiontest : is ran - sender.sendMessage("Not a valid port! Specify a valid numeric port."); - return; - } - } else { - port = geyser.getConfig().getBedrock().broadcastPort(); - } - String ip = fullAddress[0]; + final String ip = ipArgument.replace("<", "").replace(">", ""); + final int port = portArgument != null ? portArgument : geyser.getConfig().getBedrock().broadcastPort(); // default bedrock port // Issue: people commonly checking placeholders if (ip.equals("ip")) { - sender.sendMessage(ip + " is not a valid IP, and instead a placeholder. Please specify the IP to check."); + source.sendMessage(ip + " is not a valid IP, and instead a placeholder. Please specify the IP to check."); return; } // Issue: checking 0.0.0.0 won't work if (ip.equals("0.0.0.0")) { - sender.sendMessage("Please specify the IP that you would connect with. 0.0.0.0 in the config tells Geyser to the listen on the server's IPv4."); + source.sendMessage("Please specify the IP that you would connect with. 0.0.0.0 in the config tells Geyser to the listen on the server's IPv4."); return; } // Issue: people testing local ip if (ip.equals("localhost") || ip.startsWith("127.") || ip.startsWith("10.") || ip.startsWith("192.168.")) { - sender.sendMessage("This tool checks if connections from other networks are possible, so you cannot check a local IP."); + source.sendMessage("This tool checks if connections from other networks are possible, so you cannot check a local IP."); return; } // Issue: port out of bounds if (port <= 0 || port >= 65535) { - sender.sendMessage("The port you specified is invalid! Please specify a valid port."); + source.sendMessage("The port you specified is invalid! Please specify a valid port."); return; } @@ -118,37 +110,37 @@ public class ConnectionTestCommand extends GeyserCommand { // Issue: do the ports not line up? We only check this if players don't override the broadcast port - if they do, they (hopefully) know what they're doing if (config.getBedrock().broadcastPort() == config.getBedrock().port()) { if (port != config.getBedrock().port()) { - if (fullAddress.length == 2) { - sender.sendMessage("The port you are testing with (" + port + ") is not the same as you set in your Geyser configuration (" + if (portArgument != null) { + source.sendMessage("The port you are testing with (" + port + ") is not the same as you set in your Geyser configuration (" + config.getBedrock().port() + ")"); - sender.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `port` in the config."); + source.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `port` in the config."); if (config.getBedrock().isCloneRemotePort()) { - sender.sendMessage("You have `clone-remote-port` enabled. This option ignores the `bedrock` `port` in the config, and uses the Java server port instead."); + source.sendMessage("You have `clone-remote-port` enabled. This option ignores the `bedrock` `port` in the config, and uses the Java server port instead."); } } else { - sender.sendMessage("You did not specify the port to check (add it with \":\"), " + + source.sendMessage("You did not specify the port to check (add it with \":\"), " + "and the default port 19132 does not match the port in your Geyser configuration (" + config.getBedrock().port() + ")!"); - sender.sendMessage("Re-run the command with that port, or change the port in the config under `bedrock` `port`."); + source.sendMessage("Re-run the command with that port, or change the port in the config under `bedrock` `port`."); } } } else { if (config.getBedrock().broadcastPort() != port) { - sender.sendMessage("The port you are testing with (" + port + ") is not the same as the broadcast port set in your Geyser configuration (" + source.sendMessage("The port you are testing with (" + port + ") is not the same as the broadcast port set in your Geyser configuration (" + config.getBedrock().broadcastPort() + "). "); - sender.sendMessage("You ONLY need to change the broadcast port if clients connects with a port different from the port Geyser is running on."); - sender.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `broadcast-port` in the config."); + source.sendMessage("You ONLY need to change the broadcast port if clients connects with a port different from the port Geyser is running on."); + source.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `broadcast-port` in the config."); } } // Issue: is the `bedrock` `address` in the config different? if (!config.getBedrock().address().equals("0.0.0.0")) { - sender.sendMessage("The address specified in `bedrock` `address` is not \"0.0.0.0\" - this may cause issues unless this is deliberate and intentional."); + source.sendMessage("The address specified in `bedrock` `address` is not \"0.0.0.0\" - this may cause issues unless this is deliberate and intentional."); } // Issue: did someone turn on enable-proxy-protocol, and they didn't mean it? if (config.getBedrock().isEnableProxyProtocol()) { - sender.sendMessage("You have the `enable-proxy-protocol` setting enabled. " + + source.sendMessage("You have the `enable-proxy-protocol` setting enabled. " + "Unless you're deliberately using additional software that REQUIRES this setting, you may not need it enabled."); } @@ -157,14 +149,14 @@ public class ConnectionTestCommand extends GeyserCommand { // Issue: SRV record? String[] record = WebUtils.findSrvRecord(geyser, ip); if (record != null && !ip.equals(record[3]) && !record[2].equals(String.valueOf(port))) { - sender.sendMessage("Bedrock Edition does not support SRV records. Try connecting to your server using the address " + record[3] + " and the port " + record[2] + source.sendMessage("Bedrock Edition does not support SRV records. Try connecting to your server using the address " + record[3] + " and the port " + record[2] + ". If that fails, re-run this command with that address and port."); return; } // Issue: does Loopback need applying? if (LoopbackUtil.needsLoopback(GeyserImpl.getInstance().getLogger())) { - sender.sendMessage("Loopback is not applied on this computer! You will have issues connecting from the same computer. " + + source.sendMessage("Loopback is not applied on this computer! You will have issues connecting from the same computer. " + "See here for steps on how to resolve: " + "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/#using-geyser-on-the-same-computer"); } @@ -178,7 +170,7 @@ public class ConnectionTestCommand extends GeyserCommand { String connectionTestMotd = "Geyser Connection Test " + randomStr; CONNECTION_TEST_MOTD = connectionTestMotd; - sender.sendMessage("Testing server connection to " + ip + " with port: " + port + " now. Please wait..."); + source.sendMessage("Testing server connection to " + ip + " with port: " + port + " now. Please wait..."); JsonNode output; try { String hostname = URLEncoder.encode(ip, StandardCharsets.UTF_8); @@ -200,31 +192,31 @@ public class ConnectionTestCommand extends GeyserCommand { JsonNode pong = ping.get("pong"); String remoteMotd = pong.get("motd").asText(); if (!connectionTestMotd.equals(remoteMotd)) { - sender.sendMessage("The MOTD did not match when we pinged the server (we got '" + remoteMotd + "'). " + + source.sendMessage("The MOTD did not match when we pinged the server (we got '" + remoteMotd + "'). " + "Did you supply the correct IP and port of your server?"); - sendLinks(sender); + sendLinks(source); return; } if (ping.get("tcpFirst").asBoolean()) { - sender.sendMessage("Your server hardware likely has some sort of firewall preventing people from joining easily. See https://geysermc.link/ovh-firewall for more information."); - sendLinks(sender); + source.sendMessage("Your server hardware likely has some sort of firewall preventing people from joining easily. See https://geysermc.link/ovh-firewall for more information."); + sendLinks(source); return; } - sender.sendMessage("Your server is likely online and working as of " + when + "!"); - sendLinks(sender); + source.sendMessage("Your server is likely online and working as of " + when + "!"); + sendLinks(source); return; } - sender.sendMessage("Your server is likely unreachable from outside the network!"); + source.sendMessage("Your server is likely unreachable from outside the network!"); JsonNode message = output.get("message"); if (message != null && !message.asText().isEmpty()) { - sender.sendMessage("Got the error message: " + message.asText()); + source.sendMessage("Got the error message: " + message.asText()); } - sendLinks(sender); + sendLinks(source); } catch (Exception e) { - sender.sendMessage("An error occurred while trying to check your connection! Check the console for more information."); + source.sendMessage("An error occurred while trying to check your connection! Check the console for more information."); geyser.getLogger().error("Error while trying to check your connection!", e); } }); @@ -235,9 +227,4 @@ public class ConnectionTestCommand extends GeyserCommand { "https://wiki.geysermc.org/geyser/setup/"); sender.sendMessage("If that does not work, see " + "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/" + ", or contact us on Discord: " + "https://discord.gg/geysermc"); } - - @Override - public boolean isSuggestedOpOnly() { - return true; - } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java index b3fee375f..45100f525 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java @@ -29,43 +29,71 @@ import com.fasterxml.jackson.core.util.DefaultIndenter; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.dump.DumpInfo; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.AsteriskSerializer; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.WebUtils; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.suggestion.SuggestionProvider; import java.io.FileOutputStream; import java.io.IOException; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; +import static org.incendo.cloud.parser.standard.StringArrayParser.stringArrayParser; + public class DumpCommand extends GeyserCommand { + private static final String ARGUMENTS = "args"; + private static final Iterable SUGGESTIONS = List.of("full", "offline", "logs"); + private final GeyserImpl geyser; private static final ObjectMapper MAPPER = new ObjectMapper(); private static final String DUMP_URL = "https://dump.geysermc.org/"; public DumpCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); - + super(name, description, permission, TriState.NOT_SET); this.geyser = geyser; } - @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - // Only allow the console to create dumps on Geyser Standalone - if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); - return; + @Override + public void register(CommandManager manager) { + manager.command(baseBuilder(manager) + .optional(ARGUMENTS, stringArrayParser(), SuggestionProvider.blockingStrings((ctx, input) -> { + // parse suggestions here + List inputs = new ArrayList<>(); + while (input.hasRemainingInput()) { + inputs.add(input.readStringSkipWhitespace()); + } + + if (inputs.size() <= 2) { + return SUGGESTIONS; // only `geyser dump` was typed (2 literals) + } + + // the rest of the input after `geyser dump` is for this argument + inputs = inputs.subList(2, inputs.size()); + + // don't suggest any words they have already typed + List suggestions = new ArrayList<>(); + SUGGESTIONS.forEach(suggestions::add); + suggestions.removeAll(inputs); + return suggestions; + })) + .handler(this::execute)); } + @Override + public void execute(CommandContext context) { + GeyserCommandSource source = context.sender(); + String[] args = context.getOrDefault(ARGUMENTS, new String[0]); + boolean showSensitive = false; boolean offlineDump = false; boolean addLog = false; @@ -75,13 +103,14 @@ public class DumpCommand extends GeyserCommand { case "full" -> showSensitive = true; case "offline" -> offlineDump = true; case "logs" -> addLog = true; + default -> context.sender().sendMessage("Invalid geyser dump option " + arg + "! Fallback to no arguments."); } } } AsteriskSerializer.showSensitive = showSensitive; - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collecting", sender.locale())); + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collecting", source.locale())); String dumpData; try { if (offlineDump) { @@ -93,7 +122,7 @@ public class DumpCommand extends GeyserCommand { dumpData = MAPPER.writeValueAsString(new DumpInfo(addLog)); } } catch (IOException e) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.locale())); + source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collect_error", source.locale())); geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e); return; } @@ -101,21 +130,21 @@ public class DumpCommand extends GeyserCommand { String uploadedDumpUrl; if (offlineDump) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.writing", sender.locale())); + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.writing", source.locale())); try { FileOutputStream outputStream = new FileOutputStream(GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile()); outputStream.write(dumpData.getBytes()); outputStream.close(); } catch (IOException e) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.write_error", sender.locale())); + source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.write_error", source.locale())); geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.dump.write_error_short"), e); return; } uploadedDumpUrl = "dump.json"; } else { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.uploading", sender.locale())); + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.uploading", source.locale())); String response; JsonNode responseNode; @@ -123,33 +152,22 @@ public class DumpCommand extends GeyserCommand { response = WebUtils.post(DUMP_URL + "documents", dumpData); responseNode = MAPPER.readTree(response); } catch (IOException e) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error", sender.locale())); + source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error", source.locale())); geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e); return; } if (!responseNode.has("key")) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.locale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response)); + source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error_short", source.locale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response)); return; } uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText(); } - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.message", sender.locale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl); - if (!sender.isConsole()) { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.commands.dump.created", sender.name(), uploadedDumpUrl)); + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.message", source.locale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl); + if (!source.isConsole()) { + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.commands.dump.created", source.name(), uploadedDumpUrl)); } } - - @NonNull - @Override - public List subCommands() { - return Arrays.asList("offline", "full", "logs"); - } - - @Override - public boolean isSuggestedOpOnly() { - return true; - } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ExtensionsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ExtensionsCommand.java index df33437d9..24881f2ca 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ExtensionsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ExtensionsCommand.java @@ -25,14 +25,14 @@ package org.geysermc.geyser.command.defaults; -import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; +import org.incendo.cloud.context.CommandContext; import java.util.Comparator; import java.util.List; @@ -41,22 +41,23 @@ public class ExtensionsCommand extends GeyserCommand { private final GeyserImpl geyser; public ExtensionsCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); - + super(name, description, permission, TriState.TRUE); this.geyser = geyser; } @Override - public void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args) { + public void execute(CommandContext context) { + GeyserCommandSource source = context.sender(); + // TODO: Pagination int page = 1; int maxPage = 1; - String header = GeyserLocale.getPlayerLocaleString("geyser.commands.extensions.header", sender.locale(), page, maxPage); - sender.sendMessage(header); + String header = GeyserLocale.getPlayerLocaleString("geyser.commands.extensions.header", source.locale(), page, maxPage); + source.sendMessage(header); this.geyser.extensionManager().extensions().stream().sorted(Comparator.comparing(Extension::name)).forEach(extension -> { String extensionName = (extension.isEnabled() ? ChatColor.GREEN : ChatColor.RED) + extension.name(); - sender.sendMessage("- " + extensionName + ChatColor.RESET + " v" + extension.description().version() + formatAuthors(extension.description().authors())); + source.sendMessage("- " + extensionName + ChatColor.RESET + " v" + extension.description().version() + formatAuthors(extension.description().authors())); }); } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java index c9671b089..9911863ab 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java @@ -25,61 +25,59 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.geyser.GeyserImpl; +import com.google.common.base.Predicates; import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; +import org.incendo.cloud.context.CommandContext; +import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Map; public class HelpCommand extends GeyserCommand { - private final GeyserImpl geyser; - private final String baseCommand; - private final Map commands; + private final String rootCommand; + private final Collection commands; - public HelpCommand(GeyserImpl geyser, String name, String description, String permission, - String baseCommand, Map commands) { - super(name, description, permission); - this.geyser = geyser; - this.baseCommand = baseCommand; - this.commands = commands; - - this.setAliases(Collections.singletonList("?")); + public HelpCommand(String rootCommand, String name, String description, String permission, Map commands) { + super(name, description, permission, TriState.TRUE); + this.rootCommand = rootCommand; + this.commands = commands.values(); + this.aliases = Collections.singletonList("?"); } - /** - * Sends the help menu to a command sender. Will not show certain commands depending on the command sender and session. - * - * @param session The Geyser session of the command sender, if it is a bedrock player. If null, bedrock-only commands will be hidden. - * @param sender The CommandSender to send the help message to. - * @param args Not used. - */ @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { + public String rootCommand() { + return rootCommand; + } + + @Override + public void execute(CommandContext context) { + execute(context.sender()); + } + + public void execute(GeyserCommandSource source) { + boolean bedrockPlayer = source.connection() != null; + + // todo: pagination int page = 1; int maxPage = 1; - String translationKey = this.baseCommand.equals("geyser") ? "geyser.commands.help.header" : "geyser.commands.extensions.header"; - String header = GeyserLocale.getPlayerLocaleString(translationKey, sender.locale(), page, maxPage); - sender.sendMessage(header); + String translationKey = this.rootCommand.equals(DEFAULT_ROOT_COMMAND) ? "geyser.commands.help.header" : "geyser.commands.extensions.header"; + String header = GeyserLocale.getPlayerLocaleString(translationKey, source.locale(), page, maxPage); + source.sendMessage(header); - this.commands.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> { - Command cmd = entry.getValue(); - - // Standalone hack-in since it doesn't have a concept of permissions - if (geyser.getPlatformType() == PlatformType.STANDALONE || sender.hasPermission(cmd.permission())) { - // Only list commands the player can actually run - if (cmd.isBedrockOnly() && session == null) { - return; - } - - sender.sendMessage(ChatColor.YELLOW + "/" + baseCommand + " " + entry.getKey() + ChatColor.WHITE + ": " + - GeyserLocale.getPlayerLocaleString(cmd.description(), sender.locale())); - } - }); + this.commands.stream() + .distinct() // remove aliases + .filter(bedrockPlayer ? Predicates.alwaysTrue() : cmd -> !cmd.isBedrockOnly()) // remove bedrock only commands if not a bedrock player + .filter(cmd -> source.hasPermission(cmd.permission())) + .sorted(Comparator.comparing(Command::name)) + .forEachOrdered(cmd -> { + String description = GeyserLocale.getPlayerLocaleString(cmd.description(), source.locale()); + source.sendMessage(ChatColor.YELLOW + "/" + rootCommand + " " + cmd.name() + ChatColor.WHITE + ": " + description); + }); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java index 90446fbb6..5a76ab902 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java @@ -26,10 +26,12 @@ package org.geysermc.geyser.command.defaults; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; +import org.incendo.cloud.context.CommandContext; import java.util.stream.Collectors; @@ -38,22 +40,18 @@ public class ListCommand extends GeyserCommand { private final GeyserImpl geyser; public ListCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); - + super(name, description, permission, TriState.NOT_SET); this.geyser = geyser; } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - String message = GeyserLocale.getPlayerLocaleString("geyser.commands.list.message", sender.locale(), - geyser.getSessionManager().size(), - geyser.getSessionManager().getAllSessions().stream().map(GeyserSession::bedrockUsername).collect(Collectors.joining(" "))); + public void execute(CommandContext context) { + GeyserCommandSource source = context.sender(); - sender.sendMessage(message); - } + String message = GeyserLocale.getPlayerLocaleString("geyser.commands.list.message", source.locale(), + geyser.getSessionManager().size(), + geyser.getSessionManager().getAllSessions().stream().map(GeyserSession::bedrockUsername).collect(Collectors.joining(" "))); - @Override - public boolean isSuggestedOpOnly() { - return true; + source.sendMessage(message); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java index 6188e6924..5f9061618 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java @@ -25,33 +25,23 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; +import org.incendo.cloud.context.CommandContext; + +import java.util.Objects; public class OffhandCommand extends GeyserCommand { - public OffhandCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); + public OffhandCommand(String name, String description, String permission) { + super(name, description, permission, TriState.TRUE, true, true); } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - if (session == null) { - return; - } - + public void execute(CommandContext context) { + GeyserSession session = Objects.requireNonNull(context.sender().connection()); session.requestOffhandSwap(); } - - @Override - public boolean isExecutableOnConsole() { - return false; - } - - @Override - public boolean isBedrockOnly() { - return true; - } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java index 987860238..e54b83ddf 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; +import org.incendo.cloud.context.CommandContext; import java.util.concurrent.TimeUnit; @@ -39,27 +39,17 @@ public class ReloadCommand extends GeyserCommand { private final GeyserImpl geyser; public ReloadCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); + super(name, description, permission, TriState.NOT_SET); this.geyser = geyser; } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { - return; - } - - String message = GeyserLocale.getPlayerLocaleString("geyser.commands.reload.message", sender.locale()); - - sender.sendMessage(message); + public void execute(CommandContext context) { + GeyserCommandSource source = context.sender(); + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.reload.message", source.locale())); geyser.getSessionManager().disconnectAll("geyser.commands.reload.kick"); //FIXME Without the tiny wait, players do not get kicked - same happens when Geyser tries to disconnect all sessions on shutdown geyser.getScheduledThread().schedule(geyser::reloadGeyser, 10, TimeUnit.MILLISECONDS); } - - @Override - public boolean isSuggestedOpOnly() { - return true; - } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java index 7828cf1d2..a5734a69f 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java @@ -25,31 +25,24 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.SettingsUtils; +import org.incendo.cloud.context.CommandContext; + +import java.util.Objects; public class SettingsCommand extends GeyserCommand { - public SettingsCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); + + public SettingsCommand(String name, String description, String permission) { + super(name, description, permission, TriState.TRUE, true, true); } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - if (session != null) { - session.sendForm(SettingsUtils.buildForm(session)); - } - } - - @Override - public boolean isExecutableOnConsole() { - return false; - } - - @Override - public boolean isBedrockOnly() { - return true; + public void execute(CommandContext context) { + GeyserSession session = Objects.requireNonNull(context.sender().connection()); + session.sendForm(SettingsUtils.buildForm(session)); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java index 5952ea00d..eebb9170c 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java @@ -25,35 +25,28 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.ClientCommand; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; +import org.incendo.cloud.context.CommandContext; + +import java.util.Objects; public class StatisticsCommand extends GeyserCommand { - public StatisticsCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); + public StatisticsCommand(String name, String description, String permission) { + super(name, description, permission, TriState.TRUE, true, true); } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - if (session == null) return; + public void execute(CommandContext context) { + GeyserSession session = Objects.requireNonNull(context.sender().connection()); session.setWaitingForStatistics(true); - ServerboundClientCommandPacket ServerboundClientCommandPacket = new ServerboundClientCommandPacket(ClientCommand.STATS); - session.sendDownstreamGamePacket(ServerboundClientCommandPacket); - } - - @Override - public boolean isExecutableOnConsole() { - return false; - } - - @Override - public boolean isBedrockOnly() { - return true; + ServerboundClientCommandPacket packet = new ServerboundClientCommandPacket(ClientCommand.STATS); + session.sendDownstreamGamePacket(packet); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java index 1cd3050c9..f6dc1610a 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java @@ -25,12 +25,11 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.GeyserLocale; +import org.incendo.cloud.context.CommandContext; import java.util.Collections; @@ -39,24 +38,13 @@ public class StopCommand extends GeyserCommand { private final GeyserImpl geyser; public StopCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); + super(name, description, permission, TriState.NOT_SET); this.geyser = geyser; - - this.setAliases(Collections.singletonList("shutdown")); + this.aliases = Collections.singletonList("shutdown"); } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { - if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); - return; - } - + public void execute(CommandContext context) { geyser.getBootstrap().onGeyserShutdown(); } - - @Override - public boolean isSuggestedOpOnly() { - return true; - } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java index c6852d577..8d34c1bf0 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java @@ -29,13 +29,14 @@ import com.fasterxml.jackson.databind.JsonNode; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.util.PlatformType; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.network.GameProtocol; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.WebUtils; +import org.incendo.cloud.context.CommandContext; import java.io.IOException; import java.util.List; @@ -45,13 +46,14 @@ public class VersionCommand extends GeyserCommand { private final GeyserImpl geyser; public VersionCommand(GeyserImpl geyser, String name, String description, String permission) { - super(name, description, permission); - + super(name, description, permission, TriState.NOT_SET); this.geyser = geyser; } @Override - public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { + public void execute(CommandContext context) { + GeyserCommandSource source = context.sender(); + String bedrockVersions; List supportedCodecs = GameProtocol.SUPPORTED_BEDROCK_CODECS; if (supportedCodecs.size() > 1) { @@ -67,45 +69,37 @@ public class VersionCommand extends GeyserCommand { javaVersions = supportedJavaVersions.get(0); } - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.version", sender.locale(), + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.version", source.locale(), GeyserImpl.NAME, GeyserImpl.VERSION, javaVersions, bedrockVersions)); // Disable update checking in dev mode and for players in Geyser Standalone - if (!GeyserImpl.getInstance().isProductionEnvironment() || (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) { + if (!GeyserImpl.getInstance().isProductionEnvironment() || (!source.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) { return; } if (GeyserImpl.IS_DEV) { - // TODO cloud use language string - sender.sendMessage("You are running a development build of Geyser! Please report any bugs you find on our Discord server: %s" - .formatted("https://discord.gg/geysermc")); - //sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.core.dev_build", sender.locale(), "https://discord.gg/geysermc")); + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.core.dev_build", source.locale(), "https://discord.gg/geysermc")); return; } - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.locale())); + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", source.locale())); try { int buildNumber = this.geyser.buildNumber(); JsonNode response = WebUtils.getJson("https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest"); int latestBuildNumber = response.get("build").asInt(); if (latestBuildNumber == buildNumber) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.locale())); + source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", source.locale())); return; } - sender.sendMessage(GeyserLocale.getPlayerLocaleString( + source.sendMessage(GeyserLocale.getPlayerLocaleString( "geyser.commands.version.outdated", - sender.locale(), (latestBuildNumber - buildNumber), "https://geysermc.org/download" + source.locale(), (latestBuildNumber - buildNumber), "https://geysermc.org/download" )); } catch (IOException e) { GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.version.failed"), e); - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.version.failed", sender.locale())); + source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.version.failed", source.locale())); } } - - @Override - public boolean isSuggestedOpOnly() { - return true; - } } diff --git a/core/src/main/java/org/geysermc/geyser/command/standalone/PermissionConfiguration.java b/core/src/main/java/org/geysermc/geyser/command/standalone/PermissionConfiguration.java new file mode 100644 index 000000000..edacd49ff --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/standalone/PermissionConfiguration.java @@ -0,0 +1,42 @@ +/* + * 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.command.standalone; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; + +import java.util.Collections; +import java.util.Set; + +@Getter +@JsonIgnoreProperties(ignoreUnknown = true) +@SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final +public class PermissionConfiguration { + + @JsonProperty("default-permissions") + private Set defaultPermissions = Collections.emptySet(); +} diff --git a/core/src/main/java/org/geysermc/geyser/command/standalone/StandaloneCloudCommandManager.java b/core/src/main/java/org/geysermc/geyser/command/standalone/StandaloneCloudCommandManager.java new file mode 100644 index 000000000..99c53f319 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/standalone/StandaloneCloudCommandManager.java @@ -0,0 +1,126 @@ +/* + * 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.command.standalone; + +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionCheckersEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; +import org.geysermc.geyser.api.permission.PermissionChecker; +import org.geysermc.geyser.api.util.TriState; +import org.geysermc.geyser.command.CommandRegistry; +import org.geysermc.geyser.command.GeyserCommandSource; +import org.geysermc.geyser.util.FileUtils; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.internal.CommandRegistrationHandler; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public class StandaloneCloudCommandManager extends CommandManager { + + private final GeyserImpl geyser; + + /** + * The checkers we use to test if a command source has a permission + */ + private final List permissionCheckers = new ArrayList<>(); + + /** + * Any permissions that all connections have + */ + private final Set basePermissions = new ObjectOpenHashSet<>(); + + public StandaloneCloudCommandManager(GeyserImpl geyser) { + super(ExecutionCoordinator.simpleCoordinator(), CommandRegistrationHandler.nullCommandRegistrationHandler()); + // simpleCoordinator: execute commands immediately on the calling thread. + // nullCommandRegistrationHandler: cloud is not responsible for handling our CommandRegistry, which is fairly decoupled. + this.geyser = geyser; + + // allow any extensions to customize permissions + geyser.getEventBus().fire((GeyserRegisterPermissionCheckersEvent) permissionCheckers::add); + + // must still implement a basic permission system + try { + File permissionsFile = geyser.getBootstrap().getConfigFolder().resolve("permissions.yml").toFile(); + FileUtils.fileOrCopiedFromResource(permissionsFile, "permissions.yml", geyser.getBootstrap()); + PermissionConfiguration config = FileUtils.loadConfig(permissionsFile, PermissionConfiguration.class); + basePermissions.addAll(config.getDefaultPermissions()); + } catch (Exception e) { + geyser.getLogger().error("Failed to load permissions.yml - proceeding without it", e); + } + } + + /** + * Fire a {@link GeyserRegisterPermissionsEvent} to determine any additions or removals to the base list of + * permissions. This should be called after any event listeners have been registered, such as that of {@link CommandRegistry}. + */ + public void fireRegisterPermissionsEvent() { + geyser.getEventBus().fire((GeyserRegisterPermissionsEvent) (permission, def) -> { + Objects.requireNonNull(permission, "permission"); + Objects.requireNonNull(def, "permission default for " + permission); + + if (permission.isBlank()) { + return; + } + if (def == TriState.TRUE) { + basePermissions.add(permission); + } + }); + } + + @Override + public boolean hasPermission(@NonNull GeyserCommandSource sender, @NonNull String permission) { + // Note: the two GeyserCommandSources on Geyser-Standalone are GeyserLogger and GeyserSession + // GeyserLogger#hasPermission always returns true + // GeyserSession#hasPermission delegates to this method, + // which is why this method doesn't just call GeyserCommandSource#hasPermission + if (sender.isConsole()) { + return true; + } + + // An empty or blank permission is treated as a lack of permission requirement + if (permission.isBlank()) { + return true; + } + + for (PermissionChecker checker : permissionCheckers) { + Boolean result = checker.hasPermission(sender, permission).toBoolean(); + if (result != null) { + return result; + } + // undefined - try the next checker to see if it has a defined value + } + // fallback to our list of default permissions + // note that a PermissionChecker may in fact override any values set here by returning FALSE + return basePermissions.contains(permission); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCommandsEventImpl.java b/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCommandsEventImpl.java index e07a62d8a..4a6efbbd4 100644 --- a/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCommandsEventImpl.java +++ b/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCommandsEventImpl.java @@ -35,12 +35,12 @@ import java.util.Map; public abstract class GeyserDefineCommandsEventImpl implements GeyserDefineCommandsEvent { private final Map commands; - public GeyserDefineCommandsEventImpl(Map commands) { - this.commands = commands; + public GeyserDefineCommandsEventImpl(Map commands) { + this.commands = Collections.unmodifiableMap(commands); } @Override public @NonNull Map commands() { - return Collections.unmodifiableMap(this.commands); + return this.commands; } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java b/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java index 4a7830c90..0b22a8b8e 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java +++ b/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java @@ -25,19 +25,208 @@ package org.geysermc.geyser.extension.command; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.command.CommandExecutor; +import org.geysermc.geyser.api.command.CommandSource; +import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.command.GeyserCommandSource; +import org.geysermc.geyser.session.GeyserSession; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.context.CommandContext; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static org.incendo.cloud.parser.standard.StringParser.greedyStringParser; public abstract class GeyserExtensionCommand extends GeyserCommand { + private final Extension extension; + private final String rootCommand; - public GeyserExtensionCommand(Extension extension, String name, String description, String permission) { - super(name, description, permission); + public GeyserExtensionCommand(@NonNull Extension extension, @NonNull String name, @NonNull String description, + @NonNull String permission, @Nullable TriState permissionDefault, + boolean playerOnly, boolean bedrockOnly) { + super(name, description, permission, permissionDefault, playerOnly, bedrockOnly); this.extension = extension; + this.rootCommand = Objects.requireNonNull(extension.rootCommand()); + + if (this.rootCommand.isBlank()) { + throw new IllegalStateException("rootCommand of extension " + extension.name() + " may not be blank"); + } } - public Extension extension() { + public final Extension extension() { return this.extension; } + + @Override + public final String rootCommand() { + return this.rootCommand; + } + + public static class Builder implements Command.Builder { + @NonNull private final Extension extension; + @Nullable private Class sourceType; + @Nullable private String name; + @NonNull private String description = ""; + @NonNull private String permission = ""; + @Nullable private TriState permissionDefault; + @Nullable private List aliases; + private boolean suggestedOpOnly = false; // deprecated for removal + private boolean playerOnly = false; + private boolean bedrockOnly = false; + @Nullable private CommandExecutor executor; + + public Builder(@NonNull Extension extension) { + this.extension = Objects.requireNonNull(extension); + } + + @Override + public Command.Builder source(@NonNull Class sourceType) { + this.sourceType = Objects.requireNonNull(sourceType, "command source type"); + return this; + } + + @Override + public Builder name(@NonNull String name) { + this.name = Objects.requireNonNull(name, "command name"); + return this; + } + + @Override + public Builder description(@NonNull String description) { + this.description = Objects.requireNonNull(description, "command description"); + return this; + } + + @Override + public Builder permission(@NonNull String permission) { + this.permission = Objects.requireNonNull(permission, "command permission"); + return this; + } + + @Override + public Builder permission(@NonNull String permission, @NonNull TriState defaultValue) { + this.permission = Objects.requireNonNull(permission, "command permission"); + this.permissionDefault = Objects.requireNonNull(defaultValue, "command permission defaultValue"); + return this; + } + + @Override + public Builder aliases(@NonNull List aliases) { + this.aliases = Objects.requireNonNull(aliases, "command aliases"); + return this; + } + + @SuppressWarnings("removal") // this is our doing + @Override + public Builder suggestedOpOnly(boolean suggestedOpOnly) { + this.suggestedOpOnly = suggestedOpOnly; + if (suggestedOpOnly) { + // the most amount of legacy/deprecated behaviour I'm willing to support + this.permissionDefault = TriState.NOT_SET; + } + return this; + } + + @SuppressWarnings("removal") // this is our doing + @Override + public Builder executableOnConsole(boolean executableOnConsole) { + this.playerOnly = !executableOnConsole; + return this; + } + + @Override + public Command.Builder playerOnly(boolean playerOnly) { + this.playerOnly = playerOnly; + return this; + } + + @Override + public Builder bedrockOnly(boolean bedrockOnly) { + this.bedrockOnly = bedrockOnly; + return this; + } + + @Override + public Builder executor(@NonNull CommandExecutor executor) { + this.executor = Objects.requireNonNull(executor, "command executor"); + return this; + } + + @NonNull + @Override + public GeyserExtensionCommand build() { + // These are captured in the anonymous lambda below and shouldn't change even if the builder does + final Class sourceType = this.sourceType; + final boolean suggestedOpOnly = this.suggestedOpOnly; + final CommandExecutor executor = this.executor; + + if (name == null) { + throw new IllegalArgumentException("name was not provided for a command in extension " + extension.name()); + } + if (sourceType == null) { + throw new IllegalArgumentException("Source type was not defined for command " + name + " in extension " + extension.name()); + } + if (executor == null) { + throw new IllegalArgumentException("Command executor was not defined for command " + name + " in extension " + extension.name()); + } + + // if the source type is a GeyserConnection then it is inherently bedrockOnly + final boolean bedrockOnly = this.bedrockOnly || GeyserConnection.class.isAssignableFrom(sourceType); + // a similar check would exist for executableOnConsole, but there is not a logger type exposed in the api + + GeyserExtensionCommand command = new GeyserExtensionCommand(extension, name, description, permission, permissionDefault, playerOnly, bedrockOnly) { + + @Override + public void register(CommandManager manager) { + manager.command(baseBuilder(manager) + .optional("args", greedyStringParser()) + .handler(this::execute)); + } + + @SuppressWarnings("unchecked") + @Override + public void execute(CommandContext context) { + GeyserCommandSource source = context.sender(); + String[] args = context.getOrDefault("args", "").split(" "); + + if (sourceType.isInstance(source)) { + executor.execute((T) source, this, args); + return; + } + + @Nullable GeyserSession session = source.connection(); + if (sourceType.isInstance(session)) { + executor.execute((T) session, this, args); + return; + } + + // currently, the only subclass of CommandSource exposed in the api is GeyserConnection. + // when this command was registered, we enabled bedrockOnly if the sourceType was a GeyserConnection. + // as a result, the permission checker should handle that case and this method shouldn't even be reached. + source.sendMessage("You must be a " + sourceType.getSimpleName() + " to run this command."); + } + + @SuppressWarnings("removal") // this is our doing + @Override + public boolean isSuggestedOpOnly() { + return suggestedOpOnly; + } + }; + + if (aliases != null) { + command.aliases = new ArrayList<>(aliases); + } + return command; + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 9faa7424c..9cf2c0179 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -118,11 +118,6 @@ public class GeyserWorldManager extends WorldManager { return GameMode.SURVIVAL; } - @Override - public boolean hasPermission(GeyserSession session, String permission) { - return false; - } - @NonNull @Override public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index 4a20771f2..6baf9c2b4 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -185,15 +185,6 @@ public abstract class WorldManager { session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT)); } - /** - * Checks if the given session's player has a permission - * - * @param session The session of the player to check the permission of - * @param permission The permission node to check - * @return True if the player has the requested permission, false if not - */ - public abstract boolean hasPermission(GeyserSession session, String permission); - /** * Returns a list of biome identifiers available on the server. */ diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java index 4b159438c..94de0c298 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java @@ -42,8 +42,8 @@ import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; import org.geysermc.geyser.api.pack.PathPackCodec; import org.geysermc.geyser.impl.camera.GeyserCameraFade; import org.geysermc.geyser.impl.camera.GeyserCameraPosition; -import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.event.GeyserEventRegistrar; +import org.geysermc.geyser.extension.command.GeyserExtensionCommand; import org.geysermc.geyser.item.GeyserCustomItemData; import org.geysermc.geyser.item.GeyserCustomItemOptions; import org.geysermc.geyser.item.GeyserNonVanillaCustomItemData; @@ -67,7 +67,7 @@ public class ProviderRegistryLoader implements RegistryLoader, Prov @Override public Map, ProviderSupplier> load(Map, ProviderSupplier> providers) { // misc - providers.put(Command.Builder.class, args -> new GeyserCommandManager.CommandBuilder<>((Extension) args[0])); + providers.put(Command.Builder.class, args -> new GeyserExtensionCommand.Builder<>((Extension) args[0])); providers.put(CustomBlockComponents.Builder.class, args -> new GeyserCustomBlockComponents.Builder()); providers.put(CustomBlockData.Builder.class, args -> new GeyserCustomBlockData.Builder()); 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 97dd75905..899b53fb3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1454,11 +1454,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return false; } + @Override + public UUID playerUuid() { + return javaUuid(); // CommandSource allows nullable + } + + @Override + public GeyserSession connection() { + return this; + } + @Override public String locale() { return clientData.getLanguageCode(); } + @Override + public boolean hasPermission(String permission) { + // for Geyser-Standalone, standalone's permission system will handle it. + // for server platforms, the session will be mapped to a server command sender, and the server's api will be used. + return geyser.commandRegistry().hasPermission(this, permission); + } + /** * Sends a chat message to the Java server. */ @@ -1771,17 +1788,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { upstream.sendPacket(gameRulesChangedPacket); } - /** - * Checks if the given session's player has a permission - * - * @param permission The permission node to check - * @return true if the player has the requested permission, false if not - */ - @Override - public boolean hasPermission(String permission) { - return geyser.getWorldManager().hasPermission(this, permission); - } - private static final Ability[] USED_ABILITIES = Ability.values(); /** diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java index 8d4df6f3f..1e84f032e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.util.PlatformType; +import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -43,13 +44,26 @@ public class BedrockCommandRequestTranslator extends PacketTranslator 0) { + String root = args[0]; + + CommandRegistry registry = GeyserImpl.getInstance().commandRegistry(); + if (registry.rootCommands().contains(root)) { + registry.runCommand(session, command); + return; // don't pass the command to the java server + } + } } + + if (MessageTranslator.isTooLong(command, session)) { + return; + } + + session.sendCommand(command); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java index aa815fab7..a7199be97 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; import org.cloudburstmc.protocol.bedrock.packet.SetDefaultGameTypePacket; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; +import org.geysermc.geyser.Permissions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -41,7 +42,7 @@ public class BedrockSetDefaultGameTypeTranslator extends PacketTranslator= 2 && session.hasPermission("geyser.settings.server")) { + if (session.getOpPermissionLevel() >= 2 && session.hasPermission(Permissions.SERVER_SETTINGS)) { session.getGeyser().getWorldManager().setDefaultGameMode(session, GameMode.byId(packet.getGamemode())); } // Stop the client from updating their own Gamemode without telling the server diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java index 176f00b8f..c3fa2a1b3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; +import org.geysermc.geyser.Permissions; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import org.cloudburstmc.protocol.bedrock.packet.SetDifficultyPacket; import org.geysermc.geyser.session.GeyserSession; @@ -39,7 +40,7 @@ public class BedrockSetDifficultyTranslator extends PacketTranslator= 2 && session.hasPermission("geyser.settings.server")) { + if (session.getOpPermissionLevel() >= 2 && session.hasPermission(Permissions.SERVER_SETTINGS)) { if (packet.getDifficulty() != session.getWorldCache().getDifficulty().ordinal()) { session.getGeyser().getWorldManager().setDifficulty(session, Difficulty.from(packet.getDifficulty())); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java index f00156268..0590ca0ad 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; +import org.geysermc.geyser.Permissions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -45,7 +46,7 @@ public class BedrockSetPlayerGameTypeTranslator extends PacketTranslator= 2 && session.hasPermission("geyser.settings.server")) { + if (session.getOpPermissionLevel() >= 2 && session.hasPermission(Permissions.SERVER_SETTINGS)) { if (packet.getGamemode() != session.getGameMode().ordinal()) { // Bedrock has more Gamemodes than Java, leading to cases 5 (for "default") and 6 (for "spectator") being sent // https://github.com/CloudburstMC/Protocol/blob/3.0/bedrock-codec/src/main/java/org/cloudburstmc/protocol/bedrock/data/GameType.java diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index c0e3f5716..4c817ba01 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -41,7 +41,7 @@ import org.cloudburstmc.protocol.bedrock.data.command.*; import org.cloudburstmc.protocol.bedrock.packet.AvailableCommandsPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.java.ServerDefineCommandsEvent; -import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -122,7 +122,7 @@ public class JavaCommandsTranslator extends PacketTranslator commandData = new ArrayList<>(); IntSet commandNodes = new IntOpenHashSet(); @@ -151,8 +151,10 @@ public class JavaCommandsTranslator extends PacketTranslator new HashSet<>()).add(node.getName().toLowerCase()); + String name = node.getName().toLowerCase(Locale.ROOT); + String description = registry.description(name, session.locale()); + BedrockCommandInfo info = new BedrockCommandInfo(name, description, params); + commands.computeIfAbsent(info, $ -> new HashSet<>()).add(name); } var eventBus = session.getGeyser().eventBus(); diff --git a/core/src/main/java/org/geysermc/geyser/util/FileUtils.java b/core/src/main/java/org/geysermc/geyser/util/FileUtils.java index c8423c3be..87ed8af02 100644 --- a/core/src/main/java/org/geysermc/geyser/util/FileUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/FileUtils.java @@ -100,6 +100,18 @@ public class FileUtils { return file; } + /** + * Open the specified file or copy if from resources + * + * @param file File to open + * @param name Name of the resource get if needed + * @return File handle of the specified file + * @throws IOException if the file failed to copy from resource + */ + public static File fileOrCopiedFromResource(File file, String name, GeyserBootstrap bootstrap) throws IOException { + return fileOrCopiedFromResource(file, name, Function.identity(), bootstrap); + } + /** * Writes the given data to the specified file on disk * diff --git a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java index 6f46b191c..cb6ad6f0c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java @@ -29,6 +29,7 @@ import org.cloudburstmc.protocol.bedrock.packet.SetDifficultyPacket; import org.geysermc.cumulus.component.DropdownComponent; import org.geysermc.cumulus.form.CustomForm; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.Permissions; import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.session.GeyserSession; @@ -81,7 +82,7 @@ public class SettingsUtils { } } - boolean showGamerules = session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.gamerules"); + boolean showGamerules = session.getOpPermissionLevel() >= 2 || session.hasPermission(Permissions.SETTINGS_GAMERULES); if (showGamerules) { builder.label("geyser.settings.title.game_rules") .translator(MinecraftLocale::getLocaleString); // we need translate gamerules next diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index afbf78bbe..60b20023a 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit afbf78bbe0b39d0a076a42c228828c12f7f7da90 +Subproject commit 60b20023a92f084aba895ab0336e70fa7fb311fb diff --git a/core/src/main/resources/permissions.yml b/core/src/main/resources/permissions.yml new file mode 100644 index 000000000..4da9251e8 --- /dev/null +++ b/core/src/main/resources/permissions.yml @@ -0,0 +1,9 @@ + +# Add any permissions here that all players should have. +# Permissions for builtin Geyser commands do not have to be listed here. + +# If an extension/plugin registers their permissions with default values, entries here are typically unnecessary. +# If extensions don't register their permissions, permissions that everyone should have must be added here manually. + +default-permissions: + - geyser.command.help # this is unnecessary diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e50756ef1..f4abe18a9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,13 +24,15 @@ terminalconsoleappender = "1.2.0" folia = "1.19.4-R0.1-SNAPSHOT" viaversion = "4.9.2" adapters = "1.13-SNAPSHOT" +cloud = "2.0.0-rc.2" +cloud-minecraft = "2.0.0-beta.9" +cloud-minecraft-modded = "2.0.0-beta.7" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" viaproxy = "3.2.1" fabric-loader = "0.15.11" fabric-api = "0.100.1+1.21" -fabric-permissions = "0.2-SNAPSHOT" neoforge-minecraft = "21.0.0-beta" mixin = "0.8.5" mixinextras = "0.3.5" @@ -86,8 +88,14 @@ jline-terminal = { group = "org.jline", name = "jline-terminal", version.ref = " jline-terminal-jna = { group = "org.jline", name = "jline-terminal-jna", version.ref = "jline" } jline-reader = { group = "org.jline", name = "jline-reader", version.ref = "jline" } +cloud-core = { group = "org.incendo", name = "cloud-core", version.ref = "cloud" } +cloud-paper = { group = "org.incendo", name = "cloud-paper", version.ref = "cloud-minecraft" } +cloud-velocity = { group = "org.incendo", name = "cloud-velocity", version.ref = "cloud-minecraft" } +cloud-bungee = { group = "org.incendo", name = "cloud-bungee", version.ref = "cloud-minecraft" } +cloud-fabric = { group = "org.incendo", name = "cloud-fabric", version.ref = "cloud-minecraft-modded" } +cloud-neoforge = { group = "org.incendo", name = "cloud-neoforge", version.ref = "cloud-minecraft-modded" } + folia-api = { group = "dev.folia", name = "folia-api", version.ref = "folia" } -paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "folia" } mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" } mixinextras = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinextras" } @@ -97,7 +105,6 @@ minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft # Check these on https://modmuss50.me/fabric.html 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" } -fabric-permissions = { group = "me.lucko", name = "fabric-permissions-api", version.ref = "fabric-permissions" } neoforge-minecraft = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge-minecraft" } From 48311f877106ec6cf61a208358eaf304f861436f Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 12 Jul 2024 20:42:31 +0200 Subject: [PATCH 319/897] Add a /geyser ping command (#4131) * Init: Add /geyser ping command * Block just console execution, not everything but console senders * Use RTT as that seems to vary less wildly compared to getPing() * Cleanup, use lang strings * Add ping() method to GeyserConnection in api * Update to cloud changes --- .../api/connection/GeyserConnection.java | 5 ++ .../geyser/command/CommandRegistry.java | 2 + .../geyser/command/defaults/PingCommand.java | 49 +++++++++++++++++++ .../geyser/session/GeyserSession.java | 8 +++ 4 files changed, 64 insertions(+) create mode 100644 core/src/main/java/org/geysermc/geyser/command/defaults/PingCommand.java diff --git a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java index 9bda4f903..ba559a462 100644 --- a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java +++ b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java @@ -132,4 +132,9 @@ public interface GeyserConnection extends Connection, CommandSource { @Deprecated @NonNull Set fogEffects(); + + /** + * Returns the current ping of the connection. + */ + int ping(); } 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 f07092afd..54681abea 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java @@ -43,6 +43,7 @@ import org.geysermc.geyser.command.defaults.ExtensionsCommand; import org.geysermc.geyser.command.defaults.HelpCommand; import org.geysermc.geyser.command.defaults.ListCommand; import org.geysermc.geyser.command.defaults.OffhandCommand; +import org.geysermc.geyser.command.defaults.PingCommand; import org.geysermc.geyser.command.defaults.ReloadCommand; import org.geysermc.geyser.command.defaults.SettingsCommand; import org.geysermc.geyser.command.defaults.StatisticsCommand; @@ -139,6 +140,7 @@ public class CommandRegistry implements EventRegistrar { registerBuiltInCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); registerBuiltInCommand(new AdvancedTooltipsCommand("tooltips", "geyser.commands.advancedtooltips.desc", "geyser.command.tooltips")); registerBuiltInCommand(new ConnectionTestCommand(geyser, "connectiontest", "geyser.commands.connectiontest.desc", "geyser.command.connectiontest")); + registerBuiltInCommand(new PingCommand("ping", "geyser.commands.ping.desc", "geyser.command.ping")); if (this.geyser.getPlatformType() == PlatformType.STANDALONE) { registerBuiltInCommand(new StopCommand(geyser, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/PingCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/PingCommand.java new file mode 100644 index 000000000..f39be0528 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/PingCommand.java @@ -0,0 +1,49 @@ +/* + * 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.command.defaults; + +import org.geysermc.geyser.api.util.TriState; +import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.command.GeyserCommandSource; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.GeyserLocale; +import org.incendo.cloud.context.CommandContext; + +import java.util.Objects; + +public class PingCommand extends GeyserCommand { + + public PingCommand(String name, String description, String permission) { + super(name, description, permission, TriState.TRUE, true, true); + } + + @Override + public void execute(CommandContext context) { + GeyserSession session = Objects.requireNonNull(context.sender().connection()); + session.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.ping.message", session.locale(), session.ping())); + } +} + 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 899b53fb3..60321ea75 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -54,6 +54,8 @@ import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.netty.channel.raknet.RakChildChannel; +import org.cloudburstmc.netty.handler.codec.raknet.common.RakSessionCodec; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.BedrockServerSession; import org.cloudburstmc.protocol.bedrock.data.Ability; @@ -2098,6 +2100,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return this.cameraData.fogEffects(); } + @Override + public int ping() { + RakSessionCodec rakSessionCodec = ((RakChildChannel) getUpstream().getSession().getPeer().getChannel()).rakPipeline().get(RakSessionCodec.class); + return (int) Math.floor(rakSessionCodec.getPing()); + } + public void addCommandEnum(String name, String enums) { softEnumPacket(name, SoftEnumUpdateType.ADD, enums); } From 813d1978875a6ef3538eb07e9767de9819959068 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 14 Jul 2024 22:09:55 +0200 Subject: [PATCH 320/897] Feature: API to switch items in the offhand/mainhand (#4819) --- .../java/org/geysermc/geyser/api/entity/EntityData.java | 6 ++++++ .../java/org/geysermc/geyser/entity/GeyserEntityData.java | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/EntityData.java b/api/src/main/java/org/geysermc/geyser/api/entity/EntityData.java index 90b3fc821..48c717089 100644 --- a/api/src/main/java/org/geysermc/geyser/api/entity/EntityData.java +++ b/api/src/main/java/org/geysermc/geyser/api/entity/EntityData.java @@ -81,4 +81,10 @@ public interface EntityData { * @return whether the movement is locked */ boolean isMovementLocked(); + + /** + * Sends a request to the Java server to switch the items in the main and offhand. + * There is no guarantee of the server accepting the request. + */ + void switchHands(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/GeyserEntityData.java b/core/src/main/java/org/geysermc/geyser/entity/GeyserEntityData.java index c9ef7a2dd..6f8f2525f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/GeyserEntityData.java +++ b/core/src/main/java/org/geysermc/geyser/entity/GeyserEntityData.java @@ -96,4 +96,9 @@ public class GeyserEntityData implements EntityData { public boolean isMovementLocked() { return !movementLockOwners.isEmpty(); } + + @Override + public void switchHands() { + session.requestOffhandSwap(); + } } From 98c412c9edb4ab0e88ccb39a60272fbac7df05ae Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 23 Jul 2024 20:28:01 +0200 Subject: [PATCH 321/897] fix missing import --- core/src/main/java/org/geysermc/geyser/GeyserImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 464ebda96..01f1a118e 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -62,6 +62,7 @@ import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; import org.geysermc.geyser.api.event.lifecycle.GeyserPostReloadEvent; import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent; import org.geysermc.geyser.api.event.lifecycle.GeyserPreReloadEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent; import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.BedrockListener; From 03187b6139214ed3a5d3e2697409d3ba9904127b Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 23 Jul 2024 19:43:19 +0100 Subject: [PATCH 322/897] Update DeviceOs to latest protocol (#4553) * Update DeviceOs to latest protocol * Revert enum name change and add deprecation annotations --- .../org/geysermc/floodgate/util/DeviceOs.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java b/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java index 406204759..1a92f9c40 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java +++ b/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.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 @@ -39,15 +39,19 @@ public enum DeviceOs { OSX("macOS"), AMAZON("Amazon"), GEARVR("Gear VR"), - HOLOLENS("Hololens"), + @Deprecated HOLOLENS("Hololens"), UWP("Windows"), WIN32("Windows x86"), DEDICATED("Dedicated"), - TVOS("Apple TV"), - PS4("PS4"), + @Deprecated TVOS("Apple TV"), + /** + * This is for all PlayStation platforms not just PS4 + */ + PS4("PlayStation"), NX("Switch"), - XBOX("Xbox One"), - WINDOWS_PHONE("Windows Phone"); + XBOX("Xbox"), + @Deprecated WINDOWS_PHONE("Windows Phone"), + LINUX("Linux"); private static final DeviceOs[] VALUES = values(); From f3ba5848c2b9fd187c4982bd449d894a837d469e Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 1 Aug 2024 00:11:13 +0200 Subject: [PATCH 323/897] Extensions should specify geyser api version in the extension.yml (#3880) * let extensions specify geyser api version instead of base api version * fix spacing, @link formatting, properly check for compat * Proper warning, update to API changes to also check patch version * Bump base-api version * adapt to new base api changes * Actually bump to 2.4.1 * Update api/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java * Address reviews * Address reviews * Update to latest base api changes; proper extension *human* version checking * no need to apply a plugin, that's the default --------- Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> --- api/build.gradle.kts | 18 ++++++- .../org.geysermc.geyser.api/BuildData.java | 53 +++++++++++++++++++ .../org/geysermc/geyser/api/GeyserApi.java | 11 ++++ .../api/extension/ExtensionDescription.java | 37 ++++++++----- .../extension/GeyserExtensionDescription.java | 10 ++-- .../extension/GeyserExtensionLoader.java | 40 +++++++++----- gradle.properties | 2 +- gradle/libs.versions.toml | 2 +- 8 files changed, 141 insertions(+), 32 deletions(-) create mode 100644 api/src/main/java-templates/org.geysermc.geyser.api/BuildData.java diff --git a/api/build.gradle.kts b/api/build.gradle.kts index bd54a9ce4..eac02ebeb 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -1,8 +1,24 @@ plugins { + // Allow blossom to mark sources root of templates + idea id("geyser.publish-conventions") + alias(libs.plugins.blossom) } dependencies { api(libs.base.api) api(libs.math) -} \ No newline at end of file +} + +version = property("version")!! +val apiVersion = (version as String).removeSuffix("-SNAPSHOT") + +sourceSets { + main { + blossom { + javaSources { + property("version", apiVersion) + } + } + } +} diff --git a/api/src/main/java-templates/org.geysermc.geyser.api/BuildData.java b/api/src/main/java-templates/org.geysermc.geyser.api/BuildData.java new file mode 100644 index 000000000..f9a580e7b --- /dev/null +++ b/api/src/main/java-templates/org.geysermc.geyser.api/BuildData.java @@ -0,0 +1,53 @@ +/* + * 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.api; + +import org.geysermc.api.util.ApiVersion; + +/** + * Not a public API. For internal use only. May change without notice. + * This class is processed before compilation to insert build properties. + */ +class BuildData { + static final String VERSION = "{{ version }}"; + static final ApiVersion API_VERSION; + + static { + String[] parts = VERSION.split("\\."); + if (parts.length != 3) { + throw new RuntimeException("Invalid api version: " + VERSION); + } + + try { + int human = Integer.parseInt(parts[0]); + int major = Integer.parseInt(parts[1]); + int minor = Integer.parseInt(parts[2]); + API_VERSION = new ApiVersion(human, major, minor); + } catch (Exception e) { + throw new RuntimeException("Invalid api version: " + VERSION, e); + } + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/GeyserApi.java b/api/src/main/java/org/geysermc/geyser/api/GeyserApi.java index a9327d0db..5c20d06e1 100644 --- a/api/src/main/java/org/geysermc/geyser/api/GeyserApi.java +++ b/api/src/main/java/org/geysermc/geyser/api/GeyserApi.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.Geyser; import org.geysermc.api.GeyserApiBase; +import org.geysermc.api.util.ApiVersion; import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.EventBus; @@ -169,4 +170,14 @@ public interface GeyserApi extends GeyserApiBase { static GeyserApi api() { return Geyser.api(GeyserApi.class); } + + /** + * Returns the {@link ApiVersion} representing the current Geyser api version. + * See the Geyser version outline) + * + * @return the current geyser api version + */ + default ApiVersion geyserApiVersion() { + return BuildData.API_VERSION; + } } diff --git a/api/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java b/api/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java index 2df3ee815..25daf450f 100644 --- a/api/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java +++ b/api/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java @@ -59,33 +59,46 @@ public interface ExtensionDescription { String main(); /** - * Gets the extension's major api version + * Represents the human api version that the extension requires. + * See the Geyser version outline) + * for more details on the Geyser API version. * - * @return the extension's major api version + * @return the extension's requested human api version + */ + int humanApiVersion(); + + /** + * Represents the major api version that the extension requires. + * See the Geyser version outline) + * for more details on the Geyser API version. + * + * @return the extension's requested major api version */ int majorApiVersion(); /** - * Gets the extension's minor api version + * Represents the minor api version that the extension requires. + * See the Geyser version outline) + * for more details on the Geyser API version. * - * @return the extension's minor api version + * @return the extension's requested minor api version */ int minorApiVersion(); /** - * Gets the extension's patch api version - * - * @return the extension's patch api version + * No longer in use. Geyser is now using an adaption of the romantic versioning scheme. + * See here for details. */ - int patchApiVersion(); + @Deprecated(forRemoval = true) + default int patchApiVersion() { + return minorApiVersion(); + } /** - * Gets the extension's api version. - * - * @return the extension's api version + * Returns the extension's requested Geyser Api version. */ default String apiVersion() { - return majorApiVersion() + "." + minorApiVersion() + "." + patchApiVersion(); + return humanApiVersion() + "." + majorApiVersion() + "." + minorApiVersion(); } /** diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index 239ffc450..a84f12813 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -43,9 +43,9 @@ import java.util.regex.Pattern; public record GeyserExtensionDescription(@NonNull String id, @NonNull String name, @NonNull String main, + int humanApiVersion, int majorApiVersion, int minorApiVersion, - int patchApiVersion, @NonNull String version, @NonNull List authors) implements ExtensionDescription { @@ -82,9 +82,9 @@ public record GeyserExtensionDescription(@NonNull String id, throw new InvalidDescriptionException(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion)); } String[] api = apiVersion.split("\\."); - int majorApi = Integer.parseUnsignedInt(api[0]); - int minorApi = Integer.parseUnsignedInt(api[1]); - int patchApi = Integer.parseUnsignedInt(api[2]); + int humanApi = Integer.parseUnsignedInt(api[0]); + int majorApi = Integer.parseUnsignedInt(api[1]); + int minorApi = Integer.parseUnsignedInt(api[2]); List authors = new ArrayList<>(); if (source.author != null) { @@ -94,7 +94,7 @@ public record GeyserExtensionDescription(@NonNull String id, authors.addAll(source.authors); } - return new GeyserExtensionDescription(id, name, main, majorApi, minorApi, patchApi, version, authors); + return new GeyserExtensionDescription(id, name, main, humanApi, majorApi, minorApi, version, authors); } @NonNull diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index 2f0ff1580..a56e00671 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -29,10 +29,15 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.api.Geyser; +import org.geysermc.api.util.ApiVersion; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.event.ExtensionEventBus; -import org.geysermc.geyser.api.extension.*; +import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.api.extension.ExtensionDescription; +import org.geysermc.geyser.api.extension.ExtensionLoader; +import org.geysermc.geyser.api.extension.ExtensionLogger; +import org.geysermc.geyser.api.extension.ExtensionManager; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; import org.geysermc.geyser.extension.event.GeyserExtensionEventBus; @@ -40,7 +45,12 @@ import org.geysermc.geyser.text.GeyserLocale; import java.io.IOException; import java.io.Reader; -import java.nio.file.*; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -176,16 +186,22 @@ public class GeyserExtensionLoader extends ExtensionLoader { return; } - // Completely different API version - if (description.majorApiVersion() != Geyser.api().majorApiVersion()) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); - return; - } + // Check whether an extensions' requested api version is compatible + ApiVersion.Compatibility compatibility = GeyserApi.api().geyserApiVersion().supportsRequestedVersion( + description.humanApiVersion(), + description.majorApiVersion(), + description.minorApiVersion() + ); - // If the extension requires new API features, being backwards compatible - if (description.minorApiVersion() > Geyser.api().minorApiVersion()) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); - return; + if (compatibility != ApiVersion.Compatibility.COMPATIBLE) { + // Workaround for the switch to the Geyser API version instead of the Base API version in extensions + if (compatibility == ApiVersion.Compatibility.HUMAN_DIFFER && description.humanApiVersion() == 1) { + GeyserImpl.getInstance().getLogger().warning("The extension %s requested the Base API version %s, which is deprecated in favor of specifying the Geyser API version. Please update the extension, or contact its developer." + .formatted(name, description.apiVersion())); + } else { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); + return; + } } GeyserExtensionContainer container = this.loadExtension(path, description); diff --git a/gradle.properties b/gradle.properties index a222b1d99..10d236a1b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.4.0-SNAPSHOT +version=2.4.1-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 f4abe18a9..b002c448c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -base-api = "1.0.0-SNAPSHOT" +base-api = "1.0.1-SNAPSHOT" cumulus = "1.1.2" erosion = "1.1-20240515.191456-1" events = "1.1-SNAPSHOT" From 8e3977810690e301772b6ac5083868cccf584483 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 1 Aug 2024 00:59:28 +0200 Subject: [PATCH 324/897] Target 1.0.1 release of the base api --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b002c448c..7a81ed923 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -base-api = "1.0.1-SNAPSHOT" +base-api = "1.0.1" cumulus = "1.1.2" erosion = "1.1-20240515.191456-1" events = "1.1-SNAPSHOT" From 5019b5aded85e9a938b27b3431fe551d9cbc8851 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 31 Jul 2024 19:22:56 -0500 Subject: [PATCH 325/897] Fix Geyser Api BuildData directory --- .../geysermc/geyser/api}/BuildData.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename api/src/main/java-templates/{org.geysermc.geyser.api => org/geysermc/geyser/api}/BuildData.java (100%) diff --git a/api/src/main/java-templates/org.geysermc.geyser.api/BuildData.java b/api/src/main/java-templates/org/geysermc/geyser/api/BuildData.java similarity index 100% rename from api/src/main/java-templates/org.geysermc.geyser.api/BuildData.java rename to api/src/main/java-templates/org/geysermc/geyser/api/BuildData.java From 95c6f7c9cf9779205588fee5f0f1f42080a83e41 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Thu, 1 Aug 2024 01:18:49 +0000 Subject: [PATCH 326/897] Add advancement progress tracker (#4568) * Fix fetching advancements with invalid parents * Add progress tracker to advancements * Use Java language key for progress counter --- .../geyser/level/GeyserAdvancement.java | 12 ++-- .../session/cache/AdvancementsCache.java | 56 ++++++++++++++----- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java index 7d48b90af..7dad1639b 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java @@ -82,11 +82,15 @@ public class GeyserAdvancement { this.rootId = this.advancement.getId(); } else { // Go through our cache, and descend until we find the root ID - GeyserAdvancement advancement = advancementsCache.getStoredAdvancements().get(this.advancement.getParentId()); - if (advancement.getParentId() == null) { - this.rootId = advancement.getId(); + GeyserAdvancement parent = advancementsCache.getStoredAdvancements().get(this.advancement.getParentId()); + if (parent == null) { + // Parent doesn't exist, is invalid, or couldn't be found for another reason + // So assuming there is no parent and this is the root + this.rootId = this.advancement.getId(); + } else if (parent.getParentId() == null) { + this.rootId = parent.getId(); } else { - this.rootId = advancement.getRootId(advancementsCache); + this.rootId = parent.getRootId(advancementsCache); } } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java index be1eb3a5b..ac04bdf04 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java @@ -158,7 +158,15 @@ public class AdvancementsCache { // Cache language for easier access String language = session.locale(); - String earned = isEarned(advancement) ? "yes" : "no"; + boolean advancementHasProgress = advancement.getRequirements().size() > 1; + + int advancementProgress = getProgress(advancement); + int advancementRequirements = advancement.getRequirements().size(); + + boolean advancementEarned = advancementRequirements > 0 + && advancementProgress >= advancementRequirements; + + String earned = advancementEarned ? "yes" : "no"; String description = getColorFromAdvancementFrameType(advancement) + MessageTranslator.convertMessage(advancement.getDisplayData().getDescription(), language); String earnedString = GeyserLocale.getPlayerLocaleString("geyser.advancements.earned", language, MinecraftLocale.getLocaleString("gui." + earned, language)); @@ -171,10 +179,20 @@ public class AdvancementsCache { (Description) Mine stone with your new pickaxe Earned: Yes + Progress: 1/4 // When advancement has multiple requirements Parent Advancement: Minecraft // If relevant */ String content = description + "\n\n§f" + earnedString + "\n"; + + if (advancementHasProgress) { + // Only display progress with multiple requirements + String progress = MinecraftLocale.getLocaleString("advancements.progress", language) + .replaceFirst("%s", String.valueOf(advancementProgress)) + .replaceFirst("%s", String.valueOf(advancementRequirements)); + content += GeyserLocale.getPlayerLocaleString("geyser.advancements.progress", language, progress) + "\n"; + } + if (!currentAdvancementCategoryId.equals(advancement.getParentId())) { // Only display the parent if it is not the category content += GeyserLocale.getPlayerLocaleString("geyser.advancements.parentid", language, MessageTranslator.convertMessage(storedAdvancements.get(advancement.getParentId()).getDisplayData().getTitle(), language)); @@ -200,34 +218,44 @@ public class AdvancementsCache { * @return true if the advancement has been earned. */ public boolean isEarned(GeyserAdvancement advancement) { - boolean earned = false; - if (advancement.getRequirements().size() == 0) { + if (advancement.getRequirements().isEmpty()) { // Minecraft handles this case, so we better as well return false; } - Map progress = storedAdvancementProgress.get(advancement.getId()); - if (progress != null) { + // Progress should never be above requirements count, but you never know + return getProgress(advancement) >= advancement.getRequirements().size(); + } + + /** + * Determine the progress on an advancement. + * + * @param advancement the advancement to determine + * @return the progress on the advancement. + */ + public int getProgress(GeyserAdvancement advancement) { + if (advancement.getRequirements().isEmpty()) { + // Minecraft handles this case + return 0; + } + int progress = 0; + Map progressMap = storedAdvancementProgress.get(advancement.getId()); + if (progressMap != null) { // Each advancement's requirement must be fulfilled // For example, [[zombie, blaze, skeleton]] means that one of those three categories must be achieved // But [[zombie], [blaze], [skeleton]] means that all three requirements must be completed for (List requirements : advancement.getRequirements()) { - boolean requirementsDone = false; for (String requirement : requirements) { - Long obtained = progress.get(requirement); + Long obtained = progressMap.get(requirement); // -1 means that this particular component required for completing the advancement // has yet to be fulfilled if (obtained != null && !obtained.equals(-1L)) { - requirementsDone = true; - break; + progress++; } } - if (!requirementsDone) { - return false; - } } - earned = true; } - return earned; + + return progress; } public String getColorFromAdvancementFrameType(GeyserAdvancement advancement) { From 3d7e62a408b2b4a6f86430e940a0219c5b595fa0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 1 Aug 2024 18:35:03 -0400 Subject: [PATCH 327/897] Fix some server switching issues and GeyserConnect --- .../type/player/SessionPlayerEntity.java | 2 +- .../geysermc/geyser/level/JavaDimension.java | 5 ++++- .../geyser/session/GeyserSession.java | 10 ++++++++- .../geyser/session/cache/ChunkCache.java | 14 ++---------- .../protocol/java/JavaLoginTranslator.java | 22 ++++++++----------- .../JavaHorseScreenOpenTranslator.java | 6 ++++- .../JavaLevelChunkWithLightTranslator.java | 4 ++-- .../org/geysermc/geyser/util/ChunkUtils.java | 6 ++--- .../geysermc/geyser/util/DimensionUtils.java | 2 +- .../geysermc/geyser/util/InventoryUtils.java | 2 +- 10 files changed, 37 insertions(+), 36 deletions(-) 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 dc0545cee..b924461af 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 @@ -321,7 +321,7 @@ public class SessionPlayerEntity extends PlayerEntity { public int voidFloorPosition() { // The void floor is offset about 40 blocks below the bottom of the world - BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + BedrockDimension bedrockDimension = session.getBedrockDimension(); return bedrockDimension.minY() - 40; } diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 7462844fc..0ca428830 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -34,6 +34,9 @@ import org.geysermc.geyser.util.DimensionUtils; * Represents the information we store from the current Java dimension * @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension. * This controls if they have the shaking effect applied in the dimension. + * @param bedrockId the Bedrock dimension ID of this dimension. + * As a Java dimension can be null in some login cases (e.g. GeyserConnect), make sure the player + * is logged in before utilizing this field. */ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale, int bedrockId, boolean isNetherLike) { @@ -46,7 +49,7 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double world // Set if piglins/hoglins should shake boolean piglinSafe = dimension.getBoolean("piglin_safe"); // Load world coordinate scale for the world border - double coordinateScale = dimension.getDouble("coordinate_scale"); + double coordinateScale = dimension.getNumber("coordinate_scale").doubleValue(); // FIXME see if we can change this in the NBT library itself. boolean isNetherLike; // Cache the Bedrock version of this dimension, and base it off the ID - THE ID CAN CHANGE!!! 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 60321ea75..9a990865e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -137,6 +137,7 @@ import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.BlockItem; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.network.netty.LocalSession; @@ -386,6 +387,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @MonotonicNonNull @Setter private JavaDimension dimensionType = null; + /** + * Which dimension Bedrock understands themselves to be in. + * This should only be set after the ChangeDimensionPacket is sent, or + * right before the StartGamePacket is sent. + */ + @Setter + private BedrockDimension bedrockDimension = BedrockDimension.OVERWORLD; @Setter private int breakingBlock; @@ -1547,7 +1555,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setRotation(Vector2f.from(1, 1)); startGamePacket.setSeed(-1L); - startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(chunkCache.getBedrockDimension())); + startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(bedrockDimension)); startGamePacket.setGeneratorId(1); startGamePacket.setLevelGameType(GameType.SURVIVAL); startGamePacket.setDifficulty(1); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java index 7b279857a..ad5237c23 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java @@ -25,17 +25,14 @@ package org.geysermc.geyser.session.cache; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import lombok.Getter; import lombok.Setter; -import org.geysermc.geyser.level.BedrockDimension; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.chunk.GeyserChunk; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; public class ChunkCache { private final boolean cache; @@ -46,13 +43,6 @@ public class ChunkCache { @Setter private int heightY; - /** - * Which dimension Bedrock understands themselves to be in. - */ - @Getter - @Setter - private BedrockDimension bedrockDimension = BedrockDimension.OVERWORLD; - public ChunkCache(GeyserSession session) { this.cache = !session.getGeyser().getWorldManager().hasOwnChunkCache(); // To prevent Spigot from initializing chunks = cache ? new Long2ObjectOpenHashMap<>() : null; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index cf4b7058b..a6d6e6c70 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -64,14 +64,17 @@ public class JavaLoginTranslator extends PacketTranslator> 4) - 1; int sectionCount; @@ -509,7 +509,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator entry : session.getItemFrameCache().entrySet()) { diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index 2e7df51bd..288b425ba 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -149,7 +149,7 @@ public class ChunkUtils { } public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) { - BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + BedrockDimension bedrockDimension = session.getBedrockDimension(); int bedrockSubChunkCount = bedrockDimension.height() >> 4; byte[] payload; @@ -167,7 +167,7 @@ public class ChunkUtils { byteBuf.readBytes(payload); LevelChunkPacket data = new LevelChunkPacket(); - data.setDimension(DimensionUtils.javaToBedrock(session.getChunkCache().getBedrockDimension())); + data.setDimension(DimensionUtils.javaToBedrock(session.getBedrockDimension())); data.setChunkX(chunkX); data.setChunkZ(chunkZ); data.setSubChunksLength(0); @@ -214,7 +214,7 @@ public class ChunkUtils { throw new RuntimeException("Maximum Y must be a multiple of 16!"); } - BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + BedrockDimension bedrockDimension = session.getBedrockDimension(); // Yell in the console if the world height is too height in the current scenario // The constraints change depending on if the player is in the overworld or not, and if experimental height is enabled // (Ignore this for the Nether. We can't change that at the moment without the workaround. :/ ) diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index 821358bd8..f043631b6 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -179,7 +179,7 @@ public class DimensionUtils { } public static void setBedrockDimension(GeyserSession session, int bedrockDimension) { - session.getChunkCache().setBedrockDimension(switch (bedrockDimension) { + session.setBedrockDimension(switch (bedrockDimension) { case BEDROCK_END_ID -> BedrockDimension.THE_END; case BEDROCK_DEFAULT_NETHER_ID -> BedrockDimension.THE_NETHER; // JavaDimension *should* be set to BEDROCK_END_ID if the Nether workaround is enabled. default -> BedrockDimension.OVERWORLD; 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 b0bfffc19..d8c41d626 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -159,7 +159,7 @@ public class InventoryUtils { @Nullable public static Vector3i findAvailableWorldSpace(GeyserSession session) { // Check if a fake block can be placed, either above the player or beneath. - BedrockDimension dimension = session.getChunkCache().getBedrockDimension(); + BedrockDimension dimension = session.getBedrockDimension(); int minY = dimension.minY(), maxY = minY + dimension.height(); Vector3i flatPlayerPosition = session.getPlayerEntity().getPosition().toInt(); Vector3i position = flatPlayerPosition.add(Vector3i.UP); From 61ae5debd4527875a5dc0bff912c029f2501a1b1 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 3 Aug 2024 10:23:06 -0500 Subject: [PATCH 328/897] Allow dumps to be created even if GeyserServer failed to start (#4930) --- .../geyser/command/defaults/DumpCommand.java | 50 ++++++++++--------- .../org/geysermc/geyser/dump/DumpInfo.java | 22 ++++---- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java index 45100f525..fc46f0108 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java @@ -63,31 +63,31 @@ public class DumpCommand extends GeyserCommand { this.geyser = geyser; } - @Override - public void register(CommandManager manager) { - manager.command(baseBuilder(manager) - .optional(ARGUMENTS, stringArrayParser(), SuggestionProvider.blockingStrings((ctx, input) -> { - // parse suggestions here - List inputs = new ArrayList<>(); - while (input.hasRemainingInput()) { - inputs.add(input.readStringSkipWhitespace()); - } + @Override + public void register(CommandManager manager) { + manager.command(baseBuilder(manager) + .optional(ARGUMENTS, stringArrayParser(), SuggestionProvider.blockingStrings((ctx, input) -> { + // parse suggestions here + List inputs = new ArrayList<>(); + while (input.hasRemainingInput()) { + inputs.add(input.readStringSkipWhitespace()); + } - if (inputs.size() <= 2) { - return SUGGESTIONS; // only `geyser dump` was typed (2 literals) - } + if (inputs.size() <= 2) { + return SUGGESTIONS; // only `geyser dump` was typed (2 literals) + } - // the rest of the input after `geyser dump` is for this argument - inputs = inputs.subList(2, inputs.size()); + // the rest of the input after `geyser dump` is for this argument + inputs = inputs.subList(2, inputs.size()); - // don't suggest any words they have already typed - List suggestions = new ArrayList<>(); - SUGGESTIONS.forEach(suggestions::add); - suggestions.removeAll(inputs); - return suggestions; - })) - .handler(this::execute)); - } + // don't suggest any words they have already typed + List suggestions = new ArrayList<>(); + SUGGESTIONS.forEach(suggestions::add); + suggestions.removeAll(inputs); + return suggestions; + })) + .handler(this::execute)); + } @Override public void execute(CommandContext context) { @@ -113,13 +113,15 @@ public class DumpCommand extends GeyserCommand { source.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collecting", source.locale())); String dumpData; try { + DumpInfo dump = new DumpInfo(geyser, addLog); + if (offlineDump) { DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); // Make arrays easier to read prettyPrinter.indentArraysWith(new DefaultIndenter(" ", "\n")); - dumpData = MAPPER.writer(prettyPrinter).writeValueAsString(new DumpInfo(addLog)); + dumpData = MAPPER.writer(prettyPrinter).writeValueAsString(dump); } else { - dumpData = MAPPER.writeValueAsString(new DumpInfo(addLog)); + dumpData = MAPPER.writeValueAsString(dump); } } catch (IOException e) { source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collect_error", source.locale())); diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 6989dc10a..515e1a629 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -81,7 +81,7 @@ public class DumpInfo { private final FlagsInfo flagsInfo; private final List extensionInfo; - public DumpInfo(boolean addLog) { + public DumpInfo(GeyserImpl geyser, boolean addLog) { this.versionInfo = new VersionInfo(); this.cpuCount = Runtime.getRuntime().availableProcessors(); @@ -91,7 +91,7 @@ public class DumpInfo { this.gitInfo = new GitInfo(GeyserImpl.BUILD_NUMBER, GeyserImpl.COMMIT.substring(0, 7), GeyserImpl.COMMIT, GeyserImpl.BRANCH, GeyserImpl.REPOSITORY); - this.config = GeyserImpl.getInstance().getConfig(); + this.config = geyser.getConfig(); this.floodgate = new Floodgate(); String md5Hash = "unknown"; @@ -107,7 +107,7 @@ public class DumpInfo { //noinspection UnstableApiUsage sha256Hash = byteSource.hash(Hashing.sha256()).toString(); } catch (Exception e) { - if (GeyserImpl.getInstance().getConfig().isDebugMode()) { + if (this.config.isDebugMode()) { e.printStackTrace(); } } @@ -116,18 +116,22 @@ public class DumpInfo { this.ramInfo = new RamInfo(); if (addLog) { - this.logsInfo = new LogsInfo(); + this.logsInfo = new LogsInfo(geyser); } this.userPlatforms = new Object2IntOpenHashMap<>(); - for (GeyserSession session : GeyserImpl.getInstance().getSessionManager().getAllSessions()) { + for (GeyserSession session : geyser.getSessionManager().getAllSessions()) { DeviceOs device = session.getClientData().getDeviceOs(); userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1); } - this.connectionAttempts = GeyserImpl.getInstance().getGeyserServer().getConnectionAttempts(); + if (geyser.getGeyserServer() != null) { + this.connectionAttempts = geyser.getGeyserServer().getConnectionAttempts(); + } else { + this.connectionAttempts = 0; // Fallback if Geyser failed to fully startup + } - this.bootstrapInfo = GeyserImpl.getInstance().getBootstrap().getDumpInfo(); + this.bootstrapInfo = geyser.getBootstrap().getDumpInfo(); this.flagsInfo = new FlagsInfo(); @@ -244,10 +248,10 @@ public class DumpInfo { public static class LogsInfo { private String link; - public LogsInfo() { + public LogsInfo(GeyserImpl geyser) { try { Map fields = new HashMap<>(); - fields.put("content", FileUtils.readAllLines(GeyserImpl.getInstance().getBootstrap().getLogsPath()).collect(Collectors.joining("\n"))); + fields.put("content", FileUtils.readAllLines(geyser.getBootstrap().getLogsPath()).collect(Collectors.joining("\n"))); JsonNode logData = GeyserImpl.JSON_MAPPER.readTree(WebUtils.postForm("https://api.mclo.gs/1/log", fields)); From 523bcdc095a1fb6bf6f6bccca033418a5ad7d92a Mon Sep 17 00:00:00 2001 From: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Date: Sun, 4 Aug 2024 22:00:15 -0700 Subject: [PATCH 329/897] Specify 1.21.2/1.21.3 support Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --- .../src/main/java/org/geysermc/geyser/network/GameProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 18dee94e6..087ecf5cc 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -72,7 +72,7 @@ public final class GameProtocol { .minecraftVersion("1.21.0/1.21.1") .build())); SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v686.CODEC.toBuilder() - .minecraftVersion("1.21.2") + .minecraftVersion("1.21.2/1.21.3") .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } From ea6b0df9b57b209077198342ace7ddacf2b805bc Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:54:17 -0500 Subject: [PATCH 330/897] Remove GeyserImpl#shouldStartListener (#4935) --- .../java/org/geysermc/geyser/GeyserImpl.java | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 01f1a118e..5c08e34d7 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -156,12 +156,6 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { private final SessionManager sessionManager = new SessionManager(); - /** - * This is used in GeyserConnect to stop the bedrock server binding to a port - */ - @Setter - private static boolean shouldStartListener = true; - private FloodgateCipher cipher; private FloodgateSkinUploader skinUploader; private NewsHandler newsHandler; @@ -435,24 +429,22 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { bedrockThreadCount = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2)); } - if (shouldStartListener) { - this.geyserServer = new GeyserServer(this, bedrockThreadCount); - this.geyserServer.bind(new InetSocketAddress(config.getBedrock().address(), config.getBedrock().port())) - .whenComplete((avoid, throwable) -> { - if (throwable == null) { - logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().address(), - String.valueOf(config.getBedrock().port()))); - } else { - String address = config.getBedrock().address(); - int port = config.getBedrock().port(); - logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port))); - if (!"0.0.0.0".equals(address)) { - logger.info(Component.text("Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0", NamedTextColor.GREEN)); - logger.info(Component.text("Then, restart this server.", NamedTextColor.GREEN)); - } + this.geyserServer = new GeyserServer(this, bedrockThreadCount); + this.geyserServer.bind(new InetSocketAddress(config.getBedrock().address(), config.getBedrock().port())) + .whenComplete((avoid, throwable) -> { + if (throwable == null) { + logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().address(), + String.valueOf(config.getBedrock().port()))); + } else { + String address = config.getBedrock().address(); + int port = config.getBedrock().port(); + logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port))); + if (!"0.0.0.0".equals(address)) { + logger.info(Component.text("Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0", NamedTextColor.GREEN)); + logger.info(Component.text("Then, restart this server.", NamedTextColor.GREEN)); } - }).join(); - } + } + }).join(); if (config.getRemote().authType() == AuthType.FLOODGATE) { try { From 83d8c19824c9fec4218a028d0d0e833f7abe13c4 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 6 Aug 2024 12:56:10 +0100 Subject: [PATCH 331/897] Make missing locale log as debug (#4940) --- core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java index 28fd6f9a4..b8867c356 100644 --- a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java @@ -150,7 +150,7 @@ public class GeyserLocale { } else { if (!validLocalLanguage) { // Don't warn on missing locales if a local file has been found - bootstrap.getGeyserLogger().warning("Missing locale: " + locale); + bootstrap.getGeyserLogger().debug("Missing locale: " + locale); } } From 54c43f2b022f1be1fdd6bda2c3603372369c8c3c Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:36:34 -0500 Subject: [PATCH 332/897] Suppress address in bind log if it is 0.0.0.0 (#4160) Co-authored-by: onebeastchris --- .../main/java/org/geysermc/geyser/GeyserImpl.java | 15 ++++++++++----- core/src/main/resources/languages | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 5c08e34d7..8febf4d21 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -432,13 +432,18 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { this.geyserServer = new GeyserServer(this, bedrockThreadCount); this.geyserServer.bind(new InetSocketAddress(config.getBedrock().address(), config.getBedrock().port())) .whenComplete((avoid, throwable) -> { + String address = config.getBedrock().address(); + String port = String.valueOf(config.getBedrock().port()); // otherwise we get commas + if (throwable == null) { - logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().address(), - String.valueOf(config.getBedrock().port()))); + if ("0.0.0.0".equals(address)) { + // basically just hide it in the log because some people get confused and try to change it + logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start.ip_suppressed", port)); + } else { + logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", address, port)); + } } else { - String address = config.getBedrock().address(); - int port = config.getBedrock().port(); - logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port))); + logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, port)); if (!"0.0.0.0".equals(address)) { logger.info(Component.text("Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0", NamedTextColor.GREEN)); logger.info(Component.text("Then, restart this server.", NamedTextColor.GREEN)); diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 60b20023a..a943a1bb9 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 60b20023a92f084aba895ab0336e70fa7fb311fb +Subproject commit a943a1bb910f58caa61f14bafacbc622bd48a694 From 069d35c6422a05a74f960d2fdb5d2788823ff722 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:08:27 -0400 Subject: [PATCH 333/897] Likely fix for #2573 Tested working on Paper 1.21 --- .../translator/protocol/java/JavaCommandsTranslator.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 4c817ba01..01da23809 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -76,6 +76,9 @@ public class JavaCommandsTranslator extends PacketTranslator Date: Tue, 6 Aug 2024 22:09:01 -0400 Subject: [PATCH 334/897] New files for .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a44afd242..aff61aa60 100644 --- a/.gitignore +++ b/.gitignore @@ -249,6 +249,8 @@ locales/ /packs/ /dump.json /saved-refresh-tokens.json +/saved-auth-chains.json /custom_mappings/ /languages/ -/custom-skulls.yml \ No newline at end of file +/custom-skulls.yml +/permissions.yml From 86d0a4720631513c0446558bb3bd53a121050eb8 Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Thu, 8 Aug 2024 13:25:06 +0200 Subject: [PATCH 335/897] Fix floodgate not working with the default config (#4951) --- .../geyser/platform/viaproxy/GeyserViaProxyPlugin.java | 3 +++ bootstrap/viaproxy/src/main/resources/viaproxy.yml | 2 +- gradle/libs.versions.toml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java index 1eed778f2..5551b9755 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java @@ -155,6 +155,9 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst // Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser); } + if (this.config.getRemote().authType() == AuthType.FLOODGATE) { + ViaProxy.getConfig().setPassthroughBungeecordPlayerInfo(true); + } } @Override diff --git a/bootstrap/viaproxy/src/main/resources/viaproxy.yml b/bootstrap/viaproxy/src/main/resources/viaproxy.yml index 66fbdb932..89fc612cd 100644 --- a/bootstrap/viaproxy/src/main/resources/viaproxy.yml +++ b/bootstrap/viaproxy/src/main/resources/viaproxy.yml @@ -2,4 +2,4 @@ name: "${name}-ViaProxy" version: "${version}" author: "${author}" main: "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyPlugin" -min-version: "3.2.1" +min-version: "3.3.2" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7a81ed923..2ed67e96c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ cloud-minecraft-modded = "2.0.0-beta.7" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" -viaproxy = "3.2.1" +viaproxy = "3.3.2-SNAPSHOT" fabric-loader = "0.15.11" fabric-api = "0.100.1+1.21" neoforge-minecraft = "21.0.0-beta" From f5b7cc725b9bdb8ecb2e554947fed10e0cc360a1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:55:14 -0400 Subject: [PATCH 336/897] Fix mangrove propagule age (#4949) --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 597dcd3a7..698fd2b10 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 597dcd3a78d0896638788f4b966eaa8554cf0b43 +Subproject commit 698fd2b108a9e53f1e47b8cfdc122651b70d6059 From ee0b34e49033feda757f5e1a72e6a87211514476 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 9 Aug 2024 02:15:08 +0200 Subject: [PATCH 337/897] Indicate 1.21.1 Java support - Indicate 1.21.1 support on modrinth/in the README.md - Add all supported versions of Geyser-Spigot to modrinth (#4952) --- README.md | 2 +- bootstrap/spigot/build.gradle.kts | 2 ++ .../kotlin/geyser.modrinth-uploading-conventions.gradle.kts | 4 ++-- gradle/libs.versions.toml | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8eac49a24..bc60a1847 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.3 and Minecraft Java Server 1.21. For more info please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.3 and Minecraft Java Server 1.21/1.21.1. For more info 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/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 0a1271145..f680b1949 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -81,5 +81,7 @@ tasks.withType { modrinth { uploadFile.set(tasks.getByPath("shadowJar")) + gameVersions.addAll("1.16.5", "1.17", "1.17.1", "1.18", "1.18.1", "1.18.2", "1.19", + "1.19.1", "1.19.2", "1.19.3", "1.19.4", "1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4", "1.20.5", "1.20.6") loaders.addAll("spigot", "paper") } 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 d710ae1a2..fe2284137 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 @@ -11,8 +11,8 @@ modrinth { versionNumber.set(project.version as String + "-" + System.getenv("BUILD_NUMBER")) versionType.set("beta") changelog.set(System.getenv("CHANGELOG") ?: "") - gameVersions.add(libs.minecraft.get().version as String) + gameVersions.addAll("1.21", libs.minecraft.get().version as String) failSilently.set(true) syncBodyFrom.set(rootProject.file("README.md").readText()) -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2ed67e96c..b141d9989 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,10 +33,10 @@ 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.0.0-beta" +neoforge-minecraft = "21.1.1" mixin = "0.8.5" mixinextras = "0.3.5" -minecraft = "1.21" +minecraft = "1.21.1" # plugin versions indra = "3.1.3" From cd897feb1b60bcad6362a3027c95cad84b179441 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 9 Aug 2024 11:35:25 +0200 Subject: [PATCH 338/897] Unify repository definition (#4953) * Unify repository definition * Remove duplicate repo * Update build-logic/src/main/kotlin/geyser.build-logic.gradle.kts Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> --------- Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../main/kotlin/geyser.build-logic.gradle.kts | 45 ++++++++++++++++++ .../geyser.modded-conventions.gradle.kts | 10 +--- settings.gradle.kts | 46 ------------------- 3 files changed, 46 insertions(+), 55 deletions(-) diff --git a/build-logic/src/main/kotlin/geyser.build-logic.gradle.kts b/build-logic/src/main/kotlin/geyser.build-logic.gradle.kts index e69de29bb..b6168507e 100644 --- a/build-logic/src/main/kotlin/geyser.build-logic.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.build-logic.gradle.kts @@ -0,0 +1,45 @@ +repositories { + // mavenLocal() + + mavenCentral() + + // Floodgate, Cumulus etc. + maven("https://repo.opencollab.dev/main") + + // Paper, Velocity + maven("https://repo.papermc.io/repository/maven-public") + + // Spigot + maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") { + mavenContent { snapshotsOnly() } + } + + // BungeeCord + maven("https://oss.sonatype.org/content/repositories/snapshots") { + mavenContent { snapshotsOnly() } + } + + // NeoForge + maven("https://maven.neoforged.net/releases") { + mavenContent { releasesOnly() } + } + + // Minecraft + maven("https://libraries.minecraft.net") { + name = "minecraft" + mavenContent { releasesOnly() } + } + + // ViaVersion + maven("https://repo.viaversion.com") { + name = "viaversion" + } + + // Jitpack for e.g. MCPL + maven("https://jitpack.io") { + content { includeGroupByRegex("com\\.github\\..*") } + } + + // For Adventure snapshots + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") +} diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index 20d14c443..8a6602778 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -5,6 +5,7 @@ import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.maven plugins { + id("geyser.build-logic") id("geyser.publish-conventions") id("architectury-plugin") id("dev.architectury.loom") @@ -116,12 +117,3 @@ dependencies { minecraft(libs.minecraft) mappings(loom.officialMojangMappings()) } - -repositories { - // mavenLocal() - maven("https://repo.opencollab.dev/main") - maven("https://jitpack.io") - maven("https://oss.sonatype.org/content/repositories/snapshots/") - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") - maven("https://maven.neoforged.net/releases") -} diff --git a/settings.gradle.kts b/settings.gradle.kts index a39bfa3d2..9aaf6ba59 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,52 +2,6 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -dependencyResolutionManagement { - repositories { - // mavenLocal() - - // Floodgate, Cumulus etc. - maven("https://repo.opencollab.dev/main") - - // Paper, Velocity - maven("https://repo.papermc.io/repository/maven-public") - // Spigot - maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") { - mavenContent { snapshotsOnly() } - } - - // BungeeCord - maven("https://oss.sonatype.org/content/repositories/snapshots") { - mavenContent { snapshotsOnly() } - } - - // NeoForge - maven("https://maven.neoforged.net/releases") { - mavenContent { releasesOnly() } - } - - // Minecraft - maven("https://libraries.minecraft.net") { - name = "minecraft" - mavenContent { releasesOnly() } - } - - mavenCentral() - - // ViaVersion - maven("https://repo.viaversion.com") { - name = "viaversion" - } - - maven("https://jitpack.io") { - content { includeGroupByRegex("com\\.github\\..*") } - } - - // For Adventure snapshots - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") - } -} - pluginManagement { repositories { gradlePluginPortal() From 41e65b0fcc5d4c905b4c6bc21a25d3c7b464ba81 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 9 Aug 2024 12:53:32 +0200 Subject: [PATCH 339/897] Bump minecraftauth dependency (#4943) * Bump minecraftauth to snapshot build fixing rare issues with Geyser-Spigot --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b141d9989..b8c80d0bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" protocol = "3.0.0.Beta2-20240704.153116-14" raknet = "1.0.0.CR3-20240416.144209-1" -minecraftauth = "4.1.0" +minecraftauth = "4.1.1-20240806.235051-7" mcprotocollib = "1.21-20240725.013034-16" adventure = "4.14.0" adventure-platform = "4.3.0" From d3ea65196bf4f75c4500830059d6a0612eba8599 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 11 Aug 2024 00:50:27 +0200 Subject: [PATCH 340/897] Feature: Detect incorrect proxy setups (#4941) * Feature: Detect & warn about incorrect proxy setups on Spigot platforms * Properly disable Geyser if we failed to load --- .../bungeecord/GeyserBungeePlugin.java | 6 +--- .../platform/mod/GeyserModBootstrap.java | 5 +++ .../platform/spigot/GeyserSpigotPlugin.java | 33 +++++++++++++++++-- .../velocity/GeyserVelocityPlugin.java | 4 +++ .../viaproxy/GeyserViaProxyPlugin.java | 4 +++ core/src/main/resources/languages | 2 +- 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 1c0049231..e2735c80e 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -71,9 +71,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { private IGeyserPingPassthrough geyserBungeePingPassthrough; private GeyserImpl geyser; - // We can't disable the plugin; hence we need to keep track of it manually - private boolean disabled; - @Override public void onLoad() { onGeyserInitialize(); @@ -98,7 +95,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } if (!this.loadConfig()) { - disabled = true; return; } this.geyserLogger.setDebug(geyserConfig.isDebugMode()); @@ -112,7 +108,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { @Override public void onEnable() { - if (disabled) { + if (geyser == null) { return; // Config did not load properly! } // Big hack - Bungee does not provide us an event to listen to, so schedule a repeating diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java index f11b5fbd6..69d6dc9a4 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java @@ -89,6 +89,11 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap { } public void onGeyserEnable() { + // "Disabling" a mod isn't possible; so if we fail to initialize we need to manually stop here + if (geyser == null) { + return; + } + if (GeyserImpl.getInstance().isReloading()) { if (!loadConfig()) { return; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 3bb44a4bc..a2d52ce5a 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -117,7 +117,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2")); geyserLogger.error(""); geyserLogger.error("*********************************************"); - Bukkit.getPluginManager().disablePlugin(this); return; } @@ -131,7 +130,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper")); geyserLogger.error(""); geyserLogger.error("*********************************************"); - Bukkit.getPluginManager().disablePlugin(this); return; } } @@ -144,10 +142,25 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserLogger.error("This version of Spigot is using an outdated version of netty. Please use Paper instead!"); geyserLogger.error(""); geyserLogger.error("*********************************************"); - Bukkit.getPluginManager().disablePlugin(this); return; } + try { + // Check spigot config for BungeeCord mode + if (Bukkit.getServer().spigot().getConfig().getBoolean("settings.bungeecord")) { + warnInvalidProxySetups("BungeeCord"); + return; + } + + // Now: Check for velocity mode - deliberately after checking bungeecord because this is a paper only option + if (Bukkit.getServer().spigot().getPaperConfig().getBoolean("proxies.velocity.enabled")) { + warnInvalidProxySetups("Velocity"); + return; + } + } catch (NoSuchMethodError e) { + // no-op + } + if (!loadConfig()) { return; } @@ -162,6 +175,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { @Override public void onEnable() { + // Disabling the plugin in onLoad() is not supported; we need to manually stop here + if (geyser == null) { + return; + } + // Create command manager early so we can add Geyser extension commands var sourceConverter = new CommandSourceConverter<>( CommandSender.class, @@ -458,4 +476,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return true; } + + private void warnInvalidProxySetups(String platform) { + geyserLogger.error("*********************************************"); + geyserLogger.error(""); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy_backend", platform)); + geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.setup_guide", "https://geysermc.org/wiki/geyser/setup/")); + geyserLogger.error(""); + geyserLogger.error("*********************************************"); + } } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 868cdbf8e..413355813 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -113,6 +113,10 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { @Override public void onGeyserEnable() { + // If e.g. the config failed to load, GeyserImpl was not loaded and we cannot start + if (geyser == null) { + return; + } if (GeyserImpl.getInstance().isReloading()) { if (!loadConfig()) { return; diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java index 5551b9755..b5e614468 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java @@ -132,6 +132,10 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst @Override public void onGeyserEnable() { + // If e.g. the config failed to load, GeyserImpl was not loaded and we cannot start + if (geyser == null) { + return; + } boolean reloading = geyser.isReloading(); if (reloading) { if (!this.loadConfig()) { diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index a943a1bb9..7499daf71 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit a943a1bb910f58caa61f14bafacbc622bd48a694 +Subproject commit 7499daf712ad6de70a07fba471b51b4ad92315c5 From 10281a839f13547f511005ef5304c07459a60be8 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 11 Aug 2024 01:58:31 +0200 Subject: [PATCH 341/897] Bump version to 2.4.2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 10d236a1b..814529d6c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,5 +7,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.4.1-SNAPSHOT +version=2.4.2-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From ce62824899e59990e7720fb4a557d172b6f075e6 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 12 Aug 2024 23:29:00 +0200 Subject: [PATCH 342/897] Feature: Add method to close forms in the API (#4957) * Add closeForm api method * Move version check to GameProtocol --- .../geyser/api/connection/GeyserConnection.java | 15 ++++++++++----- .../org/geysermc/geyser/network/GameProtocol.java | 4 ++++ .../geysermc/geyser/session/GeyserSession.java | 9 +++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java index ba559a462..0a580f975 100644 --- a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java +++ b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java @@ -60,6 +60,16 @@ public interface GeyserConnection extends Connection, CommandSource { */ @NonNull EntityData entities(); + /** + * Returns the current ping of the connection. + */ + int ping(); + + /** + * Closes the currently open form on the client. + */ + void closeForm(); + /** * @param javaId the Java entity ID to look up. * @return a {@link GeyserEntity} if present in this connection's entity tracker. @@ -132,9 +142,4 @@ public interface GeyserConnection extends Connection, CommandSource { @Deprecated @NonNull Set fogEffects(); - - /** - * Returns the current ping of the connection. - */ - int ping(); } diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 087ecf5cc..422fa3d5a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -97,6 +97,10 @@ public final class GameProtocol { return session.getUpstream().getProtocolVersion() < Bedrock_v685.CODEC.getProtocolVersion(); } + public static boolean isPre1_21_2(GeyserSession session) { + return session.getUpstream().getProtocolVersion() < Bedrock_v686.CODEC.getProtocolVersion(); + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * 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 9a990865e..9137c4756 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -79,6 +79,7 @@ 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.EmoteListPacket; @@ -140,6 +141,7 @@ import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.physics.CollisionManager; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; @@ -2114,6 +2116,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return (int) Math.floor(rakSessionCodec.getPing()); } + @Override + public void closeForm() { + if (!GameProtocol.isPre1_21_2(this)) { + sendUpstreamPacket(new ClientboundCloseFormPacket()); + } + } + public void addCommandEnum(String name, String enums) { softEnumPacket(name, SoftEnumUpdateType.ADD, enums); } From ee43ef836925716fdf8eab26befd405836c56259 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 13 Aug 2024 01:45:25 +0200 Subject: [PATCH 343/897] Disable the plugin if we failed to load on Spigot (#4960) --- .../geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index a2d52ce5a..c52927a83 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -175,8 +175,9 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { @Override public void onEnable() { - // Disabling the plugin in onLoad() is not supported; we need to manually stop here + // Disabling the plugin in onLoad() is not supported; we need to manually stop here and disable ourselves if (geyser == null) { + Bukkit.getPluginManager().disablePlugin(this); return; } From 8f7d512073532cba3b761b99830ccbcf7a28cddc Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:42:20 -0400 Subject: [PATCH 344/897] Fix armor not being visible on 1.21.20 --- .../geysermc/geyser/entity/type/LivingEntity.java | 6 ++++++ .../java/entity/JavaSetEquipmentTranslator.java | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) 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 2a1bc1188..1dfe02b09 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 @@ -74,6 +74,7 @@ public class LivingEntity extends Entity { protected ItemData chestplate = ItemData.AIR; protected ItemData leggings = ItemData.AIR; protected ItemData boots = ItemData.AIR; + protected ItemData body = ItemData.AIR; protected ItemData hand = ItemData.AIR; protected ItemData offhand = ItemData.AIR; @@ -112,6 +113,10 @@ public class LivingEntity extends Entity { this.chestplate = ItemTranslator.translateToBedrock(session, stack); } + public void setBody(ItemStack stack) { + this.body = ItemTranslator.translateToBedrock(session, stack); + } + public void setLeggings(ItemStack stack) { this.leggings = ItemTranslator.translateToBedrock(session, stack); } @@ -323,6 +328,7 @@ public class LivingEntity extends Entity { armorEquipmentPacket.setChestplate(chestplate); armorEquipmentPacket.setLeggings(leggings); armorEquipmentPacket.setBoots(boots); + armorEquipmentPacket.setBody(body); session.sendUpstreamPacket(armorEquipmentPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index 07dcced47..11178115a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -29,6 +29,7 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.FakeHeadProvider; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -72,11 +73,19 @@ public class JavaSetEquipmentTranslator extends PacketTranslator { - // BODY is sent for llamas with a carpet equipped, as of 1.20.5 + case CHESTPLATE -> { livingEntity.setChestplate(stack); armorUpdated = true; } + case BODY -> { + // BODY is sent for llamas with a carpet equipped, as of 1.20.5 + if (GameProtocol.isPre1_21_2(session)) { + livingEntity.setChestplate(stack); + } else { + livingEntity.setBody(stack); + } + armorUpdated = true; + } case LEGGINGS -> { livingEntity.setLeggings(stack); armorUpdated = true; From 0bc39d5a191777fcded4d9435393c511a3f37f43 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 13 Aug 2024 22:05:40 +0200 Subject: [PATCH 345/897] Remove old config option (#4962) --- core/src/main/resources/config.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index a5fe2072b..15d3a20a6 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -54,9 +54,6 @@ remote: # For plugin versions, it's recommended to keep the `address` field to "auto" so Floodgate support is automatically configured. # If Floodgate is installed and `address:` is set to "auto", then "auth-type: floodgate" will automatically be used. auth-type: online - # Allow for password-based authentication methods through Geyser. Only useful in online mode. - # If this is false, users must authenticate to Microsoft using a code provided by Geyser on their desktop. - allow-password-authentication: true # Whether to enable PROXY protocol or not while connecting to the server. # This is useful only when: # 1) Your server supports PROXY protocol (it probably doesn't) From 4f7e9fca9cea213d5968401fdfc60a2495d6bec9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:07:15 -0400 Subject: [PATCH 346/897] Update Protocol and fix item stack encoding --- .../geyser/translator/inventory/InventoryTranslator.java | 7 ++++--- gradle/libs.versions.toml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) 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 ce1022936..546ebda19 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 @@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.ints.*; 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.*; @@ -894,11 +895,11 @@ public abstract class InventoryTranslator { List containerEntries = new ArrayList<>(); for (Map.Entry> entry : containerMap.entrySet()) { - containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue(), null)); + containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue(), new FullContainerName(entry.getKey(), 0))); } ItemStackResponseSlot cursorEntry = makeItemEntry(0, session.getPlayerInventory().getCursor()); - containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry), null)); + containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry), new FullContainerName(ContainerSlotType.CURSOR, 0))); return containerEntries; } @@ -952,4 +953,4 @@ public abstract class InventoryTranslator { TRANSFER, DONE } -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f46dfdaed..a4b274c80 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "3.0.0.Beta3-20240726.112706-2" +protocol = "3.0.0.Beta3-20240814.133201-7" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1-20240806.235051-7" mcprotocollib = "1.21-20240725.013034-16" From 34bab14860db0476129fb86280b3c9b69293e5c8 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 15 Aug 2024 03:03:34 -0400 Subject: [PATCH 347/897] Emulate client side vehicle movement (#4648) * WIP client side vehicles * Address reviews and remove use of Optional * Only tick active vehicle * Track world ticks * Fixes for Camel dash and pose transition * Remove vehicle parameter * Start using blocks refactor * Update BlockRegistryPopulator * Update blocks * Support step height attribute * Use climbable block tag and TrapDoorBlock * Lock camel rotation if stationary * Fix boost ticking * Keep cache of surrounding blocks * Fix bug causing BoundingBox position to change in CollisionManager * Clamp user input * Support weaving status effect * Support gravity attribute * Piston support * Tick boost for Pig and Strider if any player is controlling * Submodule * Address some reviews * Support world border * Optimize world border check * Small optimizations * Add comments --- .../geyser/entity/EntityDefinitions.java | 6 +- .../geyser/entity/type/LivingEntity.java | 49 +- .../entity/type/living/animal/PigEntity.java | 63 +- .../type/living/animal/StriderEntity.java | 68 +- .../type/living/animal/horse/CamelEntity.java | 67 +- .../type/player/SessionPlayerEntity.java | 23 + .../vehicle/BoostableVehicleComponent.java | 60 ++ .../entity/vehicle/CamelVehicleComponent.java | 153 +++ .../geyser/entity/vehicle/ClientVehicle.java | 46 + .../entity/vehicle/VehicleComponent.java | 964 ++++++++++++++++++ .../geyser/inventory/PlayerInventory.java | 10 + .../inventory/item/StoredItemMappings.java | 4 + .../geysermc/geyser/level/JavaDimension.java | 8 +- .../geyser/level/block/BlockStateValues.java | 56 +- .../geysermc/geyser/level/block/Fluid.java | 32 + .../geyser/level/physics/BoundingBox.java | 38 +- .../level/physics/CollisionManager.java | 93 +- .../geyser/level/physics/Direction.java | 1 + .../geyser/session/GeyserSession.java | 21 + .../geyser/session/cache/PistonCache.java | 26 +- .../geyser/session/cache/WorldBorder.java | 52 + .../translator/collision/BlockCollision.java | 18 + .../level/block/entity/PistonBlockEntity.java | 60 +- .../bedrock/BedrockPlayerInputTranslator.java | 2 + .../player/BedrockMovePlayerTranslator.java | 5 +- .../player/BedrockRiderJumpTranslator.java | 2 + .../protocol/java/JavaRespawnTranslator.java | 1 + .../entity/JavaMoveVehicleTranslator.java | 5 + .../entity/JavaRemoveMobEffectTranslator.java | 9 +- .../entity/JavaSetPassengersTranslator.java | 9 + .../entity/JavaTeleportEntityTranslator.java | 5 + .../entity/JavaUpdateMobEffectTranslator.java | 10 +- .../java/level/JavaSetTimeTranslator.java | 2 + gradle/libs.versions.toml | 2 +- 34 files changed, 1903 insertions(+), 67 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/vehicle/BoostableVehicleComponent.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/vehicle/CamelVehicleComponent.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/vehicle/ClientVehicle.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/vehicle/VehicleComponent.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/Fluid.java 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 9063c7421..5932ecf41 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -888,7 +888,7 @@ public final class EntityDefinitions { .type(EntityType.PIG) .heightAndWidth(0.9f) .addTranslator(MetadataType.BOOLEAN, (pigEntity, entityMetadata) -> pigEntity.setFlag(EntityFlag.SADDLED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) - .addTranslator(null) // Boost time + .addTranslator(MetadataType.INT, PigEntity::setBoost) .build(); POLAR_BEAR = EntityDefinition.inherited(PolarBearEntity::new, ageableEntityBase) .type(EntityType.POLAR_BEAR) @@ -914,7 +914,7 @@ public final class EntityDefinitions { STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase) .type(EntityType.STRIDER) .height(1.7f).width(0.9f) - .addTranslator(null) // Boost time + .addTranslator(MetadataType.INT, StriderEntity::setBoost) .addTranslator(MetadataType.BOOLEAN, StriderEntity::setCold) .addTranslator(MetadataType.BOOLEAN, StriderEntity::setSaddled) .build(); @@ -955,7 +955,7 @@ public final class EntityDefinitions { .type(EntityType.CAMEL) .height(2.375f).width(1.7f) .addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing) - .addTranslator(null) // Last pose change tick + .addTranslator(MetadataType.LONG, CamelEntity::setLastPoseTick) .build(); HORSE = EntityDefinition.inherited(HorseEntity::new, abstractHorseEntityBase) .type(EntityType.HORSE) 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 1dfe02b09..266189e63 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 @@ -41,6 +41,7 @@ import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; +import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; @@ -294,6 +295,36 @@ public class LivingEntity extends Entity { return super.interact(hand); } + @Override + public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) { + if (this instanceof ClientVehicle clientVehicle) { + if (clientVehicle.isClientControlled()) { + return; + } + clientVehicle.getVehicleComponent().moveRelative(relX, relY, relZ); + } + + super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround); + } + + @Override + public boolean setBoundingBoxHeight(float height) { + if (valid && this instanceof ClientVehicle clientVehicle) { + clientVehicle.getVehicleComponent().setHeight(height); + } + + return super.setBoundingBoxHeight(height); + } + + @Override + public void setBoundingBoxWidth(float width) { + if (valid && this instanceof ClientVehicle clientVehicle) { + clientVehicle.getVehicleComponent().setWidth(width); + } + + super.setBoundingBoxWidth(width); + } + /** * Checks to see if a nametag interaction would go through. */ @@ -407,9 +438,25 @@ public class LivingEntity extends Entity { this.maxHealth = Math.max((float) AttributeUtils.calculateValue(javaAttribute), 1f); newAttributes.add(createHealthAttribute()); } + case GENERIC_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 -> { + if (this instanceof ClientVehicle clientVehicle) { + clientVehicle.getVehicleComponent().setStepHeight((float) AttributeUtils.calculateValue(javaAttribute)); + } + } + case GENERIC_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_MOVEMENT_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.MOVEMENT_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)); 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 446e3e109..2ec23d673 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 @@ -27,20 +27,30 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.type.Tickable; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +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.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class PigEntity extends AnimalEntity { +public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle { + private final BoostableVehicleComponent vehicleComponent = new BoostableVehicleComponent<>(this, 1.0f); public PigEntity(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); @@ -84,4 +94,55 @@ public class PigEntity extends AnimalEntity { } } } + + public void setBoost(IntEntityMetadata entityMetadata) { + vehicleComponent.startBoost(entityMetadata.getPrimitiveValue()); + } + + @Override + public void tick() { + PlayerEntity player = getPlayerPassenger(); + if (player == null) { + return; + } + + if (player == session.getPlayerEntity()) { + if (session.getPlayerInventory().isHolding(Items.CARROT_ON_A_STICK)) { + vehicleComponent.tickBoost(); + } + } else { // getHand() for session player seems to always return air + ItemDefinition itemDefinition = session.getItemMappings().getStoredItems().carrotOnAStick().getBedrockDefinition(); + if (player.getHand().getDefinition() == itemDefinition || player.getOffhand().getDefinition() == itemDefinition) { + vehicleComponent.tickBoost(); + } + } + } + + @Override + public VehicleComponent getVehicleComponent() { + return vehicleComponent; + } + + @Override + public Vector2f getAdjustedInput(Vector2f input) { + return Vector2f.UNIT_Y; + } + + @Override + public float getVehicleSpeed() { + return vehicleComponent.getMoveSpeed() * 0.225f * vehicleComponent.getBoostMultiplier(); + } + + private @Nullable PlayerEntity getPlayerPassenger() { + if (getFlag(EntityFlag.SADDLED) && !passengers.isEmpty() && passengers.get(0) instanceof PlayerEntity playerEntity) { + return playerEntity; + } + + return null; + } + + @Override + public boolean isClientControlled() { + return getPlayerPassenger() == session.getPlayerEntity() && session.getPlayerInventory().isHolding(Items.CARROT_ON_A_STICK); + } } 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 0291f75d9..e06af2786 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 @@ -27,23 +27,33 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; 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.entity.type.Tickable; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +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.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.EntityUtils; 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 java.util.UUID; -public class StriderEntity extends AnimalEntity { +public class StriderEntity extends AnimalEntity implements Tickable, ClientVehicle { + private final BoostableVehicleComponent vehicleComponent = new BoostableVehicleComponent<>(this, 1.0f); private boolean isCold = false; public StriderEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -131,4 +141,60 @@ public class StriderEntity extends AnimalEntity { } } } + + public void setBoost(IntEntityMetadata entityMetadata) { + vehicleComponent.startBoost(entityMetadata.getPrimitiveValue()); + } + + @Override + public void tick() { + PlayerEntity player = getPlayerPassenger(); + if (player == null) { + return; + } + + if (player == session.getPlayerEntity()) { + if (session.getPlayerInventory().isHolding(Items.WARPED_FUNGUS_ON_A_STICK)) { + vehicleComponent.tickBoost(); + } + } else { // getHand() for session player seems to always return air + ItemDefinition itemDefinition = session.getItemMappings().getStoredItems().warpedFungusOnAStick().getBedrockDefinition(); + if (player.getHand().getDefinition() == itemDefinition || player.getOffhand().getDefinition() == itemDefinition) { + vehicleComponent.tickBoost(); + } + } + } + + @Override + public VehicleComponent getVehicleComponent() { + return vehicleComponent; + } + + @Override + public Vector2f getAdjustedInput(Vector2f input) { + return Vector2f.UNIT_Y; + } + + @Override + public float getVehicleSpeed() { + return vehicleComponent.getMoveSpeed() * (isCold ? 0.35f : 0.55f) * vehicleComponent.getBoostMultiplier(); + } + + private @Nullable PlayerEntity getPlayerPassenger() { + if (getFlag(EntityFlag.SADDLED) && !passengers.isEmpty() && passengers.get(0) instanceof PlayerEntity playerEntity) { + return playerEntity; + } + + return null; + } + + @Override + public boolean isClientControlled() { + return getPlayerPassenger() == session.getPlayerEntity() && session.getPlayerInventory().isHolding(Items.WARPED_FUNGUS_ON_A_STICK); + } + + @Override + public boolean canWalkOnLava() { + return true; + } } 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 ee3b2be70..3c0bf1a70 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 @@ -25,26 +25,36 @@ package org.geysermc.geyser.entity.type.living.animal.horse; +import org.cloudburstmc.math.vector.Vector2f; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; 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.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.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; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.LongEntityMetadata; import java.util.UUID; -public class CamelEntity extends AbstractHorseEntity { - +public class CamelEntity extends AbstractHorseEntity implements ClientVehicle { public static final float SITTING_HEIGHT_DIFFERENCE = 1.43F; + private final CamelVehicleComponent vehicleComponent = new CamelVehicleComponent(this); + public CamelEntity(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); @@ -111,5 +121,58 @@ public class CamelEntity extends AbstractHorseEntity { } public void setDashing(BooleanEntityMetadata entityMetadata) { + // Java sends true to show dash animation and start the dash cooldown, + // false ends the dash animation, not the cooldown. + // Bedrock shows dash animation if HAS_DASH_COOLDOWN is set and the camel is above ground + if (entityMetadata.getPrimitiveValue()) { + setFlag(EntityFlag.HAS_DASH_COOLDOWN, true); + vehicleComponent.startDashCooldown(); + } else if (!isClientControlled()) { // Don't remove dash cooldown prematurely if client is controlling + setFlag(EntityFlag.HAS_DASH_COOLDOWN, false); + } + } + + public void setLastPoseTick(LongEntityMetadata entityMetadata) { + // Tick is based on world time. If negative, the camel is sitting. + // Must be compared to world time to know if the camel is fully standing/sitting or transitioning. + vehicleComponent.setLastPoseTick(entityMetadata.getPrimitiveValue()); + } + + @Override + protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) { + AttributeData attributeData = super.calculateAttribute(javaAttribute, type); + if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_JUMP_STRENGTH) { + vehicleComponent.setHorseJumpStrength(attributeData.getValue()); + } + return attributeData; + } + + @Override + public VehicleComponent getVehicleComponent() { + return vehicleComponent; + } + + @Override + public Vector2f getAdjustedInput(Vector2f input) { + return input.mul(0.5f, input.getY() < 0 ? 0.25f : 1.0f); + } + + @Override + public boolean isClientControlled() { + return getFlag(EntityFlag.SADDLED) && !passengers.isEmpty() && passengers.get(0) == session.getPlayerEntity(); + } + + @Override + public float getVehicleSpeed() { + float moveSpeed = vehicleComponent.getMoveSpeed(); + if (!getFlag(EntityFlag.HAS_DASH_COOLDOWN) && session.getPlayerEntity().getFlag(EntityFlag.SPRINTING)) { + return moveSpeed + 0.1f; + } + return moveSpeed; + } + + @Override + public boolean canClimb() { + return false; } } 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 b924461af..ccf2d25e6 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 @@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -42,6 +43,7 @@ import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.geyser.util.MathUtils; 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.GlobalPos; @@ -74,6 +76,16 @@ public class SessionPlayerEntity extends PlayerEntity { */ @Getter private boolean isRidingInFront; + /** + * Used when emulating client-side vehicles + */ + @Getter + private Vector2f vehicleInput = Vector2f.ZERO; + /** + * Used when emulating client-side vehicles + */ + @Getter + private int vehicleJumpStrength; private int lastAirSupply = getMaxAir(); @@ -315,6 +327,17 @@ public class SessionPlayerEntity extends PlayerEntity { this.setAirSupply(getMaxAir()); } + public void setVehicleInput(Vector2f vehicleInput) { + this.vehicleInput = Vector2f.from( + MathUtils.clamp(vehicleInput.getX(), -1.0f, 1.0f), + MathUtils.clamp(vehicleInput.getY(), -1.0f, 1.0f) + ); + } + + public void setVehicleJumpStrength(int vehicleJumpStrength) { + this.vehicleJumpStrength = MathUtils.constrain(vehicleJumpStrength, 0, 100); + } + private boolean isBelowVoidFloor() { return position.getY() < voidFloorPosition(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/vehicle/BoostableVehicleComponent.java b/core/src/main/java/org/geysermc/geyser/entity/vehicle/BoostableVehicleComponent.java new file mode 100644 index 000000000..41224012d --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/vehicle/BoostableVehicleComponent.java @@ -0,0 +1,60 @@ +/* + * 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.entity.vehicle; + +import org.cloudburstmc.math.TrigMath; +import org.geysermc.geyser.entity.type.LivingEntity; + +public class BoostableVehicleComponent extends VehicleComponent { + private int boostLength; + private int boostTicks = 1; + + public BoostableVehicleComponent(T vehicle, float stepHeight) { + super(vehicle, stepHeight); + } + + public void startBoost(int boostLength) { + this.boostLength = boostLength; + this.boostTicks = 1; + } + + public float getBoostMultiplier() { + if (isBoosting()) { + return 1.0f + 1.15f * TrigMath.sin((float) boostTicks / (float) boostLength * TrigMath.PI); + } + return 1.0f; + } + + public boolean isBoosting() { + return boostTicks <= boostLength; + } + + public void tickBoost() { + if (isBoosting()) { + boostTicks++; + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/vehicle/CamelVehicleComponent.java b/core/src/main/java/org/geysermc/geyser/entity/vehicle/CamelVehicleComponent.java new file mode 100644 index 000000000..7d022ed7c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/vehicle/CamelVehicleComponent.java @@ -0,0 +1,153 @@ +/* + * 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.entity.vehicle; + +import lombok.Setter; +import org.cloudburstmc.math.vector.Vector2f; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.geyser.entity.type.living.animal.horse.CamelEntity; +import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; + +public class CamelVehicleComponent extends VehicleComponent { + private static final int STANDING_TICKS = 52; + private static final int DASH_TICKS = 55; + + @Setter + private float horseJumpStrength = 0.42f; // Not sent by vanilla Java server when spawned + + @Setter + private long lastPoseTick; + + private int dashTick; + private int effectJumpBoost; + + public CamelVehicleComponent(CamelEntity vehicle) { + super(vehicle, 1.5f); + } + + public void startDashCooldown() { + // tickVehicle is only called while the vehicle is mounted. Use session ticks to keep + // track of time instead of counting down + this.dashTick = vehicle.getSession().getTicks() + DASH_TICKS; + } + + @Override + public void tickVehicle() { + if (this.dashTick != 0) { + if (vehicle.getSession().getTicks() > this.dashTick) { + vehicle.setFlag(EntityFlag.HAS_DASH_COOLDOWN, false); + this.dashTick = 0; + } else { + vehicle.setFlag(EntityFlag.HAS_DASH_COOLDOWN, true); + } + } + + vehicle.setFlag(EntityFlag.CAN_DASH, vehicle.getFlag(EntityFlag.SADDLED) && !isStationary()); + vehicle.updateBedrockMetadata(); + super.tickVehicle(); + } + + @Override + public void onDismount() { + // Prevent camel from getting stuck in dash animation + vehicle.setFlag(EntityFlag.HAS_DASH_COOLDOWN, false); + vehicle.updateBedrockMetadata(); + super.onDismount(); + } + + @Override + protected boolean travel(VehicleContext ctx, float speed) { + if (vehicle.isOnGround() && isStationary()) { + vehicle.setMotion(vehicle.getMotion().mul(0, 1, 0)); + } + + return super.travel(ctx, speed); + } + + @Override + protected Vector3f getInputVelocity(VehicleContext ctx, float speed) { + if (isStationary()) { + return Vector3f.ZERO; + } + + SessionPlayerEntity player = vehicle.getSession().getPlayerEntity(); + Vector3f inputVelocity = super.getInputVelocity(ctx, speed); + float jumpStrength = player.getVehicleJumpStrength(); + + if (jumpStrength > 0) { + player.setVehicleJumpStrength(0); + + if (jumpStrength >= 90) { + jumpStrength = 1.0f; + } else { + jumpStrength = 0.4f + 0.4f * jumpStrength / 90.0f; + } + + return inputVelocity.add(Vector3f.createDirectionDeg(0, -player.getYaw()) + .mul(22.2222f * jumpStrength * this.moveSpeed * getVelocityMultiplier(ctx)) + .up(1.4285f * jumpStrength * (this.horseJumpStrength * getJumpVelocityMultiplier(ctx) + (this.effectJumpBoost * 0.1f)))); + } + + return inputVelocity; + } + + @Override + protected Vector2f getVehicleRotation() { + if (isStationary()) { + return Vector2f.from(vehicle.getYaw(), vehicle.getPitch()); + } + return super.getVehicleRotation(); + } + + /** + * Checks if the camel is sitting + * or transitioning to standing pose. + */ + private boolean isStationary() { + // Java checks if sitting using lastPoseTick + return this.lastPoseTick < 0 || vehicle.getSession().getWorldTicks() < this.lastPoseTick + STANDING_TICKS; + } + + @Override + public void setEffect(Effect effect, int effectAmplifier) { + if (effect == Effect.JUMP_BOOST) { + effectJumpBoost = effectAmplifier + 1; + } else { + super.setEffect(effect, effectAmplifier); + } + } + + @Override + public void removeEffect(Effect effect) { + if (effect == Effect.JUMP_BOOST) { + effectJumpBoost = 0; + } else { + super.removeEffect(effect); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/vehicle/ClientVehicle.java b/core/src/main/java/org/geysermc/geyser/entity/vehicle/ClientVehicle.java new file mode 100644 index 000000000..e6aaf1daa --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/vehicle/ClientVehicle.java @@ -0,0 +1,46 @@ +/* + * 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.entity.vehicle; + +import org.cloudburstmc.math.vector.Vector2f; + +public interface ClientVehicle { + VehicleComponent getVehicleComponent(); + + Vector2f getAdjustedInput(Vector2f input); + + float getVehicleSpeed(); + + boolean isClientControlled(); + + default boolean canWalkOnLava() { + return false; + } + + default boolean canClimb() { + return true; + } +} 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 new file mode 100644 index 000000000..db703a3cb --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/vehicle/VehicleComponent.java @@ -0,0 +1,964 @@ +/* + * 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.entity.vehicle; + +import it.unimi.dsi.fastutil.objects.ObjectDoublePair; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.math.TrigMath; +import org.cloudburstmc.math.vector.Vector2f; +import org.cloudburstmc.math.vector.Vector3d; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket; +import org.geysermc.erosion.util.BlockPositionIterator; +import org.geysermc.geyser.entity.type.LivingEntity; +import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.Fluid; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BedBlock; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.type.TrapDoorBlock; +import org.geysermc.geyser.level.physics.BoundingBox; +import org.geysermc.geyser.level.physics.CollisionManager; +import org.geysermc.geyser.level.physics.Direction; +import org.geysermc.geyser.session.cache.tags.BlockTag; +import org.geysermc.geyser.translator.collision.BlockCollision; +import org.geysermc.geyser.translator.collision.SolidCollision; +import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket; + +public class VehicleComponent { + private static final ObjectDoublePair EMPTY_FLUID_PAIR = ObjectDoublePair.of(Fluid.EMPTY, 0.0); + private static final float MAX_LOGICAL_FLUID_HEIGHT = 8.0f / BlockStateValues.NUM_FLUID_LEVELS; + private static final float BASE_SLIPPERINESS_CUBED = 0.6f * 0.6f * 0.6f; + private static final float MIN_VELOCITY = 0.003f; + + protected final T vehicle; + protected final BoundingBox boundingBox; + + protected float stepHeight; + protected float moveSpeed; + protected double gravity; + protected int effectLevitation; + protected boolean effectSlowFalling; + protected boolean effectWeaving; + + 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(); + + double width = vehicle.getBoundingBoxWidth(); + double height = vehicle.getBoundingBoxHeight(); + this.boundingBox = new BoundingBox( + vehicle.getPosition().getX(), + vehicle.getPosition().getY() + height / 2, + vehicle.getPosition().getZ(), + width, height, width + ); + } + + public void setWidth(float width) { + boundingBox.setSizeX(width); + boundingBox.setSizeZ(width); + } + + public void setHeight(float height) { + boundingBox.translate(0, (height - boundingBox.getSizeY()) / 2, 0); + boundingBox.setSizeY(height); + } + + public void moveAbsolute(double x, double y, double z) { + boundingBox.setMiddleX(x); + boundingBox.setMiddleY(y + boundingBox.getSizeY() / 2); + boundingBox.setMiddleZ(z); + } + + public void moveRelative(double x, double y, double z) { + boundingBox.translate(x, y, z); + } + + public void moveRelative(Vector3d vec) { + boundingBox.translate(vec); + } + + public BoundingBox getBoundingBox() { + return this.boundingBox; + } + + public void setEffect(Effect effect, int effectAmplifier) { + switch (effect) { + case LEVITATION -> effectLevitation = effectAmplifier + 1; + case SLOW_FALLING -> effectSlowFalling = true; + case WEAVING -> effectWeaving = true; + } + } + + public void removeEffect(Effect effect) { + switch (effect) { + case LEVITATION -> effectLevitation = 0; + case SLOW_FALLING -> effectSlowFalling = false; + case WEAVING -> effectWeaving = false; + } + } + + public void setMoveSpeed(float moveSpeed) { + this.moveSpeed = moveSpeed; + } + + public float getMoveSpeed() { + return moveSpeed; + } + + public void setStepHeight(float stepHeight) { + this.stepHeight = MathUtils.clamp(stepHeight, 1.0f, 10.0f); + } + + public void setGravity(double gravity) { + this.gravity = MathUtils.constrain(gravity, -1.0, 1.0); + } + + public Vector3d correctMovement(Vector3d movement) { + return vehicle.getSession().getCollisionManager().correctMovement( + movement, boundingBox, vehicle.isOnGround(), this.stepHeight, true, vehicle.canWalkOnLava() + ); + } + + public void onMount() { + vehicle.getSession().getPlayerEntity().setVehicleInput(Vector2f.ZERO); + vehicle.getSession().getPlayerEntity().setVehicleJumpStrength(0); + } + + public void onDismount() { + // + } + + /** + * Called every session tick while the player is mounted on the vehicle. + */ + public void tickVehicle() { + if (!vehicle.isClientControlled()) { + return; + } + + VehicleContext ctx = new VehicleContext(); + ctx.loadSurroundingBlocks(); + + ObjectDoublePair fluidHeight = updateFluidMovement(ctx); + switch (fluidHeight.left()) { + case WATER -> waterMovement(ctx); + case LAVA -> { + if (vehicle.canWalkOnLava() && ctx.centerBlock().is(Blocks.LAVA)) { + landMovement(ctx); + } else { + lavaMovement(ctx, fluidHeight.rightDouble()); + } + } + case EMPTY -> landMovement(ctx); + } + } + + /** + * Adds velocity of all colliding fluids to the vehicle, and returns the height of the fluid to use for movement. + * + * @param ctx context + * @return type and height of fluid to use for movement + */ + protected ObjectDoublePair updateFluidMovement(VehicleContext ctx) { + BoundingBox box = boundingBox.clone(); + box.expand(-0.001); + + Vector3d min = box.getMin(); + Vector3d max = box.getMax(); + + BlockPositionIterator iter = BlockPositionIterator.fromMinMax(min.getFloorX(), min.getFloorY(), min.getFloorZ(), max.getFloorX(), max.getFloorY(), max.getFloorZ()); + + double waterHeight = getFluidHeightAndApplyMovement(ctx, iter, Fluid.WATER, 0.014, min.getY()); + double lavaHeight = getFluidHeightAndApplyMovement(ctx, iter, Fluid.LAVA, vehicle.getSession().getDimensionType().ultrawarm() ? 0.007 : 0.007 / 3, min.getY()); + + // Apply upward motion if the vehicle is a Strider, and it is submerged in lava + if (lavaHeight > 0 && vehicle.getDefinition().entityType() == EntityType.STRIDER) { + Vector3i blockPos = ctx.centerPos().toInt(); + if (!CollisionManager.FLUID_COLLISION.isBelow(blockPos.getY(), boundingBox) || ctx.getBlock(blockPos.up()).is(Blocks.LAVA)) { + vehicle.setMotion(vehicle.getMotion().mul(0.5f).add(0, 0.05f, 0)); + } else { + vehicle.setOnGround(true); + } + } + + // Water movement has priority over lava movement + if (waterHeight > 0) { + return ObjectDoublePair.of(Fluid.WATER, waterHeight); + } + + if (lavaHeight > 0) { + return ObjectDoublePair.of(Fluid.LAVA, lavaHeight); + } + + return EMPTY_FLUID_PAIR; + } + + /** + * Calculates how deep the vehicle is in a fluid, and applies its velocity. + * + * @param ctx context + * @param iter iterator of colliding blocks + * @param fluid type of fluid + * @param speed multiplier for fluid motion + * @param minY minY of the bounding box used to check for fluid collision; not exactly the same as the vehicle's bounding box + * @return height of fluid compared to minY + */ + protected double getFluidHeightAndApplyMovement(VehicleContext ctx, BlockPositionIterator iter, Fluid fluid, double speed, double minY) { + Vector3d totalVelocity = Vector3d.ZERO; + double maxFluidHeight = 0; + int fluidBlocks = 0; + + for (iter.reset(); iter.hasNext(); iter.next()) { + int blockId = ctx.getBlockId(iter); + if (BlockStateValues.getFluid(blockId) != fluid) { + continue; + } + + Vector3i blockPos = Vector3i.from(iter.getX(), iter.getY(), iter.getZ()); + float worldFluidHeight = getWorldFluidHeight(fluid, blockId); + + double vehicleFluidHeight = blockPos.getY() + worldFluidHeight - minY; + if (vehicleFluidHeight < 0) { + // Vehicle is not submerged in this fluid block + continue; + } + + // flowBlocked is only used when determining if a falling fluid should drag the vehicle downwards. + // If this block is not a falling fluid, set to true to avoid unnecessary checks. + boolean flowBlocked = worldFluidHeight != 1; + + Vector3d velocity = Vector3d.ZERO; + for (Direction direction : Direction.HORIZONTAL) { + Vector3i adjacentBlockPos = blockPos.add(direction.getUnitVector()); + int adjacentBlockId = ctx.getBlockId(adjacentBlockPos); + Fluid adjacentFluid = BlockStateValues.getFluid(adjacentBlockId); + + float fluidHeightDiff = 0; + if (adjacentFluid == fluid) { + fluidHeightDiff = getLogicalFluidHeight(fluid, blockId) - getLogicalFluidHeight(fluid, adjacentBlockId); + } else if (adjacentFluid == Fluid.EMPTY) { + // If the adjacent block is not a fluid and does not have collision, + // check if there is a fluid under it + BlockCollision adjacentBlockCollision = BlockUtils.getCollision(adjacentBlockId); + if (adjacentBlockCollision == null) { + float adjacentFluidHeight = getLogicalFluidHeight(fluid, ctx.getBlockId(adjacentBlockPos.add(Direction.DOWN.getUnitVector()))); + if (adjacentFluidHeight != -1) { // Only care about same type of fluid + fluidHeightDiff = getLogicalFluidHeight(fluid, blockId) - (adjacentFluidHeight - MAX_LOGICAL_FLUID_HEIGHT); + } + } else if (!flowBlocked) { + // No need to check if flow is already blocked from another direction, or if this isn't a falling fluid. + flowBlocked = isFlowBlocked(fluid, adjacentBlockId); + } + } + + if (fluidHeightDiff != 0) { + velocity = velocity.add(direction.getUnitVector().toDouble().mul(fluidHeightDiff)); + } + } + + if (worldFluidHeight == 1) { // If falling fluid + // If flow is not blocked, check if it is blocked for the fluid above + if (!flowBlocked) { + Vector3i blockPosUp = blockPos.up(); + for (Direction direction : Direction.HORIZONTAL) { + flowBlocked = isFlowBlocked(fluid, ctx.getBlockId(blockPosUp.add(direction.getUnitVector()))); + if (flowBlocked) { + break; + } + } + } + + if (flowBlocked) { + velocity = javaNormalize(velocity).add(0.0, -6.0, 0.0); + } + } + + velocity = javaNormalize(velocity); + + maxFluidHeight = Math.max(vehicleFluidHeight, maxFluidHeight); + if (maxFluidHeight < 0.4) { + velocity = velocity.mul(maxFluidHeight); + } + + totalVelocity = totalVelocity.add(velocity); + fluidBlocks++; + } + + if (!totalVelocity.equals(Vector3d.ZERO)) { + Vector3f motion = vehicle.getMotion(); + + totalVelocity = javaNormalize(totalVelocity.mul(1.0 / fluidBlocks)); + totalVelocity = totalVelocity.mul(speed); + + if (totalVelocity.length() < 0.0045 && Math.abs(motion.getX()) < MIN_VELOCITY && Math.abs(motion.getZ()) < MIN_VELOCITY) { + totalVelocity = javaNormalize(totalVelocity).mul(0.0045); + } + + vehicle.setMotion(motion.add(totalVelocity.toFloat())); + } + + return maxFluidHeight; + } + + /** + * Java edition returns the zero vector if the length of the input vector is less than 0.0001 + */ + protected Vector3d javaNormalize(Vector3d vec) { + double len = vec.length(); + return len < 1.0E-4 ? Vector3d.ZERO : Vector3d.from(vec.getX() / len, vec.getY() / len, vec.getZ() / len); + } + + protected float getWorldFluidHeight(Fluid fluidType, int blockId) { + return (float) switch (fluidType) { + case WATER -> BlockStateValues.getWaterHeight(blockId); + case LAVA -> BlockStateValues.getLavaHeight(blockId); + case EMPTY -> -1; + }; + } + + protected float getLogicalFluidHeight(Fluid fluidType, int blockId) { + return Math.min(getWorldFluidHeight(fluidType, blockId), MAX_LOGICAL_FLUID_HEIGHT); + } + + protected boolean isFlowBlocked(Fluid fluid, int adjacentBlockId) { + if (BlockState.of(adjacentBlockId).is(Blocks.ICE)) { + return false; + } + + if (BlockStateValues.getFluid(adjacentBlockId) == fluid) { + return false; + } + + // TODO: supposed to check if the opposite face of the block touching the fluid is solid, instead of SolidCollision + return BlockUtils.getCollision(adjacentBlockId) instanceof SolidCollision; + } + + protected void waterMovement(VehicleContext ctx) { + double gravity = getGravity(); + float drag = vehicle.getFlag(EntityFlag.SPRINTING) ? 0.9f : 0.8f; // 0.8f: getBaseMovementSpeedMultiplier + double originalY = ctx.centerPos().getY(); + boolean falling = vehicle.getMotion().getY() <= 0; + + // NOT IMPLEMENTED: depth strider and dolphins grace + + boolean horizontalCollision = travel(ctx, 0.02f); + + if (horizontalCollision && isClimbing(ctx)) { + vehicle.setMotion(Vector3f.from(vehicle.getMotion().getX(), 0.2f, vehicle.getMotion().getZ())); + } + + vehicle.setMotion(vehicle.getMotion().mul(drag, 0.8f, drag)); + vehicle.setMotion(getFluidGravity(gravity, falling)); + + if (horizontalCollision && shouldApplyFluidJumpBoost(ctx, originalY)) { + vehicle.setMotion(Vector3f.from(vehicle.getMotion().getX(), 0.3f, vehicle.getMotion().getZ())); + } + } + + protected void lavaMovement(VehicleContext ctx, double lavaHeight) { + double gravity = getGravity(); + double originalY = ctx.centerPos().getY(); + boolean falling = vehicle.getMotion().getY() <= 0; + + boolean horizontalCollision = travel(ctx, 0.02f); + + if (lavaHeight <= (boundingBox.getSizeY() * 0.85 < 0.4 ? 0.0 : 0.4)) { // Swim height + vehicle.setMotion(vehicle.getMotion().mul(0.5f, 0.8f, 0.5f)); + vehicle.setMotion(getFluidGravity(gravity, falling)); + } else { + vehicle.setMotion(vehicle.getMotion().mul(0.5f)); + } + + vehicle.setMotion(vehicle.getMotion().down((float) (gravity / 4.0))); + + if (horizontalCollision && shouldApplyFluidJumpBoost(ctx, originalY)) { + vehicle.setMotion(Vector3f.from(vehicle.getMotion().getX(), 0.3f, vehicle.getMotion().getZ())); + } + } + + protected void landMovement(VehicleContext ctx) { + double gravity = getGravity(); + float slipperiness = BlockStateValues.getSlipperiness(getVelocityBlock(ctx)); + float drag = vehicle.isOnGround() ? 0.91f * slipperiness : 0.91f; + float speed = vehicle.getVehicleSpeed() * (vehicle.isOnGround() ? BASE_SLIPPERINESS_CUBED / (slipperiness * slipperiness * slipperiness) : 0.1f); + + boolean horizontalCollision = travel(ctx, speed); + + if (isClimbing(ctx)) { + Vector3f motion = vehicle.getMotion(); + vehicle.setMotion( + Vector3f.from( + MathUtils.clamp(motion.getX(), -0.15f, 0.15f), + horizontalCollision ? 0.2f : Math.max(motion.getY(), -0.15f), + MathUtils.clamp(motion.getZ(), -0.15f, 0.15f) + ) + ); + // NOT IMPLEMENTED: climbing in powdered snow + } + + if (effectLevitation > 0) { + vehicle.setMotion(vehicle.getMotion().up((0.05f * effectLevitation - vehicle.getMotion().getY()) * 0.2f)); + } else { + vehicle.setMotion(vehicle.getMotion().down((float) gravity)); + // NOT IMPLEMENTED: slow fall when in unloaded chunk + } + + vehicle.setMotion(vehicle.getMotion().mul(drag, 0.98f, drag)); + } + + protected boolean shouldApplyFluidJumpBoost(VehicleContext ctx, double originalY) { + BoundingBox box = boundingBox.clone(); + box.translate(vehicle.getMotion().toDouble().up(0.6f - ctx.centerPos().getY() + originalY)); + box.expand(-1.0E-7); + + BlockPositionIterator iter = vehicle.getSession().getCollisionManager().collidableBlocksIterator(box); + for (iter.reset(); iter.hasNext(); iter.next()) { + int blockId = ctx.getBlockId(iter); + + // Also check for fluids + BlockCollision blockCollision = BlockUtils.getCollision(blockId); + if (blockCollision == null && BlockStateValues.getFluid(blockId) != Fluid.EMPTY) { + blockCollision = CollisionManager.SOLID_COLLISION; + } + + if (blockCollision != null && blockCollision.checkIntersection(iter.getX(), iter.getY(), iter.getZ(), box)) { + return false; + } + } + + return true; + } + + protected Vector3f getFluidGravity(double gravity, boolean falling) { + Vector3f motion = vehicle.getMotion(); + if (gravity != 0 && !vehicle.getFlag(EntityFlag.SPRINTING)) { + float newY = (float) (motion.getY() - gravity / 16); + if (falling && Math.abs(motion.getY() - 0.005f) >= MIN_VELOCITY && Math.abs(newY) < MIN_VELOCITY) { + newY = -MIN_VELOCITY; + } + return Vector3f.from(motion.getX(), newY, motion.getZ()); + } + return motion; + } + + /** + * Check if any blocks the vehicle is colliding with should multiply movement. (Cobweb, powder snow, berry bush) + *

    + * This is different from the speed factor of a block the vehicle is standing on, such as soul sand. + * + * @param ctx context + * @return the multiplier + */ + protected @Nullable Vector3f getBlockMovementMultiplier(VehicleContext ctx) { + BoundingBox box = boundingBox.clone(); + box.expand(-1.0E-7); + + Vector3i min = box.getMin().toInt(); + Vector3i max = box.getMax().toInt(); + + // Iterate xyz backwards + // Minecraft iterates forwards but only the last multiplier affects movement + for (int x = max.getX(); x >= min.getX(); x--) { + for (int y = max.getY(); y >= min.getY(); y--) { + for (int z = max.getZ(); z >= min.getZ(); z--) { + Block block = ctx.getBlock(x, y, z).block(); + Vector3f multiplier = null; + + if (block == Blocks.COBWEB) { + if (effectWeaving) { + multiplier = Vector3f.from(0.5, 0.25, 0.5); + } else { + multiplier = Vector3f.from(0.25, 0.05f, 0.25); + } + } else if (block == Blocks.POWDER_SNOW) { + multiplier = Vector3f.from(0.9f, 1.5, 0.9f); + } else if (block == Blocks.SWEET_BERRY_BUSH) { + multiplier = Vector3f.from(0.8f, 0.75, 0.8f); + } + + if (multiplier != null) { + return multiplier; + } + } + } + } + + return null; + } + + protected void applyBlockCollisionEffects(VehicleContext ctx) { + BoundingBox box = boundingBox.clone(); + box.expand(-1.0E-7); + + Vector3i min = box.getMin().toInt(); + Vector3i max = box.getMax().toInt(); + + BlockPositionIterator iter = BlockPositionIterator.fromMinMax(min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ()); + for (iter.reset(); iter.hasNext(); iter.next()) { + BlockState blockState = ctx.getBlock(iter); + + if (blockState.is(Blocks.HONEY_BLOCK)) { + onHoneyBlockCollision(); + } else if (blockState.is(Blocks.BUBBLE_COLUMN)) { + onBubbleColumnCollision(blockState.getValue(Properties.DRAG)); + } + } + } + + protected void onHoneyBlockCollision() { + if (vehicle.isOnGround() || vehicle.getMotion().getY() >= -0.08f) { + return; + } + + // NOT IMPLEMENTED: don't slide if inside the honey block + Vector3f motion = vehicle.getMotion(); + float mul = motion.getY() < -0.13f ? -0.05f / motion.getY() : 1; + vehicle.setMotion(Vector3f.from(motion.getX() * mul, -0.05f, motion.getZ() * mul)); + } + + protected void onBubbleColumnCollision(boolean drag) { + Vector3f motion = vehicle.getMotion(); + vehicle.setMotion(Vector3f.from( + motion.getX(), + drag ? Math.max(-0.3f, motion.getY() - 0.03f) : Math.min(0.7f, motion.getY() + 0.06f), + motion.getZ() + )); + } + + /** + * Calculates the next position of the vehicle while checking for collision and adjusting velocity. + * + * @return true if there was a horizontal collision + */ + protected boolean travel(VehicleContext ctx, float speed) { + Vector3f motion = vehicle.getMotion(); + + // Java only does this client side + motion = motion.mul(0.98f); + + motion = Vector3f.from( + Math.abs(motion.getX()) < MIN_VELOCITY ? 0 : motion.getX(), + Math.abs(motion.getY()) < MIN_VELOCITY ? 0 : motion.getY(), + Math.abs(motion.getZ()) < MIN_VELOCITY ? 0 : motion.getZ() + ); + + // !isImmobile + if (vehicle.isAlive()) { + motion = motion.add(getInputVelocity(ctx, speed)); + } + + Vector3f movementMultiplier = getBlockMovementMultiplier(ctx); + if (movementMultiplier != null) { + motion = motion.mul(movementMultiplier); + } + + // Check world border before blocks + Vector3d correctedMovement = vehicle.getSession().getWorldBorder().correctMovement(boundingBox, motion.toDouble()); + correctedMovement = vehicle.getSession().getCollisionManager().correctMovement( + correctedMovement, boundingBox, vehicle.isOnGround(), this.stepHeight, true, vehicle.canWalkOnLava() + ); + + boundingBox.translate(correctedMovement); + ctx.loadSurroundingBlocks(); // Context must be reloaded after vehicle is moved + + // Non-zero values indicate a collision on that axis + Vector3d moveDiff = motion.toDouble().sub(correctedMovement); + + vehicle.setOnGround(moveDiff.getY() != 0 && motion.getY() < 0); + boolean horizontalCollision = moveDiff.getX() != 0 || moveDiff.getZ() != 0; + + boolean bounced = false; + if (vehicle.isOnGround()) { + Block landingBlock = getLandingBlock(ctx).block(); + + if (landingBlock == Blocks.SLIME_BLOCK) { + motion = Vector3f.from(motion.getX(), -motion.getY(), motion.getZ()); + bounced = true; + + // Slow horizontal movement + float absY = Math.abs(motion.getY()); + if (absY < 0.1f) { + float mul = 0.4f + absY * 0.2f; + motion = motion.mul(mul, 1.0f, mul); + } + } else if (landingBlock instanceof BedBlock) { + motion = Vector3f.from(motion.getX(), -motion.getY() * 0.66f, motion.getZ()); + bounced = true; + } + } + + // Set motion to 0 if a movement multiplier was used, else set to 0 on each axis with a collision + if (movementMultiplier != null) { + motion = Vector3f.ZERO; + } else { + motion = motion.mul( + moveDiff.getX() == 0 ? 1 : 0, + moveDiff.getY() == 0 || bounced ? 1 : 0, + moveDiff.getZ() == 0 ? 1 : 0 + ); + } + + // Send the new position to the bedrock client and java server + moveVehicle(ctx.centerPos()); + vehicle.setMotion(motion); + + applyBlockCollisionEffects(ctx); + + float velocityMultiplier = getVelocityMultiplier(ctx); + vehicle.setMotion(vehicle.getMotion().mul(velocityMultiplier, 1.0f, velocityMultiplier)); + + return horizontalCollision; + } + + protected boolean isClimbing(VehicleContext ctx) { + if (!vehicle.canClimb()) { + return false; + } + + BlockState blockState = ctx.centerBlock(); + if (vehicle.getSession().getTagCache().is(BlockTag.CLIMBABLE, blockState.block())) { + return true; + } + + // Check if the vehicle is in an open trapdoor with a ladder of the same direction under it + if (blockState.block() instanceof TrapDoorBlock && blockState.getValue(Properties.OPEN)) { + BlockState ladderState = ctx.getBlock(ctx.centerPos().toInt().down()); + return ladderState.is(Blocks.LADDER) && + ladderState.getValue(Properties.HORIZONTAL_FACING) == blockState.getValue(Properties.HORIZONTAL_FACING); + } + + return false; + } + + /** + * Translates the player's input into velocity. + * + * @param ctx context + * @param speed multiplier for input + * @return velocity + */ + protected Vector3f getInputVelocity(VehicleContext ctx, float speed) { + Vector2f input = vehicle.getSession().getPlayerEntity().getVehicleInput(); + input = input.mul(0.98f); + input = vehicle.getAdjustedInput(input); + input = normalizeInput(input); + input = input.mul(speed); + + // Match player rotation + float yaw = vehicle.getSession().getPlayerEntity().getYaw(); + float sin = TrigMath.sin(yaw * TrigMath.DEG_TO_RAD); + float cos = TrigMath.cos(yaw * TrigMath.DEG_TO_RAD); + return Vector3f.from(input.getX() * cos - input.getY() * sin, 0, input.getY() * cos + input.getX() * sin); + } + + protected Vector2f normalizeInput(Vector2f input) { + float lenSquared = input.lengthSquared(); + if (lenSquared < 1.0E-7) { + return Vector2f.ZERO; + } else if (lenSquared > 1.0) { + return input.normalize(); + } + return input; + } + + /** + * Gets the rotation to use for the vehicle. This is based on the player's head rotation. + */ + protected Vector2f getVehicleRotation() { + LivingEntity player = vehicle.getSession().getPlayerEntity(); + return Vector2f.from(player.getYaw(), player.getPitch() * 0.5f); + } + + /** + * Sets the new position for the vehicle and sends packets to both the java server and bedrock client. + *

    + * This also updates the session's last vehicle move timestamp. + * @param javaPos the new java position of the vehicle + */ + protected void moveVehicle(Vector3d javaPos) { + Vector3f bedrockPos = javaPos.toFloat(); + Vector2f rotation = getVehicleRotation(); + + MoveEntityDeltaPacket moveEntityDeltaPacket = new MoveEntityDeltaPacket(); + moveEntityDeltaPacket.setRuntimeEntityId(vehicle.getGeyserId()); + + if (vehicle.isOnGround()) { + moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.ON_GROUND); + } + + if (vehicle.getPosition().getX() != bedrockPos.getX()) { + moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_X); + moveEntityDeltaPacket.setX(bedrockPos.getX()); + } + if (vehicle.getPosition().getY() != bedrockPos.getY()) { + moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Y); + moveEntityDeltaPacket.setY(bedrockPos.getY()); + } + if (vehicle.getPosition().getZ() != bedrockPos.getZ()) { + moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Z); + moveEntityDeltaPacket.setZ(bedrockPos.getZ()); + } + vehicle.setPosition(bedrockPos); + + if (vehicle.getYaw() != rotation.getX()) { + moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_YAW); + moveEntityDeltaPacket.setYaw(rotation.getX()); + vehicle.setYaw(rotation.getX()); + } + if (vehicle.getPitch() != rotation.getY()) { + moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_PITCH); + moveEntityDeltaPacket.setPitch(rotation.getY()); + vehicle.setPitch(rotation.getY()); + } + if (vehicle.getHeadYaw() != rotation.getX()) { // Same as yaw + moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_HEAD_YAW); + moveEntityDeltaPacket.setHeadYaw(rotation.getX()); + vehicle.setHeadYaw(rotation.getX()); + } + + if (!moveEntityDeltaPacket.getFlags().isEmpty()) { + vehicle.getSession().sendUpstreamPacket(moveEntityDeltaPacket); + } + + 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() { + if (!vehicle.getFlag(EntityFlag.HAS_GRAVITY)) { + return 0; + } + + if (vehicle.getMotion().getY() <= 0 && effectSlowFalling) { + return Math.min(0.01, this.gravity); + } + + return this.gravity; + } + + /** + * Finds the position of the main block supporting the vehicle. + * Used when determining slipperiness, speed, etc. + *

    + * Should use {@link VehicleContext#supportingBlockPos()}, instead of calling this directly. + * + * @param ctx context + * @return position of the main block supporting this entity + */ + private @Nullable Vector3i getSupportingBlockPos(VehicleContext ctx) { + Vector3i result = null; + + if (vehicle.isOnGround()) { + BoundingBox box = boundingBox.clone(); + box.extend(0, -1.0E-6, 0); // Extend slightly down + + Vector3i min = box.getMin().toInt(); + Vector3i max = box.getMax().toInt(); + + // Use minY as maxY + BlockPositionIterator iter = BlockPositionIterator.fromMinMax(min.getX(), min.getY(), min.getZ(), max.getX(), min.getY(), max.getZ()); + + double minDistance = Double.MAX_VALUE; + for (iter.reset(); iter.hasNext(); iter.next()) { + Vector3i blockPos = Vector3i.from(iter.getX(), iter.getY(), iter.getZ()); + int blockId = ctx.getBlockId(iter); + + BlockCollision blockCollision; + if (vehicle.canWalkOnLava()) { + blockCollision = vehicle.getSession().getCollisionManager().getCollisionLavaWalking(blockId, blockPos.getY(), boundingBox); + } else { + blockCollision = BlockUtils.getCollision(blockId); + } + + if (blockCollision != null && blockCollision.checkIntersection(blockPos, box)) { + double distance = ctx.centerPos().distanceSquared(blockPos.toDouble().add(0.5f, 0.5f, 0.5f)); + if (distance <= minDistance) { + minDistance = distance; + result = blockPos; + } + } + } + } + + return result; + } + + /** + * Returns the block that is x amount of blocks under the main supporting block. + */ + protected BlockState getBlockUnderSupport(VehicleContext ctx, float dist) { + Vector3i supportingBlockPos = ctx.supportingBlockPos(); + + Vector3i blockPos; + if (supportingBlockPos != null) { + blockPos = Vector3i.from(supportingBlockPos.getX(), Math.floor(ctx.centerPos().getY() - dist), supportingBlockPos.getZ()); + } else { + blockPos = ctx.centerPos().sub(0, dist, 0).toInt(); + } + + return ctx.getBlock(blockPos); + } + + /** + * The block to use when determining if the vehicle should bounce after landing. Currently just slime and bed blocks. + */ + protected BlockState getLandingBlock(VehicleContext ctx) { + return getBlockUnderSupport(ctx, 0.2f); + } + + /** + * The block to use when calculating slipperiness and speed. If on a slab, this will be the block under the slab. + */ + protected BlockState getVelocityBlock(VehicleContext ctx) { + return getBlockUnderSupport(ctx, 0.500001f); + } + + protected float getVelocityMultiplier(VehicleContext ctx) { + Block block = ctx.centerBlock().block(); + if (block == Blocks.WATER || block == Blocks.BUBBLE_COLUMN) { + return 1.0f; + } + + if (block == Blocks.SOUL_SAND || block == Blocks.HONEY_BLOCK) { + return 0.4f; + } + + block = getVelocityBlock(ctx).block(); + if (block == Blocks.SOUL_SAND || block == Blocks.HONEY_BLOCK) { + return 0.4f; + } + + return 1.0f; + } + + protected float getJumpVelocityMultiplier(VehicleContext ctx) { + Block block = ctx.centerBlock().block(); + if (block == Blocks.HONEY_BLOCK) { + return 0.5f; + } + + block = getVelocityBlock(ctx).block(); + if (block == Blocks.HONEY_BLOCK) { + return 0.5f; + } + + return 1.0f; + } + + protected class VehicleContext { + private Vector3d centerPos; + private Vector3d cachePos; + private BlockState centerBlock; + private Vector3i supportingBlockPos; + private BlockPositionIterator blockIter; + private int[] blocks; + + /** + * Cache frequently used data and blocks used in movement calculations. + *

    + * Can be called multiple times, and must be called at least once before using the VehicleContext. + */ + protected void loadSurroundingBlocks() { + this.centerPos = boundingBox.getBottomCenter(); + + // Reuse block cache if vehicle moved less than 1 block + if (this.cachePos == null || this.cachePos.distanceSquared(this.centerPos) > 1) { + BoundingBox box = boundingBox.clone(); + box.expand(2); + + Vector3i min = box.getMin().toInt(); + Vector3i max = box.getMax().toInt(); + this.blockIter = BlockPositionIterator.fromMinMax(min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ()); + this.blocks = vehicle.getSession().getGeyser().getWorldManager().getBlocksAt(vehicle.getSession(), this.blockIter); + + this.cachePos = this.centerPos; + } + + this.centerBlock = getBlock(this.centerPos.toInt()); + this.supportingBlockPos = null; + } + + protected Vector3d centerPos() { + return this.centerPos; + } + + protected BlockState centerBlock() { + return this.centerBlock; + } + + protected Vector3i supportingBlockPos() { + if (this.supportingBlockPos == null) { + this.supportingBlockPos = getSupportingBlockPos(this); + } + + return this.supportingBlockPos; + } + + protected int getBlockId(int x, int y, int z) { + int index = this.blockIter.getIndex(x, y, z); + if (index == -1) { + vehicle.getSession().getGeyser().getLogger().debug("[client-vehicle] Block cache miss"); + return vehicle.getSession().getGeyser().getWorldManager().getBlockAt(vehicle.getSession(), x, y, z); + } + + return blocks[index]; + } + + protected int getBlockId(Vector3i pos) { + return getBlockId(pos.getX(), pos.getY(), pos.getZ()); + } + + protected int getBlockId(BlockPositionIterator iter) { + return getBlockId(iter.getX(), iter.getY(), iter.getZ()); + } + + protected BlockState getBlock(int x, int y, int z) { + return BlockState.of(getBlockId(x, y, z)); + } + + protected BlockState getBlock(Vector3i pos) { + return BlockState.of(getBlockId(pos.getX(), pos.getY(), pos.getZ())); + } + + protected BlockState getBlock(BlockPositionIterator iter) { + return BlockState.of(getBlockId(iter.getX(), iter.getY(), iter.getZ())); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java index c3756d663..3ea9cd112 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java @@ -62,6 +62,16 @@ public class PlayerInventory extends Inventory { cursor = newCursor; } + /** + * Checks if the player is holding the specified item in either hand + * + * @param item The item to look for + * @return If the player is holding the item in either hand + */ + public boolean isHolding(@NonNull Item item) { + return getItemInHand().asItem() == item || getOffhand().asItem() == item; + } + public GeyserItemStack getItemInHand(@NonNull Hand hand) { return hand == Hand.OFF_HAND ? getOffhand() : getItemInHand(); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java index 475a3e588..a8a711cc2 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java @@ -43,6 +43,7 @@ public class StoredItemMappings { private final ItemMapping banner; private final ItemMapping barrier; private final ItemMapping bow; + private final ItemMapping carrotOnAStick; private final ItemMapping compass; private final ItemMapping crossbow; private final ItemMapping egg; @@ -52,6 +53,7 @@ public class StoredItemMappings { private final ItemMapping shield; private final ItemMapping totem; private final ItemMapping upgradeTemplate; + private final ItemMapping warpedFungusOnAStick; private final ItemMapping wheat; private final ItemMapping writableBook; private final ItemMapping writtenBook; @@ -60,6 +62,7 @@ public class StoredItemMappings { this.banner = load(itemMappings, Items.WHITE_BANNER); // As of 1.17.10, all banners have the same Bedrock ID this.barrier = load(itemMappings, Items.BARRIER); this.bow = load(itemMappings, Items.BOW); + this.carrotOnAStick = load(itemMappings, Items.CARROT_ON_A_STICK); this.compass = load(itemMappings, Items.COMPASS); this.crossbow = load(itemMappings, Items.CROSSBOW); this.egg = load(itemMappings, Items.EGG); @@ -69,6 +72,7 @@ public class StoredItemMappings { this.shield = load(itemMappings, Items.SHIELD); this.totem = load(itemMappings, Items.TOTEM_OF_UNDYING); this.upgradeTemplate = load(itemMappings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE); + this.warpedFungusOnAStick = load(itemMappings, Items.WARPED_FUNGUS_ON_A_STICK); this.wheat = load(itemMappings, Items.WHEAT); this.writableBook = load(itemMappings, Items.WRITABLE_BOOK); this.writtenBook = load(itemMappings, Items.WRITTEN_BOOK); diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 0ca428830..50589851b 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -34,11 +34,13 @@ import org.geysermc.geyser.util.DimensionUtils; * Represents the information we store from the current Java dimension * @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension. * This controls if they have the shaking effect applied in the dimension. + * @param ultrawarm If this dimension is ultrawarm. + * Used when calculating movement in lava for client-side vehicles. * @param bedrockId the Bedrock dimension ID of this dimension. * As a Java dimension can be null in some login cases (e.g. GeyserConnect), make sure the player * is logged in before utilizing this field. */ -public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale, int bedrockId, boolean isNetherLike) { +public record JavaDimension(int minY, int maxY, boolean piglinSafe, boolean ultrawarm, double worldCoordinateScale, int bedrockId, boolean isNetherLike) { public static JavaDimension read(RegistryEntryContext entry) { NbtMap dimension = entry.data(); @@ -48,6 +50,8 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double world // Set if piglins/hoglins should shake boolean piglinSafe = dimension.getBoolean("piglin_safe"); + // Entities in lava move faster in ultrawarm dimensions + boolean ultrawarm = dimension.getBoolean("ultrawarm"); // Load world coordinate scale for the world border double coordinateScale = dimension.getNumber("coordinate_scale").doubleValue(); // FIXME see if we can change this in the NBT library itself. @@ -67,6 +71,6 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double world isNetherLike = DimensionUtils.NETHER_IDENTIFIER.equals(effects); } - return new JavaDimension(minY, maxY, piglinSafe, coordinateScale, bedrockId, isNetherLike); + return new JavaDimension(minY, maxY, piglinSafe, ultrawarm, coordinateScale, bedrockId, isNetherLike); } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 01e95fc7a..36e437026 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -36,7 +36,7 @@ import org.geysermc.geyser.registry.BlockRegistries; * Used for block entities if the Java block state contains Bedrock block information. */ public final class BlockStateValues { - public static final int NUM_WATER_LEVELS = 9; + public static final int NUM_FLUID_LEVELS = 9; /** * Checks if a block sticks to other blocks @@ -99,6 +99,25 @@ public final class BlockStateValues { }; } + /** + * Get the type of fluid from the block state, including waterlogged blocks. + * + * @param state BlockState of the block + * @return The type of fluid + */ + public static Fluid getFluid(int state) { + BlockState blockState = BlockState.of(state); + if (blockState.is(Blocks.WATER) || BlockRegistries.WATERLOGGED.get().get(state)) { + return Fluid.WATER; + } + + if (blockState.is(Blocks.LAVA)) { + return Fluid.LAVA; + } + + return Fluid.EMPTY; + } + /** * Get the level of water from the block state. * @@ -127,7 +146,7 @@ public final class BlockStateValues { waterLevel = 0; } if (waterLevel >= 0) { - double waterHeight = 1 - (waterLevel + 1) / ((double) NUM_WATER_LEVELS); + double waterHeight = 1 - (waterLevel + 1) / ((double) NUM_FLUID_LEVELS); // Falling water is a full block if (waterLevel >= 8) { waterHeight = 1; @@ -137,6 +156,39 @@ public final class BlockStateValues { return -1; } + /** + * Get the level of lava from the block state. + * + * @param state BlockState of the block + * @return The lava level or -1 if the block isn't lava + */ + public static int getLavaLevel(int state) { + BlockState blockState = BlockState.of(state); + if (!blockState.is(Blocks.LAVA)) { + return -1; + } + return blockState.getValue(Properties.LEVEL); + } + + /** + * Get the height of lava from the block state + * + * @param state BlockState of the block + * @return The lava height or -1 if the block does not contain lava + */ + public static double getLavaHeight(int state) { + int lavaLevel = BlockStateValues.getLavaLevel(state); + if (lavaLevel >= 0) { + double lavaHeight = 1 - (lavaLevel + 1) / ((double) NUM_FLUID_LEVELS); + // Falling lava is a full block + if (lavaLevel >= 8) { + lavaHeight = 1; + } + return lavaHeight; + } + return -1; + } + /** * Get the slipperiness of a block. * This is used in ItemEntity to calculate the friction on an item as it slides across the ground diff --git a/core/src/main/java/org/geysermc/geyser/level/block/Fluid.java b/core/src/main/java/org/geysermc/geyser/level/block/Fluid.java new file mode 100644 index 000000000..a9693bbf4 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/Fluid.java @@ -0,0 +1,32 @@ +/* + * 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.level.block; + +public enum Fluid { + WATER, + LAVA, + EMPTY +} diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java b/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java index b1a93d8ee..395467c02 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java @@ -33,6 +33,8 @@ import org.cloudburstmc.math.vector.Vector3d; @Data @AllArgsConstructor public class BoundingBox implements Cloneable { + private static final double EPSILON = 1.0E-7; + private double middleX; private double middleY; private double middleZ; @@ -57,10 +59,24 @@ public class BoundingBox implements Cloneable { sizeZ += Math.abs(z); } + public void expand(double x, double y, double z) { + sizeX += x; + sizeY += y; + sizeZ += z; + } + + public void translate(Vector3d translate) { + translate(translate.getX(), translate.getY(), translate.getZ()); + } + public void extend(Vector3d extend) { extend(extend.getX(), extend.getY(), extend.getZ()); } + public void expand(double expand) { + expand(expand, expand, expand); + } + public boolean checkIntersection(double offsetX, double offsetY, double offsetZ, BoundingBox otherBox) { return (Math.abs((middleX + offsetX) - otherBox.getMiddleX()) * 2 < (sizeX + otherBox.getSizeX())) && (Math.abs((middleY + offsetY) - otherBox.getMiddleY()) * 2 < (sizeY + otherBox.getSizeY())) && @@ -78,6 +94,14 @@ public class BoundingBox implements Cloneable { return Vector3d.from(x, y, z); } + public double getMin(Axis axis) { + return switch (axis) { + case X -> middleX - sizeX / 2; + case Y -> middleY - sizeY / 2; + case Z -> middleZ - sizeZ / 2; + }; + } + public Vector3d getMax() { double x = middleX + sizeX / 2; double y = middleY + sizeY / 2; @@ -85,15 +109,23 @@ public class BoundingBox implements Cloneable { return Vector3d.from(x, y, z); } + public double getMax(Axis axis) { + return switch (axis) { + case X -> middleX + sizeX / 2; + case Y -> middleY + sizeY / 2; + case Z -> middleZ + sizeZ / 2; + }; + } + public Vector3d getBottomCenter() { return Vector3d.from(middleX, middleY - sizeY / 2, middleZ); } private boolean checkOverlapInAxis(double xOffset, double yOffset, double zOffset, BoundingBox otherBox, Axis axis) { return switch (axis) { - case X -> Math.abs((middleX + xOffset) - otherBox.getMiddleX()) * 2 < (sizeX + otherBox.getSizeX()); - case Y -> Math.abs((middleY + yOffset) - otherBox.getMiddleY()) * 2 < (sizeY + otherBox.getSizeY()); - case Z -> Math.abs((middleZ + zOffset) - otherBox.getMiddleZ()) * 2 < (sizeZ + otherBox.getSizeZ()); + case X -> (sizeX + otherBox.getSizeX()) - Math.abs((middleX + xOffset) - otherBox.getMiddleX()) * 2 > EPSILON; + case Y -> (sizeY + otherBox.getSizeY()) - Math.abs((middleY + yOffset) - otherBox.getMiddleY()) * 2 > EPSILON; + case Z -> (sizeZ + otherBox.getSizeZ()) - Math.abs((middleZ + zOffset) - otherBox.getMiddleZ()) * 2 > EPSILON; }; } 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 2be4e7a38..a0fb312b4 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 @@ -38,6 +38,7 @@ import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.Properties; @@ -45,7 +46,9 @@ import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.translator.collision.BlockCollision; +import org.geysermc.geyser.translator.collision.OtherCollision; import org.geysermc.geyser.translator.collision.ScaffoldingCollision; +import org.geysermc.geyser.translator.collision.SolidCollision; import org.geysermc.geyser.util.BlockUtils; import java.text.DecimalFormat; @@ -53,6 +56,8 @@ import java.text.DecimalFormatSymbols; import java.util.Locale; public class CollisionManager { + public static final BlockCollision SOLID_COLLISION = new SolidCollision(null); + public static final BlockCollision FLUID_COLLISION = new OtherCollision(new BoundingBox[]{new BoundingBox(0.5, 0.25, 0.5, 1, 0.5, 1)}); private final GeyserSession session; @@ -128,6 +133,21 @@ public class CollisionManager { playerBoundingBox.setSizeY(playerHeight); } + /** + * Gets the bounding box to use for player movement. + *

    + * This will return either the bounding box of a {@link ClientVehicle}, or the player's own bounding box. + * + * @return the bounding box to use for movement calculations + */ + public BoundingBox getActiveBoundingBox() { + if (session.getPlayerEntity().getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) { + return clientVehicle.getVehicleComponent().getBoundingBox(); + } + + return playerBoundingBox; + } + /** * Adjust the Bedrock position before sending to the Java server to account for inaccuracies in movement between * the two versions. Will also send corrected movement packets back to Bedrock if they collide with pistons. @@ -150,6 +170,15 @@ public class CollisionManager { Vector3d position = Vector3d.from(Double.parseDouble(Float.toString(bedrockPosition.getX())), javaY, Double.parseDouble(Float.toString(bedrockPosition.getZ()))); + // Don't correct position if controlling a vehicle + if (session.getPlayerEntity().getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) { + playerBoundingBox.setMiddleX(position.getX()); + playerBoundingBox.setMiddleY(position.getY() + playerBoundingBox.getSizeY() / 2); + playerBoundingBox.setMiddleZ(position.getZ()); + + return playerBoundingBox.getBottomCenter(); + } + Vector3d startingPos = playerBoundingBox.getBottomCenter(); Vector3d movement = position.sub(startingPos); Vector3d adjustedMovement = correctPlayerMovement(movement, false, teleported); @@ -173,7 +202,8 @@ public class CollisionManager { // Send corrected position to Bedrock if they differ by too much to prevent de-syncs if (onGround != newOnGround || movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) { PlayerEntity playerEntity = session.getPlayerEntity(); - if (pistonCache.getPlayerMotion().equals(Vector3f.ZERO) && !pistonCache.isPlayerSlimeCollision()) { + // 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); } } @@ -268,13 +298,13 @@ public class CollisionManager { if (teleported || (!checkWorld && session.getPistonCache().getPistons().isEmpty())) { // There is nothing to check return movement; } - return correctMovement(movement, playerBoundingBox, session.getPlayerEntity().isOnGround(), PLAYER_STEP_UP, checkWorld); + return correctMovement(movement, playerBoundingBox, session.getPlayerEntity().isOnGround(), PLAYER_STEP_UP, checkWorld, false); } - public Vector3d correctMovement(Vector3d movement, BoundingBox boundingBox, boolean onGround, double stepUp, boolean checkWorld) { + public Vector3d correctMovement(Vector3d movement, BoundingBox boundingBox, boolean onGround, double stepUp, boolean checkWorld, boolean walkOnLava) { Vector3d adjustedMovement = movement; if (!movement.equals(Vector3d.ZERO)) { - adjustedMovement = correctMovementForCollisions(movement, boundingBox, checkWorld); + adjustedMovement = correctMovementForCollisions(movement, boundingBox, checkWorld, walkOnLava); } boolean verticalCollision = adjustedMovement.getY() != movement.getY(); @@ -283,26 +313,27 @@ public class CollisionManager { onGround = onGround || (verticalCollision && falling); if (onGround && horizontalCollision) { Vector3d horizontalMovement = Vector3d.from(movement.getX(), 0, movement.getZ()); - Vector3d stepUpMovement = correctMovementForCollisions(horizontalMovement.up(stepUp), boundingBox, checkWorld); + Vector3d stepUpMovement = correctMovementForCollisions(horizontalMovement.up(stepUp), boundingBox, checkWorld, walkOnLava); BoundingBox stretchedBoundingBox = boundingBox.clone(); stretchedBoundingBox.extend(horizontalMovement); - double maxStepUp = correctMovementForCollisions(Vector3d.from(0, stepUp, 0), stretchedBoundingBox, checkWorld).getY(); + double maxStepUp = correctMovementForCollisions(Vector3d.from(0, stepUp, 0), stretchedBoundingBox, checkWorld, walkOnLava).getY(); if (maxStepUp < stepUp) { // The player collided with a block above them - boundingBox.translate(0, maxStepUp, 0); - Vector3d adjustedStepUpMovement = correctMovementForCollisions(horizontalMovement, boundingBox, checkWorld); - boundingBox.translate(0, -maxStepUp, 0); + BoundingBox stepUpBoundingBox = boundingBox.clone(); + stepUpBoundingBox.translate(0, maxStepUp, 0); + Vector3d adjustedStepUpMovement = correctMovementForCollisions(horizontalMovement, stepUpBoundingBox, checkWorld, walkOnLava); if (squaredHorizontalLength(adjustedStepUpMovement) > squaredHorizontalLength(stepUpMovement)) { stepUpMovement = adjustedStepUpMovement.up(maxStepUp); } } if (squaredHorizontalLength(stepUpMovement) > squaredHorizontalLength(adjustedMovement)) { - boundingBox.translate(stepUpMovement.getX(), stepUpMovement.getY(), stepUpMovement.getZ()); + BoundingBox stepUpBoundingBox = boundingBox.clone(); + stepUpBoundingBox.translate(stepUpMovement.getX(), stepUpMovement.getY(), stepUpMovement.getZ()); + // Apply the player's remaining vertical movement - double verticalMovement = correctMovementForCollisions(Vector3d.from(0, movement.getY() - stepUpMovement.getY(), 0), boundingBox, checkWorld).getY(); - boundingBox.translate(-stepUpMovement.getX(), -stepUpMovement.getY(), -stepUpMovement.getZ()); + double verticalMovement = correctMovementForCollisions(Vector3d.from(0, movement.getY() - stepUpMovement.getY(), 0), stepUpBoundingBox, checkWorld, walkOnLava).getY(); stepUpMovement = stepUpMovement.up(verticalMovement); adjustedMovement = stepUpMovement; @@ -315,43 +346,53 @@ public class CollisionManager { return vector.getX() * vector.getX() + vector.getZ() * vector.getZ(); } - private Vector3d correctMovementForCollisions(Vector3d movement, BoundingBox boundingBox, boolean checkWorld) { + private Vector3d correctMovementForCollisions(Vector3d movement, BoundingBox boundingBox, boolean checkWorld, boolean walkOnLava) { double movementX = movement.getX(); double movementY = movement.getY(); double movementZ = movement.getZ(); + // Position might change slightly due to floating point error + double originalX = boundingBox.getMiddleX(); + double originalY = boundingBox.getMiddleY(); + double originalZ = boundingBox.getMiddleZ(); + BoundingBox movementBoundingBox = boundingBox.clone(); movementBoundingBox.extend(movement); BlockPositionIterator iter = collidableBlocksIterator(movementBoundingBox); if (Math.abs(movementY) > CollisionManager.COLLISION_TOLERANCE) { - movementY = computeCollisionOffset(boundingBox, Axis.Y, movementY, iter, checkWorld); + movementY = computeCollisionOffset(boundingBox, Axis.Y, movementY, iter, checkWorld, walkOnLava); boundingBox.translate(0, movementY, 0); } boolean checkZFirst = Math.abs(movementZ) > Math.abs(movementX); if (checkZFirst && Math.abs(movementZ) > CollisionManager.COLLISION_TOLERANCE) { - movementZ = computeCollisionOffset(boundingBox, Axis.Z, movementZ, iter, checkWorld); + movementZ = computeCollisionOffset(boundingBox, Axis.Z, movementZ, iter, checkWorld, walkOnLava); boundingBox.translate(0, 0, movementZ); } if (Math.abs(movementX) > CollisionManager.COLLISION_TOLERANCE) { - movementX = computeCollisionOffset(boundingBox, Axis.X, movementX, iter, checkWorld); + movementX = computeCollisionOffset(boundingBox, Axis.X, movementX, iter, checkWorld, walkOnLava); boundingBox.translate(movementX, 0, 0); } if (!checkZFirst && Math.abs(movementZ) > CollisionManager.COLLISION_TOLERANCE) { - movementZ = computeCollisionOffset(boundingBox, Axis.Z, movementZ, iter, checkWorld); + movementZ = computeCollisionOffset(boundingBox, Axis.Z, movementZ, iter, checkWorld, walkOnLava); boundingBox.translate(0, 0, movementZ); } - boundingBox.translate(-movementX, -movementY, -movementZ); + boundingBox.setMiddleX(originalX); + boundingBox.setMiddleY(originalY); + boundingBox.setMiddleZ(originalZ); + return Vector3d.from(movementX, movementY, movementZ); } - private double computeCollisionOffset(BoundingBox boundingBox, Axis axis, double offset, BlockPositionIterator iter, boolean checkWorld) { + private double computeCollisionOffset(BoundingBox boundingBox, Axis axis, double offset, BlockPositionIterator iter, boolean checkWorld, boolean walkOnLava) { for (iter.reset(); iter.hasNext(); iter.next()) { int x = iter.getX(); int y = iter.getY(); int z = iter.getZ(); if (checkWorld) { - BlockCollision blockCollision = BlockUtils.getCollisionAt(session, x, y, z); + int blockId = session.getGeyser().getWorldManager().getBlockAt(session, x, y, z); + + BlockCollision blockCollision = walkOnLava ? getCollisionLavaWalking(blockId, y, boundingBox) : BlockUtils.getCollision(blockId); if (blockCollision != null && !(blockCollision instanceof ScaffoldingCollision)) { offset = blockCollision.computeCollisionOffset(x, y, z, boundingBox, axis, offset); } @@ -364,6 +405,16 @@ public class CollisionManager { return offset; } + /** + * @return the block collision appropriate for entities that can walk on lava (Strider) + */ + public BlockCollision getCollisionLavaWalking(int blockId, int blockY, BoundingBox boundingBox) { + if (BlockStateValues.getLavaLevel(blockId) == 0 && FLUID_COLLISION.isBelow(blockY, boundingBox)) { + return FLUID_COLLISION; + } + 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 @@ -417,7 +468,7 @@ public class CollisionManager { double eyeY = playerBoundingBox.getMiddleY() - playerBoundingBox.getSizeY() / 2d + session.getEyeHeight(); double eyeZ = playerBoundingBox.getMiddleZ(); - eyeY -= 1 / ((double) BlockStateValues.NUM_WATER_LEVELS); // Subtract the height of one water layer + eyeY -= 1 / ((double) BlockStateValues.NUM_FLUID_LEVELS); // Subtract the height of one water layer int blockID = session.getGeyser().getWorldManager().getBlockAt(session, GenericMath.floor(eyeX), GenericMath.floor(eyeY), GenericMath.floor(eyeZ)); double waterHeight = BlockStateValues.getWaterHeight(blockID); diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java b/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java index f14a46999..4821734f3 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java @@ -38,6 +38,7 @@ public enum Direction { EAST(4, Vector3i.UNIT_X, Axis.X, org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction.EAST); public static final Direction[] VALUES = values(); + public static final Direction[] HORIZONTAL = new Direction[]{Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}; private final int reversedId; @Getter 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 9137c4756..607a58e0b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -128,6 +128,7 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.erosion.AbstractGeyserboundPacketHandler; import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler; import org.geysermc.geyser.impl.camera.CameraDefinitions; @@ -602,6 +603,19 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { */ private ScheduledFuture tickThread = null; + /** + * The number of ticks that have elapsed since the start of this session + */ + private int ticks; + + /** + * The world time in ticks according to the server + *

    + * Note: The TickingStatePacket is currently ignored. + */ + @Setter + private long worldTicks; + /** * Used to return the player to their original rotation after using an item in BedrockInventoryTransactionTranslator */ @@ -1261,6 +1275,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { isInWorldBorderWarningArea = false; } + Entity vehicle = playerEntity.getVehicle(); + if (vehicle instanceof ClientVehicle clientVehicle && vehicle.isValid()) { + clientVehicle.getVehicleComponent().tickVehicle(); + } for (Tickable entity : entityCache.getTickableEntities()) { entity.tick(); @@ -1296,6 +1314,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } catch (Throwable throwable) { throwable.printStackTrace(); } + + ticks++; + worldTicks++; } public void setAuthenticationData(AuthData authData) { diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java index d0a5bc094..dee4aa7cf 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java @@ -33,7 +33,9 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; +import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.session.GeyserSession; @@ -119,6 +121,12 @@ public class PistonCache { private void sendPlayerMovement() { if (!playerDisplacement.equals(Vector3d.ZERO) && playerMotion.equals(Vector3f.ZERO)) { SessionPlayerEntity playerEntity = session.getPlayerEntity(); + + Entity vehicle = playerEntity.getVehicle(); + if (vehicle instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) { + return; + } + boolean isOnGround = playerDisplacement.getY() > 0 || playerEntity.isOnGround(); Vector3d position = session.getCollisionManager().getPlayerBoundingBox().getBottomCenter(); playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), isOnGround, true); @@ -128,6 +136,13 @@ public class PistonCache { private void sendPlayerMotion() { if (!playerMotion.equals(Vector3f.ZERO)) { SessionPlayerEntity playerEntity = session.getPlayerEntity(); + + Entity vehicle = playerEntity.getVehicle(); + if (vehicle instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) { + vehicle.setMotion(playerMotion); + return; + } + playerEntity.setMotion(playerMotion); SetEntityMotionPacket setEntityMotionPacket = new SetEntityMotionPacket(); @@ -149,10 +164,15 @@ public class PistonCache { totalDisplacement = totalDisplacement.max(-0.51d, -0.51d, -0.51d).min(0.51d, 0.51d, 0.51d); Vector3d delta = totalDisplacement.sub(playerDisplacement); - // Check if the piston is pushing a player into collision - delta = session.getCollisionManager().correctPlayerMovement(delta, true, false); - session.getCollisionManager().getPlayerBoundingBox().translate(delta.getX(), delta.getY(), delta.getZ()); + // Check if the piston is pushing a player into collision + if (session.getPlayerEntity().getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) { + delta = clientVehicle.getVehicleComponent().correctMovement(delta); + clientVehicle.getVehicleComponent().moveRelative(delta); + } else { + delta = session.getCollisionManager().correctPlayerMovement(delta, true, false); + session.getCollisionManager().getPlayerBoundingBox().translate(delta.getX(), delta.getY(), delta.getZ()); + } playerDisplacement = totalDisplacement; } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldBorder.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldBorder.java index 8cb590f57..35579db13 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldBorder.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldBorder.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.session.cache; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector2d; +import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.LevelEventType; @@ -36,8 +37,12 @@ import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.level.physics.Axis; +import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.session.GeyserSession; +import static org.geysermc.geyser.level.physics.CollisionManager.COLLISION_TOLERANCE; + public class WorldBorder { private static final double DEFAULT_WORLD_BORDER_SIZE = 5.9999968E7D; @@ -190,6 +195,53 @@ public class WorldBorder { return entityPosition.getX() > warningMinX && entityPosition.getX() < warningMaxX && entityPosition.getZ() > warningMinZ && entityPosition.getZ() < warningMaxZ; } + /** + * Adjusts the movement of an entity so that it does not cross the world border. + * + * @param boundingBox bounding box of the entity + * @param movement movement of the entity + * @return the corrected movement + */ + public Vector3d correctMovement(BoundingBox boundingBox, Vector3d movement) { + double correctedX; + if (movement.getX() < 0) { + correctedX = -limitMovement(-movement.getX(), boundingBox.getMin(Axis.X) - GenericMath.floor(minX)); + } else { + correctedX = limitMovement(movement.getX(), GenericMath.ceil(maxX) - boundingBox.getMax(Axis.X)); + } + + // Outside of border, don't adjust movement + if (Double.isNaN(correctedX)) { + return movement; + } + + double correctedZ; + if (movement.getZ() < 0) { + correctedZ = -limitMovement(-movement.getZ(), boundingBox.getMin(Axis.Z) - GenericMath.floor(minZ)); + } else { + correctedZ = limitMovement(movement.getZ(), GenericMath.ceil(maxZ) - boundingBox.getMax(Axis.Z)); + } + + if (Double.isNaN(correctedZ)) { + return movement; + } + + return Vector3d.from(correctedX, movement.getY(), correctedZ); + } + + private double limitMovement(double movement, double limit) { + if (limit < 0) { + // Return NaN to indicate outside of border + return Double.NaN; + } + + if (limit < COLLISION_TOLERANCE) { + return 0; + } + + return Math.min(movement, limit); + } + /** * Updates the world border's minimum and maximum properties */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java index 2481028a4..bfe3f4417 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java @@ -166,4 +166,22 @@ public class BlockCollision { } return offset; } + + /** + * Checks if this block collision is below the given bounding box. + * + * @param blockY the y position of the block in the world + * @param boundingBox the bounding box to compare + * @return true if this block collision is below the bounding box + */ + public boolean isBelow(int blockY, BoundingBox boundingBox) { + double minY = boundingBox.getMiddleY() - boundingBox.getSizeY() / 2; + for (BoundingBox b : boundingBoxes) { + double offset = blockY + b.getMiddleY() + b.getSizeY() / 2 - minY; + if (offset > CollisionManager.COLLISION_TOLERANCE) { + return false; + } + } + return true; + } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index d1dd24855..b668a88cf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -37,6 +37,7 @@ import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.Properties; @@ -347,18 +348,31 @@ public class PistonBlockEntity { blockMovement = 1f - lastProgress; } - BoundingBox playerBoundingBox = session.getCollisionManager().getPlayerBoundingBox(); + boolean onGround; + BoundingBox playerBoundingBox; + if (session.getPlayerEntity().getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) { + onGround = session.getPlayerEntity().getVehicle().isOnGround(); + playerBoundingBox = clientVehicle.getVehicleComponent().getBoundingBox(); + } else { + onGround = session.getPlayerEntity().isOnGround(); + playerBoundingBox = session.getCollisionManager().getPlayerBoundingBox(); + } + // Shrink the collision in the other axes slightly, to avoid false positives when pressed up against the side of blocks Vector3d shrink = Vector3i.ONE.sub(direction.abs()).toDouble().mul(CollisionManager.COLLISION_TOLERANCE * 2); - playerBoundingBox.setSizeX(playerBoundingBox.getSizeX() - shrink.getX()); - playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() - shrink.getY()); - playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() - shrink.getZ()); + double sizeX = playerBoundingBox.getSizeX(); + double sizeY = playerBoundingBox.getSizeY(); + double sizeZ = playerBoundingBox.getSizeZ(); + + playerBoundingBox.setSizeX(sizeX - shrink.getX()); + playerBoundingBox.setSizeY(sizeY - shrink.getY()); + playerBoundingBox.setSizeZ(sizeZ - shrink.getZ()); // Resolve collision with the piston head BlockState pistonHeadId = Blocks.PISTON_HEAD.defaultBlockState() .withValue(Properties.SHORT, false) .withValue(Properties.FACING, orientation); - pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox); + pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox, onGround); // Resolve collision with any attached moving blocks, but skip slime blocks // This prevents players from being launched by slime blocks covered by other blocks @@ -366,7 +380,7 @@ public class PistonBlockEntity { BlockState state = entry.getValue(); if (!state.is(Blocks.SLIME_BLOCK)) { Vector3d blockPos = entry.getKey().toDouble(); - pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox); + pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox, onGround); } } // Resolve collision with slime blocks @@ -374,14 +388,14 @@ public class PistonBlockEntity { BlockState state = entry.getValue(); if (state.is(Blocks.SLIME_BLOCK)) { Vector3d blockPos = entry.getKey().toDouble(); - pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox); + pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox, onGround); } } // Undo shrink - playerBoundingBox.setSizeX(playerBoundingBox.getSizeX() + shrink.getX()); - playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() + shrink.getY()); - playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() + shrink.getZ()); + playerBoundingBox.setSizeX(sizeX); + playerBoundingBox.setSizeY(sizeY); + playerBoundingBox.setSizeZ(sizeZ); } /** @@ -391,20 +405,22 @@ public class PistonBlockEntity { * @param playerBoundingBox The player's bounding box * @return True if the player attached, otherwise false */ - private boolean isPlayerAttached(Vector3d blockPos, BoundingBox playerBoundingBox) { + private boolean isPlayerAttached(Vector3d blockPos, BoundingBox playerBoundingBox, boolean onGround) { if (orientation.isVertical()) { return false; } - return session.getPlayerEntity().isOnGround() && HONEY_BOUNDING_BOX.checkIntersection(blockPos, playerBoundingBox); + return onGround && HONEY_BOUNDING_BOX.checkIntersection(blockPos, playerBoundingBox); } /** * Launches a player if the player is on the pushing side of the slime block * * @param blockPos The position of the slime block - * @param playerPos The player's position + * @param playerBoundingBox The player's bounding box */ - private void applySlimeBlockMotion(Vector3d blockPos, Vector3d playerPos) { + private void applySlimeBlockMotion(Vector3d blockPos, BoundingBox playerBoundingBox) { + Vector3d playerPos = Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ()); + Direction movementDirection = orientation; // Invert direction when pulling if (action == PistonValueType.PULLING) { @@ -470,7 +486,7 @@ public class PistonBlockEntity { return maxIntersection; } - private void pushPlayerBlock(BlockState state, Vector3d startingPos, double blockMovement, BoundingBox playerBoundingBox) { + private void pushPlayerBlock(BlockState state, Vector3d startingPos, double blockMovement, BoundingBox playerBoundingBox, boolean onGround) { PistonCache pistonCache = session.getPistonCache(); Vector3d movement = getMovement().toDouble(); // Check if the player collides with the movingBlock block entity @@ -480,12 +496,12 @@ public class PistonBlockEntity { if (state.is(Blocks.SLIME_BLOCK)) { pistonCache.setPlayerSlimeCollision(true); - applySlimeBlockMotion(finalBlockPos, Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ())); + applySlimeBlockMotion(finalBlockPos, playerBoundingBox); } } Vector3d blockPos = startingPos.add(movement.mul(blockMovement)); - if (state.is(Blocks.HONEY_BLOCK) && isPlayerAttached(blockPos, playerBoundingBox)) { + if (state.is(Blocks.HONEY_BLOCK) && isPlayerAttached(blockPos, playerBoundingBox, onGround)) { pistonCache.setPlayerCollided(true); pistonCache.setPlayerAttachedToHoney(true); @@ -508,7 +524,7 @@ public class PistonBlockEntity { if (state.is(Blocks.SLIME_BLOCK)) { pistonCache.setPlayerSlimeCollision(true); - applySlimeBlockMotion(blockPos, Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ())); + applySlimeBlockMotion(blockPos, playerBoundingBox); } } } @@ -584,7 +600,7 @@ public class PistonBlockEntity { movingBlockMap.put(getPistonHeadPos(), this); Vector3i movement = getMovement(); - BoundingBox playerBoundingBox = session.getCollisionManager().getPlayerBoundingBox().clone(); + BoundingBox playerBoundingBox = session.getCollisionManager().getActiveBoundingBox().clone(); if (orientation == Direction.UP) { // Extend the bounding box down, to catch collisions when the player is falling down playerBoundingBox.extend(0, -256, 0); @@ -628,17 +644,19 @@ public class PistonBlockEntity { return; } placedFinalBlocks = true; + Vector3i movement = getMovement(); + BoundingBox playerBoundingBox = session.getCollisionManager().getActiveBoundingBox().clone(); attachedBlocks.forEach((blockPos, state) -> { blockPos = blockPos.add(movement); // Don't place blocks that collide with the player - if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { + if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), playerBoundingBox)) { ChunkUtils.updateBlock(session, state, blockPos); } }); if (action == PistonValueType.PUSHING) { Vector3i pistonHeadPos = getPistonHeadPos().add(movement); - if (!SOLID_BOUNDING_BOX.checkIntersection(pistonHeadPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { + if (!SOLID_BOUNDING_BOX.checkIntersection(pistonHeadPos.toDouble(), playerBoundingBox)) { ChunkUtils.updateBlock(session, Blocks.PISTON_HEAD.defaultBlockState() .withValue(Properties.SHORT, false) .withValue(Properties.FACING, orientation), pistonHeadPos); 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 index beb724ffb..1498c2184 100644 --- 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 @@ -52,6 +52,8 @@ public class BedrockPlayerInputTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, RiderJumpPacket packet) { + session.getPlayerEntity().setVehicleJumpStrength(packet.getJumpStrength()); + Entity vehicle = session.getPlayerEntity().getVehicle(); if (vehicle instanceof AbstractHorseEntity) { ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket(vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index 601517523..ccd93ac97 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -101,6 +101,7 @@ public class JavaRespawnTranslator extends PacketTranslator Date: Fri, 16 Aug 2024 01:09:08 +0200 Subject: [PATCH 348/897] Fix: Invalid heads blocking inventory transactions (#4969) --- .../geyser/skin/FakeHeadProvider.java | 10 +++++-- .../translator/item/ItemTranslator.java | 28 ++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index 6f6bcb0ae..22786a4ee 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java @@ -112,7 +112,13 @@ public class FakeHeadProvider { return; } - Map textures = profile.getTextures(false); + Map textures; + try { + textures = profile.getTextures(false); + } catch (IllegalStateException e) { + GeyserImpl.getInstance().getLogger().debug("Could not decode player head from profile %s, got: %s".formatted(profile, e.getMessage())); + textures = null; + } if (textures == null || textures.isEmpty()) { loadHead(session, entity, profile.getName()); @@ -214,4 +220,4 @@ public class FakeHeadProvider { } } -} \ No newline at end of file +} 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 aa0c3eb43..163eef20b 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 @@ -25,9 +25,6 @@ package org.geysermc.geyser.translator.item; -import org.geysermc.mcprotocollib.auth.GameProfile; -import org.geysermc.mcprotocollib.auth.GameProfile.Texture; -import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; @@ -43,8 +40,8 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; -import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.BedrockRequiresTagItem; +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.Registries; @@ -55,13 +52,24 @@ import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.auth.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile.Texture; +import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.*; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.AdventureModePredicate; +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.HolderSet; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttributeModifiers; import java.text.DecimalFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public final class ItemTranslator { @@ -486,7 +494,13 @@ public final class ItemTranslator { GameProfile profile = components.get(DataComponentType.PROFILE); if (profile != null) { - Map textures = profile.getTextures(false); + Map textures; + try { + textures = profile.getTextures(false); + } catch (IllegalStateException e) { + GeyserImpl.getInstance().getLogger().debug("Could not decode player head from profile %s, got: %s".formatted(profile, e.getMessage())); + return null; + } if (textures == null || textures.isEmpty()) { return null; From bc7866541008f222554d93cde7ec45c344ed429d Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 21 Aug 2024 09:36:23 +0200 Subject: [PATCH 349/897] Indicate 1.21.21 support, update Bedrock protocol library dependencies (#4974) * Show 1.21.21 as being supported, bump Bedrock protocol library * Dont print debug --- README.md | 2 +- .../java/org/geysermc/geyser/network/GameProtocol.java | 2 +- gradle/libs.versions.toml | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5e586463c..fb93a8808 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.20 and Minecraft Java Server 1.21/1.21.1. For more info please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.21 and Minecraft Java 1.21/1.21.1. 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/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 422fa3d5a..baa1d24d0 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -50,7 +50,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder() - .minecraftVersion("1.21.20") + .minecraftVersion("1.21.20/1.21.21") .build()); /** diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 795d351ed..f49de8d20 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,9 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "3.0.0.Beta3-20240814.133201-7" +protocol-connection = "3.0.0.Beta3-20240819.124045-12" +protocol-common = "3.0.0.Beta3-20240819.124045-10" +protocol-codec = "3.0.0.Beta3-20240819.124045-13" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1-20240806.235051-7" mcprotocollib = "1.21-20240725.013034-16" @@ -125,9 +127,9 @@ viaproxy = { group = "net.raphimc", name = "ViaProxy", version.ref = "viaproxy" viaversion = { group = "com.viaversion", name = "viaversion", version.ref = "viaversion" } websocket = { group = "org.java-websocket", name = "Java-WebSocket", version.ref = "websocket" } -protocol-common = { group = "org.cloudburstmc.protocol", name = "common", version.ref = "protocol" } -protocol-codec = { group = "org.cloudburstmc.protocol", name = "bedrock-codec", version.ref = "protocol" } -protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-connection", version.ref = "protocol" } +protocol-common = { group = "org.cloudburstmc.protocol", name = "common", version.ref = "protocol-common" } +protocol-codec = { group = "org.cloudburstmc.protocol", name = "bedrock-codec", version.ref = "protocol-codec" } +protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-connection", version.ref = "protocol-connection" } math = { group = "org.cloudburstmc.math", name = "immutable", version = "2.0" } From b792f72ec70706ce1158d3745fd164e73edf6ae3 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 21 Aug 2024 13:46:10 +0200 Subject: [PATCH 350/897] Fix invalid ping version causing "Unable to connect to world" --- .../geyser/network/netty/GeyserServer.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index a67bd8a32..5166bde4d 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -84,10 +84,11 @@ public final class GeyserServer { /* The following constants are all used to ensure the ping does not reach a length where it is unparsable by the Bedrock client */ - private static final int MINECRAFT_VERSION_BYTES_LENGTH = GameProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion().getBytes(StandardCharsets.UTF_8).length; + private static final String PING_VERSION = pingVersion(); + private static final int PING_VERSION_BYTES_LENGTH = PING_VERSION.getBytes(StandardCharsets.UTF_8).length; private static final int BRAND_BYTES_LENGTH = GeyserImpl.NAME.getBytes(StandardCharsets.UTF_8).length; /** - * The MOTD, sub-MOTD and Minecraft version ({@link #MINECRAFT_VERSION_BYTES_LENGTH}) combined cannot reach this length. + * The MOTD, sub-MOTD and Minecraft version ({@link #PING_VERSION_BYTES_LENGTH}) combined cannot reach this length. */ private static final int MAGIC_RAKNET_LENGTH = 338; @@ -316,7 +317,7 @@ public final class GeyserServer { .gameType("Survival") // Can only be Survival or Creative as of 1.16.210.59 .nintendoLimited(false) .protocolVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) - .version(GameProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()) // Required to not be empty as of 1.16.210.59. Can only contain . and numbers. + .version(PING_VERSION) .ipv4Port(this.broadcastPort) .ipv6Port(this.broadcastPort) .serverId(channel.config().getOption(RakChannelOption.RAK_GUID)); @@ -367,15 +368,15 @@ public final class GeyserServer { // We don't know why, though byte[] motdArray = pong.motd().getBytes(StandardCharsets.UTF_8); int subMotdLength = pong.subMotd().getBytes(StandardCharsets.UTF_8).length; - if (motdArray.length + subMotdLength > (MAGIC_RAKNET_LENGTH - MINECRAFT_VERSION_BYTES_LENGTH)) { + if (motdArray.length + subMotdLength > (MAGIC_RAKNET_LENGTH - PING_VERSION_BYTES_LENGTH)) { // Shorten the sub-MOTD first since that only appears locally if (subMotdLength > BRAND_BYTES_LENGTH) { pong.subMotd(GeyserImpl.NAME); subMotdLength = BRAND_BYTES_LENGTH; } - if (motdArray.length > (MAGIC_RAKNET_LENGTH - MINECRAFT_VERSION_BYTES_LENGTH - subMotdLength)) { + if (motdArray.length > (MAGIC_RAKNET_LENGTH - PING_VERSION_BYTES_LENGTH - subMotdLength)) { // If the top MOTD is still too long, we chop it down - byte[] newMotdArray = new byte[MAGIC_RAKNET_LENGTH - MINECRAFT_VERSION_BYTES_LENGTH - subMotdLength]; + byte[] newMotdArray = new byte[MAGIC_RAKNET_LENGTH - PING_VERSION_BYTES_LENGTH - subMotdLength]; System.arraycopy(motdArray, 0, newMotdArray, 0, newMotdArray.length); pong.motd(new String(newMotdArray, StandardCharsets.UTF_8)); } @@ -390,6 +391,17 @@ public final class GeyserServer { return pong; } + private static String pingVersion() { + // BedrockPong version is required to not be empty as of 1.16.210.59. + // Can only contain . and numbers, so use the latest version instead of sending all + var version = GameProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion(); + var versionSplit = version.split("/"); + if (versionSplit.length > 1) { + version = versionSplit[versionSplit.length - 1]; + } + return version; + } + /** * @return the throwable from the given supplier, or the throwable caught while calling the supplier. */ From 6801338ff991dcad75bac09ca4edf44547630a13 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 22 Aug 2024 00:50:16 -0400 Subject: [PATCH 351/897] Another route of ensuring /help goes through to Bedrock --- .../protocol/java/JavaCommandsTranslator.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 01da23809..6bbf0eb33 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -88,6 +88,7 @@ public class JavaCommandsTranslator extends PacketTranslator flags = Set.of(CommandData.Flag.NOT_CHEAT); + boolean helpAdded = false; + // Loop through all the found commands for (Map.Entry> entry : commands.entrySet()) { String commandName = entry.getValue().iterator().next(); // We know this has a value @@ -198,6 +201,18 @@ public class JavaCommandsTranslator extends PacketTranslator Date: Thu, 22 Aug 2024 13:16:07 -0400 Subject: [PATCH 352/897] Show the help command even with command suggestions disabled --- .../protocol/java/JavaCommandsTranslator.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 6bbf0eb33..f189658cd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -125,8 +125,9 @@ public class JavaCommandsTranslator extends PacketTranslator Date: Sun, 25 Aug 2024 21:31:03 +0200 Subject: [PATCH 353/897] Feature: Modrinth version names (#4989) * Feature: Version names on modrinth published builds * Also change the fabric/neoforge jar file names --- build-logic/src/main/kotlin/extensions.kt | 9 +++++++++ .../src/main/kotlin/geyser.modded-conventions.gradle.kts | 2 +- .../geyser.modrinth-uploading-conventions.gradle.kts | 3 ++- core/build.gradle.kts | 5 +---- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 41e11344b..1b81f6601 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -118,3 +118,12 @@ open class DownloadFilesTask : DefaultTask() { private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String = if (excludedOn and bit > 0) section else "" +fun projectVersion(project: Project): String = + project.version.toString().replace("SNAPSHOT", "b" + buildNumber()) + +fun versionName(project: Project): String = + "Geyser-" + project.name.replaceFirstChar { it.uppercase() } + "-" + projectVersion(project) + +fun buildNumber(): Int = + (System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1 + diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index 8a6602778..8584c13d4 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -87,7 +87,7 @@ tasks { register("remapModrinthJar", RemapJarTask::class) { dependsOn(shadowJar) inputFile.set(shadowJar.get().archiveFile) - archiveVersion.set(project.version.toString() + "+build." + System.getenv("BUILD_NUMBER")) + archiveVersion.set(versionName(project)) archiveClassifier.set("") } } 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 fe2284137..d2e207fa4 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 @@ -8,7 +8,8 @@ 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? projectId.set("geyser") - versionNumber.set(project.version as String + "-" + System.getenv("BUILD_NUMBER")) + 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) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index acd6c5147..8d022271b 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -103,9 +103,6 @@ sourceSets { } } -fun buildNumber(): Int = - (System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1 - fun isDevBuild(branch: String, repository: String): Boolean { return branch != "master" || repository.equals("https://github.com/GeyserMC/Geyser", ignoreCase = true).not() } @@ -139,7 +136,7 @@ inner class GitInfo { buildNumber = buildNumber() isDev = isDevBuild(branch, repository) - val projectVersion = if (isDev) project.version else project.version.toString().replace("SNAPSHOT", "b${buildNumber}") + val projectVersion = if (isDev) project.version else projectVersion(project) version = "$projectVersion ($gitVersion)" } } From 3be9b8a183aa2fe798b6b8d19e95eb74ba096f0a Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 26 Aug 2024 00:48:42 -0400 Subject: [PATCH 354/897] Fix moving items from output slot over multiple actions (#4993) * Fix moving items from output slot over multiple actions * Refactor and use temp slot * Ensure source slot is not cursor --- .../geyser/inventory/click/ClickPlan.java | 21 +++ .../inventory/InventoryTranslator.java | 146 ++++++++++++++---- 2 files changed, 137 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index 53b02ef88..9d6f4d3e3 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -162,6 +162,27 @@ public final class ClickPlan { finished = true; } + public Inventory getInventory() { + return inventory; + } + + /** + * Test if the item stacks with another item in the specified slot. + * This will check the simulated inventory without copying. + */ + public boolean canStack(int slot, GeyserItemStack item) { + GeyserItemStack slotItem = simulatedItems.getOrDefault(slot, inventory.getItem(slot)); + return InventoryUtils.canStack(slotItem, item); + } + + /** + * Test if the specified slot is empty. + * This will check the simulated inventory without copying. + */ + public boolean isEmpty(int slot) { + return simulatedItems.getOrDefault(slot, inventory.getItem(slot)).isEmpty(); + } + public GeyserItemStack getItem(int slot) { return simulatedItems.computeIfAbsent(slot, k -> inventory.getItem(slot).copy()); } 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 546ebda19..afa11c982 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 @@ -201,6 +201,9 @@ public abstract class InventoryTranslator { public ItemStackResponse translateRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { ClickPlan plan = new ClickPlan(session, this, inventory); IntSet affectedSlots = new IntOpenHashSet(); + int pendingOutput = 0; + int savedTempSlot = -1; + for (ItemStackRequestAction action : request.getActions()) { GeyserItemStack cursor = session.getPlayerInventory().getCursor(); switch (action.getType()) { @@ -241,6 +244,65 @@ public abstract class InventoryTranslator { return rejectRequest(request, false); } + // Handle partial transfer of output slot + if (pendingOutput == 0 && !isSourceCursor && getSlotType(sourceSlot) == SlotType.OUTPUT + && transferAction.getCount() < plan.getItem(sourceSlot).getAmount()) { + // Cursor as dest should always be full transfer. + if (isDestCursor) { + return rejectRequest(request); + } + + if (!plan.getCursor().isEmpty()) { + savedTempSlot = findTempSlot(plan, plan.getCursor(), true); + if (savedTempSlot == -1) { + return rejectRequest(request); + } + plan.add(Click.LEFT, savedTempSlot); + } + + // Pickup entire stack from output + pendingOutput = plan.getItem(sourceSlot).getAmount(); + plan.add(Click.LEFT, sourceSlot); + } + + // Continue transferring items from output that is currently stored in the cursor + if (pendingOutput > 0) { + if (isSourceCursor || getSlotType(sourceSlot) != SlotType.OUTPUT + || transferAction.getCount() > pendingOutput + || destSlot == savedTempSlot + || isDestCursor) { + return rejectRequest(request); + } + + // Make sure item can be placed here + GeyserItemStack destItem = plan.getItem(destSlot); + if (!destItem.isEmpty() && !InventoryUtils.canStack(destItem, plan.getCursor())) { + return rejectRequest(request); + } + + // TODO: Optimize using max stack size + if (pendingOutput == transferAction.getCount()) { + plan.add(Click.LEFT, destSlot); + } else { + for (int i = 0; i < transferAction.getCount(); i++) { + plan.add(Click.RIGHT, destSlot); + } + } + + pendingOutput -= transferAction.getCount(); + if (pendingOutput != plan.getCursor().getAmount()) { + return rejectRequest(request); + } + + if (pendingOutput == 0 && savedTempSlot != -1) { + plan.add(Click.LEFT, savedTempSlot); + savedTempSlot = -1; + } + + // Skip to next action + continue; + } + if (isSourceCursor && isDestCursor) { //??? return rejectRequest(request); } else if (isSourceCursor) { //releasing cursor @@ -271,7 +333,7 @@ public abstract class InventoryTranslator { return rejectRequest(request); } if (transferAction.getCount() != sourceAmount) { - int tempSlot = findTempSlot(inventory, cursor, false, sourceSlot); + int tempSlot = findTempSlot(plan, cursor, false, sourceSlot); if (tempSlot == -1) { return rejectRequest(request); } @@ -292,7 +354,7 @@ public abstract class InventoryTranslator { } else { //transfer from one slot to another int tempSlot = -1; if (!plan.getCursor().isEmpty()) { - tempSlot = findTempSlot(inventory, cursor, false, sourceSlot, destSlot); + tempSlot = findTempSlot(plan, cursor, getSlotType(sourceSlot) != SlotType.NORMAL, sourceSlot, destSlot); if (tempSlot == -1) { return rejectRequest(request); } @@ -440,6 +502,11 @@ public abstract class InventoryTranslator { return rejectRequest(request); } } + + if (pendingOutput != 0) { + return rejectRequest(request); + } + plan.execute(false); affectedSlots.addAll(plan.getAffectedSlots()); return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); @@ -536,7 +603,7 @@ public abstract class InventoryTranslator { } } else { GeyserItemStack cursor = session.getPlayerInventory().getCursor(); - int tempSlot = findTempSlot(inventory, cursor, true, sourceSlot, destSlot); + int tempSlot = findTempSlot(plan, cursor, true, sourceSlot, destSlot); if (tempSlot == -1) { return rejectRequest(request); } @@ -699,7 +766,7 @@ public abstract class InventoryTranslator { int javaSlot = bedrockSlotToJava(transferAction.getDestination()); if (isCursor(transferAction.getDestination())) { //TODO if (timesCrafted > 1) { - tempSlot = findTempSlot(inventory, GeyserItemStack.from(output), true); + tempSlot = findTempSlot(plan, GeyserItemStack.from(output), true); if (tempSlot == -1) { return rejectRequest(request); } @@ -836,49 +903,68 @@ public abstract class InventoryTranslator { } /** - * Try to find a slot that can temporarily store the given item. + * Try to find a slot that is preferably empty, or does not stack with a given item. * Only looks in the main inventory and hotbar (excluding offhand). - * Only slots that are empty or contain a different type of item are valid. + *

    + * Slots are searched in the reverse order that the bedrock client uses for quick moving. * - * @return java id for the temporary slot, or -1 if no viable slot was found + * @param plan used to check the simulated inventory + * @param item the item to temporarily store + * @param emptyOnly if only empty slots should be considered + * @param slotBlacklist list of slots to exclude; the items contained in these slots will also be checked for stacking + * @return the temp slot, or -1 if no suitable slot was found */ - //TODO: compatibility for simulated inventory (ClickPlan) - private static int findTempSlot(Inventory inventory, GeyserItemStack item, boolean emptyOnly, int... slotBlacklist) { - int offset = inventory.getJavaId() == 0 ? 1 : 0; //offhand is not a viable temp slot - HashSet itemBlacklist = new HashSet<>(slotBlacklist.length + 1); - itemBlacklist.add(item); + private static int findTempSlot(ClickPlan plan, GeyserItemStack item, boolean emptyOnly, int... slotBlacklist) { + IntSortedSet potentialSlots = new IntLinkedOpenHashSet(PLAYER_INVENTORY_SIZE); + int hotbarOffset = plan.getInventory().getOffsetForHotbar(0); - IntSet potentialSlots = new IntOpenHashSet(36); - for (int i = inventory.getSize() - (36 + offset); i < inventory.getSize() - offset; i++) { + // Add main inventory slots in reverse + for (int i = hotbarOffset - 1; i >= hotbarOffset - 27; i--) { potentialSlots.add(i); } + + // Add hotbar slots in reverse + for (int i = hotbarOffset + 8; i >= hotbarOffset; i--) { + potentialSlots.add(i); + } + for (int i : slotBlacklist) { potentialSlots.remove(i); - GeyserItemStack blacklistedItem = inventory.getItem(i); - if (!blacklistedItem.isEmpty()) { - itemBlacklist.add(blacklistedItem); + } + + // Prefer empty slots + IntIterator it = potentialSlots.iterator(); + while (it.hasNext()) { + int slot = it.nextInt(); + if (plan.isEmpty(slot)) { + return slot; } } - for (int i : potentialSlots) { - GeyserItemStack testItem = inventory.getItem(i); - if ((emptyOnly && !testItem.isEmpty())) { + if (emptyOnly) { + return -1; + } + + // No empty slots. Look for a slot that does not stack + it = potentialSlots.iterator(); + + outer: + while (it.hasNext()) { + int slot = it.nextInt(); + if (plan.canStack(slot, item)) { continue; } - boolean viable = true; - for (GeyserItemStack blacklistedItem : itemBlacklist) { - if (InventoryUtils.canStack(testItem, blacklistedItem)) { - viable = false; - break; + for (int blacklistedSlot : slotBlacklist) { + GeyserItemStack blacklistedItem = plan.getItem(blacklistedSlot); + if (plan.canStack(slot, blacklistedItem)) { + continue outer; } } - if (!viable) { - continue; - } - return i; + + return slot; } - //could not find a viable temp slot + return -1; } From 46b2c032154502378c2dcd20054703cc69deeae2 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 27 Aug 2024 05:37:01 -0400 Subject: [PATCH 355/897] Fix rare netid desync when crafting (#4997) --- .../geyser/translator/inventory/PlayerInventoryTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index bc6ff2adf..21f45a5ca 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -123,7 +123,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (session.getGameMode() == GameMode.CREATIVE) { slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK.apply(session.getUpstream().getProtocolVersion())); } else { - slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i).getItemStack())); + slotPacket.setItem(inventory.getItem(i).getItemData(session)); } session.sendUpstreamPacket(slotPacket); From 8356b63f5d52e8f8e61a7d0af71c924843503083 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 27 Aug 2024 18:40:22 +0200 Subject: [PATCH 356/897] Fix: Structure blocks/voids in recipes (#4999) * Fix: Structure blocks/voids in recipes * add gh issue link --- .../geyser/registry/populator/ItemRegistryPopulator.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index f11b58bfe..55d44c3d9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -171,6 +171,11 @@ public class ItemRegistryPopulator { List creativeItems = new ArrayList<>(); Set noBlockDefinitions = new ObjectOpenHashSet<>(); + // Fix: Usage of structure blocks/voids in recipes + // https://github.com/GeyserMC/Geyser/issues/2890 + noBlockDefinitions.add("minecraft:structure_block"); + noBlockDefinitions.add("minecraft:structure_void"); + AtomicInteger creativeNetId = new AtomicInteger(); CreativeItemRegistryPopulator.populate(palette, definitions, itemBuilder -> { ItemData item = itemBuilder.netId(creativeNetId.incrementAndGet()).build(); From 1b17c6bd8e03c8ebc9c8949b6ea7a5888e6dea43 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:50:26 -0400 Subject: [PATCH 357/897] Fix loom usage, and disconnect messages for all outdated clients (#5006) --- .../geysermc/geyser/network/UpstreamPacketHandler.java | 9 +++++---- gradle/libs.versions.toml | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) 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 e9c979b0c..adcaa2505 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -120,10 +120,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { session.disconnect(disconnectMessage); return false; } else if (protocolVersion < GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { - if (protocolVersion < Bedrock_v622.CODEC.getProtocolVersion()) { - // https://github.com/GeyserMC/Geyser/issues/4378 - session.getUpstream().getSession().setCodec(BedrockCompat.CODEC_LEGACY); - } + // A note on the following line: various older client versions have different forms of DisconnectPacket. + // Using only the latest BedrockCompat for such clients leads to inaccurate disconnect messages: https://github.com/GeyserMC/Geyser/issues/4378 + // This updates the BedrockCompat protocol if necessary: + session.getUpstream().getSession().setCodec(BedrockCompat.disconnectCompat(protocolVersion)); + session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.client", supportedVersions)); return false; } else { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f49de8d20..c564720a3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,9 +10,9 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol-connection = "3.0.0.Beta3-20240819.124045-12" -protocol-common = "3.0.0.Beta3-20240819.124045-10" -protocol-codec = "3.0.0.Beta3-20240819.124045-13" +protocol-connection = "3.0.0.Beta4-20240828.162251-1" +protocol-common = "3.0.0.Beta4-20240828.162251-1" +protocol-codec = "3.0.0.Beta4-20240828.162251-1" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1-20240806.235051-7" mcprotocollib = "1.21-20240725.013034-16" From 63e60bc93cfc50bdaafafde6f39f6ebbe3f3d93c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:09:36 -0400 Subject: [PATCH 358/897] Allow Bedrock players to sleep on Fabric Fixes #5001 --- .../entity/player/BedrockMovePlayerTranslator.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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/BedrockMovePlayerTranslator.java index 3faa3242b..6b403a99b 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/BedrockMovePlayerTranslator.java @@ -58,6 +58,14 @@ public class BedrockMovePlayerTranslator extends PacketTranslator Date: Fri, 30 Aug 2024 22:16:45 -0400 Subject: [PATCH 359/897] Ensure players aren't floating in their beds; improve Bedrock sleeping notifications --- .../entity/type/player/PlayerEntity.java | 14 +++++- .../type/player/SessionPlayerEntity.java | 2 +- .../geyser/network/UpstreamPacketHandler.java | 1 - .../player/BedrockMovePlayerTranslator.java | 2 +- .../java/JavaSystemChatTranslator.java | 43 ++++++++++++++++--- 5 files changed, 50 insertions(+), 12 deletions(-) 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 4c67b882f..b326f2e04 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 @@ -42,7 +42,11 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; -import org.cloudburstmc.protocol.bedrock.packet.*; +import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; +import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; @@ -278,7 +282,13 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { @Override public void setPosition(Vector3f position) { - super.setPosition(position.add(0, definition.offset(), 0)); + if (this.bedPosition != null) { + // As of Bedrock 1.21.22 and Fabric 1.21.1 + // Messes with Bedrock if we send this to the client itself, though. + super.setPosition(position.up(0.2f)); + } else { + super.setPosition(position.add(0, definition.offset(), 0)); + } } @Override 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 ccf2d25e6..f427b001a 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 @@ -140,7 +140,7 @@ public class SessionPlayerEntity extends PlayerEntity { if (valid) { // Don't update during session init session.getCollisionManager().updatePlayerBoundingBox(position); } - super.setPosition(position); + this.position = position.add(0, definition.offset(), 0); } /** 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 adcaa2505..5c48df1f9 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -29,7 +29,6 @@ import io.netty.buffer.Unpooled; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.compat.BedrockCompat; -import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.data.ExperimentData; import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm; import org.cloudburstmc.protocol.bedrock.data.ResourcePackType; 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/BedrockMovePlayerTranslator.java index 6b403a99b..ee80cac16 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/BedrockMovePlayerTranslator.java @@ -61,7 +61,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundSystemChatPacket packet) { - if (packet.getContent() instanceof TranslatableComponent component && component.key().equals("chat.disabled.missingProfileKey")) { - // We likely got this message as a response to a player trying to chat - // As there SHOULD be no false flags for this, print every time it shows up in chat. - if (Boolean.parseBoolean(System.getProperty("Geyser.PrintSecureChatInformation", "true"))) { - session.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.chat.secure_info_1", session.locale())); - session.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.chat.secure_info_2", session.locale(), "https://geysermc.link/secure-chat")); + if (packet.getContent() instanceof TranslatableComponent component) { + if (component.key().equals("chat.disabled.missingProfileKey")) { + // We likely got this message as a response to a player trying to chat + // As there SHOULD be no false flags for this, print every time it shows up in chat. + if (Boolean.parseBoolean(System.getProperty("Geyser.PrintSecureChatInformation", "true"))) { + session.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.chat.secure_info_1", session.locale())); + session.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.chat.secure_info_2", session.locale(), "https://geysermc.link/secure-chat")); + } + } else if (component.key().equals("sleep.players_sleeping")) { + if (component.arguments().size() == 2) { + // Hack FYI, but it allows Bedrock players to easily understand this information + // without it being covered up or saying the night is being slept through. + int numPlayersSleeping = ((Number) component.arguments().get(0).value()).intValue(); + int totalPlayersNeeded = ((Number) component.arguments().get(1).value()).intValue(); + LevelEventGenericPacket sleepInfoPacket = new LevelEventGenericPacket(); + sleepInfoPacket.setType(LevelEvent.SLEEPING_PLAYERS); + sleepInfoPacket.setTag(NbtMap.builder() + .putInt("ableToSleep", totalPlayersNeeded) + .putInt("overworldPlayerCount", totalPlayersNeeded) + .putInt("sleepingPlayerCount", numPlayersSleeping) + .build()); + session.sendUpstreamPacket(sleepInfoPacket); + } + } else if (component.key().equals("sleep.skipping_night")) { + LevelEventGenericPacket sleepInfoPacket = new LevelEventGenericPacket(); + sleepInfoPacket.setType(LevelEvent.SLEEPING_PLAYERS); + sleepInfoPacket.setTag(NbtMap.builder() + .putInt("ableToSleep", 1) + .putInt("overworldPlayerCount", 1) + .putInt("sleepingPlayerCount", 1) + .build()); + session.sendUpstreamPacket(sleepInfoPacket); } } From 1ab3f1f2e06de06720154f205a2f5bcf8402bf31 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 1 Sep 2024 15:34:53 -0400 Subject: [PATCH 360/897] Improve command registration timing on Velocity/BungeeCord (#5013) --- .../bungeecord/GeyserBungeePlugin.java | 28 +++++++++-------- .../neoforge/GeyserNeoForgeBootstrap.java | 1 + .../platform/spigot/GeyserSpigotPlugin.java | 2 +- .../velocity/GeyserVelocityPlugin.java | 30 ++++++++++--------- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index e2735c80e..7adfd488f 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -111,6 +111,21 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { if (geyser == null) { return; // Config did not load properly! } + + // After Geyser initialize for parity with other platforms. + var sourceConverter = new CommandSourceConverter<>( + CommandSender.class, + id -> getProxy().getPlayer(id), + () -> getProxy().getConsole(), + BungeeCommandSource::new + ); + CommandManager cloud = new BungeeCommandManager<>( + this, + ExecutionCoordinator.simpleCoordinator(), + sourceConverter + ); + this.commandRegistry = new CommandRegistry(geyser, cloud, false); // applying root permission would be a breaking change because we can't register permission defaults + // Big hack - Bungee does not provide us an event to listen to, so schedule a repeating // task that waits for a field to be filled which is set after the plugin enable // process is complete @@ -150,19 +165,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - } else { - var sourceConverter = new CommandSourceConverter<>( - CommandSender.class, - id -> getProxy().getPlayer(id), - () -> getProxy().getConsole(), - BungeeCommandSource::new - ); - CommandManager cloud = new BungeeCommandManager<>( - this, - ExecutionCoordinator.simpleCoordinator(), - sourceConverter - ); - this.commandRegistry = new CommandRegistry(geyser, cloud, false); // applying root permission would be a breaking change because we can't register permission defaults } // Force-disable query if enabled, or else Geyser won't enable 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 7d3b9dc5f..ad56eda39 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 @@ -82,6 +82,7 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { ); GeyserNeoForgeCommandRegistry registry = new GeyserNeoForgeCommandRegistry(getGeyser(), cloud); this.setCommandRegistry(registry); + // An auxiliary listener for registering undefined permissions belonging to commands. See javadocs for more info. NeoForge.EVENT_BUS.addListener(EventPriority.LOWEST, registry::onPermissionGatherForUndefined); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index c52927a83..a2d5c992b 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -181,7 +181,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return; } - // Create command manager early so we can add Geyser extension commands + // Register commands after Geyser initialization, but before the server starts. var sourceConverter = new CommandSourceConverter<>( CommandSender.class, Bukkit::getPlayer, diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 413355813..8fa47f569 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -109,6 +109,22 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this); this.geyserInjector = new GeyserVelocityInjector(proxyServer); + + // We need to register commands here, rather than in onGeyserEnable which is invoked during the appropriate ListenerBoundEvent. + // Reason: players can connect after a listener is bound, and a player join locks registration to the cloud CommandManager. + var sourceConverter = new CommandSourceConverter<>( + CommandSource.class, + id -> proxyServer.getPlayer(id).orElse(null), + proxyServer::getConsoleCommandSource, + VelocityCommandSource::new + ); + CommandManager cloud = new VelocityCommandManager<>( + container, + proxyServer, + ExecutionCoordinator.simpleCoordinator(), + sourceConverter + ); + this.commandRegistry = new CommandRegistry(geyser, cloud, false); // applying root permission would be a breaking change because we can't register permission defaults } @Override @@ -123,20 +139,6 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { } this.geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - } else { - var sourceConverter = new CommandSourceConverter<>( - CommandSource.class, - id -> proxyServer.getPlayer(id).orElse(null), - proxyServer::getConsoleCommandSource, - VelocityCommandSource::new - ); - CommandManager cloud = new VelocityCommandManager<>( - container, - proxyServer, - ExecutionCoordinator.simpleCoordinator(), - sourceConverter - ); - this.commandRegistry = new CommandRegistry(geyser, cloud, false); // applying root permission would be a breaking change because we can't register permission defaults } GeyserImpl.start(); From 74034f078338e3bb27092b72e9067e6f5dd3968a Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Mon, 2 Sep 2024 22:08:43 +0200 Subject: [PATCH 361/897] Fix PARTICLES_DRAGON_BLOCK_BREAK translation (#5015) --- .../protocol/java/level/JavaLevelEventTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index c10cfa018..f54de1b68 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -293,7 +293,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_GENERIC_SPAWN); - effectPacket.setData(61); + effectPacket.setData(65); } case PARTICLES_WATER_EVAPORATING -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EVAPORATE_WATER); From 65cb15400a4ac28d9a622004713b7ac59969e90e Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 3 Sep 2024 01:04:44 +0200 Subject: [PATCH 362/897] Fix: Broadcast port system property not being read on Geyser-Standalone (#4942) * this is supposed to work on standalone aswell * Update core/src/main/java/org/geysermc/geyser/GeyserImpl.java Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> * Update core/src/main/java/org/geysermc/geyser/GeyserImpl.java Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> * address review --------- Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../java/org/geysermc/geyser/GeyserImpl.java | 36 ++++++++++--------- .../geyser/network/netty/GeyserServer.java | 5 --- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 8febf4d21..bc6108abf 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -363,22 +363,6 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { } } - String broadcastPort = System.getProperty("geyserBroadcastPort", ""); - if (!broadcastPort.isEmpty()) { - int parsedPort; - try { - parsedPort = Integer.parseInt(broadcastPort); - if (parsedPort < 1 || parsedPort > 65535) { - throw new NumberFormatException("The broadcast port must be between 1 and 65535 inclusive!"); - } - } catch (NumberFormatException e) { - logger.error(String.format("Invalid broadcast port: %s! Defaulting to configured port.", broadcastPort + " (" + e.getMessage() + ")")); - parsedPort = config.getBedrock().port(); - } - config.getBedrock().setBroadcastPort(parsedPort); - logger.info("Broadcast port set from system property: " + parsedPort); - } - if (platformType != PlatformType.VIAPROXY) { boolean floodgatePresent = bootstrap.testFloodgatePluginPresent(); if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) { @@ -393,6 +377,26 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { } } + // Now that the Bedrock port may have been changed, also check the broadcast port (configurable on all platforms) + String broadcastPort = System.getProperty("geyserBroadcastPort", ""); + if (!broadcastPort.isEmpty()) { + try { + int parsedPort = Integer.parseInt(broadcastPort); + if (parsedPort < 1 || parsedPort > 65535) { + throw new NumberFormatException("The broadcast port must be between 1 and 65535 inclusive!"); + } + config.getBedrock().setBroadcastPort(parsedPort); + logger.info("Broadcast port set from system property: " + parsedPort); + } catch (NumberFormatException e) { + logger.error(String.format("Invalid broadcast port from system property: %s! Defaulting to configured port.", broadcastPort + " (" + e.getMessage() + ")")); + } + } + + // It's set to 0 only if no system property or manual config value was set + if (config.getBedrock().broadcastPort() == 0) { + config.getBedrock().setBroadcastPort(config.getBedrock().port()); + } + String remoteAddress = config.getRemote().address(); // Filters whether it is not an IP address or localhost, because otherwise it is not possible to find out an SRV entry. if (!remoteAddress.matches(IP_REGEX) && !remoteAddress.equalsIgnoreCase("localhost")) { diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index 5166bde4d..efbd8bdff 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -144,11 +144,6 @@ public final class GeyserServer { this.proxiedAddresses = null; } - // It's set to 0 only if no system property or manual config value was set - if (geyser.getConfig().getBedrock().broadcastPort() == 0) { - geyser.getConfig().getBedrock().setBroadcastPort(geyser.getConfig().getBedrock().port()); - } - this.broadcastPort = geyser.getConfig().getBedrock().broadcastPort(); } From f8884568ee717cda9314fb40ae0c7913bd601596 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 3 Sep 2024 00:54:50 -0400 Subject: [PATCH 363/897] Gradle: avoid cross-configuration and enable configuration-on-demand (#5012) --- ap/build.gradle.kts | 3 + bootstrap/bungeecord/build.gradle.kts | 5 ++ bootstrap/mod/build.gradle.kts | 4 ++ bootstrap/mod/fabric/build.gradle.kts | 5 ++ bootstrap/mod/neoforge/build.gradle.kts | 13 ++-- bootstrap/spigot/build.gradle.kts | 5 ++ bootstrap/standalone/build.gradle.kts | 1 + bootstrap/velocity/build.gradle.kts | 5 ++ bootstrap/viaproxy/build.gradle.kts | 4 ++ build-logic/build.gradle.kts | 5 ++ build-logic/settings.gradle.kts | 2 +- .../kotlin/geyser.base-conventions.gradle.kts | 69 ++++++++++++++----- .../main/kotlin/geyser.build-logic.gradle.kts | 45 ------------ .../geyser.modded-conventions.gradle.kts | 4 +- .../geyser.platform-conventions.gradle.kts | 19 ++++- build.gradle.kts | 52 +------------- common/build.gradle.kts | 1 + core/build.gradle.kts | 1 + gradle.properties | 1 + gradle/libs.versions.toml | 2 +- 20 files changed, 123 insertions(+), 123 deletions(-) delete mode 100644 build-logic/src/main/kotlin/geyser.build-logic.gradle.kts diff --git a/ap/build.gradle.kts b/ap/build.gradle.kts index e69de29bb..6c456c21b 100644 --- a/ap/build.gradle.kts +++ b/ap/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("geyser.base-conventions") +} diff --git a/bootstrap/bungeecord/build.gradle.kts b/bootstrap/bungeecord/build.gradle.kts index 5fe7ea3d1..1564b7f75 100644 --- a/bootstrap/bungeecord/build.gradle.kts +++ b/bootstrap/bungeecord/build.gradle.kts @@ -1,3 +1,8 @@ +plugins { + id("geyser.platform-conventions") + id("geyser.modrinth-uploading-conventions") +} + dependencies { api(projects.core) diff --git a/bootstrap/mod/build.gradle.kts b/bootstrap/mod/build.gradle.kts index 57f11b2c7..c43f123ec 100644 --- a/bootstrap/mod/build.gradle.kts +++ b/bootstrap/mod/build.gradle.kts @@ -1,3 +1,7 @@ +plugins { + id("geyser.modded-conventions") +} + architectury { common("neoforge", "fabric") } diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index fd9d7e99d..56bec322e 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -1,3 +1,8 @@ +plugins { + id("geyser.modded-conventions") + id("geyser.modrinth-uploading-conventions") +} + architectury { platformSetupLoomIde() fabric() diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts index 81a35a58b..4ab005b4f 100644 --- a/bootstrap/mod/neoforge/build.gradle.kts +++ b/bootstrap/mod/neoforge/build.gradle.kts @@ -1,13 +1,18 @@ -// This is provided by "org.cloudburstmc.math.mutable" too, so yeet. -// NeoForge's class loader is *really* annoying. -provided("org.cloudburstmc.math", "api") -provided("com.google.errorprone", "error_prone_annotations") +plugins { + id("geyser.modded-conventions") + id("geyser.modrinth-uploading-conventions") +} architectury { platformSetupLoomIde() neoForge() } +// This is provided by "org.cloudburstmc.math.mutable" too, so yeet. +// NeoForge's class loader is *really* annoying. +provided("org.cloudburstmc.math", "api") +provided("com.google.errorprone", "error_prone_annotations") + val includeTransitive: Configuration = configurations.getByName("includeTransitive") dependencies { diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index f680b1949..feabfdd7a 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -1,3 +1,8 @@ +plugins { + id("geyser.platform-conventions") + id("geyser.modrinth-uploading-conventions") +} + dependencies { api(projects.core) api(libs.erosion.bukkit.common) { diff --git a/bootstrap/standalone/build.gradle.kts b/bootstrap/standalone/build.gradle.kts index fd81dad63..b210693c1 100644 --- a/bootstrap/standalone/build.gradle.kts +++ b/bootstrap/standalone/build.gradle.kts @@ -2,6 +2,7 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCach plugins { application + id("geyser.platform-conventions") } val terminalConsoleVersion = "1.2.0" diff --git a/bootstrap/velocity/build.gradle.kts b/bootstrap/velocity/build.gradle.kts index 93e0c9c93..05035e271 100644 --- a/bootstrap/velocity/build.gradle.kts +++ b/bootstrap/velocity/build.gradle.kts @@ -1,3 +1,8 @@ +plugins { + id("geyser.platform-conventions") + id("geyser.modrinth-uploading-conventions") +} + dependencies { annotationProcessor(libs.velocity.api) api(projects.core) diff --git a/bootstrap/viaproxy/build.gradle.kts b/bootstrap/viaproxy/build.gradle.kts index 254787743..c13862a27 100644 --- a/bootstrap/viaproxy/build.gradle.kts +++ b/bootstrap/viaproxy/build.gradle.kts @@ -1,3 +1,7 @@ +plugins { + id("geyser.platform-conventions") +} + dependencies { api(projects.core) diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 190386667..b87490880 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -12,9 +12,14 @@ repositories { } dependencies { + // This is for the LibsAccessor.kt hack // this is OK as long as the same version catalog is used in the main build and build-logic // see https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) + + // This is for applying plugins, and using the version from the libs.versions.toml + // Unfortunately they still need to be applied by their string name in the convention scripts. + implementation(libs.lombok) implementation(libs.indra) implementation(libs.shadow) implementation(libs.architectury.plugin) diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts index 63bde189b..bd4560d11 100644 --- a/build-logic/settings.gradle.kts +++ b/build-logic/settings.gradle.kts @@ -8,4 +8,4 @@ dependencyResolutionManagement { } } -rootProject.name = "build-logic" \ No newline at end of file +rootProject.name = "build-logic" diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 950c0184b..093f0a8c0 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -3,9 +3,10 @@ plugins { id("net.kyori.indra") } -dependencies { - compileOnly("org.checkerframework", "checker-qual", "3.19.0") -} +val rootProperties: Map = project.rootProject.properties +group = rootProperties["group"] as String + "." + rootProperties["id"] as String +version = rootProperties["version"] as String +description = rootProperties["description"] as String indra { github("GeyserMC", "Geyser") { @@ -20,18 +21,52 @@ indra { } } -tasks { - processResources { - // Spigot, BungeeCord, Velocity, Fabric, ViaProxy, NeoForge - filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/neoforge.mods.toml")) { - expand( - "id" to "geyser", - "name" to "Geyser", - "version" to project.version, - "description" to project.description, - "url" to "https://geysermc.org", - "author" to "GeyserMC" - ) - } +dependencies { + compileOnly("org.checkerframework", "checker-qual", libs.checker.qual.get().version) +} + +repositories { + // mavenLocal() + + mavenCentral() + + // Floodgate, Cumulus etc. + maven("https://repo.opencollab.dev/main") + + // Paper, Velocity + maven("https://repo.papermc.io/repository/maven-public") + + // Spigot + maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") { + mavenContent { snapshotsOnly() } } -} \ No newline at end of file + + // BungeeCord + maven("https://oss.sonatype.org/content/repositories/snapshots") { + mavenContent { snapshotsOnly() } + } + + // NeoForge + maven("https://maven.neoforged.net/releases") { + mavenContent { releasesOnly() } + } + + // Minecraft + maven("https://libraries.minecraft.net") { + name = "minecraft" + mavenContent { releasesOnly() } + } + + // ViaVersion + maven("https://repo.viaversion.com") { + name = "viaversion" + } + + // Jitpack for e.g. MCPL + maven("https://jitpack.io") { + content { includeGroupByRegex("com\\.github\\..*") } + } + + // For Adventure snapshots + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") +} diff --git a/build-logic/src/main/kotlin/geyser.build-logic.gradle.kts b/build-logic/src/main/kotlin/geyser.build-logic.gradle.kts deleted file mode 100644 index b6168507e..000000000 --- a/build-logic/src/main/kotlin/geyser.build-logic.gradle.kts +++ /dev/null @@ -1,45 +0,0 @@ -repositories { - // mavenLocal() - - mavenCentral() - - // Floodgate, Cumulus etc. - maven("https://repo.opencollab.dev/main") - - // Paper, Velocity - maven("https://repo.papermc.io/repository/maven-public") - - // Spigot - maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") { - mavenContent { snapshotsOnly() } - } - - // BungeeCord - maven("https://oss.sonatype.org/content/repositories/snapshots") { - mavenContent { snapshotsOnly() } - } - - // NeoForge - maven("https://maven.neoforged.net/releases") { - mavenContent { releasesOnly() } - } - - // Minecraft - maven("https://libraries.minecraft.net") { - name = "minecraft" - mavenContent { releasesOnly() } - } - - // ViaVersion - maven("https://repo.viaversion.com") { - name = "viaversion" - } - - // Jitpack for e.g. MCPL - maven("https://jitpack.io") { - content { includeGroupByRegex("com\\.github\\..*") } - } - - // For Adventure snapshots - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") -} diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts index 8584c13d4..779d6446a 100644 --- a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts @@ -2,11 +2,9 @@ import net.fabricmc.loom.task.RemapJarTask import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.maven plugins { - id("geyser.build-logic") - id("geyser.publish-conventions") + id("geyser.platform-conventions") id("architectury-plugin") id("dev.architectury.loom") } diff --git a/build-logic/src/main/kotlin/geyser.platform-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.platform-conventions.gradle.kts index 410e67404..7a342783b 100644 --- a/build-logic/src/main/kotlin/geyser.platform-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.platform-conventions.gradle.kts @@ -1,3 +1,20 @@ plugins { id("geyser.publish-conventions") -} \ No newline at end of file + id("io.freefair.lombok") +} + +tasks { + processResources { + // Spigot, BungeeCord, Velocity, Fabric, ViaProxy, NeoForge + filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/neoforge.mods.toml")) { + expand( + "id" to "geyser", + "name" to "Geyser", + "version" to project.version, + "description" to project.description, + "url" to "https://geysermc.org", + "author" to "GeyserMC" + ) + } + } +} diff --git a/build.gradle.kts b/build.gradle.kts index dfbf9837f..7f700a2f6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,55 +1,5 @@ plugins { - `java-library` // Ensure AP works in eclipse (no effect on other IDEs) eclipse - id("geyser.build-logic") - alias(libs.plugins.lombok) apply false + id("geyser.base-conventions") } - -allprojects { - group = properties["group"] as String + "." + properties["id"] as String - version = properties["version"] as String - description = properties["description"] as String -} - -val basePlatforms = setOf( - projects.bungeecord, - projects.spigot, - projects.standalone, - projects.velocity, - projects.viaproxy -).map { it.dependencyProject } - -val moddedPlatforms = setOf( - projects.fabric, - projects.neoforge, - projects.mod -).map { it.dependencyProject } - -val modrinthPlatforms = setOf( - projects.bungeecord, - projects.fabric, - projects.neoforge, - projects.spigot, - projects.velocity -).map { it.dependencyProject } - -subprojects { - apply { - plugin("java-library") - plugin("io.freefair.lombok") - plugin("geyser.build-logic") - } - - when (this) { - in basePlatforms -> plugins.apply("geyser.platform-conventions") - in moddedPlatforms -> plugins.apply("geyser.modded-conventions") - else -> plugins.apply("geyser.base-conventions") - } - - // Not combined with platform-conventions as that also contains - // platforms which we cant publish to modrinth - if (modrinthPlatforms.contains(this)) { - plugins.apply("geyser.modrinth-uploading-conventions") - } -} \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts index efba08c8d..166ffe9f5 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("geyser.publish-conventions") + id("io.freefair.lombok") } dependencies { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 8d022271b..d30e60298 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -3,6 +3,7 @@ plugins { idea alias(libs.plugins.blossom) id("geyser.publish-conventions") + id("io.freefair.lombok") } dependencies { diff --git a/gradle.properties b/gradle.properties index 814529d6c..dd1bc915a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,7 @@ # Gradle settings org.gradle.jvmargs=-Xmx4G org.gradle.daemon=false +org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.caching=true org.gradle.vfs.watch=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c564720a3..f2a29ee74 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -134,6 +134,7 @@ protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-con math = { group = "org.cloudburstmc.math", name = "immutable", version = "2.0" } # plugins +lombok = { group = "io.freefair.gradle", name = "lombok-plugin", version.ref = "lombok" } indra = { group = "net.kyori", name = "indra-common", version.ref = "indra" } shadow = { group = "com.github.johnrengelman", name = "shadow", version.ref = "shadow" } architectury-plugin = { group = "architectury-plugin", name = "architectury-plugin.gradle.plugin", version.ref = "architectury-plugin" } @@ -141,7 +142,6 @@ architectury-loom = { group = "dev.architectury.loom", name = "dev.architectury. minotaur = { group = "com.modrinth.minotaur", name = "Minotaur", version.ref = "minotaur" } [plugins] -lombok = { id = "io.freefair.lombok", version.ref = "lombok" } indra = { id = "net.kyori.indra", version.ref = "indra" } blossom = { id = "net.kyori.blossom", version.ref = "blossom" } From 9dad34d0a82a7cb47b61016c15bb5e51dbcc2860 Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Tue, 3 Sep 2024 22:25:49 +0200 Subject: [PATCH 364/897] Unhardcode PARTICLES_DRAGON_BLOCK_BREAK id (#5018) --- .../protocol/java/level/JavaLevelEventTranslator.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index f54de1b68..5b4ff1de7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -291,10 +291,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { - effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_GENERIC_SPAWN); - effectPacket.setData(65); - } + case PARTICLES_DRAGON_BLOCK_BREAK -> effectPacket.setType(ParticleType.DRAGON_DESTROY_BLOCK); case PARTICLES_WATER_EVAPORATING -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EVAPORATE_WATER); effectPacket.setPosition(pos.add(-0.5f, 0.5f, -0.5f)); From 34f5d71e58ff0b07fafdefc1aed5169f3eb8e00f Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 6 Sep 2024 13:48:00 -0400 Subject: [PATCH 365/897] Validate sleep message arguments (#5023) --- .../java/JavaSystemChatTranslator.java | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java index 7e7a97a4b..27481aa26 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java @@ -25,7 +25,10 @@ package org.geysermc.geyser.translator.protocol.java; +import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TranslatableComponent; +import net.kyori.adventure.text.TranslationArgument; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket; @@ -55,16 +58,18 @@ public class JavaSystemChatTranslator extends PacketTranslator Date: Sat, 7 Sep 2024 22:29:27 -0400 Subject: [PATCH 366/897] Cancel Erosion futures when disconnecting/switching servers (#5026) --- .../erosion/ErosionCancellationException.java | 34 ++++++++++++ .../GeyserboundHandshakePacketHandler.java | 2 +- .../erosion/GeyserboundPacketHandlerImpl.java | 13 ++++- .../geyser/level/GeyserWorldManager.java | 9 ++++ .../registry/PacketTranslatorRegistry.java | 3 ++ .../geyser/session/GeyserSession.java | 11 ++-- .../protocol/java/JavaLoginTranslator.java | 6 --- .../JavaStartConfigurationTranslator.java | 52 +++++++++++++++++++ 8 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/erosion/ErosionCancellationException.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaStartConfigurationTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/erosion/ErosionCancellationException.java b/core/src/main/java/org/geysermc/geyser/erosion/ErosionCancellationException.java new file mode 100644 index 000000000..ae283895b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/erosion/ErosionCancellationException.java @@ -0,0 +1,34 @@ +/* + * 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.erosion; + +import java.io.Serial; +import java.util.concurrent.CancellationException; + +public class ErosionCancellationException extends CancellationException { + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java index 0b4f03643..88a7e0cd3 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java @@ -42,7 +42,6 @@ public final class GeyserboundHandshakePacketHandler extends AbstractGeyserbound public void handleHandshake(GeyserboundHandshakePacket packet) { boolean useTcp = packet.getTransportType().getSocketAddress() == null; GeyserboundPacketHandlerImpl handler = new GeyserboundPacketHandlerImpl(session, useTcp ? new GeyserErosionPacketSender(session) : new NettyPacketSender<>()); - session.setErosionHandler(handler); if (!useTcp) { if (session.getGeyser().getErosionUnixListener() == null) { session.disconnect("Erosion configurations using Unix socket handling are not supported on this hardware!"); @@ -52,6 +51,7 @@ public final class GeyserboundHandshakePacketHandler extends AbstractGeyserbound } else { handler.onConnect(); } + session.setErosionHandler(handler); session.ensureInEventLoop(() -> session.getChunkCache().clear()); } diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index c8cbe384b..7202db449 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -171,10 +171,10 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke @Override public void handleHandshake(GeyserboundHandshakePacket packet) { - this.close(); var handler = new GeyserboundHandshakePacketHandler(this.session); session.setErosionHandler(handler); handler.handleHandshake(packet); + this.close(); } @Override @@ -198,6 +198,17 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke public void close() { this.packetSender.close(); + + if (pendingLookup != null) { + pendingLookup.completeExceptionally(new ErosionCancellationException()); + } + if (pendingBatchLookup != null) { + pendingBatchLookup.completeExceptionally(new ErosionCancellationException()); + } + if (pickBlockLookup != null) { + pickBlockLookup.completeExceptionally(new ErosionCancellationException()); + } + asyncPendingLookups.forEach(($, future) -> future.completeExceptionally(new ErosionCancellationException())); } public int getNextTransactionId() { diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 9cf2c0179..befcfa4b7 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -35,6 +35,7 @@ import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockRequestPac import org.geysermc.erosion.packet.backendbound.BackendboundBlockRequestPacket; import org.geysermc.erosion.packet.backendbound.BackendboundPickBlockPacket; import org.geysermc.erosion.util.BlockPositionIterator; +import org.geysermc.geyser.erosion.ErosionCancellationException; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -49,6 +50,8 @@ public class GeyserWorldManager extends WorldManager { var erosionHandler = session.getErosionHandler().getAsActive(); if (erosionHandler == null) { return session.getChunkCache().getBlockAt(x, y, z); + } else if (session.isClosed()) { + throw new ErosionCancellationException(); } CompletableFuture future = new CompletableFuture<>(); // Boxes erosionHandler.setPendingLookup(future); @@ -61,6 +64,8 @@ public class GeyserWorldManager extends WorldManager { var erosionHandler = session.getErosionHandler().getAsActive(); if (erosionHandler == null) { return super.getBlockAtAsync(session, x, y, z); + } else if (session.isClosed()) { + return CompletableFuture.failedFuture(new ErosionCancellationException()); } CompletableFuture future = new CompletableFuture<>(); // Boxes int transactionId = erosionHandler.getNextTransactionId(); @@ -74,6 +79,8 @@ public class GeyserWorldManager extends WorldManager { var erosionHandler = session.getErosionHandler().getAsActive(); if (erosionHandler == null) { return super.getBlocksAt(session, iter); + } else if (session.isClosed()) { + throw new ErosionCancellationException(); } CompletableFuture future = new CompletableFuture<>(); erosionHandler.setPendingBatchLookup(future); @@ -124,6 +131,8 @@ public class GeyserWorldManager extends WorldManager { var erosionHandler = session.getErosionHandler().getAsActive(); if (erosionHandler == null) { return super.getPickItemComponents(session, x, y, z, addNbtData); + } else if (session.isClosed()) { + return CompletableFuture.failedFuture(new ErosionCancellationException()); } CompletableFuture> future = new CompletableFuture<>(); erosionHandler.setPickBlockLookup(future); diff --git a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java index 9a5b43816..b31f2b4f0 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java @@ -31,6 +31,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.Clien import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket; import io.netty.channel.EventLoop; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.erosion.ErosionCancellationException; import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -87,6 +88,8 @@ public class PacketTranslatorRegistry extends AbstractMappedRegistry { try { runnable.run(); + } catch (ErosionCancellationException e) { + geyser.getLogger().debug("Caught ErosionCancellationException"); } catch (Throwable e) { geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); } @@ -1230,6 +1233,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { if (!closed) { runnable.run(); } + } catch (ErosionCancellationException e) { + geyser.getLogger().debug("Caught ErosionCancellationException"); } catch (Throwable e) { geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index a6d6e6c70..6470a5f0a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -33,7 +33,6 @@ import org.geysermc.erosion.Constants; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; -import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -57,11 +56,6 @@ public class JavaLoginTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundStartConfigurationPacket packet) { + var erosionHandler = session.getErosionHandler(); + if (erosionHandler.isActive()) { + // Set new handler before closing + session.setErosionHandler(new GeyserboundHandshakePacketHandler(session)); + erosionHandler.close(); + } + } + + @Override + public boolean shouldExecuteInEventLoop() { + // Execute outside of event loop to cancel any pending erosion futures + return false; + } +} From c28522af6e91268c223941e842989c1dfc16cd64 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Sun, 8 Sep 2024 23:06:36 -0400 Subject: [PATCH 367/897] Delay clear weather packets (#5030) --- .../geyser/session/GeyserSession.java | 58 ++++++++++++++++++- .../protocol/java/JavaRespawnTranslator.java | 17 +----- .../java/level/JavaGameEventTranslator.java | 37 ++---------- .../geysermc/geyser/util/DimensionUtils.java | 16 +---- 4 files changed, 65 insertions(+), 63 deletions(-) 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 a8b8480fb..f7ffcdd0e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -66,6 +66,7 @@ import org.cloudburstmc.protocol.bedrock.data.ExperimentData; import org.cloudburstmc.protocol.bedrock.data.GamePublishSetting; import org.cloudburstmc.protocol.bedrock.data.GameRuleData; import org.cloudburstmc.protocol.bedrock.data.GameType; +import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.PlayerPermission; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.SpawnBiomeType; @@ -85,6 +86,7 @@ import org.cloudburstmc.protocol.bedrock.packet.CreativeContentPacket; import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket; import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket; @@ -570,13 +572,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * Caches current rain status. */ - @Setter private boolean raining = false; /** * Caches current thunder status. */ - @Setter private boolean thunder = false; /** @@ -2007,6 +2007,60 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { }; } + /** + * Sends a packet to update rain strength. + * Stops rain if strength is 0. + * + * @param strength value between 0 and 1 + */ + public void updateRain(float strength) { + this.raining = strength > 0; + + LevelEventPacket rainPacket = new LevelEventPacket(); + rainPacket.setType(this.raining ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING); + rainPacket.setData((int) (strength * 65535)); + rainPacket.setPosition(Vector3f.ZERO); + + if (this.raining) { + sendUpstreamPacket(rainPacket); + } else { + // The bedrock client might ignore this packet if it is sent in the same tick as another rain packet + // https://github.com/GeyserMC/Geyser/issues/3679 + scheduleInEventLoop(() -> { + if (!this.raining) { + sendUpstreamPacket(rainPacket); + } + }, 100, TimeUnit.MILLISECONDS); + } + } + + /** + * Sends a packet to update thunderstorm strength. + * Stops thunderstorm if strength is 0. + * + * @param strength value between 0 and 1 + */ + public void updateThunder(float strength) { + this.thunder = strength > 0; + + LevelEventPacket thunderPacket = new LevelEventPacket(); + thunderPacket.setType(this.thunder ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM); + thunderPacket.setData((int) (strength * 65535)); + thunderPacket.setPosition(Vector3f.ZERO); + + if (this.thunder) { + sendUpstreamPacket(thunderPacket); + } else { + // The bedrock client might ignore this packet if it is sent in the same tick as another thunderstorm packet + // https://github.com/GeyserMC/Geyser/issues/3679 + scheduleInEventLoop(() -> { + if (!this.thunder) { + sendUpstreamPacket(thunderPacket); + } + }, 100, TimeUnit.MILLISECONDS); + } + } + @Override public @NonNull String bedrockUsername() { return authData.name(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index ccd93ac97..5c477f23e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.translator.protocol.java; -import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.data.LevelEvent; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; @@ -76,21 +73,11 @@ public class JavaRespawnTranslator extends PacketTranslator { - // Strength of rainstorms and thunderstorms is a 0-1 float on Java, while on Bedrock it is a 0-65535 int - private static final int MAX_STORM_STRENGTH = 65535; - @Override public void translate(GeyserSession session, ClientboundGameEventPacket packet) { PlayerEntity entity = session.getPlayerEntity(); @@ -65,42 +60,20 @@ public class JavaGameEventTranslator extends PacketTranslator 0f; - LevelEventPacket changeRainPacket = new LevelEventPacket(); - changeRainPacket.setType(isCurrentlyRaining ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING); // This is the rain strength on LevelEventType.START_RAINING, but can be any value on LevelEventType.STOP_RAINING - changeRainPacket.setData((int) (rainStrength * MAX_STORM_STRENGTH)); - changeRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeRainPacket); - session.setRaining(isCurrentlyRaining); + float rainStrength = ((RainStrengthValue) packet.getValue()).getStrength(); + session.updateRain(rainStrength); break; case THUNDER_STRENGTH: // See above, same process float thunderStrength = ((ThunderStrengthValue) packet.getValue()).getStrength(); - boolean isCurrentlyThundering = thunderStrength > 0f; - LevelEventPacket changeThunderPacket = new LevelEventPacket(); - changeThunderPacket.setType(isCurrentlyThundering ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM); - changeThunderPacket.setData((int) (thunderStrength * MAX_STORM_STRENGTH)); - changeThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeThunderPacket); - session.setThunder(isCurrentlyThundering); + session.updateThunder(thunderStrength); break; case CHANGE_GAMEMODE: GameMode gameMode = (GameMode) packet.getValue(); diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index f043631b6..8dc94a165 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -28,11 +28,9 @@ package org.geysermc.geyser.util; import org.checkerframework.checker.nullness.qual.Nullable; 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.packet.ChangeDimensionPacket; import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEffectPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; import org.cloudburstmc.protocol.bedrock.packet.StopSoundPacket; @@ -89,18 +87,8 @@ public class DimensionUtils { entityEffects.clear(); // Always reset weather, as it sometimes suddenly starts raining. See https://github.com/GeyserMC/Geyser/issues/3679 - LevelEventPacket stopRainPacket = new LevelEventPacket(); - stopRainPacket.setType(LevelEvent.STOP_RAINING); - stopRainPacket.setData(0); - stopRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopRainPacket); - session.setRaining(false); - LevelEventPacket stopThunderPacket = new LevelEventPacket(); - stopThunderPacket.setType(LevelEvent.STOP_THUNDERSTORM); - stopThunderPacket.setData(0); - stopThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopThunderPacket); - session.setThunder(false); + session.updateRain(0); + session.updateThunder(0); finalizeDimensionSwitch(session, player); From 723840c7fc13dc468f5bd3ae84b89ef80f9225f1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:42:57 -0400 Subject: [PATCH 368/897] More clear message when logging in without a paid Java account --- .../org/geysermc/geyser/session/GeyserSession.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 f7ffcdd0e..9a50d7acb 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -40,6 +40,7 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; import net.kyori.adventure.key.Key; +import net.raphimc.minecraftauth.responsehandler.exception.MinecraftRequestException; import net.raphimc.minecraftauth.step.java.StepMCProfile; import net.raphimc.minecraftauth.step.java.StepMCToken; import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession; @@ -231,6 +232,7 @@ import java.util.Queue; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -877,7 +879,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return task.getAuthentication().handle((result, ex) -> { if (ex != null) { geyser.getLogger().error("Failed to log in with Microsoft code!", ex); - disconnect(ex.toString()); + if (ex instanceof CompletionException ce + && ce.getCause() instanceof MinecraftRequestException mre + && mre.getResponse().getStatusCode() == 404) { + // Player is trying to join with a Microsoft account that doesn't have Java Edition purchased + disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", locale())); + } else { + disconnect(ex.toString()); + } return false; } From 14cf104cff850dc06438358b5415af32d43d8bd2 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 9 Sep 2024 18:23:19 -0400 Subject: [PATCH 369/897] Do not send thunder strength if not raining (#5031) * Do not send thunder strength if not raining * Address review * Minor optimization --- .../geyser/session/GeyserSession.java | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) 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 9a50d7acb..4589afe23 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -572,14 +572,16 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private float walkSpeed; /** - * Caches current rain status. + * Caches current rain strength. + * Value between 0 and 1. */ - private boolean raining = false; + private float rainStrength = 0.0f; /** - * Caches current thunder status. + * Caches current thunder strength. + * Value between 0 and 1. */ - private boolean thunder = false; + private float thunderStrength = 0.0f; /** * Stores a map of all statistics sent from the server. @@ -2023,23 +2025,30 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * @param strength value between 0 and 1 */ public void updateRain(float strength) { - this.raining = strength > 0; + boolean wasRaining = isRaining(); + this.rainStrength = strength; LevelEventPacket rainPacket = new LevelEventPacket(); - rainPacket.setType(this.raining ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING); + rainPacket.setType(isRaining() ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING); rainPacket.setData((int) (strength * 65535)); rainPacket.setPosition(Vector3f.ZERO); + sendUpstreamPacket(rainPacket); - if (this.raining) { - sendUpstreamPacket(rainPacket); - } else { - // The bedrock client might ignore this packet if it is sent in the same tick as another rain packet - // https://github.com/GeyserMC/Geyser/issues/3679 - scheduleInEventLoop(() -> { - if (!this.raining) { - sendUpstreamPacket(rainPacket); - } - }, 100, TimeUnit.MILLISECONDS); + // Keep thunder in sync with rain when starting/stopping a storm + if ((wasRaining != isRaining()) && isThunder()) { + if (isRaining()) { + LevelEventPacket thunderPacket = new LevelEventPacket(); + thunderPacket.setType(LevelEvent.START_THUNDERSTORM); + thunderPacket.setData((int) (this.thunderStrength * 65535)); + thunderPacket.setPosition(Vector3f.ZERO); + sendUpstreamPacket(thunderPacket); + } else { + LevelEventPacket thunderPacket = new LevelEventPacket(); + thunderPacket.setType(LevelEvent.STOP_THUNDERSTORM); + thunderPacket.setData(0); + thunderPacket.setPosition(Vector3f.ZERO); + sendUpstreamPacket(thunderPacket); + } } } @@ -2050,24 +2059,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * @param strength value between 0 and 1 */ public void updateThunder(float strength) { - this.thunder = strength > 0; + this.thunderStrength = strength; + + // Do not send thunder packet if not raining + // The bedrock client will start raining automatically when updating thunder strength + // https://github.com/GeyserMC/Geyser/issues/3679 + if (!isRaining()) { + return; + } LevelEventPacket thunderPacket = new LevelEventPacket(); - thunderPacket.setType(this.thunder ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM); + thunderPacket.setType(isThunder() ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM); thunderPacket.setData((int) (strength * 65535)); thunderPacket.setPosition(Vector3f.ZERO); + sendUpstreamPacket(thunderPacket); + } - if (this.thunder) { - sendUpstreamPacket(thunderPacket); - } else { - // The bedrock client might ignore this packet if it is sent in the same tick as another thunderstorm packet - // https://github.com/GeyserMC/Geyser/issues/3679 - scheduleInEventLoop(() -> { - if (!this.thunder) { - sendUpstreamPacket(thunderPacket); - } - }, 100, TimeUnit.MILLISECONDS); - } + public boolean isRaining() { + return this.rainStrength > 0; + } + + public boolean isThunder() { + return this.thunderStrength > 0; } @Override From 73f7259b6dd508680582418bbb7963ad0b460907 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 10 Sep 2024 20:10:31 +0000 Subject: [PATCH 370/897] Add proper text component parsing from NBT (#5029) * Attempt creating a simple NBT text component parser * Fix style merging * Rename TextDecoration to ChatDecoration, use better style deserialization in ChatDecoration * Remove unused code * containsKey optimisations, update documentation, improve getStyleFromNbtMap performance slightly, more slight tweaks * Remove unnecessary deserializeStyle method --- .../geyser/item/enchantment/Enchantment.java | 2 +- .../geysermc/geyser/level/JukeboxSong.java | 2 +- .../geyser/session/cache/RegistryCache.java | 4 +- ...extDecoration.java => ChatDecoration.java} | 34 ++---- .../translator/text/MessageTranslator.java | 103 ++++++++++++++++-- 5 files changed, 105 insertions(+), 40 deletions(-) rename core/src/main/java/org/geysermc/geyser/text/{TextDecoration.java => ChatDecoration.java} (74%) 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 3c0caa60c..5cac45534 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 @@ -69,7 +69,7 @@ public record Enchantment(String identifier, // 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(data) : null; + String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(context.session(), data) : null; return new Enchantment(context.id().asString(), effects, supportedItems, maxLevel, description, anvilCost, exclusiveSet, bedrockEnchantment); 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 b00dc9f98..86d66e209 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java +++ b/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java @@ -44,7 +44,7 @@ public record JukeboxSong(String soundEvent, String description) { soundEvent = ""; GeyserImpl.getInstance().getLogger().debug("Sound event for " + context.id() + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject); } - String description = MessageTranslator.deserializeDescription(data); + String description = MessageTranslator.deserializeDescription(context.session(), data); return new JukeboxSong(soundEvent, description); } } 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 a393d461d..4a4167f15 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 @@ -49,7 +49,7 @@ 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.session.cache.registry.SimpleJavaRegistry; -import org.geysermc.geyser.text.TextDecoration; +import org.geysermc.geyser.text.ChatDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; @@ -78,7 +78,7 @@ public final class RegistryCache { private static final Map>> REGISTRIES = new HashMap<>(); static { - register("chat_type", cache -> cache.chatTypes, TextDecoration::readChatType); + register("chat_type", cache -> cache.chatTypes, ChatDecoration::readChatType); register("dimension_type", cache -> cache.dimensions, JavaDimension::read); register("enchantment", cache -> cache.enchantments, Enchantment::read); register("jukebox_song", cache -> cache.jukeboxSongs, JukeboxSong::read); diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/ChatDecoration.java similarity index 74% rename from core/src/main/java/org/geysermc/geyser/text/TextDecoration.java rename to core/src/main/java/org/geysermc/geyser/text/ChatDecoration.java index 94aec22ef..fc7597cfd 100644 --- a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatDecoration.java @@ -25,17 +25,19 @@ package org.geysermc.geyser.text; -import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType; import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatTypeDecoration; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; -public record TextDecoration(String translationKey, List parameters, Style deserializedStyle) implements ChatTypeDecoration { +public record ChatDecoration(String translationKey, List parameters, Style deserializedStyle) implements ChatTypeDecoration { @Override public NbtMap style() { @@ -53,38 +55,22 @@ public record TextDecoration(String translationKey, List parameters, String translationKey = chat.getString("translation_key"); NbtMap styleTag = chat.getCompound("style"); - Style style = deserializeStyle(styleTag); + Style style = MessageTranslator.getStyleFromNbtMap(styleTag); List parameters = new ArrayList<>(); List parametersNbt = chat.getList("parameters", NbtType.STRING); for (String parameter : parametersNbt) { parameters.add(ChatTypeDecoration.Parameter.valueOf(parameter.toUpperCase(Locale.ROOT))); } - return new ChatType(new TextDecoration(translationKey, parameters, style), null); + return new ChatType(new ChatDecoration(translationKey, parameters, style), null); } return new ChatType(null, null); } public static Style getStyle(ChatTypeDecoration decoration) { - if (decoration instanceof TextDecoration textDecoration) { - return textDecoration.deserializedStyle(); + if (decoration instanceof ChatDecoration chatDecoration) { + return chatDecoration.deserializedStyle(); } - return deserializeStyle(decoration.style()); - } - - private static Style deserializeStyle(NbtMap styleTag) { - Style.Builder builder = Style.style(); - if (!styleTag.isEmpty()) { - String color = styleTag.getString("color", null); - if (color != null) { - builder.color(NamedTextColor.NAMES.value(color)); - } - //TODO implement the rest - boolean italic = styleTag.getBoolean("italic"); - if (italic) { - builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC); - } - } - return builder.build(); + return MessageTranslator.getStyleFromNbtMap(decoration.style()); } } 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 152bf4160..0547a21c9 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 @@ -26,16 +26,21 @@ package org.geysermc.geyser.translator.text; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.JoinConfiguration; import net.kyori.adventure.text.ScoreComponent; import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.flattener.ComponentFlattener; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.renderer.TranslatableComponentRenderer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.CharacterAndFormat; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.packet.TextPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; @@ -341,16 +346,16 @@ public class MessageTranslator { // Though, Bedrock cannot care about the signed stuff. TranslatableComponent.Builder withDecoration = Component.translatable() .key(chat.translationKey()) - .style(TextDecoration.getStyle(chat)); + .style(ChatDecoration.getStyle(chat)); List parameters = chat.parameters(); List args = new ArrayList<>(3); - if (parameters.contains(TextDecoration.Parameter.TARGET)) { + if (parameters.contains(ChatDecoration.Parameter.TARGET)) { args.add(targetName); } - if (parameters.contains(TextDecoration.Parameter.SENDER)) { + if (parameters.contains(ChatDecoration.Parameter.SENDER)) { args.add(sender); } - if (parameters.contains(TextDecoration.Parameter.CONTENT)) { + if (parameters.contains(ChatDecoration.Parameter.CONTENT)) { args.add(message); } withDecoration.arguments(args); @@ -426,17 +431,91 @@ public class MessageTranslator { } /** - * Deserialize an NbtMap provided from a registry into a string. + * Deserialize an NbtMap with a description text component (usually provided from a registry) into a Bedrock-formatted string. */ - // This may be a Component in the future. - public static String deserializeDescription(NbtMap tag) { + public static String deserializeDescription(GeyserSession session, NbtMap tag) { NbtMap description = tag.getCompound("description"); - String translate = description.getString("translate", null); - if (translate == null) { - GeyserImpl.getInstance().getLogger().debug("Don't know how to read description! " + tag); - return ""; + Component parsed = componentFromNbtTag(description); + return convertMessage(session, parsed); + } + + public static Component componentFromNbtTag(Object nbtTag) { + return componentFromNbtTag(nbtTag, Style.empty()); + } + + private static Component componentFromNbtTag(Object nbtTag, Style style) { + if (nbtTag instanceof String literal) { + return Component.text(literal).style(style); + } else if (nbtTag instanceof List list) { + return Component.join(JoinConfiguration.noSeparators(), componentsFromNbtList(list, style)); + } else if (nbtTag instanceof NbtMap map) { + Component component = null; + String text = map.getString("text", null); + if (text != null) { + component = Component.text(text); + } else { + String translateKey = map.getString("translate", null); + if (translateKey != null) { + String fallback = map.getString("fallback", ""); + List args = new ArrayList<>(); + + Object with = map.get("with"); + if (with instanceof List list) { + args = componentsFromNbtList(list, style); + } else if (with != null) { + args.add(componentFromNbtTag(with, style)); + } + component = Component.translatable(translateKey, fallback, args); + } + } + + if (component != null) { + Style newStyle = getStyleFromNbtMap(map, style); + component = component.style(newStyle); + + Object extra = map.get("extra"); + if (extra != null) { + component = component.append(componentFromNbtTag(extra, newStyle)); + } + + return component; + } } - return translate; + + throw new IllegalArgumentException("Expected tag to be a literal string, a list of components, or a component object with a text/translate key"); + } + + private static List componentsFromNbtList(List list, Style style) { + List components = new ArrayList<>(); + for (Object entry : list) { + components.add(componentFromNbtTag(entry, style)); + } + return components; + } + + public static Style getStyleFromNbtMap(NbtMap map) { + Style.Builder style = Style.style(); + + String colorString = map.getString("color", null); + if (colorString != null) { + if (colorString.startsWith(TextColor.HEX_PREFIX)) { + style.color(TextColor.fromHexString(colorString)); + } else { + style.color(NamedTextColor.NAMES.value(colorString)); + } + } + + map.listenForBoolean("bold", value -> style.decoration(TextDecoration.BOLD, value)); + map.listenForBoolean("italic", value -> style.decoration(TextDecoration.ITALIC, value)); + map.listenForBoolean("underlined", value -> style.decoration(TextDecoration.UNDERLINED, value)); + map.listenForBoolean("strikethrough", value -> style.decoration(TextDecoration.STRIKETHROUGH, value)); + map.listenForBoolean("obfuscated", value -> style.decoration(TextDecoration.OBFUSCATED, value)); + + return style.build(); + } + + public static Style getStyleFromNbtMap(NbtMap map, Style base) { + return base.merge(getStyleFromNbtMap(map)); } public static void init() { From ed5195a84211a9aa0e0c0a63b42cb3910b0cfbc4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:48:54 -0400 Subject: [PATCH 371/897] Fix some instances of enchantment names not deserializing --- .../geyser/item/enchantment/Enchantment.java | 6 +++--- .../translator/text/MessageTranslator.java | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) 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 5cac45534..5a5a37e4e 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,8 +25,6 @@ package org.geysermc.geyser.item.enchantment; -import java.util.List; -import java.util.function.Function; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; @@ -35,11 +33,13 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.geyser.translator.text.MessageTranslator; +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 org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; +import java.util.function.Function; /** * @param description only populated if {@link #bedrockEnchantment()} is not null. 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 0547a21c9..1932d3e47 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 @@ -40,18 +40,25 @@ import net.kyori.adventure.text.serializer.legacy.CharacterAndFormat; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.packet.TextPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.*; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.text.ChatDecoration; +import org.geysermc.geyser.text.DummyLegacyHoverEventSerializer; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.text.GsonComponentSerializerWrapper; +import org.geysermc.geyser.text.MinecraftTranslationRegistry; import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer; import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType; import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatTypeDecoration; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; -import java.util.*; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; public class MessageTranslator { // These are used for handling the translations of the messages @@ -434,7 +441,7 @@ public class MessageTranslator { * Deserialize an NbtMap with a description text component (usually provided from a registry) into a Bedrock-formatted string. */ public static String deserializeDescription(GeyserSession session, NbtMap tag) { - NbtMap description = tag.getCompound("description"); + Object description = tag.get("description"); Component parsed = componentFromNbtTag(description); return convertMessage(session, parsed); } @@ -482,7 +489,8 @@ public class MessageTranslator { } } - throw new IllegalArgumentException("Expected tag to be a literal string, a list of components, or a component object with a text/translate key"); + GeyserImpl.getInstance().getLogger().error("Expected tag to be a literal string, a list of components, or a component object with a text/translate key: " + nbtTag); + return Component.empty(); } private static List componentsFromNbtList(List list, Style style) { From 34fda8a743f7a6617aec63d299eb32555ae6f664 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:51:39 -0400 Subject: [PATCH 372/897] Small optimizations in Enchantment --- .../geyser/item/enchantment/Enchantment.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 5a5a37e4e..301f69a5f 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,6 +25,7 @@ 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; @@ -33,13 +34,14 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; 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.Function; +import java.util.function.ToIntFunction; /** * @param description only populated if {@link #bedrockEnchantment()} is not null. @@ -86,21 +88,21 @@ public record Enchantment(String identifier, } // TODO holder set util? - private static HolderSet readHolderSet(@Nullable Object holderSet, Function keyIdMapping) { + private static HolderSet readHolderSet(@Nullable Object holderSet, ToIntFunction keyIdMapping) { if (holderSet == null) { - return new HolderSet(new int[]{}); + return new HolderSet(IntArrays.EMPTY_ARRAY); } if (holderSet instanceof String stringTag) { // Tag if (stringTag.startsWith("#")) { - return new HolderSet(Key.key(stringTag.substring(1))); // Remove '#' at beginning that indicates tag + return new HolderSet(MinecraftKey.key(stringTag.substring(1))); // Remove '#' at beginning that indicates tag } else { - return new HolderSet(new int[]{keyIdMapping.apply(Key.key(stringTag))}); + 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).map(keyIdMapping).mapToInt(Integer::intValue).toArray()); + 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"); } From a5e45ad7eddb190ced403af42dccc109b33c8dfb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 14 Sep 2024 18:30:25 -0400 Subject: [PATCH 373/897] Workaround for goat horns on the client side --- .../geyser/session/cache/WorldCache.java | 31 +++++++++++++++++++ ...BedrockInventoryTransactionTranslator.java | 21 +++++++++++++ .../java/level/JavaCooldownTranslator.java | 2 ++ 3 files changed, 54 insertions(+) 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 fb5137b05..86cb69314 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 @@ -34,6 +34,7 @@ import lombok.Setter; 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.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession; import org.geysermc.geyser.session.GeyserSession; @@ -70,6 +71,8 @@ public final class WorldCache { @Setter private boolean editingSignOnFront; + private final Object2IntMap activeCooldowns = new Object2IntOpenHashMap<>(2); + public WorldCache(GeyserSession session) { this.session = session; this.scoreboard = new Scoreboard(session); @@ -201,4 +204,32 @@ public final class WorldCache { public String removeActiveRecord(Vector3i pos) { return this.activeRecords.remove(pos); } + + public void setCooldown(Item item, int ticks) { + if (ticks == 0) { + // As of Java 1.21 + this.activeCooldowns.removeInt(item); + return; + } + this.activeCooldowns.put(item, session.getTicks() + ticks); + } + + public boolean hasCooldown(Item item) { + return this.activeCooldowns.containsKey(item); + } + + public void tick() { + // Implementation note: technically we could empty the field during hasCooldown checks, + // 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); + while (it.hasNext()) { + Object2IntMap.Entry entry = it.next(); + if (entry.getIntValue() <= ticks) { + it.remove(); + } + } + } + } } 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 1e4c82da1..6ae21067f 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 @@ -31,6 +31,7 @@ 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; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; @@ -42,6 +43,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.LegacySetIte 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.UpdateBlockPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.Entity; @@ -75,12 +77,15 @@ 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.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; 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.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; @@ -373,6 +378,22 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator instrument = 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); + } + } } } 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 8e07a7d89..636671651 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 @@ -57,5 +57,7 @@ public class JavaCooldownTranslator extends PacketTranslator Date: Wed, 18 Sep 2024 00:48:36 +0900 Subject: [PATCH 374/897] Update to 1.21.30 (#5041) Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../entity/attribute/GeyserAttributeType.java | 2 +- .../geyser/impl/camera/CameraDefinitions.java | 14 +- .../updater/AnvilInventoryUpdater.java | 6 + .../updater/ChestInventoryUpdater.java | 4 + .../updater/ContainerInventoryUpdater.java | 4 + .../updater/CrafterInventoryUpdater.java | 5 + .../updater/HorseInventoryUpdater.java | 4 + .../inventory/updater/InventoryUpdater.java | 4 + .../inventory/updater/UIInventoryUpdater.java | 4 + .../geyser/network/CodecProcessor.java | 57 +- .../geysermc/geyser/network/GameProtocol.java | 8 +- .../populator/BlockRegistryPopulator.java | 37 +- .../registry/populator/Conversion729_712.java | 141 + .../populator/ItemRegistryPopulator.java | 4 +- .../inventory/InventoryTranslator.java | 4 +- .../inventory/OldSmithingTableTranslator.java | 2 + .../inventory/PlayerInventoryTranslator.java | 7 + .../ChestedHorseInventoryTranslator.java | 3 + .../entity/JavaEntityEventTranslator.java | 3 + .../JavaContainerSetSlotTranslator.java | 4 + .../geysermc/geyser/util/InventoryUtils.java | 3 + .../bedrock/block_palette.1_21_30.nbt | Bin 0 -> 180490 bytes .../bedrock/creative_items.1_21_30.json | 6214 +++++++++++++++ .../bedrock/runtime_item_states.1_21_30.json | 6898 +++++++++++++++++ gradle.properties | 2 +- gradle/libs.versions.toml | 6 +- 26 files changed, 13406 insertions(+), 34 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java create mode 100644 core/src/main/resources/bedrock/block_palette.1_21_30.nbt create mode 100644 core/src/main/resources/bedrock/creative_items.1_21_30.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_21_30.json diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index 3b543a943..1e050c840 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -54,7 +54,7 @@ public enum GeyserAttributeType { // Bedrock Attributes ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f), - EXHAUSTION(null, "minecraft:player.exhaustion", 0f, 5f, 0f), + EXHAUSTION(null, "minecraft:player.exhaustion", 0f, 20f, 0f), EXPERIENCE(null, "minecraft:player.experience", 0f, 1f, 0f), EXPERIENCE_LEVEL(null, "minecraft:player.level", 0f, 24791.00f, 0f), HEALTH(null, "minecraft:health", 0f, 1024f, 20f), diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java b/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java index 7bb25c9ef..1cf6a794e 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java @@ -43,13 +43,13 @@ public class CameraDefinitions { static { CAMERA_PRESETS = List.of( - new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()), - new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.of(false)), - new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.of(true)), - new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.of(true))); + new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null), + new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null), + new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null), + new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null), + new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(false), null), + new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null), + new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null)); SimpleDefinitionRegistry.Builder builder = SimpleDefinitionRegistry.builder(); for (int i = 0; i < CAMERA_PRESETS.size(); i++) { 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 7afd31cc9..2e0c75708 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 @@ -32,6 +32,8 @@ import net.kyori.adventure.text.Component; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.GeyserImpl; @@ -78,6 +80,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(bedrockSlot); slotPacket.setItem(inventory.getItem(i).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); } } @@ -98,6 +101,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); } else if (lastTargetSlot != javaSlot) { // Update the previous target slot to remove repair cost changes @@ -105,6 +109,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(lastTargetSlot)); slotPacket.setItem(inventory.getItem(lastTargetSlot).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); } @@ -168,6 +173,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(slot)); slotPacket.setItem(itemData); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java index 5d6214871..9f3d00c57 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.inventory.updater; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -61,6 +63,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(bedrockItems); + contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(contentPacket); } @@ -73,6 +76,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(inventory.getBedrockId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java index c9f313f2a..3d372c083 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.inventory.updater; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -49,6 +51,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); + contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(contentPacket); } @@ -61,6 +64,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(inventory.getBedrockId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java index 4474d420c..315b84c6d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.inventory.updater; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -56,6 +58,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater { contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); + contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(contentPacket); // inventory and hotbar @@ -67,6 +70,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater { contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); + contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(contentPacket); // Crafter result - it doesn't come after the grid, as explained elsewhere. @@ -88,6 +92,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater { packet.setContainerId(containerId); packet.setSlot(translator.javaSlotToBedrock(javaSlot)); packet.setItem(inventory.getItem(javaSlot).getItemData(session)); + packet.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(packet); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java index 7441e66d0..1a46fc02a 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.inventory.updater; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -49,6 +51,7 @@ public class HorseInventoryUpdater extends InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); + contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(contentPacket); } @@ -61,6 +64,7 @@ public class HorseInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(4); // Horse GUI? slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java index 68ee334ba..b7ef4720f 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.inventory.updater; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -45,6 +47,7 @@ public class InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); + contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(contentPacket); } @@ -54,6 +57,7 @@ public class InventoryUpdater { slotPacket.setContainerId(ContainerId.INVENTORY); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java index a23385b53..f4f40d6ce 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.inventory.updater; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.session.GeyserSession; @@ -46,6 +48,7 @@ public class UIInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(bedrockSlot); slotPacket.setItem(inventory.getItem(i).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); } } @@ -59,6 +62,7 @@ public class UIInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); return true; } 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 fd18c01ce..741369c46 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -33,7 +33,6 @@ import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobArmorEquipment import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobEquipmentSerializer_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.v291.serializer.SetEntityMotionSerializer_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; @@ -43,6 +42,8 @@ import org.cloudburstmc.protocol.bedrock.codec.v662.serializer.SetEntityMotionSe import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventoryContentSerializer_v712; import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventorySlotSerializer_v712; import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.MobArmorEquipmentSerializer_v712; +import org.cloudburstmc.protocol.bedrock.codec.v729.serializer.InventoryContentSerializer_v729; +import org.cloudburstmc.protocol.bedrock.codec.v729.serializer.InventorySlotSerializer_v729; import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.cloudburstmc.protocol.bedrock.packet.BossEventPacket; @@ -139,6 +140,13 @@ class CodecProcessor { } }; + private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V729 = new InventoryContentSerializer_v729() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { + throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!"); + } + }; + /** * Serializer that throws an exception when trying to deserialize InventorySlotPacket since server-auth inventory is used. */ @@ -159,6 +167,13 @@ class CodecProcessor { } }; + private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER_V729 = new InventorySlotSerializer_v729() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { + throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!"); + } + }; + /** * Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client. */ @@ -214,16 +229,7 @@ class CodecProcessor { }; /** - * Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v291. - */ - private static final BedrockPacketSerializer SET_ENTITY_MOTION_SERIALIZER_V291 = new SetEntityMotionSerializer_v291() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityMotionPacket packet) { - } - }; - - /** - * Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v662. + * Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client. */ private static final BedrockPacketSerializer SET_ENTITY_MOTION_SERIALIZER = new SetEntityMotionSerializer_v662() { @Override @@ -256,8 +262,27 @@ class CodecProcessor { @SuppressWarnings("unchecked") static BedrockCodec processCodec(BedrockCodec codec) { - boolean isPre712 = codec.getProtocolVersion() < 712; - + boolean is729OrAbove = codec.getProtocolVersion() >= 729; + boolean is712OrAbove = codec.getProtocolVersion() >= 712; + + BedrockPacketSerializer inventoryContentSerializer; + if (is729OrAbove) { + inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V729; + } else if (is712OrAbove) { + inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V712; + } else { + inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V407; + } + + BedrockPacketSerializer inventorySlotSerializer; + if (is729OrAbove) { + inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V729; + } else if (is712OrAbove) { + inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V712; + } else { + inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V407; + } + BedrockCodec.Builder codecBuilder = codec.toBuilder() // Illegal unused serverbound EDU packets .updateSerializer(PhotoTransferPacket.class, ILLEGAL_SERIALIZER) @@ -286,11 +311,11 @@ class CodecProcessor { .updateSerializer(AnvilDamagePacket.class, IGNORED_SERIALIZER) .updateSerializer(RefreshEntitlementsPacket.class, IGNORED_SERIALIZER) // Illegal when serverbound due to Geyser specific setup - .updateSerializer(InventoryContentPacket.class, isPre712 ? INVENTORY_CONTENT_SERIALIZER_V407 : INVENTORY_CONTENT_SERIALIZER_V712) - .updateSerializer(InventorySlotPacket.class, isPre712 ? INVENTORY_SLOT_SERIALIZER_V407 : INVENTORY_SLOT_SERIALIZER_V712) + .updateSerializer(InventoryContentPacket.class, inventoryContentSerializer) + .updateSerializer(InventorySlotPacket.class, inventorySlotSerializer) // Ignored only when serverbound .updateSerializer(BossEventPacket.class, BOSS_EVENT_SERIALIZER) - .updateSerializer(MobArmorEquipmentPacket.class, isPre712 ? MOB_ARMOR_EQUIPMENT_SERIALIZER_V291 : MOB_ARMOR_EQUIPMENT_SERIALIZER_V712) + .updateSerializer(MobArmorEquipmentPacket.class, is712OrAbove ? MOB_ARMOR_EQUIPMENT_SERIALIZER_V712 : MOB_ARMOR_EQUIPMENT_SERIALIZER_V291) .updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER) .updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER) .updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index baa1d24d0..d3abf934f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -31,6 +31,7 @@ import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; import org.cloudburstmc.protocol.bedrock.codec.v686.Bedrock_v686; import org.cloudburstmc.protocol.bedrock.codec.v712.Bedrock_v712; +import org.cloudburstmc.protocol.bedrock.codec.v729.Bedrock_v729; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; @@ -49,8 +50,8 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder() - .minecraftVersion("1.21.20/1.21.21") + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v729.CODEC.toBuilder() + .minecraftVersion("1.21.30") .build()); /** @@ -74,6 +75,9 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v686.CODEC.toBuilder() .minecraftVersion("1.21.2/1.21.3") .build())); + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder() + .minecraftVersion("1.21.20 - 1.21.23") + .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 22321246b..9603cba63 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -39,6 +39,7 @@ import org.cloudburstmc.nbt.*; 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.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -110,7 +111,41 @@ public final class BlockRegistryPopulator { var blockMappers = ImmutableMap., Remapper>builder() .put(ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), Conversion685_671::remapBlock) .put(ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), Conversion712_685::remapBlock) - .put(ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), Conversion729_712::remapBlock) + .put(ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()), tag -> { // TODO: Remove me when mappings is updated + String name = tag.getString("name"); + if ("minecraft:sponge".equals(name)) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("sponge_type"); + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + if ("minecraft:tnt".equals(name)) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("allow_underwater_bit"); + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + if ("minecraft:cobblestone_wall".equals(name)) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("wall_block_type"); + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + if ("minecraft:purpur_block".equals(name)) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("chisel_type"); + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + if ("minecraft:structure_void".equals(name)) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("structure_void_type"); + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + return tag; + }) .build(); // We can keep this strong as nothing should be garbage collected diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java new file mode 100644 index 000000000..3b8d6d4a2 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java @@ -0,0 +1,141 @@ +package org.geysermc.geyser.registry.populator; + +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.type.GeyserMappingItem; + +import java.util.List; +import java.util.stream.Stream; + +public class Conversion729_712 { + private static final List NEW_PURPUR_BLOCKS = List.of("minecraft:purpur_block", "minecraft:purpur_pillar"); + private static final List NEW_WALL_BLOCKS = List.of("minecraft:cobblestone_wall", "minecraft:mossy_cobblestone_wall", "minecraft:granite_wall", "minecraft:diorite_wall", "minecraft:andesite_wall", "minecraft:sandstone_wall", "minecraft:brick_wall", "minecraft:stone_brick_wall", "minecraft:mossy_stone_brick_wall", "minecraft:nether_brick_wall", "minecraft:end_stone_brick_wall", "minecraft:prismarine_wall", "minecraft:red_sandstone_wall", "minecraft:red_nether_brick_wall"); + private static final List NEW_SPONGE_BLOCKS = List.of("minecraft:sponge", "minecraft:wet_sponge"); + private static final List NEW_TNT_BLOCKS = List.of("minecraft:tnt", "minecraft:underwater_tnt"); + private static final List NEW_BLOCKS = Stream.of(NEW_PURPUR_BLOCKS, NEW_WALL_BLOCKS, NEW_SPONGE_BLOCKS, NEW_TNT_BLOCKS).flatMap(List::stream).toList(); + + static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { + String identifier = mapping.getBedrockIdentifier(); + + if (!NEW_BLOCKS.contains(identifier)) { + return mapping; + } + + if (identifier.equals("minecraft:underwater_tnt")) { + return mapping.withBedrockIdentifier("minecraft:tnt").withBedrockData(1); + } + + if (NEW_PURPUR_BLOCKS.contains(identifier)) { + switch (identifier) { + case "minecraft:purpur_block" -> { return mapping.withBedrockIdentifier("minecraft:purpur_block").withBedrockData(0); } + case "minecraft:purpur_pillar" -> { return mapping.withBedrockIdentifier("minecraft:purpur_block").withBedrockData(1); } + } + } + + if (NEW_WALL_BLOCKS.contains(identifier)) { + switch (identifier) { + case "minecraft:cobblestone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(0); } + case "minecraft:mossy_cobblestone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(1); } + case "minecraft:granite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(2); } + case "minecraft:diorite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(3); } + case "minecraft:andesite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(4); } + case "minecraft:sandstone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(5); } + case "minecraft:brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(6); } + case "minecraft:stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(7); } + case "minecraft:mossy_stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(8); } + case "minecraft:nether_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(9); } + case "minecraft:end_stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(10); } + case "minecraft:prismarine_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(11); } + case "minecraft:red_sandstone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(12); } + case "minecraft:red_nether_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(13); } + } + } + + if (NEW_SPONGE_BLOCKS.contains(identifier)) { + switch (identifier) { + case "minecraft:sponge" -> { return mapping.withBedrockIdentifier("minecraft:sponge").withBedrockData(0); } + case "minecraft:wet_sponge" -> { return mapping.withBedrockIdentifier("minecraft:sponge").withBedrockData(1); } + } + } + + return mapping; + } + + static NbtMap remapBlock(NbtMap tag) { + final String name = tag.getString("name"); + + if (!NEW_BLOCKS.contains(name)) { + return tag; + } + + String replacement; + + if (NEW_PURPUR_BLOCKS.contains(name)) { + replacement = "minecraft:purpur_block"; + String purpurType = name.equals("minecraft:purpur_pillar") ? "lines" : "default"; + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("chisel_type", purpurType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_WALL_BLOCKS.contains(name)) { + replacement = "minecraft:cobblestone_wall"; + String wallType; + + switch (name) { + case "minecraft:cobblestone_wall" -> wallType = "cobblestone"; + case "minecraft:mossy_cobblestone_wall" -> wallType = "mossy"; + case "minecraft:granite_wall" -> wallType = "granite"; + case "minecraft:diorite_wall" -> wallType = "diorite"; + case "minecraft:andesite_wall" -> wallType = "andesite"; + case "minecraft:sandstone_wall" -> wallType = "sandstone"; + case "minecraft:brick_wall" -> wallType = "brick"; + case "minecraft:stone_brick_wall" -> wallType = "stone_brick"; + case "minecraft:mossy_stone_brick_wall" -> wallType = "mossy_stone_brick"; + case "minecraft:nether_brick_wall" -> wallType = "nether_brick"; + case "minecraft:end_stone_brick_wall" -> wallType = "end_stone_brick"; + case "minecraft:prismarine_wall" -> wallType = "prismarine"; + case "minecraft:red_sandstone_wall" -> wallType = "red_sandstone"; + case "minecraft:red_nether_brick_wall" -> wallType = "red_nether_brick"; + default -> throw new IllegalStateException("Unexpected value: " + name); + } + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("wall_block_type", wallType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_SPONGE_BLOCKS.contains(name)) { + replacement = "minecraft:sponge"; + String spongeType = name.equals("minecraft:wet_sponge") ? "wet" : "dry"; + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("sponge_type", spongeType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + if (NEW_TNT_BLOCKS.contains(name)) { + replacement = "minecraft:tnt"; + byte tntType = (byte) (name.equals("minecraft:underwater_tnt") ? 1 : 0); + + NbtMap states = tag.getCompound("states") + .toBuilder() + .putByte("allow_underwater_bit", tntType) + .build(); + + return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); + } + + return tag; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 55d44c3d9..bea213aa4 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -42,6 +42,7 @@ import org.cloudburstmc.nbt.NbtUtils; 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.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; @@ -92,7 +93,8 @@ public class ItemRegistryPopulator { 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())); + 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())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); 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 afa11c982..3338d2e52 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 @@ -981,11 +981,11 @@ public abstract class InventoryTranslator { List containerEntries = new ArrayList<>(); for (Map.Entry> entry : containerMap.entrySet()) { - containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue(), new FullContainerName(entry.getKey(), 0))); + containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue(), new FullContainerName(entry.getKey(), null))); } ItemStackResponseSlot cursorEntry = makeItemEntry(0, session.getPlayerInventory().getCursor()); - containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry), new FullContainerName(ContainerSlotType.CURSOR, 0))); + containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry), new FullContainerName(ContainerSlotType.CURSOR, null))); return containerEntries; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java index 21fe9ca21..685d51fc0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.inventory; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; @@ -139,6 +140,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(53); slotPacket.setItem(UPGRADE_TEMPLATE.apply(session.getUpstream().getProtocolVersion())); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 21f45a5ca..a276e4750 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; @@ -83,6 +84,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { contents[i - 36] = inventory.getItem(i).getItemData(session); } inventoryContentPacket.setContents(Arrays.asList(contents)); + inventoryContentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(inventoryContentPacket); // Armor @@ -99,12 +101,14 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } } armorContentPacket.setContents(Arrays.asList(contents)); + armorContentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(armorContentPacket); // Offhand InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); offhandPacket.setContents(Collections.singletonList(inventory.getItem(45).getItemData(session))); + offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(offhandPacket); } @@ -126,6 +130,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setItem(inventory.getItem(i).getItemData(session)); } + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); } } @@ -162,11 +167,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setSlot(slot + 27); } slotPacket.setItem(bedrockItem); + slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(slotPacket); } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); offhandPacket.setContents(Collections.singletonList(bedrockItem)); + offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(offhandPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java index f1a5723c8..ba3b7285e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.inventory.horse; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; @@ -94,6 +95,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); + contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(contentPacket); ItemData[] horseItems = new ItemData[chestSize + 1]; @@ -107,6 +109,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven InventoryContentPacket horseContentsPacket = new InventoryContentPacket(); horseContentsPacket.setContainerId(inventory.getBedrockId()); horseContentsPacket.setContents(Arrays.asList(horseItems)); + horseContentsPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); session.sendUpstreamPacket(horseContentsPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index 6c2e02cd3..3195a6536 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -30,6 +30,8 @@ import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; @@ -167,6 +169,7 @@ public class JavaEntityEventTranslator extends PacketTranslator{b}{oh^g>v{Y5 zYCf}b&dhu#<+n>3f%F9WhrF2KD)`dkW$#O2Wei0acoYhTaCpLt@Yc)nZb8_vAnW%5 zSe}Olhpm~dmrFxoy8FO`!b1Jn2ovMkeVW6c%{RXVTnl2aMmFZ$_lC`Ik*c2&btQ

    y~X~fSRC4qf9|8?EGuigK`m<68)H^lo_Im^a9Vo_UnQDQKbmli8ogD zod(lyCahD~#A(oy3%^O@4@}0=7i-1;g{M+>CjD3XU@ZNSetqUU?45wHzhu#`XS213 zycee=rx(Fw7e8V$Pk**}^J3h@sC-EJQqKxo#ri%XLCNPq*yV4?h32N{)m@FX?`Tee zX7@5$x6fF#NcFF;q0!zqCkQw0Z~n?qU&qi;DXwV*#C}HFvawpZcyq)PmbI0~(RGi( zg`zWwoTrrYLS_w1%l}oT&7OdscUfBAIagiTAlVjggyAEHuqo}oy^RA zRi$7CrBYSV;z<0U%=@Nt#sgKV*X-^JE#Ko{`6xL=Bc-ozTziy)#c|3f7UX?N4DATi z7*!(C&}v!YRwrdn7(@~K&=3lyDeGID>_lI2W%O}a3M2NBAQarS&Y$nBaJ8>|FH&mc zAtsW*OUHRRsP-*z{b}G!#n-~ph<*47wASy<<$1W~4D5stopwbLX?dT^U9PB={aI;f zU)iyZBzlk7hmBAmf8~GdWarSnA{w(>k{!5?5SZJL7oHOsA5XB|n0o#_O@ZON!(G$c z_c@7l&Qu94r#fGr{^b=G{v+V{V|K8S2J@!&ZKH<<_kyUA?skmnn!QI1>no+w{`6B+(zkXHWn;Sa~&!YPj*Y<8VY%mFrL zBdzYk3#A&tM8a*WYoQ>PebkX>d++D%8oR8;4wGu4Z=juvts) z)|Qn20L0$ZqI&(r45Qw(x@SU3*#zV5qN&*>BPT%d?RD)(dzS)4Np6!p@7@{mC_z>; zgHV#bCJD+~c&nr+K$(>Z7EYv7ydpfb>jv zN-oJAN7`m?#9(e{XHf`~SR4cYh)Nsxt+!{U-E3S76}L)#Xkzni9pUonXoxvu{XZK{ zy_?>DjA{pmDB*aKxNJQ73g*s1(oAEbdq3>*l;ZA7dNEwe3TRv65;a8wB+sucTX=U! z$e+mzFy{CsKP4W#4D6)DQ79yZbE5l*{!aTNOz<_@GoFN)LDvPQEQMuKp^&wP<(o8k ztlehH9ffMf+XF4Z>^4q{YePYL!}O)~v$>2=Wl8L3*AGa^jNjQzuYEE8%%wc#sF}*e zB~_M>&2sVfv=7mn|Ng_M^1#qUH~*#8RFID#nP$_U`u)j4>@g~tkW8n`Y>PiRsj)-j z@=oVMGckMw!S{&9)Y5rXvWlzLGXeY=#d2+qiu?9CicKeS4|!*CVu>&8t621yUk*`e zWh`ah=Vrk3oB0ZhnL9b`l8#}%P8Bd(k}DlHkf7^7zM-8AQv2Xe9l$~qq4Pm^U5JZm z5lIXux=7?yMFa;8u}tUTqux;NI?=Hee>a>oDF+csi{NF$&Y5qYmHW3V2AmTzB8A;h zREp1b&vwGyO;wk_W`D2#LD{^%f+g1mOf#0xJyu*Da(5 zYPh#`$>_&^<9*$&edfJ^<1-J*F!_HI`PfNuOIQ7r`ciyGEGba>9y*R3ginmINY`NU zVyF#ELUKKI+yojHKN5H(A%b#+d$fBZw($5QbmfD&0}`Vukfqheqh^5z@bcul0XeU@?EOV+&YWPvsUYmrJ;eByeh@0RaO4FOs z#P;O;2Ig4&?JprGpxUeIioZ<2ZHqYl(Tu0s$K)gm*OGW;-p@U3!WT|vrJg2igG%Fu z3Z}_Gv82A>aAQVDjLxZ6{KGFRkeA__tLu(|M(6yrS0@Fr3ESjYNw=3WM23X*v)2M3 zY*2!GwOB$_Lf6fRF*;3|RE||z+R@Si&O;sgSoh%@kA+3bF1;nP&tkxn^%wH9I z4I4@EfOw=!dKkuENpc|O@~eGWDaI*NH?ujv00nGboa2(Rxr@h>5~gm(I4SIdU)JY- z+#r&bEJ0f%GKFixEwGL6&R>o+H@dCExD4vMl8@M;8%zbe!B>CVlS%ta@(S^(G`W7R zWlo8}odBMZ3o2<~IseszK~UpyZ}0*4bCqCnJ^z0?OY)ag2pfE z|A|o{>Egvb9!ERDzlg|e@pCmh9PJo+ zqnDn1M3rO-2z;(eoTF1SiJ&U+8g~Cs8vLKSo_0bY0!$0Fe<|vb(T|a-);^oFLzNT% z`_KmQH}zVRU~g}NDv%=vwM}>R=_^`)07YI%$=jLZs6#b2$7;8kn@(Ssf;sY& zXKul+1olMZt)NefT9c$Ld6v*S|dt<|!M0;)GJ9OO5MQsxM!QAN) z{&Y_iIyrBwJLh|}`eL-I!SyQF>>@rS#97_R+$CKuHHT1Dl8zF2)>RR{th3cu`^fvu zY~?5$vn@H5_5BUyu?ro0--#GGyBT8P%i5AxKqjmiC2JaC;`ks z@nL^YV|W71F=S%)Qv{cq9^eUW())vM2$o;Ngv*Vpx&Y6aGjX;ZYAX`8I+gDRxmaTU zxx6#vO|aJ?WgPby-qO+~UvgYT#GejQ{ zmF&MMG>YC+P8Wx2U`|c-qR0r$o@Iz` zR_DeGv=)7_3+PC2&8IICeV`Abk|x5*osgf28kxh@eB&^FmGXkh(a=TI3_DvPmUn%o z+cN5X$jT_IJXV9nNS)fdCVV8*yUx6$5M8Z`yK*$i?qqqAL@ThC<+AoG?%Q6h{MYYnc5IRmG8rx{&UUa8Y|}>%$%_cyuU;v-9sglG3g`62i^n zU!oh6Ar}0dX$o)JqOBjl{?$m+S|On_Xz3slt_)i!Z&!DGqgB z+|e}CywVseW9fCVq<7>)<~rA8X6{dW+ara~Rey}H9}J9jZF%SR!zuUYG!hr&lCVm> zx_Z+VU8)CMoxaX##4X6xmEQ7wd^^2f7k}qytZDdG4WKMOUh=p1YAw33Ipo}*oaVEsIo-=c@KBRHtA9t+s=2k!!$yB|00^tlF1s)j?D_>X|GeiH^1&IY2l zTUK|54r$Rr`1NkuG6UYPdMe#j}Pr)F$3ywD6>&PEn9xPqbCZnT|27w2s*74Y8;Fi!2h1 z6sJ*Rl>NDuL9lT|QhoBB*j;&5`(`+oGmfmlM=`VNO*ZgfcPi-!3oP=%j=bML6mvCV z(RdPa%f1O)V(mJGVQh*PkEas!2#1S?RJZB&Fiz4AH{kY{M-CVW;38$uVGC>bK z^5&V5uAC*7I$eSz^R=g9?uMUm<3D#dAxkVyx&%g)KHNO<0ja1pi>=CC0jx$*?9?{R zxO+t^42tUB3T15X{&(+o=lcj{X?3Z2GN^RqTA5if-NY?JQ_k23TA!UPKZBQhn5%y^ zB(y15F!)aGwUb~!Jz^58xl>9uoJ+cc!O`0Rkxyu$T$_Spyw2KePVJe>Xx1caJYTcn z(9#{qsGY2kJDI4Sx{?hDwW|oLXd*57N956SB=L>{<1&hQPtBz?^*r z=-Ib9)E|J^Xe(%5`k4Ly^K_cow@wf|(6Fq_4fqn^+I~9c@;{~Rzd8FTp|hNqzd0#~ zg`-!{_U|;r!$9KCO4j*AaD|AW_G!fNmwax0eihDA6fIK6{dGNttuCy1qAnxvOM zgwei2Q5vK{`G7PW0=56DyOtFa8a?s*id3WU)(+8!2i=r`ycjqs*w*?%jtq?2ca2nE z7)Y-9fMvozk^yjL<@MAAAq1CbGN&AH*2NCdt9A4pgyjzRww(lIr8@UwJ^%x7$6uZv zcu=0q;It4Hvg0IzI)Y+Ym<51{WHPfTsIVHyhNc=TS8QlnqHS2k#NtK$H9~ zKeGiwiIJ9ZJ%(Y3;{fkU79yYO4BeL)gXjw7;E}DjTomZ@tAA!wb^CSd+!+7zIDi0~`I3_%+7A2PTF@=Qll$oRgquLgzG#4>&kjkE z4h0kxvhU9QVS^<57rZKPApj~;Z2$luQxvXksz@LM4X!d~aA*IpKHX?<8_jco8VP%| zyZoRWXy#J61y>}5$M-L7tr*ZX3DcLK=b!_r9r}t(T24<~4MsCH@-cHDu)3uQKU7YD zuu(TT09|s(1uMHoamVb+b&&4e_nlA^iskI*XY@+ea$o1J$cC+I;Ay z9#7mKM!@q)u3vwT?Od(_2xC8(+&xkXlcuw-k31eXZsliV`=ASBgPTiLkn&m1Q-vk1 zAXkHv=}sWQ0UWdHRHM=8`XIlgujzRo}#Xn|1^``?_OvUYHs>zH(AYKgbEw7{L2W z*zS@MN|1jJu7!`(j*|PVEhMLKIDsSqP(m5#-_ZrHXvo|Uo39nL7u(kSFii(VT;2SgqGrW*zd9E>8&C37x2U|WDkXoiH`Bhodt0xggJlN>Z& zr$Fwo^DmNYe(_r&Rv@0&PXkyAoUWupscp%hp@5`+k>eYN?k?vi?p6_oviO(1ZI~70 zx8QwNuL)#1#`hY!|B5WL_nP|=Q)X%!6K+ftn_X5aKYOy9m=;Z(K(o~+P(FGs{WxL~ zL41s1)k4AfbK=Lc|N7F=v@vU-^RWmqWPQ^%W#DV<{2+q}wr=j!Imj{|JiLfE{9ip>?DhsXrVn+X@PfUO>`i1r3Yuk_;JYcOPeS zwxO1GBTr-Memn&VwvQZeet`xBkxw<{P%^Ss9MA^o9LlZ;gES?d9<;yK_x(@1x_*Q# zq_j}r=E4CQ5z^dSY{dPLZ|!;~{QsR#S^af})yZUne$eiI(@Y2@IQz2KG^8jqp1Q@L1L>45#2;lbPwd>x)`d{q{?r4rOEjUBwrOaO5 z89@4J&&^){Prt$50jK6$)H(`ab{uWZ#WSIhmG*-(oR8`C7O?XGzWU|e)wH-+hyi^u zYds=SQ_rgwl(w@s>3p1cad3aDy^69R)3AR?hXLb?)(-LF?K@zBfKnp%#G_04QS-A4 zW5}V5_wnU7_=60q(1ML!IjcfSCP=k({CkA$j z$AsOUYR7`COX;`K#xTp?2c{jya1nH2n$~;ovnGv|iwy=SP7CJ5r2_>D((Q<^4wEbBLj6IQ($pe%v+Wylvh*rpTb9^y9Rb)LxE;8eqVn zFfZbJ=oZN`YHtY4UrN;}kDgC1?QCfhLiX@)l=hwZ1u~%E*V4dP#yZW*44(ZYg5vg+ z^|1YM+!rhAg<;S`ow0E0vR@DCDt0C!c1f(*-^;)b-#G=oM4%#`lqyd^{It<~^K zeC%YT>0kc5W`wR?{HP!MUjV+Iu$sql(wW53Zqa)W+>6+Ax;PFKXk4=kpT6=-Pm@2N$h4zuTICHy$df04&S zlhBeu@fQEThPcbAnFRDOn?2U2=MHnY0(_67Vnf)J;_*~(^ML;22zxyykzbntW$lV? ztAjc?3|i+^z7TFoy=#GsvK?XSgxc}G&vS$SZ9PZc4BU^*pBFk8tdGN`V8Qsm!SAKh z5@hia8(L}TJZ+;Wq)e(?hX!!7mXJ7e zo&R4L!o8|^A8plY#QU!WrpgHjLrw`E>n)_Vbp}9iyP&@};)#7+5k8mbrd}-OK^q1S zoT~>kAYf>}elP?u4w% z#o=Sj{s+I{VS0!{8}^GOeu|3w`1e9Rg8s0p;fO z(O(?nh#}A~XYuLl0o_NxjGHL`YeHiv1q6><9fR2E6u3IZ!r4BnctXA4QSC$HYkq?QwE5P)61lb zBd{Sz0mgqs+(l4`E-;85sEV~UR_wBT*d_3|ZXZ0@&%YKwP(Hq{(PJ4VExwkj+EgsR zQ>V4Tn0SF&{>xJVetTr&X)6DS=&mn^8m2s3?UaxE`dz)%XT-Bw)uFLBruu!6^ismW zA6w9rd;6WJlxI$u@CiI_C>s+)%+Fxb^rARY97fr(Y2t%kZXBM>e?xJXu*HZi{fByn zJMrD2$DoIHB3%4I_K(1O0jAI{_V6P*W6z%#%Y*yhfUch#yO6JG$GjZ_u6Fs zr%E53v;%+jI8VPMdFt=MRmFi+F=Trwf%6pl#g;_c(EH_>D!-_|F0&54RtruOqHw_j zFTma+8u0{9=u-1FXa1mXB~ysVScdB^MvoJ?!hmX5i48eczkDOvLX0B30&=n2TQHs6t2quUaiug7z$zG`Nzl}l^GEjduq*lil%!JfJ zOhF=t<#9reyl-hZv90O9LxPlvhH+?H8@eilF{>(kEWMyFWLt?xf^RFeD#duy;}r_q ztYywc&VuF?68yyoubk021=r9(9kuOBr#l<0)*Wmbd@E+DbDa2g09+thQU5;Pq!BcE>o}icsVc~x&T9V6srtjAQVf(Y#Bc- z+F!9MEPfU~>%Su5LxOFVK5{H&!@JN!$IT=2xw_SdB#Er;E}#(GFtq=gjhsYW)j zrpYQxg8EKjYXWU+?UayvKKEycVKiJ1c!k|H~(s=HF5cYf;^jvXpMZA)iDIKe;%0-^`nBw_< zvEfEzYI1|B@F$Vy67}^*n<7}VQ^LuORSvVdIC9~Jy_M}FEl6<9mW9eI!l>ogajUU` zSq|Ctx1n&&9&|HH#?Sh8`|bKyGnB@Iq3}hheX?CsqsK>ky_k`*he(>!UXFth9+AGS z!3^*w!zjg1AhrK0zMU*G&~}l362G$L+k(`t#L1#^smTMTgilpdL18{apSO>*f;Z*b zP$((tGWY5B*L~Mgrg}=(XE|usZ)jZb`Wa-N+qU*0u&jYR<*DvX$UHl%0`I}bVm6`x zb4}(f3VGO$a*F7;iDf2Tv2Y7ZS))iY2K09_Re|7trac#p52gCF7pt3qLT0(AW zZS%AI>C^X24cV&B``f}U$_Fsjre|1-9ZFZ82V(K-WeP+>4M4wH_0!+OZZUe5vYY31 zKVIS{Dy$+YW*GOF;eGq{!8z^)q+Efs2-RyWB;JUQ6(7axI3nJ1c3st%qYruHRj8rh zuWmg^YUiKJpoHyIs$p#BBxBUx5g8Jby1MR}n7VGy0(s8r5S`PMY6~&>;tvM%Otpa4 z22?#{T!)W&?rLEiK!&eMCCfP7WC&rW7{&@8^W^Sav~>}{CoM~#ao~?Xb&c^<}##`IO5TeNjsOBEl1+so~bb_A5@1+Fa=Txu$xgr2`-QDGf~ zigxs{;Nz;67(T-5r}|dck8&bt!>NN+0c_8WxGHm|h@pltd7U0}fI^(Dw}`+Re9tLA z;oV64ldQ7z>1B;Om)iSJLdXJer(ai~qUhqpHfm6n0eEsh17Y1Up1LH)UhkQcMq_^l z&|^7V?14JLE2pLLPMs2pF0xO7UAz*Hwe7h3mxhQDRhbMk^OYNOidK+V`ZC3GRGS%eIRwW0y z_-ngov}gHe9m8&D#G7nl-*i4GF4QUMwAOt`AV#*l1D4K}!OXW#bcGz2j6J{EwA043 zv!=7lum(7LaSKEYM;UsGPP)ARC~#Fu+jE=SQuAO%mnx-`zOH>vj7+OWkCrb=JQ^U3 zl*}59Hl3L*(qY@ig+F`9MvUxo+Ve-I%XU25fKxx6km~>jV&!2fXHI}DoyJ$Jd$ zUPkGUg2Fb6XQyD?vQr!*wb9urOO?+cws?R=gE*g?eMj)dWr4G|K)ZR_7tYg~vn1zm zyD+7P=0PNXW4!E%7h@QbGJN7Uzl1RVAaR_3bE@_48w!=6AA4|a@aZj}lD(|n)|xB! z2t;k8O7J`#)wv1G;Y>WX(h?F!P}Z6ctt2+E$T81we?tDe{mbvhk`%vTFoA&h7?!V`I8KfKhX zHgV<&`~}w{eL9czT=)8cOKaPxn%w%`8mkXx)}bo9eV>q`?&YPD5^7IIFN?=Mx14i1 z#l*)I9K85!7tHXvC6yd&Lv6=o4F4-#bW)-3D0?t0dai)#&@*B~_ku|^9a)E29+U=Q zwAD;GPlYAea^es>Wgq870~qyga-A4lLu}@ic}JxBuelElC=F;toi-0|LVgwxlXVB| z$#?73FuYmm&~+Lpk5f&BLAU+OEl&9DJsTX!;=2NbrCRXe@8-M?(-M%i(fHFd_9s5m z`)%v)-wi#djN{yJ%?)9CLNRea@n?I^z4mX3|D^ltE@Is{%R{W+S8SUvA*py$lGzxi zpY1FMU1JiM(8Jbdt39f3jtDOHzBcEwVmu!Va4&Cqk@El*vpvKqd=^aO+=1|m3kW*P z?-zIQic%b!r#3}Lbktdhhvg~s|Ct>+tMIlXRjJ{4zCjydv9p1TAN$ZxUEF_mC?SHu zGw%IVT`X7P4Pvk!ZB?m!+l>FxeaxL{U=?g??>Oh>gU;)Jd&p@emIKuhHt*iX{=n+f z4HI8-%yxIZmVea}5<-VpuP>&*F7%3Naaa^9lC*oyQfF^7N}k}Rcf)ri#Jt^{^5A#@ zm&ob>;7!5T0&ffAy&7!T!{3x)#j|T|JC-t5oco*n4+9m?CUk2{certS`Cs=7wzEk_ zy&yPo;^c@h^R`vua$GKcd$$Jb+^bC2mNCDv-qfp_vDWjE&!ElV}n?kP)5{@srL$6~A-#J}-uEzKF zdTuLUf$HBoH*kD$EbBQATkjkSi*b8_hUd%|hn{!UOVOaW{;ylH#rf4py~b)3LgZT< z>*eJD$FjcHnfb#r!z*H329vLig#W@X?ukarlSC!O?6t?ZweJ}BWRnP`Tgd{v6T%0+ z4N$J?Na*VyojuiPc_LRi?AAUIquhk93Zir?U4X~x{e^T5lv}Ot-e%kAMX&F%_mJPv z;1`7xCp;~0%U|$&UfjsdZxPg1AyiLI{L`SFF83;s_jkke9?@6!-psU?NOS-p@xm|a zM15&r*W-H^V`$M&LD=auY;Z<6Q@hTE0f%6Uv}iwae`_6+6TF(A%{ITqbEprQ82>kZ?deYP6iyufnVdeNeOWRO zzs2N{l}Z?-Iwpgg*Riw_;9<4=>PkceW0P>y?Y_uxI^;HcB$+GnK=>C3d6w#6c$hl3 z+IEOC(fLclf2W{gq+1LbM?EyvU4R+B=g&T4?UoDkoslOWb|jv4cBnc9au4F0NVGwo~DE((ekW+%Q zbyxVgb(pnjn?b?Zm#b%N()i8qc|Bue6~lMaqkZ*h+_iIH?2Fmpwx!U}zaEikD_T}SF z%BVi{t#L1J>}ep~jZ@BE|9*i}{0bwN9gX9wnCnF_2M|c}Kc3B~^}DdIrHxzGzj5;+ zAw;sFA!Xb+meK)&KKygu>0oyDwvQLAHLAS`RU~pI*km4xuxl?|uj28QipG9wgw+@R zI<6jQ2U+#*=eqC)48NW1vRATj9neU)W$U`Rf3b+MW4*n)EZpqh6Pz>p60 zq2jOrYHk=Gn-+tOgZ=RGUi(h(P}{epqy8u#J?x4!52*o=R6L4Q$A!uVlHD;gWd z2rI;K^IhT zd-YO5FKOfEmxGn4Zi2eS6@Q)1@|DTczVL@v;l@9Eq^F>sw)pRRe}q+{FJ8~8V@+TX z7!nC3$(C^AV1Q+xZ}KMtGEXZbCDhhFW=oaw-?!I>-ri1x0{ielaqn`iQbc3l877Ed zNtN+D_5i{k_q_F%_phXlS2n(*LMY#c({^1vUH{I0FmwLtFH*0C&9_POH(#u#d;qe7FzO1*rv(uwzxi-W`4}h8M0p4W--W)vZ zqKiUMohe-b`}k_>(c9l>@`BDjczI){lO|25nRW<)TKK|oO#5T$@VQoYzT45`tYDjk%`}nd__iLpP`$1c%`mRe!PdbKD2yQ`r z$uLNK(0_|!Bqv!W((H{O{P4b0Ln__Jjcg4|Ni5)Apwrmt`nE)Eh@Gn2H>6)$UZ*Z` zQSkdl2ahjC5h^D;-p@n}E}fj`>N_UAW)9{OQkVNIRdKhSW3sXlV{eQF+6{UcCn8mZ z%+JiaweqMUO{{*#XJwg=ejXT|zNcE}q}?33#cNf}5RNH*&@~Nee;xVjPpEm41r0mW zi(lCF@zx~$Z!X|jd zv5RP5CyE_@NUV_{Ws)wRU~=j08-a98Z!uWW zw(QsQwf=rGmQ!*Djlr-6GcI-mr{{W(sZ-a??B$P_qA4`qXo7?2R5^;ZW-hni6yidW zTMu=Dw-mhR4LH9ldOVL&6c4L)h!VyT%fxGlazFXkT_S-lHO(-fPRxShRfUXef|!>jFMpdN08?WpAaVs*8v} zpmN!8(rAu$A2n?Kf*yO&?ez=t=>gNVHq1OF9QkUxhZY0N2;wlRh`S$CmNKI`E14Ze zhQ<-s=ret6-ecME7VMwx?h>?wtLI(2M&Fg$Mw4ltYhCjU(A76dNOocuOCr#dP)Ev_ zj7~7OD+s9486xN3r+L>uh1r6 zwLX8<_{PwQAWTad<6B(&ozYNXPM}0Q?%$WKgBk2>U!%@ekige+ld8r{%?=~PN)?Ys zsy_r%cZVci&i(tTX*jpqWqHlO#lpz+g1@v*2o6E3h#AFVoTk)xjg+`-66cG?%zk+z zzWrVU)^ycJ$PrGBeB!rMl#iIXk3OAiaC=;w zz~R66o1qrMs&S;TCSnE?_7{#c)|Ky#R~cnEYOGZYDUj?VwHU}r4>oLnoc0vFndv8d zDFugsw8KmhEHYdu!Wh4UJFtOTx%m4d>fCgtozQ1uS1GU3v4d}4?s0p5_?}*(!uiLm z;E;zY?rKocoek=X3B~G4cYix%)8ZSfdbT#4!;fk%81w>%;`QQiQUVJNQ-tjJ;!yl& z71{z{8iD7yQ_t%7pVM)5Q*UZ%lfpHdztNV!M=Yu4;>f1XD7kmONcP-o{eVte(Ii#= zJx#lftT(-{RPcBc5L;WA*0oA?PfS)T0KQ(nn6eQSKIgNyiS_4 z(K0rh5ueO7_gB_WtV|L=f~=vc6{J%pihm7USVylPh*J#>d09?b2!GeHn^lFx$n1Q< z_|U{;-Iup{laOkrNwl)gc0Zqj2%S`$VICc>=IZRr`)I%F1xod-``_5qFv%U+Tlk(x zN;NUztYMmOb;|c{Vop%r@ooR`UVO8*DtsdP*K*G;?M)v0&>niDFr#w*L!Z8@{3&0u zm(1UHxlab%R)5QRTM+mfneh}ygoXaI%3ja@J-LzQ+Hd|j+uO!tNw^lR=0#rbQOt5| zY2!Z8$YOnj>{n8m9`J?msImTT%Za%r3F-RrIUEiuU-Vp@x(qX_zI0zTTP?9~(mCH7 z0whA&$~9*iC+To-j&~Fg>I*r;34*VwNXQ2(M`d3YDKahMON6ksN_~w2-Zw2cLQ*tq zjae3o681)j!Jt0QHF?GnPKh{<7ma)2ElCW%*JDUj&Me-!Hd|8k41_Og4v}Ol{*L=;e=R&*E5WV%DEfg z_)m+iw}$uR2R>2hV3x;z8`aF~rONC<7gLcceux)!u+!Oj%gCuRCWOS^7_4?smJ^8A zI$*58FSaxqsuu z`IFyi@X(*;Bjgx;&`yp1Hf;Cdr^)J*1@Zh0bwnSKCMl14?->$ZZ4A&n0PUS4K}Vlb z%Ai%3NPm6w1mBUy<$Q91mnMPxWwS>(Sq|@;4>{BE<|Y0Equ*xNT*pL`rergdFPfZe z)(NCwb+q}lpNzn*=$IkLjU;$_=q>12>gRoM_?&t&g?O#a?Or)>aC1>muEniiIZ!@d z(K0wlA7CDky36q<*vdC?%uV$uot<;p#sS_fB8#-Z!so|_VM*O2e&#D(FZt?88|^&T zj0JY`3d`byY|U|&&-hH(w>PDljKGx4JM6}^r;2}fjr-0%e~97a(?PuQp#@L<&qzm0 zDYpdvv~W8Iyxi-h*`}M!1f4Rri*1y&85~?L_hNNhq=Q}QfNm{Go>f^!k>%8Gygywp6y9)7tgHd(qn!zC-NloDRq zYp3D)fT*s?M{xwh&pWS#1=7SX>PrEBP>bNHqwNoV`0H^r zG=m9!`0Haxy9GVVJoR>khd#u0uyp1GKE$;_O-E8B1CLFoGZjkeSNP8C2}i?AIS03b zUj_!{lqvUOtQ~5(WWAO9jJ^gb6kfj;p_54{S z_~o*ITD@C1UL>+unrC%j$iNPA?W!I+Yn&@2W#u9OB zI7xniN{8EZd`bma3&^$PLuoYctuID3BiF}#*Xm@?js zFKTW_AhR&*vqKQN@e}x$MRP27W^8^rJ_?FLvdQMOul=g+2H;;zX8n<3rOOJ^VCN`3 zh`fBBWx&pHaurYk5iYv|um}pT(vX`~ZYkjth;d}Y;80qPp1|i89R#+LyzvVdQ`yF< z=LLn&vmJjuL8g0wBkTP_4gcp8WN~Fyv9_mhba=9@nuNcSVXz|e(MUtJBw$Qq#FPpRq z#wLc%w%Wa_?rdzs}o7%iquJX&@Dnf^DN)uIQyt?YW#0=kwK z_drV=W-~xcd0+&s%n(!{!mKu801~-hIY&N##7o_9*Bn2Go}41eJ>*)*3Sh^P!3P}N z{jNKg2?ABie_8bexsXVMz1CthwHjhEQ&6XXPPjBKmk)qypE<$~Dhf6lj;SoWwo!xU zr5Ct9z5oHD*xDQ(g-o-WN)dxed>N5H|E}mqEO?$kfRQ5_B+}%IxKcsFfs|P-19p%& zBHv+)RU-~$d9?(70YjI7tC&v$q8at~yAc|^3JX)3G*+oTp`%I8k$HL+j4iazkw|F5(-e7)^rpr1p z8k@ZD9@XBZ`;oH^BTTtax z(Pk?FM4S)RV1T+kj{i%;pW(|vRx2aiUXKf8`q{%k1GqPt9`BhWGYGn zRA)0sEb2@-4c@%G7GGE_6mC2=xm}YBQ17$-roDR*6jkw3g<;BWu6vX~3W%!3Lu(^l z7Hp;Y?$&<@uuw=OYd-BJJ_D1U$Bms;^|XymgWWmdD9_RnLOgy6Mg^5z zHrvl5jTkM*G6Rb84(ywv^2CIm9Qt50iYa&^5Y_>?$owWXBQQ#p!huCBD=8pwdN(Az z^jQIw=9a7Ie_+5YOS>rPv4n`)>Mk0P&?35uF5amm!jTU#(#V1X;mb>^tLOsz)v~e5u{G4yC0el}03mp^*mZmTr*lndi=Zf4*z|*7M(4`<|U= z$DKQOUV~UD?cXPT_ceXVo=J#4Q94hZ2{0E{uu|LAXn2CaP@?zJ0hoN#XWLLFL*?!gMfSnGK7?>+LyG4JwU z5x;*Gb2Uw7G)PVGHl~3_ER9zlWoqr>NSKsMzK&~p04Gu+BT^~ssSM&XS3lovD2@EH ztlJw$^W(=f3RY!0J=P|CCG}TRDhd|XgxN;L>icVwU9W*(Sp(0XyY>^*a=BMqLalsW z>8CB7V=wRv^0L|&0AMnD@CXs#Upg$fF-ghnZIw+|Hz8E2ilmaPQw?xE4^khiK)vt^ zbj3y$vs_qq&|fFvdVL#$J`OpYN4$Q2^#^O*GzciOsYClt=Jumfed}IhE7FTo8FCfkvCzoxehk{jNNC8DG#Tt=@dkFqsHG-69#xJ zE#OU9dhgkSKvJtsj&VA74SaFRAidxvFEiHY66WJK%PP!a;Tln%|2?F%FY`_c`7yXm zmcl@fvp0VpH$IK(OQrPOm3gu@cC#phgk`}=T)iP6izEx5*Kpu7VRHHG0oM;-wPq1M zHUR>g`sU1C<%-Fyutf*ag~j1cN}atp&w2_+i(loFRQpaeYrRZ{-vp=U28yNwkbqf)c?h!ZB3V?64Gi{nv5@5V^S6KMCgdjQj zZ!wAg)N&!6CB$)Riu1O<@It4sCz@`#&&KseRf}ad|5k=d0oCc^){^Po+ejso6QIy$ zMs?zI{H&_JiT6P_gWtj2-tv>C{>3llAv)~;@%kh5Tj((~)`)-M+>gXa@=9o zUlU>c?O43c!0FF^!r>66^gVO+!V^>HaIU@h+%Y zWQu7-`vOuD3z4+!jujLVYSonQ(&~PUYp0m{LwqlBEd*Ip7d%w0!?rFa|M z*)2HznhSG>={WpWbKo-Jn-C%>Nn|DblVE1)0jKH86wVtl-QGNyf)Dv9NoRNqnQq-t zYA!`f4K+S*{wKW^OIrDi&gP4nP=e)%-73c;i{82AqfZ&U294w)={3f!e=~_=r#0&sl8YtG)>3NQjpg$Wv)r!bGIr; zDJ?Xh$>(|egX45oc>5pUsV7pE>C@6jVIOVZ?Z>kvp~yE5A-$QkYhDzUcuXFJCHh(WC z@~c=B-oi{xP12ug4pik$R5bjoDbeY6$te!P$?j7$ipyp5qIH2ZemW>KI69|POOQ`& z9{MJYY-3wa4Z@PsNuzwZ+jHp(qj@`N85moTZ~R&XaL?qI{r9_vOX{deEf{gxioBs; zlTi%|TV4}BnC_>^6n>h2^bIHNK+E)jP8dF`& zSk6$M(S77JPW8&03=V5bJw)M;PF+y@_IMg&?`kKjr@;*Eb>fxo4g2TkUuEdhowt+< zGb4u^->SSWW6C_oVqnB>f@9vT$y|PNH|{U$jj>;UL>eXcT|+UJGumpAngnz49Imy` zQtmeZ$2B^;zhaqB=gO8NtSoRt5C0u3&(SA3?)CRd`;GI7E+@^KWEk1MJ67%n>d5oi zO*J@{0@P^mB`kv8rK^-M*DzimC`>g!(60tTx^xIr{?QKK`AR$UFntV;>cVHt}E>iVROEZ z%&yVM0&c^LSde;yn{x=J01`WK_YCikg_D&ir%)9VHIvBKbKmw#-_R!gZWV>>sk?XC zwPk4ap2zJE4fn7Mm|-1#IN6Fzlk|Oj*-=9ABk9oht1OYKf_=Qr9q+KpPy6!Mp8}nq zW|=^X5%`5}n44@wzWb{S5gW?vB&g~F25kTLy_Btx9hXR4Je4hSh(Wm>7b61;M_rKA z2f`54g6-k)AM9otwDox%b`tfvrdZ^YY0YD1d~FM1)xefvWnv5FB>Sn%bXVS}^0CQ5 z-lwBAcM1}9juXYC!>@HFVh6RNU~ho0P$jHOQ~bP=TeH5~N1tZrCLYASZ-dP4AdM&z zzW5<#DP`HLn3N~PTl^B+6EYGe78fsOr6hfEHU6=x)anFlP`sP5tR%0hxvT(Re%Gl^xnI;)o}!J}DR1D`Iy=qlJAsNfY`~k+nvCCppG(KU2(gvg`45>3 zpvWPFu9^`j=QE}nk2oHLi6558J_m`%RK0?nJYh1MfnklU_(@^Ro^)cL>zZghs%J|I zy>E-jOKzf1LI)7)lJ!#hcld5fg%%vlNluHZ#l%_vP!k$vP+Y_7dZQ2^KBwaztKlUA zP!};j>YMLU%j*$4b3|=??#4RG-OqanZvQ1>FHxK3RY9cflk){F1vdpVN2AVpu?Ner z7gPdE>&kwwFuyE+?!pXc3&i7fr_fNHb@abe z9RW5QybC+)L2-ahM&7|o%c0{@r@wnqWVl}uyO+!TMsP@3%6-zSM^QPX%8pmz)7Cy# zZy!zr7ZoA~PWi8!Y~s!8#!>P=#oTo(@HL0BH+^mm&8=#gVR8GZ)>t7;^0M3R5HsE+ zn9=I1r0U~ntH5wAf)_JIoapP2s#xvaGMS>+$_8|Iy8>TUQbhc@G0LvTMu&GRaGq=q zzZE1hzrCoFmY(0cQhvVz6{r^Q#c4h`7%=9W`DKai^@#nBMMwGVMv1T1pkoA!fWa$? zkZ33@YRk(tC_^+eL-erN^!)2nocr(UbXPF}rn??kR+M!#wx@NU6%{;e1$$L4f3p|$ zKmVX0c}GwG(zk|TL*czMp%zSL373N27cRkt$@2DlEDkvca0quUwXb^imd7?YVJ`Rg zPNLEc1BI$G{EpzvEAWco;ekk6Dt<*WpSh0DIVlfIz9Gd~*asgMi{WXl>(J*uvi}F* za6hqN<^~_{`G?P+Og*Ll58&_@m4OEyUMF%9uAsfy3%}L8Kw_9FYTA#-x67L#HW%aa zDsQvTJuNopRgdUCh>?{6ec8s-$r66`c&Ng+DB>SI0Fb3eqx+R|7&&bK0dXiNtaz0P z0vE1`HB+K=t;(3KI~G9 zS%t=yo$4)o;A*a*zXW0#zporI72e7Zpc?ull!=9d5RivYg^i`E5U7SvWNhR2#pu|*A}`*H;6czE*G7d*Rv0F@mPg3W;2f9HX~NgeEl9gT^#`Zuf&j}NWU*Z6o~tY_HQd{ z5a_T)M)2kzfXe5s2{(?bHi(9Isa&X9gl=lx(^~glt0FJ6tT(>O)P`dH((H8$>#o$$ zL0O_)Ykc+n>Fmj8yb~nD{?GSAE~ek1c%=NQ``vyJNo?w zRvF-!bRr}cb`6Dx2TFtOAk=u z5uk<&C&mxbpet5X7n?XBq~XToS5)QyYE^%Q2d|G6fH~Z_h|*^P_lY@ZI&;h@;hiWI z+J&L1UlRZpHjd`_6L~~L?i1RJ7pfwG778#NEw1YzKQjs5FwpQ50U;6--rbJ`9pM6b zOu}Y*xrG2fd=HzO*<56m2JkJf+#Q#}?9wxQzt29_N|?P zPX}rUUzeZiO?xgYf#pXvQ@_+%feFxjM5kb6h-MOhL58NXp?3qo;QdO{(KYDTP;P?h?VliHR69E&1 zAhO}2v1{g5R^vZJWWrFr4ZAD8OP8NE@;b`0fI;M!^T}P;Q>0&hvsk)u5B8;pj{Y04T=fm9nJ%jKfW)WcvBMk z+qp1r@~SOc-&5&9)($&W*~Wkwd~a~M^gn>ORc?`x4-Z#Fay$?l|M}(UceqJIxeKO4 zjXV4>Xp|0O&6u9GpLrxAlE;D33opIL z8Rm5S)nO2&;^-j#ZERq|@?`tuhLaT%wzgb3_u|v>5wm^+CwCrd?Q!&zwhcC{B84_q zDdopsbhm8nJa2bD3bD%_XGVvfzVpghU&qR(_cl+Sk$6Cpef~T9#L?oXT(K&=dE!%! z!e0PRS-12VfF;h%z>EF|ZcbLd(KaAo@u*-#sXm0{>Uqm3E0<_$NAx*I+Y&1m!Jrxc zl1#3_6Pr;Uy{SmGtMW(gW)uheQC2PvT=Y35rx9E4&CA+n16f!0FPrtA^j^NXX&M_} z)CsP6c-!{;*H(nKnUiEnmHNA%4VbaF-|BK5kl1oCipL>&%e6+5{R8Q_w%oB~7yjAN`nJ&(|aF6qqS4IZ*5Fi-~UFTP5b)N<8XM=F(HA%KSe0$oa`a z1a1vvl|FcpU>Z%nE>}4-tqp6p+Z(g{j1i9ixHpM5@S?Q9+}tw^mBBy%1^>4Kb9%RJ zZnH)z@k0k`5=DbCl5ewgrtLosTNLV{p1D48Ta;4oY;c|RlJrbCNbCs${M*)Eq4(cT zMbTo>8!}Y4Z@bqUvM2ZHTG=wwM<{;nLYJnde-rizT3SU_wZX(pLZ9!!G46}m%Bj>i zXI5rb{E{R;YI?#Z7Wo!W)2^6SV-CeW`dJ--gDFI> zGu&!u{4!LSI&n+FvwY?=Vxa}$f7eAFZ{U8(JKPQ+=*cBrs3k)8d(9Ou)Hdikv^gpN zQO*$)l1z@v<~~Zq7Vng`@#?l_-G!K%^?sQq{#FWacckB}T4JGppwu=K`Yx1Tu&48| zrOS8c;pqilyeW1Era+*)rDY`=cgz@ys9J)KM*;#4@8`sx}(I zcY&X^Xs759C>oTIyri+7xl-6pVT>86l%R@x%B~xw#)6Ud#)UE(B?ov7j9Glvk7xr* zg!u*b!)5i$69OnBPj5UuG*S6}pcZ~)^V_A538s4{=Fhc3<`yL>?{UBret&7S=B+5M zpFt0OoOTT*tM!&ihlGyZKf&@!q#u&}dr$9c<0X|2X}@u7QCmvjf(M<&e5?(lLtHW^ zvNZ;Fx8Izh(X@T!g3n5wtz@O~5Shb}w`q5;zLR&}KOU)y`!^qsV1p>^ynSpA3!YIQ zJIO*n!xMt{39Lvy8O-cBIM-O=DE=T zgfEiaZHLyOH+@et;q7^sVfb6Lu7NXh?{YwsJ|x&=MIy8b`twMGi*0Q7B^-prt3v_( z5H7gTt1~oge;<4VDVO43$5T+7sM{(rLO6gs*pZJg4q863gN#@}BFdf=07~TTVD!$i zl%SS~?Eosk-=MRrYyt=kD2ZoRjuABT$JtYFge189NscPO$6^O-9Bczc!P{JNof#03 zE5S2`1tSF9IiO*Kj&H&a&p_D;w8z3xfSEF9f(NY&Xb9m6ZB*SJ57H?>e4r*NJjRk* zo3yU5t9+OAO4HI)Adn;T%PKPoZxQxi;m)j~pQ#Jj!JhsIpOi+#R9xJKX9-#~0O%dh z#p79$EI};Y*;LG%A<77$SIaNDJ>Xwh0ei}n?$Cf^pUc1LgIx#Wg4zcdteXS#5jQ71twrI)hU`pZv9KhNBy??6yCF5uXwAkY1*Yu;@ zHwd1l*8Bfa1N*o|itn}&#zTVK2MmCdCCP-g7kK3Yf?Q!);`bTToS+^i`C9G@TF?*| z8;ta6&ijOxGbBfcxp`N*phz6H%jKT%=vLqlIvU86k&+U-85J~ZbPs^P@CYZNy8MXa zf7}`qjpKhM*NT2etzff0l$qh41NS|8I40OOq;;8I&S;$xOufZxgu!~qVzOy#CL!$? zwqJI)LTlhwLDQyo4heJQcfjQ_Tjib+7lS>?zqjhkl}uiN(^_!k8Oep>kFz(b$`5Ep zaQu`Xvp4#{G6&8_MrC#&Nznm?yc42`uYm{cU)fKY9^8K{f<3N;Z`Gw)Y|FD>(7HZE zlk9hoaOxqXI(ja@@CxikNQHU=Pc3?3pD+v{C$hb?p#CAv!S4U*w;a776_s@S28bOs zsQB_f{ZL&fAlCLJLacm@uYXcMyypD@3iAV&VVaXHGaOA0GFL2ofe;orvnsEX*bfgL zhd4}1eHmTpxDbSjYaGBNEns-DFiJ1Oo@Kb?Ob0f)hyKlR~AFP7lc*aJn$_QSRlTmYDN@U#Al0T?A==9y((-^^f zQ~SEx;Nj_j5Xf0wPZifCU~0sBYXR{MjTs(&Jp>SsXLqy+K%%X47P9~piyQC{%C~aw1}G0Yg11snf>z{y9wxfG$3F5Au_3-C+%0GtdUe>N2+|TF9iCl22zKAo=H2Bc*8ZoX zvDwN5F#6S%q^F1YZ-gmTDINMwu#h6yCsYH-1zDTL%E~K*fAGVj0WDCFdZWG%17KL* z9sGzy4UCBC_vw!e;6-_bKjDCd$juPDk{(|eZX@h{E^71x>?0V?c@wgl67s-GLA=jL`S6u<_JYqTKj=SATOEE2BnFi5%U!PKZX5KwYTF_9 z>|V{|v~0!Qw5_y9WYLXQ~{o z1r$oR1-LA^a8x>boB#^NIooRjBMcu|@y7C5jnj?u`2~Tp!ntgEpFMz#i-A60W zK<-~Yx&M*LA3QP1PQa{#_FRQcKx#IxKvKZ|orkj7JBw{WAe3h3 z{-NiczA(B*SZWyN2T=WrkYnWRJ!tB7i3u7|(4YaMRKH#y+@pgf^>sY=|LmgGFl6xx zL;=Hc_xJ22mG0x6`{kXoACAxGUEds_MZD(;&TQ>oZv?GR{}}5;6Bq?efK(r2f(RUH;4P;I#H7e zh|`7lU9w0$y8yRKURwG@-!**OLDYO#9}dYN9%%O;dE26E*eg~jS5xN@WOwAFfe9M~`q9s*@!PQcP#p zmzco-=$#xq=DN(~`@2G$RZsT6h~HpsFZUoK)~CW#ECl@&4NMHlOJ|yz8BQ>jdAH9@PRDlmo#~dxD2;;TTllhKQZz3DHx@yFD;3vAS=6RY6tn9 zx`^EaE7aTKMhfh9-wlpTKnC+WCsB~$gQPam|8gw1OuP3hc(pH~dAMU1@<(RBYF5}( z6tu4nGus<_UNLoTkgm$d>SalnRLE;K={{UCC=5^g`%`3|GAg;YN%> z`OK!s)EbolNCM*oxDB{I`on_g&ZjY**rqlP zcj=xZ$^Y8!+{`x?L?=IcQ~Q#bn(MFrUnK!!d9=Z`4FXJ>yu!kdfE!~s6=d-V zbO0PvcZhu_$MAYS&}*zTxoN~iIls4? z&2j=gD}%lz5`}})7{0gYWw8xG%=1gQGM@zEo~{&Pf=&FtAgd>QApm*M$PCy8pp-z5 zv;*#RZT?TQ8t(Wom@wY`I_+8Dxjl^H%7LMjY_dQfIrDD6IGz_)Ke*=vn}2MFL(SP8 zm^-$TY|jNGk--U6+EUH~nyV~Y`Je7s7|!9Zo-ILeLa#JDQ*wf_fD&r;<^IcRq*l0w zeJ&zd#%?ZHCf3CuEaG*rndUZJ(BfQoH^MB_2*gx^>Q<##oUMQf2EmbF6o4Y`Aa-Cs zyoJAP9|!HP=&D(QX9RIz@dw*h`_8eE`TP?wtwyi23H$>wLFGBTN-_T{DRohE7kxzi z9GhO)^QVEnKl+*43>JY)vSiwS`IH|xdS8_u*HfILAGhc~aFgR{ENkG01HiYTLHxY%DvkP0lp`au8}_F} zk13?0L5^u+=hu@bjSb&5|M_@`uOc1xSD!*KT|XC2l<`wGNipNSrD770;-YkxY`&tC z#R=x3^n2$_`sHi5Sq$aDGeW*bMu)M|)(^l4zJv7&z)D z2Q0Lc^_^18xDO}BzDCBptf|%8v?4Wpspqtx34H1%Gjy`9QR-)}m#fyxX{$*C2v*kI z4ZsdIy`hKwLVJLvu2!!HAh75in0L=6+r`Wo)z<2TS&_yNkMw>ysrXo*zM)PwnA4c9 zcErXza6x(Y^Hud^_an0T#cES_y}flVsF)&$jQz&)_gr1NL5lZ~*1gN7g;B;I-&5FJ zYC^S@nJT}}*iZJFrm4mmtvd4U*0E-2Z6Dh^FU!R(zRBB&7V&5uZzz1#A1}=|&$zp+ z7-(%n!~9dak{e#$tGxF28*he3;J-&73Xas|2%huro|8@~Rxy>b{Zr>?#W|(RP_*Xy zO|r$hsmM<H34 zaw&zUj17jEO;X>cGuhOCJ+2kpyH}Oyu6u1lV~VREV;nSK_l$Y7v-q*<*t_vPY?OC% zHLXg19)@qHJ&n|lUFi9UsTN@cFabq>7LygpP|L(R-5%F0+Y?Jju0$QJQ z`^rdKW+}~u3402%SSfDKltYbt=R5pbwQe@|ICV#0u)Wo{fknv&ih9DjYXcHnHs>ww zzt2x00l1fG^8$6YFr}q1L+L6#<4F7_J8%f`=uifG|CQr+e z@+_`#@pJ=n@jl(GoM86A!dxB;xjqVt3VZOAkaq9nxq}A}_8nG^koZ`Uf@He`ZgRNTv!5hU9-`8nB*8x?*5_xqHAs zQ$yl9$^REoGy4T#uC37N5)sowe$~^2QklwP3S9>$=)Z=vNl{yz!b%c>28J*wOx#4e&03_nyr(JPqY)GZg$4k1% z#ww`7Yka8dT*b*ukX&olZQA0h{ROc@PIlWfTmsUOUxjaV?r`TV0Hhi}+qg3$A7rEzohoc_u*X0?F1JWd?Ppvcxn7d8?P z2Pb4Yw}xKS!E7VF+KiUW#k**7ISfH-`D3>I$lXZ#B80!|mYP2~EknE}+hc~|*X*UY^+y!kv)lQP?0H!t*p?@jrgtWYsK_!k^oq`AHWY-1 z(Qp5^>#JqGdL#=<5YD1zm&INhf21vn#^s}+73~B~@1 zH5Z`vrYe8f1J0w{J=s=ZVlK0#;Og_n;?@G9)MSxMSR=QigK(BLyVlf_%z-s1j~P!I zKR4mkFhK4+S#awvVeqH`n!@q7ti1kz=oB}S!(Wklu1fp!I{tn00Qv&(6iBY~Xq5}A zM`Yo>62hNOS;EDziVjf&4WoWfA#pUdSA|?QOE>W~-vE*r>waT28XH|svNl!FwHS)? zMm#Ag!IJ@c3B3FRAaP8oZ6s`*)&SyEZbK

    YrJkdVHz~Mle@U@uoaxq4WA>+KOf4 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⪻p16)P*4V9Gnmrh8KSsNDYgZCDxa54ktI%CTv8n_P z|9PF=k@AlQs0yX9AYYzt?F>u?-^;-@$1{rY#75$yAOgIxxF@5?{l4Afyo3nCzCNaO z@7`~kL#W}uN7{D;MQ||-&R`~qDlQM*R6)jjcp%t*Pph5#i9Iz|G2fz`ynAiGnmUyK zBqhp|nT)efXFl{-E;Wsv90b4x063|4fj*s?Q*8t}&d|Nzkq+QPcLFn6-hFEcRE8Kj z=KRe3yZztkJ0Ek*H@Ghi2N-hLcxBsA!^6l&{_y}L0)X%!qI2~FjBEho24tz;0RTq< z%=37HGB}L>(Et}05R0W7YJHbM09n1s_ly&8%a4>u_}EGI-I+aH5NxB%7QJ_8I*{XL zik4VDoUsQp3ASxrN&zfcaeQWew3Wd9@Ew3t7d6$q!&{K!6xI0}k=}i`12dWb&Bn@5 z1b4e&>t?BW8k8bN>EdMS)%-&%&ybH>&T_BGX>yJSHMN8c@@-P*#}uEgGFM)@BG_!# z+PUd*u|k1Pxw4cHHaY{rq~EShV@Xtmawo>vZ;4YIo;zd83Uvu`slH9s&=t7pm1Tp`SM(}B_{m)i0;IvY-R_#DK#h#E;np-BH%-Z!hO;4KeQ<%f zU{TJ&%6*d3j#)jj!(No9c>RZpd8nuFSlDVpij(yCi8kLn-!hMT%ZKWXz%!nMSl0sUYoC}Yf#><9?$hZSiCl`DsB(9FkGjflI~+q}wYRO*<%?SD>w zT*z5IlF#^X<>`D}hJ3$iexXwr8&&k(5%`#kg@AX*xnH+ppaFR6s_;~TOd+rF6X1G9 z3>}xuxc%38w@HOG7G>MkX~q_*QO*e?tIO~g_n{~0pKY_XS!3xn#{OY{G8Kmp|H5Q& zNl~dusd%*{*Fd>ib+Brl?G2Is_HgBhjaq(FwNztihivib9Fxk%`D(2G6 z?6`sj7Lmd3CRMTKKz~%s0^OG0RFqtOfZ2+t?&RTgz7{VEXDspLU+x0Z`f%}&zHlje z%(7Q!w}JXoxt5G=UpvNQlQb;0jr_3Hm1fam)hmq}r49YcU7ZZ`)cEC!M^B0uWR(%= zwlr`VFT&#Z4&{G8)5q#SRpZM>4dxym{VBJ?4;m#T{oVIuuK99Gb|*FwBXjSdWy!g- zJTb&BP=873l#W0Gnx{v#u|x}DQ^!MJA!SLczmZDs!pM&=uSqjc!G$PykUvPLpMrfs zYE7k7*1Tgx-^cQOR~pNEXM?mxr;gnC!kQFL;2I-xfqIL+olJ#|$!yH+l{Ky6)HW2O z|3R0Eql)`s9wEW&2;lXF?lP4UvwgJ&{lIN*Wsf`@@&oqbQ4>IAtCV|GYZ)Vt0;h|o zuM2dP8km9C(*<)?Bph$&NKedRIZ?=7rrKTyACt^U_4*TT^g2S?dhX4=O!1G_G7s^t zJkW~iQ-7Zi#)gPjbdf0;;5WPdH9*;#KTx43Cc3`IbaVohht>+!G9KFfH6gi#MvvaG zY~{E)Hoaa(N64koX&({)?g+S`ELV~^_MEfB7d}hkh?x;N!A36E@4aM;cCeUQ5#zSB z$7SO34gPj|=Dbyo9Fm^h|B$n7a{rCSEfPmoK&*7(5voSczFFa?Rui|af8f8d)sZDE zBT~6C<_i-#9cdZ0)PwpEhVXLAM(y|z+5!?DAqKOo-|4pxLUTRxH*Hw8T<1RS=#JZ$ zrWh<+UFH$4Rw1*^)7RSEuy)@3^|b$ZH!^Ij4q-?Z689lH zc42s+tLyVEwQwKj+V0eq{PRC_vlr4gtlchuvJ?u3ys4?=f4F}(UNG)=jK z+ktOG0b|@aSW9@W(N`I(o7x-nX~ocsRVHu-1KjxMZ`ffhYdrAE@0~8ojFzCvu%K4) z6>XKmmcY8O)x3M|+kJXatg#?hU*cw)1g!gEzu@LI=rfMGb8?S;@HUf0jY!&H0plH= z{tfIbG9uJJ;A@@B5Wn9Sm?|6rI!R`9?mcok(KFjTf7A|QJm`O8K9Wk7liU_|Db z^&pom3iQm+Vc1q3#f49-7=Gq(O)cYtaM{27+-aB!JBPi$s!LhvBcXkv952JXfq622 z-dI$Gti#;ZpNC~frg4Fg97qp3ajMILf>#in$67mTLLIZ$5ibULEkM2!l1{rVSLdI~ zf5bk0G>j;cK-Rz|@$)S1L{GZknxbn*pp9@}%%2vK87>`b($I?&`rGj&83O| z^q9zyy?>2c8BwE;Qz6S=B9adBD5b97ed-=(knwIB1C zsf~evw7SUVrcR2iX$kpBh;vW^vbaA~hCbZT$C@=kcl{L58 zH45x3^YEToovG(cf2WAbY2~idj$Bxin!dv^Gt2*XK_ByI5&zK#? zGCezBXDaNetK5jFxa+d?bydz{ZP~+XZ=q(;?F86)w6+t+!SAJr%CG^pO1eC`wX_BV zrq9E@TRDu0zgRY7CSJ}VMN%x3+I|ESb0*R;0kJj#M9E1n=6k*E354FC(NTb8?3=@0 z4`9Jj?Me4}{&52>WVk;L*1uv?jc*I=%uLr_Uh{ z9Pi|zY^-q^&K!&+SBQZMnV&mkRkAlcv)L)Yuish9Xb3dSUWXr@dH4roqYdB`+ys{` zKYG|9*K>y~=ge}afH)m=ZbN%OKtWz$GyC&o8j6{)O4=E0ItTf<-?H9~`LAlX`pa2_ znltT+8i4NArDiLjuDh`g&`p?49h!W2NblDg`V--k8*mE$Ebe6ztl#33UKp^{@p%6q zPuCsK<@d#{BC?artWajj$jS;C*~yNq2p@Zo$jZ*%B0DpCZ;_qtV=H9u6@Jfi_5FSS z`QF!k?mg#y&OPJydCqx^s>2^C7{p_-sK9|gXK+gUHujj~^Tr#9a|&CRbuXl%)9U0g z&0Dv|d3bcm)6Y}3pr6g*(53y#CT`%ccxQ+pkLLyjbn=jS)?1~@;8>zlaIn#KPj5E> zW5U{Nw0mZHHU|ClPjnC@R}9%_gLvoXMWy!^dJvbHI-4F#fKo;%#Flt+hFh0>p}i>a z3>f@}spU^v7!~#*v3`7!LU~~zAmu!^9u?Bx(1z3~%pjbi51hBHPo2=}3;c10465Ia zRAEjgy<3p;`jgi@$T5HZITW5ZsJWNH&i32(j;W*1mlM}EXY*n<^SZLubekW9*##$5 zn14(xC#s$jO?to}avUosfO8uB9n!OTZ=nvM)!clWJPX3HTVt8b{jbwzb!FlO$@LW) z@R|F)=W(aF@h+bnI?E~7DHCv(11Ig)!-9Hg$?#I$Gh_~GzZ)L9EAP0+_dC~9d-Mn1 zmMIO{*{D^Ck+6^6Z&3>#T#2bTarraJ))R>;c|v-6X&UejdC#R@f}A$?{DNWqU8(Q$ zFRM>wvj#5cr#cwV_qwPG)ueI_8)Z2?6$}^mt=td$BknYn_)qt}Mhn2Wwr%EUW-o`L zC5lRE{?)n#qnP+sQ!M#8Iw$J-wQJ#%-YYMp1@uC5 z%6;z;(A+kPKo;XU13Z{YRQQjduU2gXu^p|G*JC4FEpK*1d^|IB?8SgDSt1>YjiEB%~Di>7*h63%HFKpRWgUos81TW7Rfq_q0jpZZb4L?P*P6>vcQ11lDq+EVd`ts6A0%u4+EA{97`Pd zl$xScc=%z&iie02QLw5+3vJUk7*_Y;*LR#BU<^sf8dGXfQk!d-#{;Cc$gm7$_! zAff!~U(k=CY*v#1fhxYk6|mi#TEdX6Qfo{1S1Y7ltJQ< z!RoHkv4{iGSmrM7LXtWjw^JYSYl9=taFqKh4@i_)&C{39Z zV+1-S>Nynop^k;CBMjDgjG%>W^iFg^s|yUBU^$%XNUY;GbegW+WBB*rV{ND~>4z99 z91A@*X9Q~V`gEA*1TW__d-L!vJlI~;%GU-eQZ~z`29g?Xjm1I&lJYg}vk+Tf8EGEU zOveY-8b+w_X*4`ouN%ky$57@ZyC0A+PNl%+KM@l_eZJVhc2|^14+|@8f5?b_bqPn* z9j)GBD=U%%14FT1I+qz;gka8UqjUJ0GpmmtfD=3uW^`{nXDc zQZzKvny;}5FB%94np|f&A*~v~!^7Y7h;M3OA;0JI1UZ;YQ@%s9o82zF_g#s*JUlg5 zb!LtXW@~e!r9nADM|FpwprRUbRNQrZiS`hFjy$WW1e2`KSA3?#0$^MesTVZWW`xvp zwsQTq0X>6zmDU`F;9-K#A7e0==kRyb55VetvP?PvBR%G)&!bF+czMO#P09jO;cjmQ zqv2H|K~jBGfYXZk>hnTPI}}Xm+Q-=cg#FzxI&ax3)&miFrF8F%7U*ZeT?O%v>$&7F z0O|GGaY`6;I`n)Zz62DmU|GZbLw11ZWwOBYU3nqFrWOIc{6QGd%KkUcM-ZT##OlSJ zDjdBD?e8}z)4C56s@OinL1!^g5}`m15m9u^Xmp9ngpVhj(+29jx(SpMxBT}#psd_C zYbpZib6r5uh6D(>YIJua9bP{-uWN7}Or>N*RhM4f>p zY^2Pz_r{CE*qzLeNO)O^VA)=8aNX~U^qNEEvCxW=f%m)~p8mhS-8y$@fHE+Du3Lv$ zi}sLumkx^2R*^n}z~wl97Tmgoouu4g?IZvVf}VCbKv~@Y%uHllb`}#zlaQpW_XW7p zS+fH2%?u<=+Ph&3B_2ST7;~6X3SeE>toe7&+pDeXykIX~G`e)kM=X5K?O*Ty^QAwd z`Q(t2y(ilrf77|9fJv?=NTN&@m%z}p2LH@)G4=E5J6|B&Os=B9BJnSJ)&$z zwfj~>$p}Ymt)N(9klvm}luyHYX^KPBWjs;_G}F(v*j-?;Y6CZR{*GmU>cygs6 zd|r5f26nuCL#GlT;D58f+wQcbGUCm+?3#Zd>?(@TDgky0-R|?wRjCwtc&1zRs6xMax zSlyE<{KtU)6Bed9VP!g)g5cEO>;EAb_J8>wf{O#ZGDtwnZ4`w`dvNc0k-%RSSqrv1 z7qPY^>qhu(->E2@WVuI|2*==~ZJJ=xvE~&4 zN@%Oh^{Ksf4H&on;Dag(8W33MMs?b!y}cnZ4?Y!1k7IbVFQMXv=QrK5f-QlQ;Sc|& zu_6dD=Y;2o%0(c9ToO&|^i2?A(%gSyI0~>sS{N?tRwa#;nv9P9%00|373HGp_#skiCvp7~q5;T*I5A3V$30pTqcAePAuw zEr8oN>}}PQHHdPQc+%FqJ^+o~`OBOCAiQWOzo7s}xoZsawWE7Cq0pMMet=Uj3kL!; z#HErqNNuP^{S33it?0vn<6dVTz~R$+zQk7bqrZcFo3C*TyGt!-8>J?q^&`BK|CO!I zCO(KX4>+WE(m+PZRz_6-p~-}U$2uEK{d`jt1+rpD>w`~Lf96q%ivG6gaQVZ+7pKp0 zL8E}LJe-B>zf7lNA*)`%L3DW0won$t zZ#h#0B`?EODqGx@ErjD~3g*nH+Y1nu^>&{jW8Hw+Jdaj!xys;AnhB52;fO~da$a36 z-H_{#Y3gYsLIv!yKtC6}vEgv8Y;tUK zL1K~v>m2IUng<>xT0ckd7ID`UfY<#>ay5&J+QYIV>@6Kd`+?heBsBV8BbMf&V#hp{h*tl>=iGmyKc}aS5QaR}5-gWSX-S zg)^~B*Yc7(Ecviw+U~|TKuq0o0E`!3e512W% zd9tt{(RgvrvQ z^ufN3-zn!?k@+h6IZ)OCfgB$jAmB^FD7)gH&59ZCLyip`) zQ#Um-3*Mrj$|PNOm6&7sRW`%Mg_2i<2|UA^D8Zi}MV=t+@akY`49Uji=rcb=aqmHV5Sn z2@NjE2}t+*s#iS@2^XBuOrzSVyj9axKbYY@9o(j22~j>ISzCILtoeh0%QB}>z1h)+ z%z#{?vHRBIJC%WBCNm@KXoBq`1P+9xVteKH~3tO<`ysO=EbMeD~sZ_eCaH9mh9*#Q_Q$UhC@d!Nch>b;{mb--+{?Y(EX%JH1auxhRDV8x z+c?M&inFMpVz~Hq^t;++AKm2+tGu4hG;f5sd@eCm`jjbN5Cj!L?G|pXBJ$GpBKI1ye^BiI%1DENYIqaGUJ|nb|<6lb3dZ)itDW z?Gta=Nqz)e7sWrA6%?d+8hY2B{hP~UZm6KDfrP7_Si5Ik0LA`5+*}nZf}$Djr8*z# zX?UZ~WYcZ7`cXHZb0sqHo^qfnEg{Rud)p$4q?76*?MbaX@rrxt;uxz>p|}O=eX$OdT4Sz1BxwGDq`Z%9kK>D@4kzgSHEz= z3)rgJL)i9ie7wn>YtE#=cwi?cs@oT#-cRf-S5n?J5Yy@OQ7iFc-nUClxuZJ;YSEp` zcC9pi_$BJcm=KDEQJ8#hu;xi{2kp7%H*Kj~MJ^Qj0=67`7RR@!+ zuoIf!8fv)AEz2pM4Ka>hyc7MPJ1>~a1`j{?kxVx4t1wln%%MwHo$#)ESXA z&9U-t?9~YL8wUhtLcQ&&L(+bs2=N&R(6@Byn+!73%V+h+ zq7VIC-&k*Ec1i2VwvN1iuC$MkGbH}0@>D;G{2Bh)nWv3Q4exj(7Bn{Fg2p|Q!kEz5 z1sd}==sv}L7DgYQ;t=wQF@41vZHRb0-O>D(P@jkk+HD65@AS@V(qWgKhxSVQRcNdC zNAsMyZwXn7xR_<%3=$b!#QTyh`R&e)kJR`yLTbOwYcf`LFosm--6fcA3F)r8^ck(( ze^(@?3 zP~6xNwBr0w75J16i=XH&R=KyMJmZSA8_kj@xv%S6alsLY>ZDjnSLCf;1cNZaz6X`u z^@O;2=?X!bI%)GriGhe?kpRl#LwZrE1@zCZ6X|aN9qtC9$MHA@e)K!X9*G7wZAx+H2hdj7HZg!-ZI`5tBOGtNc!PA?OW*o_#b3@6Au7#?Ub5_0)V1s z`&(4-ObXMFhhaq;&&@6Qu3(!5L)%_sGr^0)8(q&}_^%q)YP(paxF{hiKMrCRbSDWE zP%*{%?&aC|r9ph}SEUw03n`sNj@J+}1VGT*nJqMUFrV$ZCk%KvN1x{r+Cku3*yTCI z0NwaUXZ)g4HVdeqr*mkKl463SlsEMU^rq2oz^Z2QPvvnw^e2Nf(}H`Bij<{TSe<)~ zMMeG<`V-<1oxa#jPoFgUCwpE4h9UHuBV;?l2+j{mQ!%jS?$0Aq#dc(>^i0}pTbc>P z*zG#G)!HJVq2^KqEI~gurg%Vd19C~U)tK)S4nEcsH~G{aBlti#E88)Ui56|dt<3~U z)SZhnxpXOHc)V=L#Rr?2xI4p$s$afOe=G=J(5Fz~`3+QM=?QsBFvVYy3z9iH(=Jpm zyvFJc6>ip93Un&vyVEjy%u*$5LD+xW-}Q%WTl<}N?;6P8mT6vP4ItaHdi{_jqgw`6;loYiTl5Hx$B(!y! zKC`b&av-A4N#st%?Vu^?faOp~PgE%Z6m;*Mb|HrB=W<94=x?ug&L47Uzw?KE(Vg-p zt;HN4@)bqfUS~6buDn%6^b294PL0SV0ztQ$69U+5bgNSe6@XW&tYoY%(Z8o<-ptV( z=#oMcKTeo*eE?gnXoJ-+=pQH2ud#%UNEdjB41|g9w2*C_%G>QmG!Zl$*;>lM6jmIv zZb26D@a~P9^LvNfI4dwU)!c7sG|6rZoF9}OEoOegbg_~yETG>Sp{XZNislM?#d~08 zF||lez+s0@tks!+ayzqve1GubjRO$KbjJOF9PoI8)>sII2(o zX|2JvjwPjo1?HPA@~Zs~sLe0VS;HQ`7cn=p`*lWs7vniTHGxBHEEG6llkzSN!Q5N` zQhq3=53*M8gQR#*8x<{M4aJ=kX#|Bn_Qay46r^c1@qk92l`BQ&vy;HS4wl}~{#YwY z1Vf+yK8Jy{xYEDMVdo;`>JZ8)onv>*%@_+vqAJ%f6a}tV=9;v@4D`^vQ5J&Lfg2$L zElpHO-bdkmj|vg9yllbKy0Uv@{vMe+;*A9`#}}64uXnL-L_CAEN~lol5wqzV=ml%L z_)Sh&mw*~E7SK28b!iiQIvVIiuI*JI3Ieaz%+*d!TqB0bZ>Aw?&l$tQIa?zn1Zj>9 zYeS&010U4Hk6GvEux(@Aw4MN-Z>n8R@z3-1yK}4cL58zc=#LltIDAv8^cU*qu%8x@ zR?Z+>TUz{ylYzJAB#c$u1)2B9W&-1pQ^GuSk@!nKtR@dXjjO0j@2V7pf-e<5mXTET zA~+4?jZgJ9cEEMl1J+z(poIHATyvHLin|~b~HAHlv7oYF~zfZNpfpWtI1 zA=rR5>$|g|c(6CWe$|Zuz6xOID96SCxka{y7{lneTj3kPihH)XK8&ZO;=*5^krTQJ zxzQM|omn!%eC9RgdZxi1CE2_X=*Hnj6BXuWvdgT@McEaI`5|0k{$J2TymH9DxrzG z-m+N>+_2;`HlKl~(|8*)v@rkSf{TV*&?RIZmA0ec=07idye6~{wgp{^7K2)Q&hd;{!B)wSpZs-Jv$+>i{bZ@c7! zf-X>x($-uTl&(WCKhW#-{R=>1xLsdM!OrhuN2%bF<40NR2c;YIhD* ze=Oy{^g_V-XOJIk7&=cl1Io$8v4pQkAbR2sS%7o;P$l>WGE+fkk@2W$=*y?jX?~Wd z`1u2DuySPSKNFh0ma>$w52zrz2cmA-?#5q`qTF8X zX59u;=UlNTgK*AYDYFXb%8+LJA>}RbJ)_^_DlrL&mNt&VcM_zJNmMN_*djmeeHB+< zW1*{iwt}dKCT^-%l<*&NK0R7&-UpN*oNnAY5Qfq*;z(NFd?p*n=(P2S2xRDXzkBST z!Tq3i`gNp~^s5*s1}ZkTDFEhBzNkM&v)sQ6ZZp#laQLr)=Dqs(&%(y}Ca&=kUx!0s z#PXO9l0kt-%4P|*`AB8K2rx)>c{ZB{GeGFuQ6ax_f<$B{) z%Q+5w`ot0YUtVchp}mLT^#%ENc%1x695}zcrl5bR4TE?3V<3DS)PhC(&^JnpAQV5KM$2$g;;`7_TV%hG0(YyCk{KOe2!|!Y_4WZb)PX7?AG6F2sWoP~e(r@+VvK+VBRDog0)*D&0gOoiOfAjCbc5qa2I! zIP7t>#9WGB-W#8&;$)S+`e|$RmEYwSN#-CK`#~rRSlE1YhU%U-cHWo$X~Y&a-+Tl$DemVJlsR}BeZ$Sv^G)MkUfinhSy$iQ z8XdnqiE4bvQZ<^El-ULb-gp*K(4dpeN!f2yFkVx}r3_v5_|G3|&)dFq7iZhf@oc_3Bw~m2{$5B)#5I2?z&bj;rr7fYtw;?mm_n5uevOD0o-C8mwpjwk(9cf054*V!qT#~M332NPI0lPka|`qwpw>PeE zxSr}{#*25LR^O3`*EN1Ah05s9Vv}_X^c&e64c3A#WytPdZVR7<|LQR<#-l<$$Bp=9 zmUn&skBISW86)Y3r(}af1(NK#C_tJC}J6X;7hw`f{wbov0 zjM^DE`Yw}k+g>i)oG*)OwaiVOOe*A2HRa?NRIPEX-lq$CmfK+=(@ffafm``XHMKTh zZ!XB75+&%Fue$DOz&KOWFfBl_!> z4Jm;yhlCX*pEq7MOsjS>8-7HMFXFv~erBDYI$g0$5A5lVz~n!A<6OT1TDY*)s{YPi zW4P3i`=q;a*B;5Sd_&f;pWcT1o({vi)y%{3u}Al&UyctI%|>(c+?#$eKD1b~5vQ+P z6m%RTT-{|*?p)tjyI-L19FsV}u`&s*O4G`v4KjIpmv8nr)odL4D8o}GC$Ha&D$bjx1!dFoS|laCOhvyCzH zz{U(1n_bCqT`T};nRxcLXU%>l(~~-VLjr=s@%+WsW(5<>0pIbG;2DgtKQ2iqISgL|M_y zAqRbX$EQbLwx#!P)+;nR8Hy+MrA8|iDjGitlwlmZzi*?GU-+AZLR*=)T8Ub+SE2q{ z=W{lDx@@yGsi}D8Jib`LiE-l{7Zz=n!PN_G8?K`E=Fco0ZkIuymn?lhB@&W02KOvv zM(gGeNKj1n4O}-fF5&uF7kT@zzXORkv@<2C;*7=P$)A!aNyRpHaW+*}Erb&m`&4=OlJblJIC@3loc=C8wJc7#N&nVR>>>AZ% zzE+XK1FE8uQA0**|3+)p@87hw{Be5aQcQd1t%l3FzyEUUk@L(bw5W2AXf-~iu($A` zV2bAbIh$iHKt6IF5q}}6qm_2_?HYJCc|$>`XP-B8y6&8-?1X~j`#J~d5%1spc@HJF zAQCB-eZmFkFM{WXbHyz8)K31|9{Am55wGC>D`x+(%f)-Nj4I*IO{N0ITrDD7h`ldYd8plU0$~- zp{0*hs5kRIMKNQp=LNlXLMggA5q@_`tgH&&Yk48|8q39@DB@Qts&cJ{?DExK+y??$ zd#JHl$fg8U4-zYzx83MpbNju#WVI7^(ag!!B+U9V@82!X(m$`goEuu|&3nFoS;^NR zSyam4ms%LJPhwtXlg!?|U2J*$z9+!Pnb&c6hO?moU%W42`df&)h%;GA+hy0s=lE7J z%unum1%A|seu2p6$SgY-SW-g{uYGoxQU(O&$tpNPbE=-h?5_Rb-uM!G?$ zU&>Z9yWjbZn4CDA`bch=ica9iC*KYlymfA#aj_^ptTmiUgsHrOs7&=89E?L$G9fC6 zvmF|ThwEY467B1I$XP#VxovK}`fXVeIad0F*iyyHjon?so~gRBBBr#%8qGZW?2Trh ztg=rtNVD8g+#t(3|H)ox^lOWM+HbM}8eN}_+WdXMa$#dETW;*AMTS={I-*?gGj>z= zwQggJxlk$JC2kH|PK=pFLj43mj!<@t+4{GUcQa@2PidcCOzH^O?kk9-UUaKl*&=p_zAJuQ(yE zm?*?Ha%%TJpKW;ag>1R*UCOsM3Jj|oNf1-gqa~}H^TZf4weq)j(aQCIDiyFZ7H2o1KZxMUvrvoKfKDt<1OTCTnZIy)hypP z5{^-IYfO1S2PAx4ztxFXp51tV0P2tqsHt)g z5)fEXAFj%5XozKwDmS)qZ^g6WkC@!R3h3nZc2M$+@j`iHq(}9u z!mv^EyP}qb5G`wz&aOxoBrLBBC_`2KGGk2YcJEW z6=v}h8l1hAc9X4S40=gN;#oQcm$F}#)|c{sMQ;D7ZY}@A9KG&%@=198!~bz5osu+F$I$-#7!?1QFJ8moXpn!v3kK#ztVK{;z`JHt z8-E>P(Cp!XJNOlJ6X^M?JqMMa=nR{Twne=Ns1Kp-hl&m;u#G6|C%sV{prWLW!ITQ}2jaQ(E)%KQd$ZRPiT1geRBI*bDt`m>TSQ&)61%pJ^R<4iui+VDoQhRSCB`JFJxLM@MO(YenR6I}{V@ zJ@NJI8nZ&%q#%bG9M}Ge_zVuFq)!xC83hAL8+Y6T%}C>qSf0tkOpT=+*2D*Vkxi(6 z_G`gsetvLMi^Bo4HmGv0({d+1V!H?ToygUtuz@*ktKti6SW{J{=lh1xnc(3SSL?LNM1fsbLG`$QnGS`0Yh>AUIbs?IY+XYp5FfBqPWOYCFK>6FJLYvsT|M zh5Kw)wKr`+l`?m1S5^Ml1XRlV`l4JOG|apfHyktvbbAj1l%a}lV#+3#UznSrmawej zztYx0zsqmCRKG;CCb)0KC$w7_^v>i8eMtdK#kDgZLOXFT*fNi)|Ly$VkS^~ED>Hnt zM;EDz4m3Ap-}V?-X4+pbPca|?0D&#whU}!_hQv3QX1TF^js#y(C09Ad)f>Sd= z@RW$%^v)rex|q~0xoT|?#Sy57ERYW2^?YnY5|m@!StJQgWC5kQoQ~Q?$jnYqkcVz^ zw`F=T1TI?L<}@5Pfodfc)faekIY8kfMmh8yc0xQ*L4EmENC=okNbzzscsfizfXizF zp3V&xb|iz!&48`KozGA`E5^XXoijWZ;Fe|Th-3MK~2iqw3S`yu^h*r-%LY}t)=zYATzX1(J>G+Cp zpo-Z7UlY)9v#k)+-Wv^S7VikSMbm?d#HIIJ)|L98J%f_W`tTu`{4m{WP1*qQh5Avv zbOUS0(Lo)ivEk+}0H2;vR&~{ju)bka^~4siKCmSH116hlCqt;fx)h0mQh=s7eVq+i zrvwUBdoAuRvNuAt+-PXuow-OHyFllU$TUBpIMCqu%Z(YRk{>E%kIJ7!Ig$bGCTUow zHZkC^jlWPIS;E!OW-jj4hF1l}L2M&Gfug_0FI0e@BCos|3na@!xGLKqEN2cKz>x`? z3~;?_3<#{6yuZnh{vKlXssug> z>Bgy3y;h6>JG;nz8f~1;;g**$y*+76=RYbigG31gE>l`Y|Bc3^GI=EUM z1JR(LVhOfCSWR7E^n{p`@`)(EBfBCXg0ivr?y6K++vPVD4M6XXV!duO^#0yAjmO82 z8aD&-2@-i_JGJ2ZD9{T_xWx=FTZX$80~jeYr9QFu4R~9$Kr(OJ(nEGe6j0RcXGjqf z03Ki<>_zt?K>v#3^1xTyIw-L~*|(nv{|9J0Ne%J|fP;G*Tf^JkJEWj1;f32z(DIiy z;Dj0Z6K*yUY}!!Yx(fvKIBcun6}q`A8usl8EEkENt8GPv5-D+o(;r} z)wijCp{+uEB0;y8u|c!p)J7*SXdDQcPE8c-Xuk=^_}ZM(t|nE0Ks;CsG#Bdrp4xzd zEoBqxuEl9_GAyQGh^&?*oKAEpk?(BKKftN=wTiJBJ{&v=9Mcj7K*FHE+>V4C%p3if za^`UYypffxVhMDT@Ez2IbS=7rONNcRU))VO?pBDN-Bi5}tWc4r67?YHzCp~_)J0Df z1Z4SnL){#t__GuKcsXuPc)g1NCKX84_+bS+)wX~-;Rd205xgZ zxr4@^;+}E|5)l65&VD$8n19;s5V<1=PN$>YQEv0|!&W#a^L$M$ON1d)&OTWOSBCFe zjE8jKmNM?-)8$4BD~U#ZGR7LDsW(TIdJte1KCdMMt;mRSKrr9Z+zNE3=HaHKfD0JM zva=lk{KjUZ8>shFM~-}ol(8R9^?P)?(@_q5m_?2|-GCvh54f_dmRk|QbK$s~`j43V zVG#$~f+s;!D1XmOe26a8VpfYknIO0@2|o?M?w$b0l+;);V%QK4Q`zP&`_iSN2z44c zc^S8(U2$wi&j~w8ycx#Z>MICc2u2EyLt%-N$g`+Hzj0rf?q`4+&zD~A`Y)*8WE&+g zG*;g4dLlfu#SW>0ZhL~wsDhP_od0@-ByjZ-z&)pjTCtQI#w}gPR*$LjjS!TTBm zl{=;HzkEUSWg{yZ1PJUHJtN5de!#KDAzRJmsylSFB7Ovl+M>zgwsk*m!AZ8WP9azq z&LMvg6X{eHP$L8y8XuSCr>-~JtUsXfakZt31&FZq!&6M)F*D-rGYv2$Zgx8qL`6l5 zxl^ca2;wDtRBZ$~F2pyju#Jf&1@x^zuk?RFuLz+qZ9=>ku3c`5i8sJ#*yIGJj1-ti zKnf^c+SaQ&!-N|;LY?uSd^qz1JyT5{1{d*w_Gw#TTL`1REv+j8Mg8sjJvgXsLVvk1 zMFQ?~Xlic!_#f(RvPfhANFkxQTGryw>sg3qRpCl-EpAXR?7!a2j1%BK@+x9DZYl4X zlb13}t336hfd-s6-ZMH{kI6tSOrpI#_o^|WRPOE4JjkDW4FvvLM+?x+;zTf$c?Zlq z54Dx2-ZF>w4%aFAV|#+!pW`Ol5DU`F4@_=^<8Dbcv<2j z8>Ri64v+<0vPPfE>@v`(BfQc%h!ICuX*82=hl52AOw2w2kAD7ipsk%V1_w^e@8`t1@)Ci++Ac&D+Y5VfpU$gr9|-es zy`lsulIsNIz#93nM$m$^ZEEHEi3znCo!QEXRjUXU-9fj4a*B#@K@vjh*EZvE zi-4{TTd0OK#OlFBYxY|y`0RhMyBGFB_sBN9*Q9Z%;atQbxt!7=FY}{2N=cp6HI=RP zk4b(f?blPs*LIFenYl`S{u}QLKFFn-{^|bD%R%+N98&wrj)Z5?>RhBJjhdbvrg7_0 z*g{esL=mMNR35>{3L1y{B+0$$U)eR;$AZLvXa4t*V5EU0Omm8TGCKv$1y1Y!ee{vEm$gudg`{S7rXWiC><|3r z5B~mK$TQY=pR{X7LW$Jki%jUA_Fgn%nIzW5KOLeGDGHZ~@@ve$`OW&K+S&txJNpEZ1TjR_FGz#{B%T3x8eMvn`!7xF9DY9~mjXk}5VHvT_{2$F{6B$*Nk)2H8Lu09 zyxr4P=lx8mk|i=83lfs6YuOnd{38Ep)u?ZooHHxXwqo7cg_3YV+3k^gPsvFoFp1?G zbC1Vhxn8VN)oWw@w;#lq)X6vP?EE_GW_kI87y6fxeD>oUzSVE@Y(f;v9^Pi_&WW2| z5r^KgVONh<^%yjo>89=}xU?{dV-deYX9gS?;G)^ma$Z zN1(T>^KsQ2rGJl80E5b3U*^l_T-0=3w>;}>R<41O!YUMiJGAblv5?pW=Z0WCSA%UU*331fqnWVHmWp78hUvwfrv zop@;ABAog6)%$e+>9y~x_Y;v%DLzskVyfA=p#90yR@^Us+V$z@;#2yb+fai-2Ky7C zXL|dme(C<_8gWS}Ee8UgB7?0L#d0qc-XHT6DM8ESBY#F7sYPZpyNuth>{{&_Dee=x zB}Cc3c&*g!)!*}U5%^{9#S_{FhMZr1LYXEU203rZe+qNyG_~ZqC?|xH;;RtEf2rJv zq|J#N)Uv3Suo^IQ`Vu3#+OAwK`KF5PLR=lOOuk5c%c7}{P4{slR>>H-VW!%&QkVbt z@Cnl1fnUidT!uvAgymm~Ufqw~kL6;Fi@9#Eqv0-JpnQ{CD;tkX_+FPvq^>;tmu(xf z^(1%-mB{1gj|dpwNPiF1waF~4yWx4}?ME0o)!Q~CxkY5O&wUrpM(B1AN^_$=cXI8Sd?3?K zrJeWvVq)g&auA=0clU_O*lt3^)!fvfyo)=t#Pj8%(_3g9sN!N;GE0`AW3m48g?ot} zJW}0w`DmTj&sd#;r$DLbX})zG=i}PRv?WcQi?1C!4Fl_DCH5@ktsXki{v5K*#5av> zk83p>N!!U^H?lsiO~~_jp8(TWhn@@XJYhN42w7D7JTcOuTOHl(p1BSG2`)X->zvgubIFCL<5bpn@wfw~P5y?}enYV`&{}X({;Vr=|CS^CUuAJb*5|iG zbY<-yYqgQnGJ^}Z9NF5ZlNUC(KgA5N$~*KMhcRrq&$=E7n{qWiIoVpDc*6B9JWj@5 zKnbT?vbDUFj5%_|2ZcOP=BM3{6_d=>Or{H;JsH`pYj*Ns8)%f6wRkI#+v#oD z`}M1tJxPL+t=6c|hoBL&2uYTot2Z^{r86GW4LH5=mFFS#aP{e!DjI82x}E61uNl9u z5ML-}*=E2o<>j9~ogQW^segaL%m0z-&kw6T%&hmQwiQoZL*u>&wq=!7YCS@CY+A z%EaCn-}=4m7{FZL&gR0I!TA&^F0opYAu0t;GkFFu?^+0*LetsTXws$K1*GGY;%u)I zC=JhaOG67jph-j(&kQy6F!xMc7Y!!6_kAH(D}TUOMf2Kuu5J6|w?!$O+sH2yv!~1r zoZ~9lKV~PjgD%DqGVCg=_qC|vSQc&;T-SCTO*P(KJFc;)=JseQrEGLl=6_M2YN^o^ zv#0q^o1WV&dDZLDFNAVY=40jZgqRnvcDjq4&gfAMTu7v9$YY+1aA+DOE6(MPepmH; zu{cBl{WTg@#!q?lswgI}Iqy@L6UR=a-{QY%RNq0$KbdZ4eWyF4ptPXu+3Fw8CIq@qB7Scj~>9@rJORY z)r>0Fv-+vU~qWYFUL!?4A3>jLE51+3Xs- zW=CHcBvmG#?LR7r`IK|u(oJM#bW{{J(#bPeJAG)>ID&$}f7;$nmaNM7b43oHg|1rj zK1uHCa(aHvtuBh)(ue@#hd-NwT||N|UcTsHj+W4WQ2434t%Hdqq5RyQ=tsk}Wa=vd znyyB?0Zla)s?X=lKA%P%zy0|lQfnGs$>dJxS?_6Sy^duQMRUt3C*)}s&k9BgTB;#e z`qC_^6S?QiapbvSj;WMtV+Bzh&k5&ynsIgc$zJVlMU(^s!fy^aT;@!y^>mUUH9MkM@&&rrqXVCR{*=+8 zGg_5^9rJqdCp%)SO6(`Ai}u|x`+*i#7tLAQRLPbps_&<99z;|d1s{Jlw~|h6qHw?K z?GeSF+rU%&$v$4|N>nzDYBuf{^ypWKR=F6`H6H&B*GRc~`MCa?;i_Jb<%mHx8}z9% ziz2g<*4rQJJLj$6KPwM#d>q2DyooFOEkMa?d7>O2hFCZ|WyAqP6uQOv80T?$`t0}h zALD79tj+1!AzJok?2miXJEv{WEznpe(zD(5*i{6aYSD*X) zb7hh2LON&`jwl!`b(VhRNi~d-zU1iKxV)bS%fs@^4@|2j3WLj8jWbgltFYa~MjmKH zN#9>%dQ(*L>)O!9BSMOMA{Nkx zs`qQ&&XJ2^4H+onCE5$U<@P36YRh3&Yla34dOJ^uo4H#aO$FfxR4ql^L4?p?gJ#7h91iM zxEte{PmWNvTJSYi?Jv0!H)e^l<6gA0%iVZ-9%O9Rly}Na_HpvB{9QV1wVaD!d<7K- zv%GAXW_`Af#on4+llLAsGcEAiYt*@&1jOGbikDE|?rHp?`1`lw*A}TF?!#5JfMjm< zNX-AybdBM0eNDWvlg4V2wy|v|jqQzX+i2LhvDIK3+fEwWwr%U(3hj-c9CEVi>o_Ze^dU&4@(!dS~R+# z6*EZJOJw-)GB5Ik91F&<)Y0RB&g=q{@rb}4H%(n^6hvBH$b?%1EeIl<9|wC3K7`}f zcldrstk&H)vz}I7y(;S-q(fAzJSP+lIs;W6KJdI?WolI=k@fk&<0$F&Uwu<=c51J(LwbZ+7Ba+(rB)gs$TGWT3;Zyp7; zmMl^AM)z~~3X<~kumq@3c@jB?xgzHpW!K?^qD6K42MiXaS~(RA{}hL(r!uKWLLe(~~uyt@iS&3P_EU zH_z^lW0k2XKRl~`Pn?Q56`MN1vJjGT-bCh2lG#3GP$F613>dX_~oc^WJc;SxgG%yh4$d9$0c`@pJ zD$$VJivy!7GP_h5ryuq<(y|y97bku( zsvNlxe_+)f6vftS!h;0A^EWtx6q1JYKd8yc$AY9whGl!f=mC)1_52tIYQH%|aOs7T zJ;P=4v^Pa5!1Ti*mo(1>zZ0u`h+boVArfIija6YO;7AqZXZ<%XLJx!&iNdo{y{>3m z5N?r?!Dq*;^HI81O9ea7Zp*yDZ$}Zq6PsO6sw-UeKUerSn`*#%_CbMB8>X+(%r{fR z0vg#cv=BVWL9AxaQOpWgnX*+An((B6SKLtivRMWAP|T+J)Lf#|#`Z?=R{VqcbC`;5 zY@Vh_R*D1-BT6O*i4EEk3VG4{Rw7WxW9Jf5cCeD0#1$kylk|DLLUbVu2p?|0oL zrXX{Vcjg|UD;s^kc4MC(RQdz3d=wAWAe|W8uWmQY4RF+2nf%2UwMc);4s{#9p9;Fg zdN*bn^fuzyJNmNX9CcQz%A&+%+-F(ARMDazHf^(nAUQcxo0CFP-IJvEIc>5Xtu|3{ zQr^eMGY@cQ&DToT{*+wlr~7kS(tl2ChQLBTIOTHeP+Th9GO)ZDHxRwc9LrSq{0t%) z4`5SgcCo3NFGN^`Jy5G0p8ylfYOHA!FS~RTYEto*(qqAQ0LFnqN*#i<9rxW&c*6SM z4F{h&I0pv8B|E}K9F?E20_bWKxYs0<9YuVj1Ho1tlb>*mx4u698Z2P(6LODCc^2C= zTs)T@rBMMzjAYLH)d2Yv<#-+yww)QYI$ecI6Xgw}3lYLeTP1H5nQ~1%d!J}bs&~Qf24dGPV~&!j)sI(bP7=|ODT=XX`S-+ zHv_6SEX>$fnw9eQL1u%5`n#83yI9T78U#$}cJGXHHt~p9hC@=qA9mFLHkd$O^kO9d`hvX%D$ywW+gW!uT=(xS!Tz2jDR3rAV}`hwW}cr@&tlxJUzV{ zfoRMmyXb^K5epMlQkB2k16d-(3yyRXch)^4EV0xHHHqDXOarwR0g|cD&0k{W&fUt^ zPKY47x|vF#@Z>hVFIYYkCU$-uccYWuXT}Z;F@}X=$=r%tjD+0K$94M@x#yH%gD&6( zXnM}M`0`hk9y~C_od_y=@4VY2K+rAu4y2GTV$lf+#9o7p-jhnXZ~n?N{6y-;Lq9~z z3)R)#BIn4kxwI8*{RzZ|>D+46 z)n8_NXGbr6W|p&|eqw4&RHVE%AF7&5Z!R#Ou_SDDXum2%EX~cgV-7^72*F#&8V}zT+tnGBqm>4y+iAc@p@|=SRIJ(!iz&xf!K`fiv!Z^}DbJepeUFQFec54CyJy$gh@zk|? z(6O$OH+}cBb>wF!>shuUxMwu6Q?-NP)Ilx$7VXHrUf~2D2~&(BEwD2oZP818{V|lK z;l!E6n&x{^v}lg9q6R8v;W%8Nf*TGW<|zLdnJ@_<^h$`mu{G1RXY4tJ-Y~f&A!#R*I zzBTC=yIlDG{D_vDe7W47AWXF5hW-KJ=E&5m&@&hv4-Kt(i~AvRM$>Nul&chS-^^6C z-jU6&Zm->eEZ{(XzGdS%LzesHo;kql6rPS}*fjIm-6JWBCn!kl7xSyQ%}DA<5RCKl zfdjb*2R7mK1+Z^^VyodiJBr`BuNVnrv@a_PlNj1zLy*8XRRwFH@m)lFHlXq$5~{Y; zG1{>2#Pz*wElTcq*EFz_y{$mU^LI<`wh`*i{(T(P?7>4Y0?OgNl8Z^7>BqoWdX3e+ zt^lrAjN-X-=y$`W3nh+I05>iB-Yga8@{yf);Xl6i`oQ;r)jqw|IPXfwuIKDgKQt^j zx*+eqgNDm}^+-N6Obnr;f4Dv(Nn7%-Yb%)fl?9Knn&l&|lZqRp4W91 zGZVCNVIS~bZy&XfP|;s*JX}6JJ~zI*vIpf%-9~SBz)&GzElY8bBIcs~#fVGc7t;Z7ila1!ifdv+!~F2DK*C zTHZ#6#{)&Jj{ii8MgX%b+iFtvBxwhIwv~-F}uYlU# zYf<+E$2_6L93vuO2AR)_30C+g9vQbp* zBaWxMdr20`r6p`m$@`)$gdc4)ngDQZ3JZ3s5bqE~APL9yL)+3;&tdwWuXB0IRVzqj zvHS_=Er)SmL^8;|I{soTYah{|H8FM{Y;_rWB&er7KgCbmF8uewHS(U|EfU^2ywlMiuebTc#9y0MhKPrLQ8}STu-^oCaaU$DuRy@tHznmmb5nTE{e8MOlcvQck@H`o}bqtfV4i zOy#1dAtf{iBo?KT1tN0H^~OH82^aEz9~C5_f_o&^^8Hf1?WKt+YCLx1UD6YN!Z9UG z?|LOPWFOyHxXYmAMB4!_zt^G>%tnAy7`3MQHuPsi>~O%rt3M^O-`SHJa;o|Z%^qBJ z=PnNbqLQ+IL+NP#)&E*;s|toub)9cYl`Ti@C$!7#5Sz@6i=5%Uj59;K_BR4UwVKHaizE}*4WUcxVUTBMBs1v4U5&%{ReG{)rH#Jq_gyu?r zU$RJ(nh?mGW7|;zOQy-~u3VhYw55o9?eTbEn!XA&UQfcdHt(%EZqa+#EboZdl}c%O z0k*GZPWiwZrA%g}nqlJ($;R-jLoehgxWrV(&t8yUE!9#l(lI4|=YBN`D!ju#`EE#A zza^LG`*bw}f?%v(kQZNVT!5J{eao?|?(9T+HPUPs&u4b$-fc|)@^!F!gK=)|m$rLS|Mpojb?(IP$q&07Or^-8L(a-hBMmW5l zrqSxPCT1_OH4w`-X3FI0bplT+LcGhCN`!6; z#y4plH0Hd>bp_vLE5ed5>b7o+tN>)!--FtpB$+dgOqkVIeLW`Q zsBg@W4p@pNhtSGbDINVpRq86Ez^!bD_418bg+vd8-;}Y*eQ(|@tdtU%Y`gq1B~uj+ zBBTizjaR-Y4tW+@^F0WTwh8B*y6i}LNUOX3nht;$G470y3=!ugIeoy9R(Jn3J%|^5 zWH>n5t#yPg6Q(~nDV$e!&3OcGwm@t(4K)|u%4mG@O|jf6d2M$9cKew3$KkQ<6;Uu& zd8NYHE%mpbA4FQ~Ie3j*WMq>O&_S2M_)fp<=HU$5>;ez}Cdu!&&G;rO+uP-j_|E4d2_rb*4^E%H z-yA!iF$oQ6Y&7FJns~#~dIm){ofY2{XZKiIxu#fHLi=_&d3=g_G@9tuNtQ+Zs@TlB zq6(+c(kn{f#@EVUpak`6I>TkB_8|iK!3pfU^PFLAlyLameVOQ7;3UYmp@n`C>S;XO ze3d~bv?;Us&!rk=%KgITrP^u1w=40)N>MY{QBi!=N^6l_Cqea}DgP|7`5MLfKO}(Y zz;2@2I*HEbNzEi(RoUWy$_;?hx=Hm4^O@oc+A`Sosgk+dxAaGujw8{VAYo;A#*ELbtMhE|amp zHH3X!{rY?6Zp62jj_G=Cw{A1(^L4A>SIgPvXBkLu+t2+P?rOe%*=I=L>Yxv{#({*5 zp~FUkiP{H}`Ql|Scf)T(Ekcg6{92N77OVKviL0q&JC#YGcR{Yn78o*&R$XZsve__- zbGc_-?x7DRRzuFyjK&^a4hdBsghoyraY3l^lo(g5u7=feUV|S`ovwT;Ej6iD?G3AK zWU<6WSaSR5nuD2H6QtF`tCrB_CF#-(w7`rndazkymI5??RNo${ zk#-y)btS2m;PUr_9+{jpudxWobWyM>Y+yHp8endcw5c@*APuJ;aZva0$5Kf4Tz(Iu z9o!sphLE()HC^VWF^6f$(=Op*5I2rj#weOCiiq~okW6uDn!s}2C1_qHT$EzQTk8NK zCo3dLsrGu~_-aTlcnB>pQPm8Os>^AaLvL*pd!Kk~1PGrOs3eTu@)dS|lQ-7ApBx3U z%&D9B3%$js;X?Req#dJirMm&_7WNsC zuD1o;KsiNP-`1vXA3!$%` zopN|FdqhUS&WJc3^-qbignmZrnK3~ET6K(#EUy8)evbI zy;nxX%ZJN1>vTO@;qzax0w&nAj>l@GGl%2~}f7_E>z>8^hn%M11 zdvmf4e6zdJn)eYp3`{=jng3CG)Wifoc&D-ab1PIJm~5a&B&(6^JtgFnS0ts8%-5irf{r7T{_NB^As`!(WL z3?;VI`HDK?YlEthdGrZHioh`ah=3duW!(U^Xe_^Nlz?39yk{JDt{oDd0#gL+(k9|a zvn3&VY&k02QNs0U$9SBy0N4OF`>x7k3tdICH)_ZZmL9(%ppy!w@y8dVuk1pma_eaJ zzkeNdyxxSV?LyW`)=>rRbZpq#S7{eORgsZdp?`^%2HXZ8Isi zu9MHVUM^S*wsRm{YZ31oFW6v6FV3CgGcg;s!x??Lq-Ms^VEhssN7X!RG6WmWryho| z;Sk09^5<8^hD{)zN_-wxusMsV)Ma8jt?IrR%eaz2;lj zeD8ZWJRR-&`baX;*mN2N{Z1?t{Os7(lf?2iXpM3~E;Mq4WC-W0bg;SK^#MIWuo-zJ z(nYpZD2Fxrs>`|KxIBS{*UFMNv>#f$~JOAcoqK2teI!{4N z`~Y|FpCtwb<7t`C8Six;=~LOX1~TJd<{Kg2N;df*t;z2@A>!L-0r9xqVo! zgaNBwcMt4VHbjM-_{%annI=A}r~ctNm>apDBKGeL!QvZEXQw6YU4C7J*Xg9UcB^sz z1ntM>^W&^|TKu{yviX_gc`Na$(y>C?Ez@SV!i%6u)be+KiH(*EOZxX^#=q+b9{J}z zuC_5GdD-LI){_rBu`C!EP5#lnqQnw>f;mHqSLZ$?l;jjnMQXKb-z8WCa}elG;?N~L z;NVxbbd#vRN>B;r9BF->gpr^Ev8LwL!edB&XO9O>Uwnxov4#vPD|jTBViE0f%17!c z_$q-am_yBDJm5$Y`i;X$n_E>d7TI5jy<$qTpwJ=kU{yNIERf`ec;4`Yh9zDxxe2wq zn=*mLTF6kW|3+W8b=hSCwi_x~HPIOstyZ##0X21T@Z`%TB$Dg|WecM#hcq?tjG+p~ zl_Rm`6Ag#Vady=52H+C1VjcS5@P0Qz6shee1iH<+A8;T94>(Oj#l=Gx&iXOl5lDk} zWpX0-mx5vyPoNeCNR^spd*w{9T}Zc6?XBDTWa_)D_U^}-EJ$V9YaM^>Ah1(LuS!`Qejd|*CHkj*y?{!OCbB-yE0pyxi-!ecnvb`q8(1=`66 z0_Dg&4kpxYu%jJtz?URqF!2pQpc}v{p3n*J7;%6WlGYYGtq` zh#$Z6bIRa-yTg_#0B?C=d@G`l)SKwB(0AtNPsB7YqTFj@>F$<)Z!P%{FiT0&+SaOH z;oz!kai0PXb`F0mxYY4}?yYDgA4&u|$#GxzI&cU7Q?@F*Eh^!~@LnQ8{{38Ecmwlw6 z+VNXM$}|{LM33$+7iU4$v~miAaeOScv2q0Nr5yIeZ?fJ+DiWAb=2Sh|%vBo-7e(ehyRwnvV^ z++U@3amd!oRu`p~!BVcUbR=*Uh`>wF z6k!4l6GeIj9`eP5#=jn?V0Og&IQB}`+)I}Yt@RFb{(wlg*f)2tvJ#8MA{)t5BG@}G z&JUDe=Cd6td=8`3pNxnyRVaKUpsfQQK$l)?i`Ov4wRHOW3 zhIGY&+Cv{-mvt6PB3*5_1SNqtm$5x7Ey!^(Z0Z4h=RBdJ{j5d8Z*#BJTWdFsYeioY zeh9MUde!G4sWLt{WuMmxv6J{A?@K*UsWU-q?5-OXxW8Pqch3NIvWC0=IATJ?99GD?e@12rAsjRr3g}MwKo&-Gp(7)At2GlW=Ymjk4?7P7Zr3fFuyk z8*b=nS3C2pJq}eS^wVt?t&2upL-5!8(cv7gdC&^Pb+eRC$+IL+%?tWP~06NRfXX1 zrFK+a?u@6_=AQ1xXd1;_WhpR42p3H+ty-5Bq;ML!H{YWa8kgf;d)s)>jmT(*$D*jF zhl;&qO3FA{HFbgs0pb}9%ZV5M%9Z4lj{Kq3jB+Y|$qG(z# z$_<85^&>jvo_qv<9}1fRClD_l+o{R26RMF!#eI>BKqV&+wGJ~|ED&=&tR zsrr*s0^(w9135~Gi$}`eK%y$n?$q^ZiRfEy{O)F_>)v)pkCbgh*S8HwDSsu>$kiQq z2u-xzq0P60f~^De#6H|vNT94FOkE+Qt<0;O4flqwb_iF`pLONITuQYk!4{8KdK(_7 z?|npe!K|HyaUopZ80#a+18Z+U{IM`N7)j2~*mY$IMYj&$@x<-7?K-8JmmK`j3Nj97 zrqk;)nsd60xA3&l(2+C}*$NU46(LOBH+)mB0WW*bD(Oqs`?j7B2XsRD&U#Yi9H4XJ zt!jFQD6yb`ibB1o<$lch+lWHyITIq>?_mvm({F1AI7*Iw#n^}&>d7!ru%pUva_Mzz zksvkwJs5p)cf`?Gv_3tU{544la0S986p(77*oTR9rnYC@Y;uiG$1=l;u)5g`ngY<% zxzrg?I@L-VNliaX_BSyd{in}uH`6af*KSg3^lLnJz9E>L#6TIGY{ovDZcq~2C(dbc zbvCg?iJ(C6^GT`wL`a~dsFNozj-|r@oRP!d(@Att@PI1{wbR-Tjjo-0Ci?|$??h0# zWE0~1HQo?b;pzI4B(m1Bjy@ui7^Qq#xiCpc7oe!0yYJV_}66fiwM z*V6T6><+h|_0AdrQXn1~Zk{LM$E*)bJRi)im##Z_r9_lXwAC}0fZX(2dB(9DgDwml zx-dq|l1H|)lyj1(n9W}HfTEZClyAkcb4g4Y*OgV=Jw*OZ3p57@eAW&~Fh{W@^zn@^ zN0Ba|xhjmG2?M586vTtPl3N;nIzY7aS0X$VVTYxJj4k1SEBqwGzSL6 zTDMFfp-*T@L4X*g{n|>!QOnePaf^vOODmy6rA=9HBU?$qkuYgzNb|3({4IKE?3X(4 zw>s|^-(_$3d!L?kTSxF59;#_r$F32$_$pr$8-m&ESaew9eQ0CUk2D<=S+4eVHjxb= z7`x2rYJQ|?XKVDpCu)`rWMXM_jd%Y`vA+^^a}&9@OU0`LUFM0O<9PV6$05_r6%IBi&E((l1qxXHe4Fqr0#{!*iLyBjwSH2 zrDh^;J9ZUOl9!61mdd)PADK~Vd)##{DF9hECz{`>`lt<_^XPNeiZT#y;HeUz1~Oc- z$G61J>r&GDj%#PgEBU|~aj0*l8ak_zmE%dIr28_s#D3IoP1H%%c;_Nj=#bGQMwaPE zlTT*xQ78aq%bZEQ~$w@gC&@NRis7I1N?MH~&|cN3owcCh&FnN$qov zCrzNfyvVwNy4TpYv>fyXgg1U0o(XL{!DG?aw}z{D$^)Ot$|lOtp&uFcrex#*v=YqO z_TbL6sT*I1rIasT(5u;HZ*k4C|90Z8z7)sBHb@t>z}aklEOGRpqbs?H%31}qB#8?` zgN`eMs`u&*DQ^j2kAYXbVX)7M@Y2Lz-Diq_uVC!l@6*VjRBBN$7ZB2|e^mN|i)XuQ z&8x(wkh@)>V}ue7{OsN)3Ir?i9FK$+)ggYqD`#JkUa4THJ7P8U)7#c(TG!nXaCd{y5yN?DF;oPNjuBZc|dZJYzI$F0AtewI4~K^~Ipb@{R*AL}H&p!F4uy1NAOS@n(!bEMG(32UI2WQ+CbXV z_jS$kidsoDY{@gHT(Gq$Q5TsCz7ypqhp|d7($JwiuaIEo3_S_Eq91&Qs)mI2zZ6V25Od|0QV<`)vnY>5s1-;}Gx>AuW z7Ux>D7%x(qdXkco(b_%L3$zR9yFR~I5ro?Vg)Qkv@*RRXjG8!1Q=3_G zR~ci=^zSxP%xbo>nHeN-yDK7&{Ivk}%VOfmlrFfaW|>8G=`og##0^LxX4C1x*$Y_-$VO9?KKBnpsSPgS!1%Wy2isug8%4>(m#>^Mf}K88c80dflw z*TL{XTBG@{#?7=&jl8q~EUCiZZLKnM9E=gRI|;oUy~cEXd6ru=B4ZF4t1mx|?Yz_{ z)aivPoU?zxcY}lwgzphnw$jIIm}6&(%yck}u|Pxd*RE2-nqW(>G0{EKduAkOEj%d{ z{<2AYU9X`oK55-Kp`-JDvdNjDdhW)pi^}DlwJde22WKMg(ZkMVJ?ev~d9|h18 z#q%0gIqM^YB+Gx7TCp9$LSxLik92zoqopwrTHxqs2%u##5PE29T7;}S{{@$?8x@kp zp)ELk=fp?BuM9T?qW9&C*eFkW58#DDCcj%rsK}~)=8A7)Mq%4>g31vtWP8}b1hIxx zo$7H(qoLsQ6T)hGmk3X8#e|1aPNmND)yu}m1CQ$ZKJhV;Czn2I9@iROryp*hb@FOQ z_sJGu>l*VIsxzL+9Nff{uxJ%bBJf1|{*A@M?p9ehKJy;;sUV;a(cOdX-6=EUpU1o# z=l#;zuuOacgWp`TDH5fpb((w|09UjJu!0ySj#nIzkdVGQU$C&za>GzHwLE465sH?XqVc7}3FydDO=rg1<+n<8O)CvA6tZ)cy#HhS5hJd~b+Lc>acNV-- zi7DNUB-tvIOOjh`lFN0x0~;)+sU{bgwFM${AA;l>N}wxm0PuZ9j{xRzYTx(?$9n5JaaY& z?{}RL_&@`-Vs-1W7h3Oxpj3P`j=7ufbpB=+u+mm`owj0AQPk(-4$gyw1B9`N%z=ObvBDsW2BzG#$5FRQ{BGZSifnHCxmSI zEDQxbt@FJUfpb(Wcw6OCHDPuc8l;m4#v3f-L8u~+6j!tO$t6F|3PwPwH0o8?~*Jv))3DN)Vv@5$^TBjPO-2`Qz%X!boSS9917lFSt$ zQJFh1B8GHPQ&7w~h7AQ|SA1#f6mXAk^+o@Tu?tQ^L2>tJapa%PfUPemC^5W3gAEJs z_zepqUMbk4^DD)04?td??x-o@lb}Qh;m&iY3zVQd&v>pE=)c@Q+wG6o!whoecz@Uj#DS^ocMe&ccSz2Si_ zA;Ml%PnG9p^i2J0+vigN4L9X0V8gL4yuq;Yxai)HHu7jD5ll*4T$8#v#AzccNK5m| zqpoO-0HLuC%iYPMmmpkSlWuMpfQ53o5kH9I`84nYuT(>L07+7#^)bd(DREn)&JI4( zdUy2?9hTMZ6mD+iwJ-m_ZJ<_f5j8-3%Ky>}M%2JuH#o3{p~B)516p;a-nS7X+9Rll zKrtypCQm+SQ3D_Nz#x{wq{&4pIJiO2BH(IjVhQm^%$?cU>1-Ltk+|D7uTA*0hE`Qn zpxElfQffP-sDXq-O|2q0T@Hx{#EFf=^xn_4%qh>y$>t$u#A2(;B^Rg(IwDV8*T~|8 zS;C>#^pIA)h3R1Plgi~h_xYhrADi%+TY!rT&+*P;V~w|l=l*r99NH3XDR1I1Hi~D^ zGn)bkn^*5PPu;}J#{y!1!9wvQEetpW4MS7mIZn9YT%ZTBtuRnLG3zpk;%5n^217$y zss0=hPc9k`P+wH2bsxRngW$1ZJjXMu=`5@uI3g;F=Z$AuS{w+D_ba5emv9XWSlgF= zWN&U&y0rLJW|Rx}4M2pKKQ%?OcbdRoe`Z6Uy7N-}udp1_bdv_IU(qm6F@@L%SL7 zYH<;J#mG9ktVoyu$MSA6Cw#ucb4D%bS@K%=)?uF7gEa*iv3%pJ*D_cB;7qE8s^&~6 zobsQF=Ld({6wa`LQO>{P*U!?whi?c_qVrA`5J#0gH8_`Fu9|ufPh1c1X75qED^bRY zx^Bz%R3Yui;Hh~UxS6jd}@Pa4Lad6NKa;%Ot^M%4DRXp6Txem zWg6s~AmCoi!KjZYTjbRXHwzw4Cs~7ghiXNu*Q(R?Gw4Fmo^%!$3nH8;Y>?mCuO4UA zhZ)Yg)+0u#1RBeFI^AvtdoyTrxjyb^(?v#xK4S%i;Rg3=s3>W%yQ$HJdnxYBiP(ot{f!Zh>#FXR9Oo~HBU3OrLCnC<+Q ze}VQCW3@V?6*z$Sm^JGWfs#;ykVNR4mN`Zs0EuRiLzRK~-<)cfeU-TuS z_3zlT@hb^H95*s85|zsa>j$=B6Q902ZN=Wqewc1MW`r{lBAlxQ!M8DpwR3BHlS8F` zL-_-@uj&*?KKdnESjtdVVCVM3cI9TB0p2VLh)2AARYxXUi3g~$cNh0mOLr#>N$f4* z40qw^HqcWLb*txvup{&Mv>GQRjgx=9YWxwokhn9!Pu8KW{;t1M|JWx!CR2#5v@n=? z0K@|@0_Vg*fzvd(eQke&w+!x!35qG7xi0!Jt+3Z4gfd(!jZA}teV4cLVfv!>_}3hu znmdXn^4?@Gk^94RxTW^my7VbW73cxSyW&$w%bz0HQZ1ycl_oA<)NwYS@mD$DalOjX zR%$yYri+eH69Gx0^6C$f#D|?)(eL8~)qCar%iu-EpKgz>Z7rMK6^`{b!lsumC zS$u$6TYv-WxlykgQQ0Oy+Y>Us^0xig#)q2|2PcnMZgKA};i?s?|2IQkX8OO1H?HgB zD;;k>(_;eLfjs+Pd(%%GjO=Mp*8DhEcKR0qxYysR4V}+W<9oZ$iYZJ1h&-H^4XUIB zCEn55ESqwpt!Eg;KSl8Ip+b2pciq3J<9S!_z&d^S_rz^U;97yj=Reusyss_#k-p?@ zZ@EC$sjc}+}|keDLUfEQbzz`^9~Juge6L7!ar<`*AfB@N?5VeXGb-QLxzed`44J3Iz~f7WW= z{@1o5#8@a@sh9R<=GQvsRp}p%h@tZ;ab(u&4cUXr&H$$=DSg61iB=< zXJ$uC9*>uv6^5patQpi<3Pz)tu+U(t5CL4!F6Ei4&c98AF1J`uL+Cuv5uLoGUW<9J*j>>epkK zX`nNs9^!_+oDl^5%R_xzkKAf)k4LcUChtl&xAxGQ9f}`+8A(i z0g58L3I^*x?=De7`ZzSui8#%98c^*!L6s5C_Si^O#Q{J8@vI~Uzx~&Ot*3I3Q8Qhj z$oO@Jt^e!lZXb~~`-)dyhc2_vULH-LD6ou=_niow0H4b0G0@OO;|o6Te}RjAUjg1S zDAU&UT0OS|CvFGU^*^T2zQXDpOU!bam>fy}d|>Uv$q5qkA8;^7OT^@n6MIx*pw(=B zz*Os?eYkS*wjWOTb{ByCzBaqYJvDuXIa(lgW9C$#82wnuR_ke(2P!o{uw1R3BPq~| zm+btlL0>1_tI#rs(Tr6x1$46ZIF$FjRk}Ez#G*B`N-NfoFvc533l>jMGgeh**ZQ%U zq|D#%v*aK70TIO@wjdR~M-;wv69izXerIPR7r|cn!kGV-KPvE~*_d11PK$AKT8BrE z3?T|%H2pBkDNfyP8P{HGEY;otxY=LJlrrdaAqjc{WY{fIRNPntPij=i(b1yWCK=P%QcOeI-Mrp%Dg440J^4N@<-Uk20HcFePJfn+BDTh!hFCH@{W zrSjkMl3Qm~!jK35L|6WHPjp=q@w~#pM!a9AAh91X+aV-ZRg7iGSZ!d(#HFRE;ldjW znem(voCA)#5k^1U_iv_2*pBZc7L*Pi0H4)U)D_By+L@&}rg)Oli+zKZCT31_I2kG@-!xqAE z8oXAQZVDE^pSSH#DT-z6ILIfgEw%~xocDcTITob{8#0#5LF7Py5CvxBd9mOM+w&!t zhxJLc4Se`s|21Vhav5g>%d})=a7yrwIRcdoFxg}!#XPwdGO0kb*~P#FFVXrOj#?>S9Kcjax%UJhmklS_sV0gP) z(3*wQVnm(R#GMIHfT0;Pe};>KK5gm#3$YEECP!P+^G>kapr|n%`WYKm_elSywlUs{%!!iyrdLB>Z`(3jT`UmT4%C<(WAgRo&Hl3!R8P6)wXad+qXDwel z|H&|NS9jG&K<`%5y#OC*4`m2~8INva*)7C|K3|Dn-&L-N)@N9hD|0BG%=%K3H|PzC zkkGyEB+>%`Hy(xyo+q|lTG(iEvdpBRwCZiMx?v5;L`0ik=M z&EryEdD@cQY~IF~AvZ3%|2b}`B^iF@c};dJ`*+O;(G{2J4s$y{9LJhKp00??Uz#ON z!nS{7!8I8EZ7W2f-gZ*{xr*(xhLIGwl8;Q@#Gn(`7V%crKZ3nKNEB9JAsTLrJ-tDUnG%)6#w#7+#l?J_b;oDH+It#HbwV4|7YD#MYwojvNC#+X6s zi>kQ*17?3~MLCp2g^ObjXa{6>t>P@jUR-4M_kR8PQ`i$V?0%?fV#sN|SNJBOkR=@f zSgI(j!t|z3)z+CXppUsYvvuH<_k+4R{?!D{jVQJFeL`{}Iacw&Sc9v>n98?6B1B_6 zJjR<$k~VJx)#CX!f=W+f`MeTvtDS+QN>i1dVpQc&LnJ7IH-rBzSGv)0t6gIH{d#L` z(M*j)hZ3mcB39}j@x28?8`R0dgYN!#-+>mw1K}Sz@Nw}n^^7?kN~JM{ug{(y!c{pK zJhzJG^T+Mj)7rM-+WYIro`h|(H9e=B>&K3w(ajd&D>I!7QoFy|D&@|EHjjg{PMvDy z&bAk>veXldvQ`JG+1>bLOx}rl9EK~Bn)|4SRb|Wjkn-_OZj;;2c8drLzoY#c*gFT?_CyC&!>eyNbM(Z9&Fq4J+0#zT4B4&~fxv?PmZI~G zyz08_P2@bi%pw<`i(ewp7+{0kVA7^L-0`F@ky6gM6&4wfWHB8${?> z{R`N+J;>nk1THM>fSlR&oEq#~sTT-8OI{$|sml0pYfaPr5FO-minnW4y=iuj>+tcC zsdjA&`T7@-i%D;f`iSpRZB(`^)|&g#;Zv@K;Y{*`jMn1Q>EG)@FXUF@V*GxT4Bu+~ z{U6ddViO1@^M!2l3YC)kc>2;7Il=c64Xwpxwd)_07+u{#)^mnX{0z_xxbpPF(Fez%m>Y0aE z!3ocnLm5if9j8NRz1sq`FS~NX;nAtx2O&D&2CkcAfz<7k!!3m?uVHo#yCr^>0pQzSRa->lu2SR>C)}Ml|AK#cT zUzTJz_B4(9L+I7_yE(Cd?O<+*Eh|>E?K=a-z4tTtzU=t{eR{~2J2XgH18Q5(iKEp+ zlR!ksHyWdF)I^a&g?TmKsT6b2VRP+bx1Vb(%VlE4(@DaI*jn}D^7xtmN7GdXMAdX* z0i}_Ul z?sPT_v-HLX<=UWgC~dME?hpM0=i*kON-J;Ga*Hz~9dZ7WGN@`uBig_hA~>}b%V)fu zs!}dXcO~~#t<1_2M4LF~HJsd6)>G zaPn^#kH4`X_h!^w;mj~^GVm6+T(v0e*@dSPqBxsTf))EZX>V=&=sSE>qiTs4uqJ}o z3@81M4e*Twmp7tp`mU!o>99_mSq&$1PBUj0^dv=FH=>%ZEHv;G!|Qxi>G{%yF(-br z9Nq7Zc=GZEeU3HpI?}G0tZJ+a^F0|LIMd5aF3eTOG|s**IVqX zx@TW*C130+{APpP*VjZ`fDz)Jx-OBx|xo6)I?%y78hV- zD&E4Hh!*|%x7kjtr$O7KXc9(pXu+CD(G+v4+OIj47hIDAdTkeZ1Kg2Az22Ku<$4-g zLKT>w=ck`Cl@TDG-CFznNHMh#s?iKUD}yjaTGU!ODIf6+2TU|yT>L0#dlIFqD)99z z?ok!WI*dNw!^9;9U8*_Y9-i%WM^aZ8`Alaa+2OtQav3UwufVbrdtSO%=)LeQ840*5 z7&3?THbV&i)DDTT?7Zee5Rs+1(5U;@bm`Bx-%TlJrW2+L2%LK*D$2JGm@C&~ew-W@ zl1-aX1VQ`|Nmr+_fPm2B?y_+`T zzq%dNZ0e=ruM+s&gav2ya^)hZSzogUHwyXvUrvslmpwXC9l`RY4(Ajr-H3nMggjgYkJoJsMWqBlj~hvE2Sy~Y$5Dk?9YK}1z9EyLJ0vsetomRtMKFo zXJdUoB7xd)QPQ*#OjumHk2)X9jVD0whBVQ40SnlFS6p%iB_h5>1R}9IEItIol(5^b z$J2v)BkPFUkpaoxqoBLr(iKc5kik-@lkk8q+o*AIlkOJ0$<=6DR7tdh~ouAnOhf+X?Y~$-){kn`{mairqm}iO6a>jD9C z(kL(m;vf&oSe%IZuh>^=(pTqn2VnCm*&`|yi>;tF16QU0BZ18N5NB&h2YTG+LU0K< z@$j@1N0eY=F1#Bi=VVvNHuD@6j8i){!1cfc3?I2wCEOP287Oy)()-=x8#^pKXuEUL z2g0cFwab;EnD_rLLt^c4TT2k_&aMcn|9jDdPW*jo3=C;A;HsyNEdh*lHRDqM5%94Ri?Ec_Gmae zuBE>VU$NI%VuRGrToy02@!&>a@;8==^x~g@idN zEV$cFEEJOxX{x)(8^GTj7w`C%ry^M zAB;;$u6E=kq!W*F8Ocx54p$bgyhg zQ(sl^4|M6V`G?BA?kiv$0I|YqxLbG$DtiBl!3Pr@ zNue1!0C@z`Z~yDz5M08CG}0S^Fp`Sps1fLm+@mq?jJG3p{5KUN4x{k!h zkS-fbk)2@4YGFQFO}%~wGJj^RF={J|3q(3Dm;UEPl?c6d+9;1BDyUd;J&5gJp(Q$Z zH;U3Dz=}pZmhty@(LYbX@gjCcqo_GNI390g2lgo-lq$^_W`pnlC-(~YvoB9=2QLTn z&XYN7VuPX7Hk0@9oT33%=G&|^j4OV7f}m|TcSY@yVgQcT`^9CE4|($7{52BKiz|S6 zQC~CoJII#&IiSGKlK+*K%R%-NFpOPC0+$1mfARmN5vw4@1@Tld8-%McV1YR_)yDQx z6bnqGz8uN0rZmXlI!BHxQK0(hTzN9xAZ07Ev{4ge?IY%w@kDas>++ zu%!K?H1su}f^unZ-mJ{&{)4;0J8^4n5e7;U5?-WV_;rO0JlVo`?7{#0Ak$!FTGJ-i zXX}q$fudM&5u-aYh5!Qho%c`C@TK|O-zWc^l|J0-{%>j)U$dS=786``**||P#gT~o zgRN)4-yP^Sl>V6Sc&Zi`ZDnD5dx?FceVgn;46Lp6SMJU)q|IRiCC=WwXw3*Vzjq?{ z_R|EvVML0->~Fe;X0j|UokyLEjCn}FGJPt{uvF1Q1?~_v4f_WeVB5PJa!>P1@#q0I zM8)*mdr?r6|H0(&zjFc9mpp^O1lFC#s$TMdO`aiY+b+`_v|UwcWbz7B=u?*N2=>vA z0u@6Zpv%duTxV-Wvw_P|#yVgbT%n(RM$%P5Qk#EUJSj|X=dfTq>T8&H#pQ**z{>Kx zBeQD}?X?)LB!%@=Wf_NB-CGA30^;kzT)ei+2N3`>zxe$u94r8%rLk@@P$g=}dL0-u zM3%x3Y7Qj?-3|?M76d&MuPlRtdxDcpvn>r6raV!=9q1SPaFxJQU_EvmiFeeK$%0|} zKDdnj--!?18+0IogxPyvFhRF5y2EKfv)<^-?Xb1nb0i+#-9--4m=*|aPX9x-*6F~V z3?>p(`=@vToNiJy_=XK?iNo{x2?YP{O5|7DJmWuKO4BPiyuw1wr(Z-5SxIw&(dfKK^T*y()e z0t3WkN#cdw8>4D!{OgrV3U%jxZ4e-;xC=^9qKc*H4cK~|-jbTvuuXs!SAj?60;;+4 ztx#hJ5*)Q0%mZgW0H!V(`&Iq*;X5H%%U|$OQ~{-tXWqAm!#3fSafYtVGjecN(5_Jz z4nPYyHBLWO@&XN?harFY=b@n(8v^J8CtK<7^h6^t>tvE8LjRBsG4w^_z`tI*%wFrm zy9ePQaU$jh6B2X@)k$-_tEGn3grVF_CMc4cN#;oeBAp@o<1OIU4vKJ|Jq{~a2!FF| zbn!qBQ0#%bBw!fzz1T1SG3xAepUDO5fIIHhiZ>~6Vu&iCpQXdAEPjABAiD%cZQi=; zHbs9}J71w1caR464{UWL=W;c$M+d{rn}>tFEGS^)e(m3G9hQ0e-J=nJ-r^<)W{u(oqBtfiU9mklesx2 zZK4MKr#CL;OGx0JtEPk%6p=*ZX zzg|VVcX;#xzX6FWzolpC9gy?io{0~Uku|N8^oGB)%fogZj}2G+Yuf+LO}`$-Pm#g1 z0=w4-`XMeq;P0e|`frRN8~-vj&2zB7q$}uSfc6p(6_@`tjOPoH4uPQM)#mHaekMMV_gcL)(%aXnaIA+1K(;qL`-48yrU-8Egh{x4|8E1R7lHx* z4r@b^yCfN7B>mNys?j`W6GMorR~3#UM~IYyN3=~NW3?*8T!o&z{vtQpLC_0>(gWWcLdP3 z{MQa!?`TlhF);eSI zjf?&jaE&r1;=l5HQ!~@;OAoC0my?yl?o3p$P6}M6A@pBC&9@bsaa2r*|2y!Eq>=o~ z@QujQJuZj~I>zszbCK15{r+q=ArA!MwcmrL`@fT<<9Of>EN~%N;tWq((81)2efZN1 zsi(q(Urx=4LAGDq)mv2ml27ApP64tJ)->YJc!JAJi}C&L1qnExEj(5FuXN=0XRZ1F zDV!|YLjz|ia1MgNwvH~QRg4QvvXG^7`(QzLgWi~^gnhi}$8|gGi&GGKXTK-Cb|`G+ zwCg{j`I%=Sdy-j7Mo*V1wjU{jg7zYt+BzU-SxN<`)^@zG*any3Bbr(~{ut$0Hcf?` zyaX!i0y1PZ3@RmTv}vP)I-;b93W3F2-Z-CzSfkE1FdkPNQoZT45t&UR9T(qY#%zEJ z%_mfg-$?BW6_<~srv06!JNXQn|5Pphz4=ysHVtiDyq(Z&6A^3{OmX=E3R>sIlWTkidEI;(_@kL5fJ8}qJ$5Tk#USsMPm>~Yg8W*ZiGmhopXd$` znop&M^EkY-92Bo10a;z!I3|JSbE?JDJo?#+%a>Bnda*3F!9(+z)Z%ZCiSa+gYe+&| z=#8dWRN{B#*YXwfNXJ?dO54XTfN3XImm#4_)_U$NaM{;a8WIiA$*8_FDIpC2@~RxTW4jBdB(mSvQ- zDgR{Q?3%ZKQgYe*iv^!(xs5mb2bq>l2$dOBRHHCaUK%HO$x1UX&f1#yMRTjb%vkvg zzoPVlV@LM1F2`v*HNEJu?Bf|tHCuOi%TP2!^zB)iK#Q74S?KI)TK#=Im7*}7_r(G5 zb(j7hgxDgF%Wp4%%Q*$f-wRKzg)zN;pIqj*a*T`TZvPbEI0ZOXrt9l~t3jCqR*s>+ zzivMP$d3RypI{0nB)kz7nM}FXRufvA+Hz;ygvYuL!MZS>FxR8o7Ca7 z>%;Kl<(96sMpr@k!GKfL*e&sPPt`lV%D?Y3*ROd)9yjsGlqDX6%dZ{Z{W(r&cB+2y zILs`Z8D%+gx!&#-+Uv@5(gcNZjV_%k44%St3GlPmzXZARLV2e)K(19g-xm*Q+V6#l zqcG4mVWgVt)$jVCp?b_rz0aVE3MyBHzsoJCEyKbo>RuAiUE~+x@w>9RF6qoD8=J}g9GTAgC+ZD zi}Z@)gX&I#4~!l8DlNeK;0_yLCw}sJfcd^R%rzGwXS2WFG=w# zIL~Nth|j!v>-Juu8g!NnVr-`yw=x$r7>Ga&iZ*60?q86!)x1E2iFaoY~+hGi-R=%Z%%t`-ri5bY+ zH%&@-kKHurmcYQ@M?JpM({Jrv&EbNA5xW&9IHN_pyM zyN3=%6-5pWheb;>qNhQds)g{=bi^F z#m<|&AuN4cTSIGIrYU0`AzvBSuUhimPl!O&;XB+bgAspW>onPyd#&$WPU%&w&1{(I z)re~8PKBejDYhtef0`gP$}nNb_skUM0YB|Tol+`XkKe^Rp0S}le_rEe}JtFm<(RS7(anc zdTix;AYr;H!JF~HB0`915YuqE0d2A)Zma zz7v`_+WnXrn|1F3RmLf6YP@ay>nIG-kPH7Wi%5Rgxzm;1`p7~KaV%yc#wZwE5Xtju zE3FMJN(@K5(n}K6i;vMnK?3s09e<4zAXt-}83UhN5dY+Q?=*jcdruWoUN4Xv9?N>WVF;OynT&2~l zvDqCLNKfpVqdpl>^ww}_iw;eb&h4QEZIoz&fjF4Gx8m#a?Pm1@<=5%l+&YU_dXucp z&#^@aoBgAv?)Wm^6le{esp&!oR%kwMYR;J_sm15I;Z}}!zk5JdR&CoDggs zz@nT;dldKsrx~kw$o4F$h1h$JWx*GN1jyb31v@#a3;4>3XP#H><;41iX zU`3(3=kKIwK0o%ldYWejD*zCw5BzHKo;c+yQ;|$en~O^0#6M`` zVz{wPa#f3E$^(T-l+W_Zx<-GIGvp6DrY#&l-f`~NNG!Q>{w7P?T#3-7U8YQJs5vB5 zXd0!H^=$18GtO_ecX3O)tk_p>+M<&sNb^&r*#S<-i^UUbQ3;3b{bSKlnTHBZX!Npt z-<1O#$6NUYn*M}_6VNQhU0Ng)GoMwfoFde4;${#p`%XRRWa{$-<@uwsm!y66UxY`I=EMVacOs0B6Z_&6K%{x)J&l_x@ZO$+t|O?`f`J| zV=f@1X~uIp5z>80;#OF5(T-$osHZQ?jj&HFv0i?v_<6`0l_DYUji2L!E+P3#+0Db~ zY2jz2C>4s}Un)|?b-5mTiaDQHB;e2`y0LQnl|7n_QO!-TOFJmINw85fHSkZLCH5pp z7YhgfLUw!dwe&E85gIC8j1!FI-SYE87lOJes<{PrX&(hQDt0M>w-0jWXIq0XzVtZ; z^IEUu&n4(%5gMT^1YgP~6tGMBMAM!dU0^uAQp=pK6sLxIn=!9${F&nFxqG3BqMGun z(!o(NkqI9Ua}Nol0NtzWyYQApJI7xx)b3E zl%niw+v%D+>B>mQz{B6-%?lG6WU9uQW*WDfScPJc0xSbh_qF$(EoD6cmVqa?cme+F@E3X>oIIOMrO4!p?83A#wbG| z#;ANXk?#10do(|tV(@55^M{RTi!<>LJ3gUvnK-cZVMc)w4uVN|PX*LAMw|I2UvE9Exiy?wAaaZoYAeCnxb z4Y2~&`NBMvh3Uw$D3{;5p*F)yHKz8KIj>ym0<_-)t+9Yiy1vZw;)VN8OA@hr@#=6mIm(G}Tk}6GuLlk} z8Xoon2;fqME6?HJPbpnqPY`>E${2}CJ-6C?d#wwST(?3D>DbAskhs_L9yvi0HNJ+f z0?4J9CzysZ6y66H9kBeKAm|!PAlsd-$d?wzU+esn#1iCxYx}tO2ITKOoyvT=DY+hq zKh3v51>-t9+7rbDRlLgLS$_tqm~!uJ@$?m4UzmW`=(5qgyF9*bACXhiqj&^<9K3sA zGVh^p(~e}!{DMbpXW^-=cAOVwOI=wrV)$oQk>A!>-98HDcg<3DRM(pyZLgcfbhPVT zjNRn(doCK29dS3%Z=FA!AE#MSDTcAPY7rlA?QYbq?e&(C<4NxEi{dX?`Qd4Ava1)5 z?>f>fv2-3+#}N+AiA**L^^#YKC$N|swFi7y?uKR>M!D&$Zc9I5~Uh? z3>A_)Q!S%yDx!&=?^z~pdJlbNgBx33;y-e*@Uz6a5A@}TNU zsd_(s{^q*I|514FQY&Onw>=>99HZp6#pwP)fS19*Ob2I-UPxN*C8Ij^v$Gk;TBb>> z$5a;N{@Rqsk#DNr+Gt!<1bOfL&(7!8F#wY)o~FkwSuH0%8HbAPPr+|B$<5O{)6;$ir=X| zelVpGiuL^;e;$`tKdl}-SD(xAVlFpO{Y79QC*VXx{Bzy8^ztE<(n4=cT&%|kSx4f` z^m3ElvTvEa?<*f+m-HWG9hvbM^&Tuc?p1P&51$08BRa9FLWD_A^WiqX4_+8QrW#vJ z#dkP@DqlE+kWp{;0>bHn+ZjseVS%*ycCi<j8Jtd&5vOk+#K*A*DLb5J7$ z7Z0Z;X%qIRER^JQ;Zi}Y&rw9F;Kl?nBf7AwK7Hq7j3;&RllzNpt#cTu2Q{FC+nvwMKG<>&2xox=P*_)DbkoDf@-m;q&8%2c5VL7G&E0o$P@6&~`?QFCr zd~9E=>I1O6fPCnAS=higzNR?~RJ?otmmK>F?n`V6Ciww^0V$66YeAuBXE?!>PDkdP zY`_b_YXD#54NeS%K(<3?A7?}HCz_OW^@28VjL8BBhYC!ku$)LJXWdjqNlL`ZRbCL# ze}rLp=C@AdBo2|<)ebk5+K9;7v&<1MXNpSg z`A2R2AzNo1_%HGEr0E1`UrFLzvkoXfCu4ADvhNV4r(`b^Ii zI@C-AlXp1wE@ z`(dnB6buw@XR;zB0|6X=IT^8%#V z$O%xH7mjv`2*i~F#YI%&wg0M0O?m(uuFHWNUUXgIFQu->iqKzGrw_{gNh}5IXfYiSe8%wn)vdS5 zJl0TBxWPUI-H+8>rFwvHL95Rqh&777=)AmmUdZ!oOo&M~bW(aK!nT%>Lc zZY%Q%(Sy>yS*WdMenQe{N;V>@3&dsn26t&Boa*0kz;Pn4scPgN<%Zxg=r@lAR6~R3 z`nu1o>*!Om&q`@uIx~If{`#)R5Nqlh@c>-o*IHA?VEV4pzQ8Y8)1E~vpnQa1ilsmM z#9}`QJe9wTwA}k`ChdIU&x+CNQ&>UdPKjO)iG7-z_ZY#S93PC= znNA#_?!5k4m~^JZcy`av2|7)lk05#5qXmmkBRXB1(4PP&HSfpQdAfhnH@` zX1rPz*%Sa-BW#BVhGY1m95h7@u(c~G;9-LctHH{}KL?K*2zylZ{NJ9vnHXuyP^Bl;gxwftK7|Wf zCYf0Z&UBK|6Ef%Gv7XTF!5VFOvlFuvxN~2zCpU)S|LiUpb|k;D`i8)_xj{USM#ogZRKpb7h)ENzpL~LP$*lrsA7Ux=;FH4 zFb&xt64`ki}+d+HBqMU3zNo;RKSouTc>DS z%0THw)(;C8rK`3pnQ?oEdE({59*UFU+I{K5A6LAz+~mA8MgI8tit+*SIWxO%5Ropm z?>mtSVoky_%G6e_JUcP^1oWd=Df$H{b>n=Gy$k7|yfv+gIolFe_TQ0oIp1t$hakwp zN4VZ+;UEb(rNcS%E`3djMd*EoW!aryg+sz$5y+3NO)R$3A^$AG^ed-BPWh`Sziby| z%VqD;SM~KQWX>(Oi)U4J=Eo7Hcia~rfN9xuKGh|x|><>Q~kw zT^!qIbd8+Go525UB;tb3Hs8(^j|$bFi!V>z7>aaE^*mvpUij|wsmvPA=qvg08H;uT ze8=qmMs?4l$=ky^6x_nB%z*aWkmh3zI{yw2cwRdLNTIi$7J# zG~&744E@F+>#xtW5kb{a5}Mf2u&GmIOO!4_e-m#-5g|z}WT=Qug^HZp8H35A9WuV;yq7W*NHi=DQzv4N$~HRR9+APGraM55567Nw9mh^r_(hnXjLtl1loH#{~8?o0EyW!9`u&2;X3Ol&eYIEwa z`Hg&C?Q%gIOGB4Yf6A`cS!g=wl2Z_)!Z_5AMAv*+Q;$!OVp}!zWVnveDFKZ@yA-)V z6!#^|m2@ofeAnohXMCrg_A6!2`EJY)9&GC;eres961)w&NwK_PJ zPzyA2q9rhRxI9EsJT*50!C_}KlrH*k}jhz zGQ~lz<}81lorhSO+Vl+KdM zY3SF}gr_Olh0>g8H^rvhC7Ob^IYP|s9s)Y^_6x zPITO7YGSuy9XAxHO{7uDFM4r_2mY3I+?^U(RK|^QxzF z&$CV!W@%^8Eb~qs3J}%Izc$<+ZpX=0D=V-uXDdiOJ)Yvo4GVL3sDE+1qq>(V>oWhQ z=OJR3Q1z7Br}{TARsqIEl1Y%+H$80uzc_L)mWurB=uMU(+k~o4BeHn*^pIidu?Y!< z>1yo8Qu9``&(V*@M~#Dah^sXR?H}h_1}!K=(;lMKZF%R>dn^ZIg`BsOhhO{h-eErT zB(EZh81*=Uid|I0NVlp8(=(O`ky+6UQ124)yyy_S`)(8M$*QEN(Kkk`*M9c<8>=;J zgxbD7>OPHE`#2W3BE)uV1X&{8lm4C(PPKLUM-$mbz=(M#;Ns`xJ4CCr(_x#b5yo)Sv<6!p<`3)z`YekfsAUvb|L-m8$@ z>quk8#N-IGkE?O(VId?6rHM_hAV57fsvje{Sgzj_2)yl$>nSC ztcA55ivE9IS-Nl(AXp3})x2k8Ej;T`T$+Q|V=YAQP?V-(!q_kwKpxWg8)zuTN{4Aw zILk$y<-*|w&y~T<`In49ozAF`IMkxYnZq2>qG{Y`m6)}Vr9)9RGBjh=WB_%@Ej!?n zT3_*ZV9J~G=%$e$P}1a`SpfqUf&>EgiRL?5G#8GICl=mQwpn}x>Tk5@`mw_DkUtf! zT=_YAr|6~rO_(ORgz$NbT3_e?LGIo4f|Hl6sM>8jG-DF_w*ObsMj2}g!pHQ$e^&M6 zrkY+dnk~7s{nC%1cIom})UxyCZ5~~E3l^267VY6w0H3YD_b7S9VbNj{pHAap+|}My zvrhkb%czSPo)Ctt7pH1!R*J)cd698IJ-xyy&)K+#$IFW%?->aCEq$=2w^y=2p+V28EBK(ocLd7mwVlxB@5+@;)r*TzhO{hB!+8J~Z4PB1bl?RGTN5 zOA*6rtDQO8c0QrcnG}slUr;Bc52(Gm^L_M-O%T)b{dRfl^JhI4-|$yZN%O%Fx!f(` zHN&E&&?!<^(dn*A_sCt)U!_O?{g907HU3~@!R{9}$%>VqcQsOb26UpYv0rJt;v&o! z)UCFx4RCBgwt856Cf>R~VaI4eI_-t%ICSbB?X_ydErvO`u9v48hFsydOUXHUl4k{ zef{-~Q!G?ErQO{g3dz|e4WQ^Hm-Shi$4eS(ez@vJp15f{w_Ndi@uq}O)Xz66!m#&s z)cs+`&hd_&z%p$_yuV__tM?Eb&#;Y{Wu*Hb3Z-@1HB+HNc(-gvQv_pZl`1A-iSxXq zo^nr(%rl8E)t;{K?|w#pJ!a{ir~cGPZ1YzMuA~s3lvSO~Y4@wO6za=EtsNI`rxV{Z zyuI`9iTQful=-s3d8Js^A*|(uqucTxoM}9x_bqrr4)aszVj=X4gU{7Dh*wafjCh$5 zpq$osg1Kt3EVT=lk7R^zFKij5nCLDRpD8lFm>3Uxmr~_m{oof3k8P_uHG3ai`4k(i zb++HAt~L(g+Wu6#fCpmUUihf^$eO&d+|Pl^L-P0}c;=`i@)V9n;{HhrlaGntlX^#r zP)wv#xC(C9-bk!@zSrjnxIT4X3A5}2O=pVN$c>iK?~z64pB#~AOFtm!kasNccHAN* zgi;>Ow@deY!eO|tbg-WN)TyL#yd93Vr^J?gaUy!>)pUt;^@GW)jI9;hr zJM-+wt}Ry1mZ^Ho=Eqwj_nDds!Adq}g~t?COMBRR3P+M>d#EN%8WPcfYVB^guSta#s~ACm2;th=WrHdMlq zaOWFRZ@G!S=HwxT#@S7o75}tgnuxO+qzm3i^;>88P(JVeIdou`?Ov~O+d6(Hy7e*Q zraN2IJODrC6PdHv?c1E`o;gy=Ldmx^yp%QRE+NLFspd9hKD;12&L}s%;Vu|6G?B?3_@l#5cbnQk;e#e z*sk!YOBgkpb=T%{YhYv$^+>(+9a;Qq(+{DZ7Ha~{xp|bTjT`6nK{JZqG*YUY} zcsc9uc~1B(zZr1YL*B`12azf5#}LpKEfXV^PxmHnhQG>aoR6pUED^mB2=Fc1Yy227 zUfwTOkj!T6FGjL)pI1Ubjy+~Kb6B_>cQcATT;VvX*pvQov|wv}Ks9^OioOoesw~84zCA;i2+N-aEQg__{Q7{|@K*)FAgUhA?d{#=D8a z8Q(Lpr{x|CiQPT>RBw{#D|B2re>gY&EVav1&2d~1*_ zyiU1rF@aCo{^C;jxh-Giw6R&_90{MU7ia6R#^Cy&0K0v^RhRL#!&y61>>cc8z4ESo zB2P|qkM_+gN=Wo|P1wLMK3e4utQ)p|EuP3!v-@qb@uL9_$#O;GG=~C8`XdT+hEF@E z8#ZWlA$B+ecGMnko*VsU5Kk=c{~j2i!z-_1PV8ydJ`mI5%z~0&T!#OSp_$YR!C0uJ zcY?PZ3AzXUxBgSuAz@Ud@%!?inKH zf7{_89l6Y?u=INF!^Pqq?mRp&oJHIay_}6{398cktVL`hyTp%=QK&PEsw<{KTp*w1 zvYpsoK{cLRq#!CVXX>5M5uSzBcYiovu{KOXtDBNpGBto)@DunhM;gi+B66V1NPZJo zZSD7-zfg^rmsSk1;5=gdc=`vY36r^{I#X|U2&;pLmoZax$@-7N_0jBFY}H+1E<3nF zwdcGAPY?@~BF67m5@p#FU8)(MaWdG;Kt&HnUC@EMNYm835DQ*KsFmnWaS%|_F4;lw z2%+`4FT#03Z%mjrEYwT;vTHF^^|X0hNfir(?I4N3G&RIneS++#22*$Lde*+ruCW$V z#Gy1Ruk)U@VnH>iVuT9PjC7UNt-#SfOgAKs zL`W55qNz$#AOlAG8TM%mn!G$OZ2)3{j+;aye=$L!8V4_}A!0$)wxx?depHD@x>A3v z_zq64Mr#l7N;XRrmKW~8xI;8AZr$)kQ_Ote&y;M*-;x~l8cC>_kjP5!!3 zIt-Ei6fu5!9^T5HxciM!(?o@n5;7Qkw9%ze+7E*dHZpcMS|I{C5&{+gh|s> z{lrvdH=IG*ntYohv9tyT{ch}`t`e7OScyikQh%1X^^@GmqmF0K3f1uN3j)nv@pXOG zz%8%eqwvc>RWIR8QT6h9rXKeo#O}3c8a3b7tyHquFk_2h<}4?>?4j z1i^gWAIQE>%Wl@aK*5A!1S@1W9Muz@ zFI%*Q@nUK5NQajrb+(hh&1K(ho$&i7TLT?4J)JyQ9)I!Y;t%o2#kfCc~5%1I1zg?ssebZi5*QAku8SQjQL60ujppV?k|`l?mI z;Kq||@bY)@4=>3Fv15v1IQTmAUARyUIZaIfu>dDxeEySXp)pe^uxz*(5~ZN&1N-D3 zOK^X}iZ&#Zd(3w#7$q5^Xt{f*g=(e(Tvqu=U)*n|SU?82O9UODfQA1}# z{&W1h4@wiT5G+-0Vnknr;r?7ypfFd5`5Mca$uI0@tXSY+2Z2L}h+!98j>NheF_BuR zL@u|QNBj!Q`{AZ+nK<9NoiK>uX4{-_R;KweXzf|~^OGy>g|hC=&SEontS$FgW6!?_ zoeakApDmAC;-dZ@{P}9&e$&b}vP)%Mr&z>Ev%GtG)}FBSvfL|zHNV2(9jWVl(BSJR zl?$4jo)@GzQDWHT;f>?buiA0T1G5717i<*Emoaa&%=u8l=~G3<8KWaK7TWVFFLsg% z4w?nGr%meH?9uDI`*-c4ITOiBrhEz+#vGN}cY?O{iYyh!HHpwIzclfC$uMbphfaq{ z9`=usqW<>j@eqtT<%t-}P}Og95F)*$yjtIWv(Nv+78vIM6W9Lc?C=XbJQW{%9>E6wllSLoce#)?>0JES+R-~PT5sDv!t(Q`HNlq}WcX&Dhp zZ_;QG%Q0Ul7Y=-5d$@dfQZ}Hi>zE?=peR%DmB5>C=u|6SJ4>YIG1zMQe#c`R!j;GR zZqVpc)>FDK6a_pxxW~l%0#Opk9r+_;7VNC(MqdtWd4Hdgh7du^Cxl?XKC0j`QJZP==jazvf&E6cqCD3u zNQk|Q?FxjM(d%QJ!ushyw?Dp46h;cy!TwGQe8Kyz7|WEwQ{ypD^witJ z4<+JZOd{%*6L<`D+j7}Uckt^Gd@lJlBm1+*j4C?Km|aIwY9-159ISipojFqD`vM&qrvanm<}8jPd!(m!KeDva8?A&We3(7% z{TQmJs&n&iqI+knL^%ez81VY4m@=>_k2yuRLT8veRYF2d(CDI| zExjSrJAO7);t4a&u)@{NChEeyyI7p;-Ig)%WnOBxP=jC9ha? zJPx=i12w4}bKLVAlCe5ahYZfM4|G~A2bIaI<~>+qh82T}E~H*6b#C^5(26B1e=PmA zK~5AKny1YXAUe^&^A2+-^+)b{hHvJH?VI?!!!7Nkx1Ua!v55nbSw(%>=WOPZ@2rMD z9S2CgEF8aULLI(YAALIL_N5HMUa?6fxv<)Y=LhM*5y#Os2pFcPHL(=ODVrfT7V^~z z>!*EWx25TU31@> zKc4qe^eo2`v;w~xL8N@glgBr|fdEglbb2n2U~Id)~i?ohO98a%|cObgi5LGH;?%u-7qdrUE<#2T&OXTZeQ*z^_pujE|tF2Ee=VV6G5}&uuv?JJ(yg2B1sm zw+#;9TAuM<0=^pPEzOF9zIr~k5B1!bVwuExR4|V4+8+W=4%T~pUj4MR`9K)LKaq#( z9&z4FvUk%SyZpD-e=PM5e)fMgJ!M!_&)0~kfP_m)OM`TGNvCv3cXu}e(!F#l-6=?S zw}5naN|)6B@9yt?zs)oE?5R01cXrOXa~x%Zk_wu!#F_f#b>342sOLNKNFB+VtKaIs z41>;<-&BsvNoST-kGxo@{}9diakw_cMY^BWMipJX@3aSr6E9jTUw!wwkUyd4jb3(0 z`+QS9*+HF0xXNy?e!}6EOi&jgi#Jy^ADX(^AFp~{147p^w4i@cX$z~2%rRiI(5{Hr zjK^m0aR(x)L%V3Bxp@Z}nQ#8)#{{We^6^apV_RTso2em$%9pB}(Mj}1`?kHgmyx+$ zd*@IhK>rwit3{1bU-3Rm*TAP?*k1_8&+a|$T7{Eg0zW$NaDMse;ffQzj8v;+MvPo+ zNd|?(1$Poo0Nc~BR}13ZNwi*O*KGQNWIoRwvuMsAu_ zl~j*#mwPsR__M2K^)VfiGvU$I6MJ;n`#_!;SHD(s*`*o}`|uRn-F*W-oKptJ+x#W* z@DwkenEI;WE!JPgj)cc&4`{6-v#|#qH(%eBnO>ar()mC#OIs~l57yFOUweEzSE_%D z=jq`^742z1jKoEpT_A1Tp6MdQg|0B0&+=WcIXgOZ&t@w1192-;SC0ypf(;)s=naN!8*y7nU4w6-6p1*#UxTblhe_LZa;wx~JDVixu z#J}ta3w2PKZ~37AjoxwC;7^%|XwtoY8>YX5UhPto!}=6eCuJh}%PAt83f>@v6vb2& zDGk@2o$EV&8=o#dl4X*$#TJM4WjWsc(dbmgBM_PvJ{!KvX0q(G&wy#r_|jrS!tADB zL8m1jy+GXiw+z{`R#Pu>3v6|6SaGy`=)Q^*s1*$nmseBP!E63%{IescX@gV&mu!0- z{6&R`Rnp^x}J#3gfOLm8U6)mQif67-#iMzK3lqA{Mwjk8Z!3 zjt4Een7_6pchSzlLTo4gZ(maLcOpC`Pcd1wj+Ehe0KSf-!&@*Ws+d2QBi@!3^#l3#UN*X=%qImXZX8pC5^@#*RFuP%cyk6i#h5$m){d8p^Gaz5s*H3A&#h( z1y=+#!eH}16S^&2J)iQVqiw~_nR~&#d^?EwbF2&Cv3a_TVBFaO5MaE1 zF`p|2kg1!at-7|9oSZh+0{h4;?EuF2`pu#bOklNCo{Lb}!@L{s0yh(}9nhGqaHKs< zPSbKFiA^ZH_RoW-N*?xHC!H{t6vL6^PeoiqNhqO??GRx^@xV<9b6+U6Sx^R zAi8u4oE#3^+yWeNkD(XtYTUg}*+POfr$ zEDum>7!NAKsx0E2S=V+N8=pQc%8Y;_RGNE;DrgAX2j@vsKWY>Eb%ksQCN7iW{0%3Z zJB!{Byk8awp3GLKgJGHGxRC`6q_Iv6myP~E9TLdqL)+WN`Le$^ypp*MpUy`i`Lt7-WDz1CenLf zmph#1u#uxvHc8=jrEFaHIql5ABAIfG%midUHF5%mE<_R*) z|E@;Pno9B37WZ!=g1Ea`_NdcAKpVeaLTOV(Hb}#~sB*FXJ&{p00yCu$SxYF`noHuc z1JhgTMouR|8zBbHEPww`pYa)?p*^Pmq{F4h*ikwRm}tPnQgR&JVceNEd3h$HW%(~^cr_+oUhRF3Icax@5%Xf9y|k@LCe@jt&0(1Y~;2ufZ3~11pY`oaNhgHE%!oBW-CHIJAjcqoP_2;dt8SEictA_{bn_ePMR!C z`n%epC`@QZaapi-z>{o9RuD(tU`5w6W!~o)+8JcwN-BVY#$r@6&1+dWmE3uc%w^se z<4ciZa|ndsZtAwd3aaxxL<5NkkIIp^&B+vxaWsOj%6biu3}n!36skgWWPpoxnR}-T zwD6K}Y~a6RC4|*WKM_8FIaA&Y^+Ca!JN#-9JlvDljg^^g|9#FqLtv&ZaJEwntRzJe zqGB3(8l{AiW;L^rSl)zZeSrShSm0(${l{+?1ZMJ)TbnMQ4sk2*9=1rjId}1Z# z*N-3H<+Q(P76Pu;HSzg8pn$mHd8jS@LzcVY;#WGuZDV&c^UaB!MkM*QfTbLM!>0RQ zvy1#XRji6%RTV26Zg>0nm*w6!wM!`hD#6R3i?A+?&cvv}H97L?T**Tgo@1&7*y3z@ zyJGD+f6$pBzy8tc`989VUw8?tGv5X80?&B~RdWNF-cHm0;OvfL3TWPmiN=IrUj}?; zto)lRB@(vc5pk3Quhbs_Is&g-iD-}&NN&k2mkSZgp5wjbkYg>T6;YDm3iB7jx$<7A z!$}KJZE-#m&_UNRH@ldDp$=K<@YBaOqdi^6RQOb^m6;+vc)GxRVyuqa9fdHcRUoW^ z$8of9+e9`{w`$_(FV_t$`<73f^n%IH z0HQ_#RnVl9c4$cZm^~c?~dxCcv53a_R9J>s{Rm326i4Lqn8+c$LpFV|5_F z3(`W1Q4$URi_xK3?MR0d(f}*6l7a25jbDwCGpY=LiOb#UZJ&6N{4`DVlHbM6JbcRaG@_PWAr}O2EB-CRu_Rd2`5X*(ZUUF7x zxq0FnNZWdcy9&ypmDGTZ{~VdH{0KEPr>&vfiEdi39CNgh)Gl9#79G4K$r?n!M_1PX z8(b$^yR*Hi1alhni)J}&^#F>$aac|(PO?z9rck(<qI=OnfkGgle0Q!~={`Y2(h)Uc-h52u4uk9^~`!4QxsDbycKNG{3h2#?@IR1gk>O#Te{ zQe685s0mNSNbhm*vBDe+p&xso)d~?1Xqc2`wKc}`1GXBV^F5U2Ni~C+SU?^}xA0Mz z&L@^rp2^EMB^OD*=$`3f0)G9)_S}`~c)_|GeWj$Xu z1B;kNEB^qnICyS$bi!?j4V~)u6gUd&1l>e6ey-(K?i~jGUs2r`{Bn&nf8`vGS7l>_ zR$rKnWILz@V~OieLgz31kEx?mFbvn}iqB$CA&RCVINBKxX;p_YsF5IVi;tB6EH7KV%p8E}FoEMBH>C*Gx zQ%%$5Td7&3D&d!=h|7-o4?Lb?O)1uo8dT%>>ywPSPtMC_?a6g5 z)e#PG`h1f$^kN$sncd_zEQL_GL^$BW*FU$RKB-2?gb(p*-!gsb*DqGRfL)JQ{}vaA zJzgEQ+-%coYvWZ3YiL|sn_1IsVOu~t)MytLhvx%y>{#i)A{^Dn;{(+&T<8N@c_1Rb z(4oDRa%V0Mt)OWKIn>sgX| z62~ZCn4TsGFIV7Es8`(iIXrTT{W(|$CufExUrV6Yt`RetR6l}ephe_q!!S(@%54)u^Fp8w>&gcK{KvK?)1$GG&h z!mC|Lx2#H#+^BESC<@nI$`Ax(dcL|4xHhec7G`XP&ni_f7C{!aGh~&garrhbNUOHO zN$iJ-#rN??wk`kT>wTG|QhA%L4KAUF*Aw%p@Udl|3KRoF_7qEA@!5Rc;NoFZ~2-LM$y$UO5Ku#%VoBq z7}ap50#6Cm0adQ~=>7CF=OLMYx-%(kRv$Z$;<57c*$8On<&(saejr!5O>Wf<9d~cRL2Sfg89o9f!eTl zC}M*agxggE$@mJQGYMTbJn9O@4=46zeWHF%eK#RCS$Ns@X`};~8z7w+59>sH#;mFA zop-ISUlob|RymFxjGMVGggMqf;q_K$p5c#T6dOkw6*AqOLSN(P3QpIo<691_0U>iQ zQYgCKy((83W3)WQ_tC$@d&kQ$Pa>cg&yD(nl&d)wMWV$@Ua*n%ts_9v&X$E3=$iUT zHv{tiMT95=Jo=L@KD6?oH%SFKA5vyXZ5OLM=fjAPJULY%=oWzNXox+to=K4D;C3+u zIszI0AaY?9@Rq;SZNapo+8x!MdF4_d(U{Z7S+~Thq}k<9i|^Ma<3Oph{8DPsMjWZq zG{PIfvw6T&aNjE0!MNtoDUvg{IuN2-{91<)t;v9VS&<$c&s81e^VxSKuIVwqA9S4E zsN$pFz&m1wuOKC7c0U`Kw{xQ%L>+Y#o=ah@+3L^s{{8raar*}*5>ta?;}e2B`JF;< zU!2*1!7VNl2gX7=uQ_HA=A(J;nT|C6Z+Qtot44!`vt-PH5V5GVOKgwWctvtYn?bF0 zUvrVM-WeNNCwO}n3@aM56i;UvEcLVR5$B*J_0ALMTsr!PRe2bHJu7P3BpOx-1mUQX z1sEXQ7uD21w>Z(~1poqKY(Yn#Sh&0Vsjvhu$bV!+eZvp$R)frGAV{2j533Nskw7e? zV5|w~k|eVl90@dXfHzQU5&mujUlyK+9r4+67#Ail&BN50sHUl7ok&hN13m?8eWUz5 zS=R2q&h$+p_fh`i8Py0#tXLPqzN9W%WUTAv)~eZWFHMpl)I0kg$;g2Yw{}B2uep7& zjpXyb+CZh|emo+ln>H38V$P!bIkF4snJxa|ihRAEt}A4-AJc!mkFKkb%sfiP+c0Sm zpfJNHKMjLA_bR^6>$KXo2+p8k@f>Gt! zib=~Xl4Kvm#}8$Ef^_;o4)pv>D>i_60=^N7QRL|T_D3y`Ru1AIJ8nbOk3+!bi_a|B z?1%(aR|qQ`N9&{y5_5Mh)(^ULaJ` zeBq$HIx~bFtj;e-b{i5D1ae(Jxzj(QF5pxQ7BA7-m+;Dn~fmG4PnzXEi0YZ<{VR#00#qmLS!1`=zM2 zpKi|ex+HV&T_K}n%<$`1H?=%xJ*r3M4lVNRa94tJ9ki&88hy9g0ULexJEK zxePH1jvI3LnRb-Rz(CwNk?j0@&~5a+flC$;u}Yr4D`05#5f&&CT56TF!)$@BwZq_q z0FEvdpiCTq%Iu!-+Z9j_%E4_@@$b?dn&8|Mq3g;>=t3)PIq?S4rEL-m-$NQg*R={8 zCF6|g-W$w%cd895MFc{D{$}Ui={fY8I1rqXhG?ATkF&tX>-bmL8T(S$G1{bR;a0N-T38pm|LV zcQX@ZH6?11yqQ}j z-l5d?kOCeWyh;jH6cEd4fVE~tU(=9#XzbY zRIB8-4sNaKd4l$5X1}dLD$Jj4tSYP0qmF<4`Zr9Kuw!9W!cZHWU_x%HBonMkP@r7w zl>tF-QZG_DEXeV?{2-3FeaoeG+w$cDDWVpwf0%jQ5piUl2DnZHhx9Fn^)P#zs>QDd z+6R;qqIv+3C}S)g&M`|to5onQ`E12FK1D1Czw-E@6?UXOI0HM4KU9Q z&d}A~%1E3a_msf*yVn%;NxB;fGOLHWyGo zf@9EUoDylO_Q`{rcKU(=(#_B}rY#m6;3ms4e<|yTSY4cLbZJb#KsFFU*p2?M!y*;g zP1HLQUOer)c6qVm5>jE8a+7QVPSAOF-uz~Oy)Bv3PR9Q6*Qp5`GMPTEcqOCK0bz=q zxmhw`V{U{AI<=K=llam_MYg(>Ug<05ni1wkWMG+Y2~Q6+5;aD`*a; z@x}nYE}2kf;x8ELcWymRv$rQ{xL;4abTqIzmXnF5T~|wGnfAR4<#owtGZfLp;R5ez zw}S@xFz`m$gT^TJsvl0lqdKOeZMA1|X&h~$OqOS<)uVI$#t2pw*l=qll&mzgeYAw3 z+Sz>5zx$WzdvHkOs-@s(gb;_T?+B@MU^{g;d#R<$hT|Z3 zzLXFzCvK`u;}}gE=o+N>Gs*PcN>Dc73xY{z7~t`cN+Qt zS?OP1)6D4h0et--c2bLp$ld&X!Ik6=c$N=BGj0J{)}mZw3$b>SVV&<9ztzz;{Ehk@ z)09IHFU>QvYUF^xNX`}GenL|1Y`-r-aT^j9DQ+(<_HR__*d3sp;FGc|fHv5zew3+E z#d$wOtbLwC2P?U=fI_}!b|Bb23~eQqFo^+|22Ekz3EVIr>k`PP7HTJFH)B_)0fiH* z70_nPA^IuGMZvK*K-0I5s3WoXkF$)TQN?{fq?gWOR#r(9zEN`B3w2cEi^IT~;wr_N zA^q;d=Vm}hCSLZKO~Ef%v1?t(r~HNmogyV4@!(V9lAkXjn2Rg|F668%8rJSC-0&&! z@haL;*z--moKt@62qg#?fOBSB!)V=nw#T(#Mb!~G%YEoD%x@y_#kstf?^N;K4>37U zHW>z)~(ALQu;r}F|hztKsX#kqWhTg>j<$-n7e>>MzCD@esi zO$GP8fblMIpRey-`QSZ4Nal6@{X6=hd*HKdGaJ0?_3T}t6h`}Y>wWB9McbzT;t7J) zh5=TN(g#8SvYpg~Jr_yvWv2N=VA3pJ|98QZ4j&KpJu6FoN8ka+LmJ^eEP%5!JdNo#oKR{99#3xj5v?vY_9--(4a3q2 zGL~12A9vJ=yXnOP>8$dJ60;L>S?Fdhyx~(4&WcoUkjpFM-Q;9imhGsa7;Bw%J4Qt4 zYygZ*(@#FV8%XPR^(}&*;md4+DF&AJzzIJ_W8$`)Hm>^^sJIn4u3GG9k7{9*p8<7R zwVNNXA(poTllV<;^Gq;J|E4Qb*QAW86ICA3P?v%_WPaZsh6;lE7NCVRHc3t_sK}mt zJD=@xuz99p!u3x}a$q7q-+H@)G_wHJ@5iR-QNaYJIO4+F#sHs*vewEex@1A!-(JxmU^3Up!pRUI8Pxnv2oo1rnmObGN0DGNn2+$N3fB^TLZ_Lk{9a-h^zW|jw;0T`3I(s3 z*B%40xs+oDHE+2`Z`)mn0!G5D4+Xc!1IX&;Qku<*<4h9GE6N%2rcqVYe`!h(wFjxU&F%D*RW z+G+{~TyW*zllrqd6WNbx||pQUzx zr9KL@LBMPuXJB{@4SKSUSeH~J)gyF3A-?@qduocf5(fe!skp}2J!7>9Afczv+2m_j zJb7tN{%JxU(?=|XmIYu;yuEn54oMlxIl{n-!$q}_lQYo6lGc3#d@dyM79$a#rtrV3sv`ENcoO7V!22B z&C(i^f>|V>m-MycBXh(uH=sqqqMybxW&r6ik|WQcL6|zz^f%fq4xlyL0$LWQa?T&} zkVkuo=UD7%KGKl<;h*dWS|T@9h85x*x8F-yqeX}y`WrH0=i*7z;Fqu9L46l{J_!+( zV;@w<{ykx0JYSXT|1{|)WT>eS=hgr_CRn>Ro1k^zKd;rRo_q?kQH<+g z%I>K&$7`QMtmt~jz=1pVGMQboiWOpU@x!0tIe({x>eP*-wCFvj0C_c7b?Nk+(o(8F z9>X4l+np^14vA__^l$%7s|+Z7-&KqNrdq=ft$_&YU>PnlRMugCST^H7(#y$)ftk2o z#WBI6@5TpvgOlM`^il-`;3O_8BfFJC8zA__%nWI(SzwpAh;HgV9wWk>Z6VFpDIh5y zsQ&LNDslP`qgV3FTNNX zbw1Iq#67xK1in%U&w&K7mQ$rhnd`JAT2VSnsv8Ey{RMvw7}~BH^fsP z6SjRYy~}Nbr;{!qh$jU7oeGEUNW_R0v$3?qX;;EjTiXq*aR~u!ui7~~Dij6MLIJho z6&%rvU|A6vmjSpC#!LWVv?OBPzwKyf)Fs zG!WW7Jd;o`)&G(GjjMa|bIyYz9}K;JJ^Bz1%Z(I2TtK65BWSeYQ^0Ib7eW|X(A+4O zPRt@n2xP|X`+to85Y&5sEam*2se=R>w3Qv712(#8je%%9xY0Hq0o9cbvc99JfooKq zD68@Qzz|FW-Wl1xq~*#Ii==p1>F)6`v6`=bGQKTO27-IwD#s-#nDVPNWpqer@DS%U#PVz)oAnQ6Ghzdv*PH^El86;QfGOhG7#i5#DVNEE zt!rp^b&$sQCDSl$6x=EcpdM7PsW%y_TSns``Sdq$l0TGugulVSp;d9Diafk!H z%rTz`=_GiD{9?wkTLEd-THicLpGil46fPb(`?)`cgU>?R2 zow1(Xi>P{PF(A-RfohqX8t#ooE)Tda#xMU{t^jO4APv=G3lP8zKC>BH?~7)AOd>gW z!(r7BNT?3xF2P<;uhjQ}gc^O(ON0#=JGC+D-(XKhN}VJi1({@f!(E;!4?|t|cAvXz zMOT`O;t5hg-S{AXVAeamBp{>70U(^xsXh7%OO#hxo2jSN>nD}@1o6ZAa;f$;`@Hat z!-x8zI=Vob{oTj`d|Q|H&K}oXOWjLI%b+hh5!kFkYBga3A@z^Pi_eRgoRl2c%j zWs)PJQy}SODKtqwZu2=P*yS7o38oG-(1Ki13QYP)ZV%GK4A)2N6AQd)RmBSr`=(C6&hsL1VIUrrNM6e#8>9{kYIw>_ z{4}ssY5AC25enlkS~;y5vHUAQ*vVY5Q4aQAG&6Hm5vF**N<1!k0W|Pg=aKXtR_*SS0Z)QTRbz; z^NvsJQBI{;ZQ@lJ5hc5Lg}a`q!X1NUm|W%5H{g?vzGM{%8Pb@QlM+^6i@m zb94#e=ARZ6lsUv<6JSgdo-Ij=Rf-ACU>(Q*SsSlADR23#9kCF})1KRq!i5mu#HGBh~!1 z;j6QPmEf5hC%;z+A4_A^-rB8KDeB!7Nvjxq`(55`JKDFCy!WQSDi{PUxU;>;y5;&i zNPxJs--*ru9cVAn1-~}hm4{!!`CNgV9-YSJ@XI%g>#7r4dbi6y4-kOhhkrH*XWzh?W(>1{z?zG5pi-&-bRb{N0n`s29u)$w%@US^S_1RCyp=F}3c zpbu}N=x|4)GJR>CI`fS}dHVlM)mv2v5>sr1k3ag85*|Wq&mefdZ#MShU5ELMj)+X+ zkZ(_Y(npQn;ALCA^|zt=IrS;TT;ez&M2zY2O6s|_$MTqx~7w~$*^n4 zsJ=5tjRsR)`(2dabRn)8eQM-t?Ydjbi`A)+ORmT`4X`4t7&uA70+lt15Tso*-(b)a zLNF;(^-svjs4{Q#R~WW5#@mDg>?wnK>5m+cSC^2|u+wSiF+=ikke#>w^ZfQv?7P41 zM5d&vA6z=b`6R)=^l(0^9n|lB6nmT?wF+$ud2Mt2@It8!4_6TVGQrI(EI|t!-z<^J zWyvW`uZUgitsg{x48o)FoJ_z_H_BJdS@@$voLL+EV?2MZBxy>j0_RIKgvG$VPYq<> zPp%x0_Firv!HL!|emI???|3tIKC50rcgP=4*Io8WC!$1kBzN0#Cs!^<@eq`>XDi`Z zk(eVJou!b(ushE`_Tn5ZI0DDPMsN44N5<+uCmv38XW`a9yei=KcMIV=d#zsbHseeB zH@!jk%>_;tdOMjBhG1&gALWGw({!k>6ZAgLlq3j9Jl#2nDpUWif8(W-QRf?m9W`+3 z>J>z*O0MD@@|_}bX?IuI4d>>UFqrbPUy+>et@kv^(B=kXw1K&y{YQ!~PEF!yX26h} z;!Caj%#ERWfVJc+-q_T^aWH-q<;4Aqy!kK7otk=H9!ZAg(l7fjR1cIAv-*glc7j?h z)ZCKm4Cw8D?Y%WImwwZKVQU>MaZG>Er737mqaB(>`4TtMy7@KH{1?{18tx&hIurAA z1M?<(!=aR3Bj!Uj-mHH)j3R|dGuGZ83#@F5IffNt+g|k-5r^BMF7kKmXp{}?yYMDy zF-*&vD$xcdP~b=8&i(R)$i|Z)M{GWwsa~t(?~e&)jde0-aR~X}D3eVD33-bV3%E2> zH-je^B-7uXew26mW_ci1$YnLA++1x@qJ&c}v3ct}-hxm5o*^w9@ty$ZejTaV%xpe3 zH(L3l>bY!=Q^kUDn<~(3&iUqhS>yzxPNf}p?m~^3B11Bl6y6pjjC~a7M*VyauMhOI zk$ESxy}8OGiPCHx5UTM-j{ynOOLskuh5j`28`6{G&Oc6iro3-R3{};;`VXuOId7iU zDw4d9N7%*pd81jcYni68a_k|vC+7NvA4T>Kx&M;a_@x_=)fgZkR`@CP zc2sbF^-MwAWvzO5jr)j;HM}FHBRCv)us6tgwK@onhm~>ePth^S@dH;_K-5%p+W=a3 x%~%O@&ufKXxje1)?;(_z&Mt^kT5|lewQh_^h Date: Tue, 17 Sep 2024 20:34:14 -0400 Subject: [PATCH 375/897] Properly update mappings and fix walls --- .../populator/BlockRegistryPopulator.java | 57 +++++++------------ .../registry/populator/Conversion712_685.java | 4 ++ .../registry/populator/Conversion729_712.java | 16 +++++- core/src/main/resources/mappings | 2 +- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 9603cba63..bface58da 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -34,8 +34,16 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import it.unimi.dsi.fastutil.objects.*; -import org.cloudburstmc.nbt.*; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIntPair; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.cloudburstmc.nbt.NBTInputStream; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.nbt.NbtUtils; 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; @@ -63,7 +71,15 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.io.DataInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; import java.util.stream.Stream; import java.util.zip.GZIPInputStream; @@ -112,40 +128,7 @@ public final class BlockRegistryPopulator { .put(ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), Conversion685_671::remapBlock) .put(ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), Conversion712_685::remapBlock) .put(ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), Conversion729_712::remapBlock) - .put(ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()), tag -> { // TODO: Remove me when mappings is updated - String name = tag.getString("name"); - if ("minecraft:sponge".equals(name)) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("sponge_type"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - if ("minecraft:tnt".equals(name)) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("allow_underwater_bit"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - if ("minecraft:cobblestone_wall".equals(name)) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("wall_block_type"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - if ("minecraft:purpur_block".equals(name)) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("chisel_type"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - if ("minecraft:structure_void".equals(name)) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("structure_void_type"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - return tag; - }) + .put(ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()), tag -> tag) .build(); // We can keep this strong as nothing should be garbage collected diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java index 557a38f1f..db715e015 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java @@ -32,6 +32,8 @@ public class Conversion712_685 { private static final List NEW_BLOCKS = Stream.of(NEW_STONE_BLOCK_SLABS_2, NEW_STONE_BLOCK_SLABS_3, NEW_STONE_BLOCK_SLABS_4, NEW_DOUBLE_STONE_BLOCK_SLABS, NEW_DOUBLE_STONE_BLOCK_SLABS_2, NEW_DOUBLE_STONE_BLOCK_SLABS_3, NEW_DOUBLE_STONE_BLOCK_SLABS_4, NEW_PRISMARINE_BLOCKS, NEW_CORAL_FAN_HANGS, NEW_CORAL_FAN_HANGS_2, NEW_CORAL_FAN_HANGS_3, NEW_MONSTER_EGGS, NEW_STONEBRICK_BLOCKS, NEW_LIGHT_BLOCKS, NEW_SANDSTONE_BLOCKS, NEW_QUARTZ_BLOCKS, NEW_RED_SANDSTONE_BLOCKS, NEW_SAND_BLOCKS, NEW_DIRT_BLOCKS, NEW_ANVILS, NEW_YELLOW_FLOWERS).flatMap(List::stream).toList(); static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { + mapping = Conversion729_712.remapItem(item, mapping); + String identifer = mapping.getBedrockIdentifier(); if (!NEW_BLOCKS.contains(identifer)) { @@ -153,6 +155,8 @@ public class Conversion712_685 { } static NbtMap remapBlock(NbtMap tag) { + tag = Conversion729_712.remapBlock(tag); + final String name = tag.getString("name"); if (!NEW_BLOCKS.contains(name)) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java index 3b8d6d4a2..5d4ebdc47 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java @@ -12,7 +12,8 @@ public class Conversion729_712 { private static final List NEW_WALL_BLOCKS = List.of("minecraft:cobblestone_wall", "minecraft:mossy_cobblestone_wall", "minecraft:granite_wall", "minecraft:diorite_wall", "minecraft:andesite_wall", "minecraft:sandstone_wall", "minecraft:brick_wall", "minecraft:stone_brick_wall", "minecraft:mossy_stone_brick_wall", "minecraft:nether_brick_wall", "minecraft:end_stone_brick_wall", "minecraft:prismarine_wall", "minecraft:red_sandstone_wall", "minecraft:red_nether_brick_wall"); private static final List NEW_SPONGE_BLOCKS = List.of("minecraft:sponge", "minecraft:wet_sponge"); private static final List NEW_TNT_BLOCKS = List.of("minecraft:tnt", "minecraft:underwater_tnt"); - private static final List NEW_BLOCKS = Stream.of(NEW_PURPUR_BLOCKS, NEW_WALL_BLOCKS, NEW_SPONGE_BLOCKS, NEW_TNT_BLOCKS).flatMap(List::stream).toList(); + private static final List STRUCTURE_VOID = List.of("minecraft:structure_void"); + private static final List NEW_BLOCKS = Stream.of(NEW_PURPUR_BLOCKS, NEW_WALL_BLOCKS, NEW_SPONGE_BLOCKS, NEW_TNT_BLOCKS, STRUCTURE_VOID).flatMap(List::stream).toList(); static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { String identifier = mapping.getBedrockIdentifier(); @@ -88,7 +89,7 @@ public class Conversion729_712 { switch (name) { case "minecraft:cobblestone_wall" -> wallType = "cobblestone"; - case "minecraft:mossy_cobblestone_wall" -> wallType = "mossy"; + case "minecraft:mossy_cobblestone_wall" -> wallType = "mossy_cobblestone"; case "minecraft:granite_wall" -> wallType = "granite"; case "minecraft:diorite_wall" -> wallType = "diorite"; case "minecraft:andesite_wall" -> wallType = "andesite"; @@ -97,7 +98,7 @@ public class Conversion729_712 { case "minecraft:stone_brick_wall" -> wallType = "stone_brick"; case "minecraft:mossy_stone_brick_wall" -> wallType = "mossy_stone_brick"; case "minecraft:nether_brick_wall" -> wallType = "nether_brick"; - case "minecraft:end_stone_brick_wall" -> wallType = "end_stone_brick"; + case "minecraft:end_stone_brick_wall" -> wallType = "end_brick"; case "minecraft:prismarine_wall" -> wallType = "prismarine"; case "minecraft:red_sandstone_wall" -> wallType = "red_sandstone"; case "minecraft:red_nether_brick_wall" -> wallType = "red_nether_brick"; @@ -136,6 +137,15 @@ public class Conversion729_712 { return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); } + if (STRUCTURE_VOID.contains(name)) { + NbtMap states = tag.getCompound("states") + .toBuilder() + .putString("structure_void_type", "air") + .build(); + + return tag.toBuilder().putCompound("states", states).build(); + } + return tag; } } diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 698fd2b10..3e85fcc87 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 698fd2b108a9e53f1e47b8cfdc122651b70d6059 +Subproject commit 3e85fcc87d7cfa4162cd8823192fcee0830be049 From 1ab740915a61430baefc04df9e22ce56fdc06db0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:00:33 -0400 Subject: [PATCH 376/897] Fix diorite wall mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 3e85fcc87..0fb6f09c1 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 3e85fcc87d7cfa4162cd8823192fcee0830be049 +Subproject commit 0fb6f09c1507632f1a0c2520a78d3cf450f7bea3 From 2ef6172bfc84c11a4689e32fbcb64de99a687e34 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:51:48 -0400 Subject: [PATCH 377/897] Fix wet sponges and purpur pillars --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 0fb6f09c1..830085e37 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 0fb6f09c1507632f1a0c2520a78d3cf450f7bea3 +Subproject commit 830085e37e0053c9d6116bcad37cafcba83aded5 From 7af5bac9057a65c299d8328d9b5711df42b84be1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:42:24 -0400 Subject: [PATCH 378/897] Update sponge and purpur pillar items --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 830085e37..93f207e7e 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 830085e37e0053c9d6116bcad37cafcba83aded5 +Subproject commit 93f207e7e9d73f58a7c8902f7deda9dcb0524c8e From 4f32fb717463dbea85740e6045ce218e0b689595 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 22 Sep 2024 23:06:22 -0400 Subject: [PATCH 379/897] Indicate 1.21.30 support in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb93a8808..dec1e9dd1 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.21 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.30 and Minecraft Java 1.21/1.21.1. 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. From 84dac08058d3d2130442ddfc33a32ae028e1a5d4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 24 Sep 2024 21:01:47 -0400 Subject: [PATCH 380/897] Bump MinecraftAuth to release --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2ff669803..0f9087c8f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ protocol-connection = "3.0.0.Beta5-20240916.181041-6" protocol-common = "3.0.0.Beta5-20240916.181041-6" protocol-codec = "3.0.0.Beta5-20240916.181041-6" raknet = "1.0.0.CR3-20240416.144209-1" -minecraftauth = "4.1.1-20240806.235051-7" +minecraftauth = "4.1.1" mcprotocollib = "1.21-20240725.013034-16" adventure = "4.14.0" adventure-platform = "4.3.0" From 23cf397fa8bed956973244e33d1060209c8d2d42 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 Sep 2024 18:10:18 -0400 Subject: [PATCH 381/897] More accurate turtle scale --- .../entity/type/living/animal/TurtleEntity.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 16901a844..ae7f2d2bd 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 @@ -55,6 +55,17 @@ public class TurtleEntity extends AnimalEntity { return ItemTag.TURTLE_FOOD; } + @Override + protected float getAdultSize() { + return super.getAdultSize() * 0.7f; + } + + @Override + protected float getBabySize() { + // 0.3f is Java scale, plus Bedrock difference + return 0.3f * 0.5f; + } + @Override public boolean canBeLeashed() { return false; From 172cf82725f36b7fffd9b4cf4610976d7d79fbb8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 30 Sep 2024 18:22:11 -0400 Subject: [PATCH 382/897] Indicate support for Bedrock 1.21.31 --- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index d3abf934f..c188e92bb 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -51,7 +51,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v729.CODEC.toBuilder() - .minecraftVersion("1.21.30") + .minecraftVersion("1.21.31") .build()); /** @@ -78,7 +78,9 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder() .minecraftVersion("1.21.20 - 1.21.23") .build())); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.21.30/1.21.31") + .build()); } /** From 26c4c5250a55fc81ad2848a18d308e06064563a9 Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:12:57 +0200 Subject: [PATCH 383/897] Add support for extended world height (#5002) --- .../java/org/geysermc/geyser/GeyserImpl.java | 4 +- .../geyser/level/BedrockDimension.java | 83 +++++++++++++++++-- .../geysermc/geyser/level/JavaDimension.java | 11 ++- .../geyser/session/GeyserSession.java | 35 +++++++- .../protocol/java/JavaLoginTranslator.java | 7 +- .../JavaLevelChunkWithLightTranslator.java | 10 ++- .../org/geysermc/geyser/util/ChunkUtils.java | 9 +- .../geysermc/geyser/util/DimensionUtils.java | 55 +++--------- 8 files changed, 141 insertions(+), 73 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index bc6108abf..9df1d2189 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -76,6 +76,7 @@ import org.geysermc.geyser.erosion.UnixSocketClientListener; import org.geysermc.geyser.event.GeyserEventBus; import org.geysermc.geyser.extension.GeyserExtensionManager; import org.geysermc.geyser.impl.MinecraftVersionImpl; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.GeyserServer; @@ -95,7 +96,6 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.AssetUtils; import org.geysermc.geyser.util.CooldownUtils; -import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.Metrics; import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.geyser.util.NewsHandler; @@ -425,7 +425,7 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { } CooldownUtils.setDefaultShowCooldown(config.getShowCooldown()); - DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether + BedrockDimension.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether Integer bedrockThreadCount = Integer.getInteger("Geyser.BedrockNetworkThreads"); if (bedrockThreadCount == null) { diff --git a/core/src/main/java/org/geysermc/geyser/level/BedrockDimension.java b/core/src/main/java/org/geysermc/geyser/level/BedrockDimension.java index 250c0f7a4..d62a17232 100644 --- a/core/src/main/java/org/geysermc/geyser/level/BedrockDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/BedrockDimension.java @@ -25,17 +25,84 @@ package org.geysermc.geyser.level; +import lombok.ToString; + /** * A data structure to represent what Bedrock believes are the height requirements for a specific dimension. * As of 1.18.30, biome count is representative of the height of the world, and out-of-bounds chunks can crash * the client. - * - * @param minY The minimum height Bedrock Edition will accept. - * @param height The maximum chunk height Bedrock Edition will accept, from the lowest point to the highest. - * @param doUpperHeightWarn whether to warn in the console if the Java dimension height exceeds Bedrock's. */ -public record BedrockDimension(int minY, int height, boolean doUpperHeightWarn) { - public static final BedrockDimension OVERWORLD = new BedrockDimension(-64, 384, true); - public static final BedrockDimension THE_NETHER = new BedrockDimension(0, 128, false); - public static final BedrockDimension THE_END = new BedrockDimension(0, 256, true); +@ToString +public class BedrockDimension { + + public static final int OVERWORLD_ID = 0; + public static final int DEFAULT_NETHER_ID = 1; + public static final int END_ID = 2; + + // Changes if the above-bedrock Nether building workaround is applied + public static int BEDROCK_NETHER_ID = DEFAULT_NETHER_ID; + + public static final BedrockDimension OVERWORLD = new BedrockDimension(-64, 384, true, OVERWORLD_ID); + public static final BedrockDimension THE_NETHER = new BedrockDimension(0, 128, false, -1) { + @Override + public int bedrockId() { + return BEDROCK_NETHER_ID; + } + }; + public static final BedrockDimension THE_END = new BedrockDimension(0, 256, true, END_ID); + public static final String NETHER_IDENTIFIER = "minecraft:the_nether"; + + private final int minY; + private final int height; + private final boolean doUpperHeightWarn; + private final int bedrockId; + + /** + * @param minY The minimum height Bedrock Edition will accept. + * @param height The maximum chunk height Bedrock Edition will accept, from the lowest point to the highest. + * @param doUpperHeightWarn whether to warn in the console if the Java dimension height exceeds Bedrock's. + * @param bedrockId the Bedrock dimension ID of this dimension. + */ + public BedrockDimension(int minY, int height, boolean doUpperHeightWarn, int bedrockId) { + this.minY = minY; + this.height = height; + this.doUpperHeightWarn = doUpperHeightWarn; + this.bedrockId = bedrockId; + } + + /** + * The Nether dimension in Bedrock does not permit building above Y128 - the Bedrock above the dimension. + * This workaround sets the Nether as the End dimension to ignore this limit. + * + * @param isAboveNetherBedrockBuilding true if we should apply The End workaround + */ + public static void changeBedrockNetherId(boolean isAboveNetherBedrockBuilding) { + // Change dimension ID to the End to allow for building above Bedrock + BEDROCK_NETHER_ID = isAboveNetherBedrockBuilding ? END_ID : DEFAULT_NETHER_ID; + } + + public static boolean isCustomBedrockNetherId() { + return BEDROCK_NETHER_ID == END_ID; + } + + public int maxY() { + return minY + height; + } + + public int minY() { + return minY; + } + + public int height() { + return height; + } + + public boolean doUpperHeightWarn() { + return doUpperHeightWarn; + } + + public int bedrockId() { + return bedrockId; + } + } diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 50589851b..c4592517c 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -63,12 +63,19 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, boolean ultr if ("minecraft".equals(id.namespace())) { String identifier = id.asString(); bedrockId = DimensionUtils.javaToBedrock(identifier); - isNetherLike = DimensionUtils.NETHER_IDENTIFIER.equals(identifier); + isNetherLike = BedrockDimension.NETHER_IDENTIFIER.equals(identifier); } else { // Effects should give is a clue on how this (custom) dimension is supposed to look like String effects = dimension.getString("effects"); bedrockId = DimensionUtils.javaToBedrock(effects); - isNetherLike = DimensionUtils.NETHER_IDENTIFIER.equals(effects); + isNetherLike = BedrockDimension.NETHER_IDENTIFIER.equals(effects); + } + + if (minY % 16 != 0) { + throw new RuntimeException("Minimum Y must be a multiple of 16!"); + } + if (maxY % 16 != 0) { + throw new RuntimeException("Maximum Y must be a multiple of 16!"); } return new JavaDimension(minY, maxY, piglinSafe, ultrawarm, coordinateScale, bedrockId, isNetherLike); 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 4589afe23..bfdf84bca 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -74,6 +74,7 @@ import org.cloudburstmc.protocol.bedrock.data.SpawnBiomeType; import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData; import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; 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.packet.AvailableEntityIdentifiersPacket; @@ -84,6 +85,7 @@ 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; import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket; @@ -175,7 +177,6 @@ import org.geysermc.geyser.text.MinecraftLocale; 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.DimensionUtils; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.LoginEncryptionUtils; import org.geysermc.geyser.util.MinecraftAuthLogger; @@ -388,6 +389,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private boolean sprinting; + /** + * The overworld dimension which Bedrock Edition uses. + */ + private BedrockDimension bedrockOverworldDimension = BedrockDimension.OVERWORLD; /** * The dimension of the player. * As all entities are in the same world, this can be safely applied to all other entities. @@ -401,7 +406,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * right before the StartGamePacket is sent. */ @Setter - private BedrockDimension bedrockDimension = BedrockDimension.OVERWORLD; + private BedrockDimension bedrockDimension = this.bedrockOverworldDimension; @Setter private int breakingBlock; @@ -711,6 +716,30 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Send all necessary packets to load Bedrock into the server */ public void connect() { + int minY = this.dimensionType.minY(); + int maxY = this.dimensionType.maxY(); + for (JavaDimension javaDimension : this.getRegistryCache().dimensions().values()) { + if (javaDimension.bedrockId() == BedrockDimension.OVERWORLD_ID) { + minY = Math.min(minY, javaDimension.minY()); + maxY = Math.max(maxY, javaDimension.maxY()); + } + } + minY = Math.max(minY, -512); + maxY = Math.min(maxY, 512); + + if (minY < BedrockDimension.OVERWORLD.minY() || maxY > BedrockDimension.OVERWORLD.maxY()) { + final boolean isInOverworld = this.bedrockDimension == this.bedrockOverworldDimension; + this.bedrockOverworldDimension = new BedrockDimension(minY, maxY - minY, true, BedrockDimension.OVERWORLD_ID); + if (isInOverworld) { + this.bedrockDimension = this.bedrockOverworldDimension; + } + geyser.getLogger().debug("Extending overworld dimension to " + minY + " - " + maxY); + + DimensionDataPacket dimensionDataPacket = new DimensionDataPacket(); + dimensionDataPacket.getDefinitions().add(new DimensionDefinition("minecraft:overworld", maxY, minY, 5 /* Void */)); + upstream.sendPacket(dimensionDataPacket); + } + startGame(); sentSpawnPacket = true; syncEntityProperties(); @@ -1594,7 +1623,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setRotation(Vector2f.from(1, 1)); startGamePacket.setSeed(-1L); - startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(bedrockDimension)); + startGamePacket.setDimensionId(bedrockDimension.bedrockId()); startGamePacket.setGeneratorId(1); startGamePacket.setLevelGameType(GameType.SURVIVAL); startGamePacket.setDifficulty(1); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 6470a5f0a..fb9159c47 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -33,6 +33,7 @@ import org.geysermc.erosion.Constants; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -62,7 +63,7 @@ public class JavaLoginTranslator extends PacketTranslator entry : session.getItemFrameCache().entrySet()) { diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index 288b425ba..96471a2ce 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -167,7 +167,7 @@ public class ChunkUtils { byteBuf.readBytes(payload); LevelChunkPacket data = new LevelChunkPacket(); - data.setDimension(DimensionUtils.javaToBedrock(session.getBedrockDimension())); + data.setDimension(session.getBedrockDimension().bedrockId()); data.setChunkX(chunkX); data.setChunkZ(chunkZ); data.setSubChunksLength(0); @@ -207,13 +207,6 @@ public class ChunkUtils { int minY = dimension.minY(); int maxY = dimension.maxY(); - if (minY % 16 != 0) { - throw new RuntimeException("Minimum Y must be a multiple of 16!"); - } - if (maxY % 16 != 0) { - throw new RuntimeException("Maximum Y must be a multiple of 16!"); - } - BedrockDimension bedrockDimension = session.getBedrockDimension(); // Yell in the console if the world height is too height in the current scenario // The constraints change depending on if the player is in the overworld or not, and if experimental height is enabled diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index 8dc94a165..b4fd6b924 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -44,17 +44,8 @@ import java.util.Set; public class DimensionUtils { - // Changes if the above-bedrock Nether building workaround is applied - private static int BEDROCK_NETHER_ID = 1; - public static final String BEDROCK_FOG_HELL = "minecraft:fog_hell"; - public static final String NETHER_IDENTIFIER = "minecraft:the_nether"; - - private static final int BEDROCK_OVERWORLD_ID = 0; - private static final int BEDROCK_DEFAULT_NETHER_ID = 1; - private static final int BEDROCK_END_ID = 2; - public static void switchDimension(GeyserSession session, JavaDimension javaDimension) { switchDimension(session, javaDimension, javaDimension.bedrockId()); } @@ -95,7 +86,7 @@ public class DimensionUtils { // If the bedrock nether height workaround is enabled, meaning the client is told it's in the end dimension, // we check if the player is entering the nether and apply the nether fog to fake the fact that the client // thinks they are in the end dimension. - if (isCustomBedrockNetherId()) { + if (BedrockDimension.isCustomBedrockNetherId()) { if (javaDimension.isNetherLike()) { session.camera().sendFog(BEDROCK_FOG_HELL); } else if (previousDimension != null && previousDimension.isNetherLike()) { @@ -168,22 +159,12 @@ public class DimensionUtils { public static void setBedrockDimension(GeyserSession session, int bedrockDimension) { session.setBedrockDimension(switch (bedrockDimension) { - case BEDROCK_END_ID -> BedrockDimension.THE_END; - case BEDROCK_DEFAULT_NETHER_ID -> BedrockDimension.THE_NETHER; // JavaDimension *should* be set to BEDROCK_END_ID if the Nether workaround is enabled. - default -> BedrockDimension.OVERWORLD; + case BedrockDimension.END_ID -> BedrockDimension.THE_END; + case BedrockDimension.DEFAULT_NETHER_ID -> BedrockDimension.THE_NETHER; // JavaDimension *should* be set to BEDROCK_END_ID if the Nether workaround is enabled. + default -> session.getBedrockOverworldDimension(); }); } - public static int javaToBedrock(BedrockDimension dimension) { - if (dimension == BedrockDimension.THE_NETHER) { - return BEDROCK_NETHER_ID; - } else if (dimension == BedrockDimension.THE_END) { - return BEDROCK_END_ID; - } else { - return BEDROCK_OVERWORLD_ID; - } - } - /** * Map the Java edition dimension IDs to Bedrock edition * @@ -192,9 +173,9 @@ public class DimensionUtils { */ public static int javaToBedrock(String javaDimension) { return switch (javaDimension) { - case NETHER_IDENTIFIER -> BEDROCK_NETHER_ID; - case "minecraft:the_end" -> 2; - default -> 0; + case BedrockDimension.NETHER_IDENTIFIER -> BedrockDimension.BEDROCK_NETHER_ID; + case "minecraft:the_end" -> BedrockDimension.END_ID; + default -> BedrockDimension.OVERWORLD_ID; }; } @@ -204,22 +185,11 @@ public class DimensionUtils { public static int javaToBedrock(GeyserSession session) { JavaDimension dimension = session.getDimensionType(); if (dimension == null) { - return BEDROCK_OVERWORLD_ID; + return BedrockDimension.OVERWORLD_ID; } return dimension.bedrockId(); } - /** - * The Nether dimension in Bedrock does not permit building above Y128 - the Bedrock above the dimension. - * This workaround sets the Nether as the End dimension to ignore this limit. - * - * @param isAboveNetherBedrockBuilding true if we should apply The End workaround - */ - public static void changeBedrockNetherId(boolean isAboveNetherBedrockBuilding) { - // Change dimension ID to the End to allow for building above Bedrock - BEDROCK_NETHER_ID = isAboveNetherBedrockBuilding ? BEDROCK_END_ID : BEDROCK_DEFAULT_NETHER_ID; - } - /** * Gets the fake, temporary dimension we send clients to so we aren't switching to the same dimension without an additional * dimension switch. @@ -229,16 +199,13 @@ public class DimensionUtils { * @return the Bedrock fake dimension to transfer to */ public static int getTemporaryDimension(int currentBedrockDimension, int newBedrockDimension) { - if (isCustomBedrockNetherId()) { + if (BedrockDimension.isCustomBedrockNetherId()) { // Prevents rare instances of Bedrock locking up - return newBedrockDimension == BEDROCK_END_ID ? BEDROCK_OVERWORLD_ID : BEDROCK_END_ID; + return newBedrockDimension == BedrockDimension.END_ID ? BedrockDimension.OVERWORLD_ID : BedrockDimension.END_ID; } // Check current Bedrock dimension and not just the Java dimension. // Fixes rare instances like https://github.com/GeyserMC/Geyser/issues/3161 - return currentBedrockDimension == BEDROCK_OVERWORLD_ID ? BEDROCK_DEFAULT_NETHER_ID : BEDROCK_OVERWORLD_ID; + return currentBedrockDimension == BedrockDimension.OVERWORLD_ID ? BedrockDimension.DEFAULT_NETHER_ID : BedrockDimension.OVERWORLD_ID; } - public static boolean isCustomBedrockNetherId() { - return BEDROCK_NETHER_ID == BEDROCK_END_ID; - } } From 482089379228eb93b2a423dd42f97d8138eaf325 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:02:01 -0400 Subject: [PATCH 384/897] Fix NPE with dimension handling in online mode This change should be fine since all dimensions are iterated through in the registry cache --- .../java/org/geysermc/geyser/session/GeyserSession.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 bfdf84bca..6493e812e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -716,9 +716,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Send all necessary packets to load Bedrock into the server */ public void connect() { - int minY = this.dimensionType.minY(); - int maxY = this.dimensionType.maxY(); - for (JavaDimension javaDimension : this.getRegistryCache().dimensions().values()) { + // Note: this.dimensionType may be null here if the player is connecting from online mode + int minY = BedrockDimension.OVERWORLD.minY(); + int maxY = BedrockDimension.OVERWORLD.maxY(); + for (JavaDimension javaDimension : this.registryCache.dimensions().values()) { if (javaDimension.bedrockId() == BedrockDimension.OVERWORLD_ID) { minY = Math.min(minY, javaDimension.minY()); maxY = Math.max(maxY, javaDimension.maxY()); From c656e415f36dd04233559e01ed192224f4725d37 Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:39:50 +0200 Subject: [PATCH 385/897] Update to new MCPL (#4902) * Update to new MCPL * Add flow control to localsession to resolve race conditions * Update listeners * Update mcpl * Bump mcpl * Remove default listeners override * Update core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java Co-authored-by: chris * Bump MCPL * Update mcpl impl * Bump mcpl * Update mcpl * Inline lambda * update mcpl * back to mcpl snapshots instead of jitpack --------- Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> Co-authored-by: chris --- .../geyser/network/netty/LocalSession.java | 122 ++++++++++-------- .../geyser/session/GeyserSession.java | 25 +--- gradle/libs.versions.toml | 2 +- 3 files changed, 71 insertions(+), 78 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 958e88288..d9e450c62 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -27,15 +27,29 @@ package org.geysermc.geyser.network.netty; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.*; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.DefaultEventLoopGroup; import io.netty.channel.unix.PreferredDirectByteBufAllocator; -import io.netty.handler.codec.haproxy.*; +import io.netty.handler.codec.haproxy.HAProxyCommand; +import io.netty.handler.codec.haproxy.HAProxyMessage; +import io.netty.handler.codec.haproxy.HAProxyMessageEncoder; +import io.netty.handler.codec.haproxy.HAProxyProtocolVersion; +import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol; +import io.netty.handler.timeout.ReadTimeoutHandler; +import io.netty.handler.timeout.WriteTimeoutHandler; import io.netty.util.concurrent.DefaultThreadFactory; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.mcprotocollib.network.BuiltinFlags; import org.geysermc.mcprotocollib.network.codec.PacketCodecHelper; import org.geysermc.mcprotocollib.network.packet.PacketProtocol; +import org.geysermc.mcprotocollib.network.tcp.FlushHandler; +import org.geysermc.mcprotocollib.network.tcp.TcpFlowControlHandler; import org.geysermc.mcprotocollib.network.tcp.TcpPacketCodec; +import org.geysermc.mcprotocollib.network.tcp.TcpPacketCompression; +import org.geysermc.mcprotocollib.network.tcp.TcpPacketEncryptor; import org.geysermc.mcprotocollib.network.tcp.TcpPacketSizer; import org.geysermc.mcprotocollib.network.tcp.TcpSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; @@ -43,6 +57,7 @@ import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; /** @@ -72,44 +87,53 @@ public final class LocalSession extends TcpSession { if (DEFAULT_EVENT_LOOP_GROUP == null) { DEFAULT_EVENT_LOOP_GROUP = new DefaultEventLoopGroup(new DefaultThreadFactory(this.getClass(), true)); Runtime.getRuntime().addShutdownHook(new Thread( - () -> DEFAULT_EVENT_LOOP_GROUP.shutdownGracefully(100, 500, TimeUnit.MILLISECONDS))); + () -> DEFAULT_EVENT_LOOP_GROUP.shutdownGracefully(100, 500, TimeUnit.MILLISECONDS))); } - try { - final Bootstrap bootstrap = new Bootstrap(); - bootstrap.channel(LocalChannelWithRemoteAddress.class); - bootstrap.handler(new ChannelInitializer() { - @Override - public void initChannel(@NonNull LocalChannelWithRemoteAddress channel) { - channel.spoofedRemoteAddress(new InetSocketAddress(clientIp, 0)); - PacketProtocol protocol = getPacketProtocol(); - protocol.newClientSession(LocalSession.this, transferring); + final Bootstrap bootstrap = new Bootstrap(); + bootstrap.channel(LocalChannelWithRemoteAddress.class); + bootstrap.handler(new ChannelInitializer() { + @Override + public void initChannel(@NonNull LocalChannelWithRemoteAddress channel) { + channel.spoofedRemoteAddress(new InetSocketAddress(clientIp, 0)); + PacketProtocol protocol = getPacketProtocol(); + protocol.newClientSession(LocalSession.this, transferring); - refreshReadTimeoutHandler(channel); - refreshWriteTimeoutHandler(channel); + ChannelPipeline pipeline = channel.pipeline(); - ChannelPipeline pipeline = channel.pipeline(); - pipeline.addLast("sizer", new TcpPacketSizer(LocalSession.this, protocol.getPacketHeader().getLengthSize())); - pipeline.addLast("codec", new TcpPacketCodec(LocalSession.this, true)); - pipeline.addLast("manager", LocalSession.this); + initializeHAProxySupport(channel); - addHAProxySupport(pipeline); - } - }).group(DEFAULT_EVENT_LOOP_GROUP).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout() * 1000); + pipeline.addLast("read-timeout", new ReadTimeoutHandler(getFlag(BuiltinFlags.READ_TIMEOUT, 30))); + pipeline.addLast("write-timeout", new WriteTimeoutHandler(getFlag(BuiltinFlags.WRITE_TIMEOUT, 0))); - if (PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR != null) { - bootstrap.option(ChannelOption.ALLOCATOR, PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR); + pipeline.addLast("encryption", new TcpPacketEncryptor()); + pipeline.addLast("sizer", new TcpPacketSizer(protocol.getPacketHeader(), getCodecHelper())); + pipeline.addLast("compression", new TcpPacketCompression(getCodecHelper())); + + pipeline.addLast("flow-control", new TcpFlowControlHandler()); + pipeline.addLast("codec", new TcpPacketCodec(LocalSession.this, true)); + pipeline.addLast("flush-handler", new FlushHandler()); + pipeline.addLast("manager", LocalSession.this); + } + }).group(DEFAULT_EVENT_LOOP_GROUP).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getFlag(BuiltinFlags.CLIENT_CONNECT_TIMEOUT, 30) * 1000); + + if (PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR != null) { + bootstrap.option(ChannelOption.ALLOCATOR, PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR); + } + + bootstrap.remoteAddress(targetAddress); + + CompletableFuture handleFuture = new CompletableFuture<>(); + bootstrap.connect().addListener((futureListener) -> { + if (!futureListener.isSuccess()) { + exceptionCaught(null, futureListener.cause()); } - bootstrap.remoteAddress(targetAddress); + handleFuture.complete(null); + }); - bootstrap.connect().addListener((future) -> { - if (!future.isSuccess()) { - exceptionCaught(null, future.cause()); - } - }); - } catch (Throwable t) { - exceptionCaught(null, t); + if (wait) { + handleFuture.join(); } } @@ -118,32 +142,20 @@ public final class LocalSession extends TcpSession { return (MinecraftCodecHelper) this.codecHelper; } - // TODO duplicate code - private void addHAProxySupport(ChannelPipeline pipeline) { + private void initializeHAProxySupport(Channel channel) { InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); - if (getFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, false) && clientAddress != null) { - pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() { - @Override - public void channelActive(@NonNull ChannelHandlerContext ctx) throws Exception { - HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6; - InetSocketAddress remoteAddress; - if (ctx.channel().remoteAddress() instanceof InetSocketAddress) { - remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); - } else { - remoteAddress = new InetSocketAddress(host, port); - } - ctx.channel().writeAndFlush(new HAProxyMessage( - HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol, - clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(), - clientAddress.getPort(), remoteAddress.getPort() - )); - ctx.pipeline().remove(this); - ctx.pipeline().remove("proxy-protocol-encoder"); - super.channelActive(ctx); - } - }); - pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE); + if (clientAddress == null) { + return; } + + channel.pipeline().addLast("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE); + HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6; + InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress(); + channel.writeAndFlush(new HAProxyMessage( + HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol, + clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(), + clientAddress.getPort(), remoteAddress.getPort() + )).addListener(future -> channel.pipeline().remove("proxy-protocol-encoder")); } /** 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 6493e812e..9c20e9909 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -963,8 +963,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Start ticking tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); - this.protocol.setUseDefaultListeners(false); - TcpSession downstream; if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP @@ -990,7 +988,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.downstream.getSession().setFlag(MinecraftConstants.FOLLOW_TRANSFERS, false); if (geyser.getConfig().getRemote().isUseProxyProtocol()) { - downstream.setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true); downstream.setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress()); } if (geyser.getConfig().isForwardPlayerPing()) { @@ -1000,22 +997,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // We'll handle this since we have the registry data on hand downstream.setFlag(MinecraftConstants.SEND_BLANK_KNOWN_PACKS_RESPONSE, false); - // This isn't a great solution, but... we want to make sure the finish configuration packet cannot be sent - // before the KnownPacks packet. - this.downstream.getSession().addListener(new ClientListener(ProtocolState.LOGIN, loginEvent.transferring()) { - @Override - public void packetReceived(Session session, Packet packet) { - if (protocol.getState() == ProtocolState.CONFIGURATION) { - if (packet instanceof ClientboundFinishConfigurationPacket) { - // Prevent - GeyserSession.this.ensureInEventLoop(() -> GeyserSession.this.sendDownstreamPacket(new ServerboundFinishConfigurationPacket())); - return; - } - } - super.packetReceived(session, packet); - } - }); - downstream.addListener(new SessionAdapter() { @Override public void packetSending(PacketSendingEvent event) { @@ -1788,8 +1769,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return; } - if (protocol.getState() != intendedState) { - geyser.getLogger().debug("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " state"); + if (protocol.getOutboundState() != intendedState) { + geyser.getLogger().debug("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " outbound state"); return; } @@ -1823,7 +1804,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } private void sendDownstreamPacket0(Packet packet) { - ProtocolState state = protocol.getState(); + ProtocolState state = protocol.getOutboundState(); if (state == ProtocolState.GAME || state == ProtocolState.CONFIGURATION || packet.getClass() == ServerboundCustomQueryAnswerPacket.class) { downstream.sendPacket(packet); } else { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0f9087c8f..70d6e915d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20240916.181041-6" protocol-codec = "3.0.0.Beta5-20240916.181041-6" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21-20240725.013034-16" +mcprotocollib = "1.21-20241008.134549-23" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From ef4acb121f0f8746fa18a27f6acb1fc032ec7b2b Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 8 Oct 2024 19:26:46 +0200 Subject: [PATCH 386/897] Scoreboard rework (#4947) * Initial version of the great scoreboard rework * Fixed some issues and added some initial tests * Addressed review * Added CubeCraft's scoreboard as a test, and fixed a discovered bug * Removed var usage for primitives and String, removed star imports --- core/build.gradle.kts | 1 + .../geysermc/geyser/entity/type/Entity.java | 104 ++- .../geyser/entity/type/LivingEntity.java | 19 +- .../type/living/animal/RabbitEntity.java | 15 +- .../entity/type/player/PlayerEntity.java | 197 ++--- .../geysermc/geyser/scoreboard/Objective.java | 187 ++--- .../org/geysermc/geyser/scoreboard/Score.java | 199 ----- .../geyser/scoreboard/ScoreReference.java | 132 +++ .../geyser/scoreboard/Scoreboard.java | 419 ++++------ .../geyser/scoreboard/ScoreboardUpdater.java | 1 - .../org/geysermc/geyser/scoreboard/Team.java | 360 +++++---- .../display/score/BelownameDisplayScore.java | 56 ++ .../display/score/DisplayScore.java | 70 ++ .../display/score/PlayerlistDisplayScore.java | 61 ++ .../display/score/SidebarDisplayScore.java | 139 ++++ .../display/slot/BelownameDisplaySlot.java | 182 +++++ .../scoreboard/display/slot/DisplaySlot.java | 162 ++++ .../display/slot/PlayerlistDisplaySlot.java | 158 ++++ .../display/slot/SidebarDisplaySlot.java | 189 +++++ .../geyser/session/cache/EntityCache.java | 62 +- .../geyser/session/cache/WorldCache.java | 9 +- .../org/geysermc/geyser/text/ChatColor.java | 58 +- .../java/scoreboard/JavaResetScorePacket.java | 20 +- .../JavaSetObjectiveTranslator.java | 61 +- .../JavaSetPlayerTeamTranslator.java | 112 +-- .../scoreboard/JavaSetScoreTranslator.java | 46 +- .../translator/text/MessageTranslator.java | 70 +- .../org/geysermc/geyser/util/EntityUtils.java | 20 + .../network/NameVisibilityScoreboardTest.java | 270 +++++++ .../BasicBelownameScoreboardTests.java | 227 ++++++ .../BasicPlayerlistScoreboardTests.java | 204 +++++ .../server/CubecraftScoreboardTest.java | 756 ++++++++++++++++++ .../sidebar/BasicSidebarScoreboardTests.java | 218 +++++ .../OrderAndLimitSidebarScoreboardTests.java | 533 ++++++++++++ .../VanillaSidebarScoreboardTests.java | 265 ++++++ .../scoreboard/network/util/AssertUtils.java | 52 ++ .../network/util/EmptyGeyserLogger.java | 75 ++ .../network/util/GeyserMockContext.java | 143 ++++ .../util/GeyserMockContextScoreboard.java | 93 +++ gradle/libs.versions.toml | 3 + 40 files changed, 4838 insertions(+), 1110 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/Score.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/ScoreReference.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/display/score/BelownameDisplayScore.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/display/score/DisplayScore.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/display/score/PlayerlistDisplayScore.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/display/score/SidebarDisplayScore.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/BelownameDisplaySlot.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/DisplaySlot.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/PlayerlistDisplaySlot.java create mode 100644 core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/SidebarDisplaySlot.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/util/EmptyGeyserLogger.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index d30e60298..b0ea5fdf6 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -61,6 +61,7 @@ dependencies { // Test testImplementation(libs.junit) + testImplementation(libs.mockito) // Annotation Processors compileOnly(projects.ap) 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 08e87dc03..983455da8 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,6 +25,12 @@ 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; @@ -35,12 +41,18 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.*; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; +import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket; +import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.GeyserDirtyMetadata; import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.EntityUtils; @@ -55,12 +67,9 @@ 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.*; - @Getter @Setter public class Entity implements GeyserEntity { - private static final boolean PRINT_ENTITY_SPAWN_DEBUG = Boolean.parseBoolean(System.getProperty("Geyser.PrintEntitySpawnDebug", "false")); protected final GeyserSession session; @@ -68,6 +77,12 @@ public class Entity implements GeyserEntity { protected int entityId; protected final long geyserId; protected UUID uuid; + /** + * Do not call this setter directly! + * This will bypass the scoreboard and setting the metadata + */ + @Setter(AccessLevel.NONE) + protected String nametag = ""; protected Vector3f position; protected Vector3f motion; @@ -97,7 +112,7 @@ public class Entity implements GeyserEntity { @Setter(AccessLevel.NONE) private float boundingBoxWidth; @Setter(AccessLevel.NONE) - protected String nametag = ""; + private String displayName; @Setter(AccessLevel.NONE) protected boolean silent = false; /* Metadata end */ @@ -126,11 +141,12 @@ public class Entity implements GeyserEntity { public Entity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { this.session = session; + this.definition = definition; + this.displayName = standardDisplayName(); this.entityId = entityId; this.geyserId = geyserId; this.uuid = uuid; - this.definition = definition; this.motion = motion; this.yaw = yaw; this.pitch = pitch; @@ -341,7 +357,7 @@ public class Entity implements GeyserEntity { * Sends the Bedrock metadata to the client */ public void updateBedrockMetadata() { - if (!valid) { + if (!isValid()) { return; } @@ -410,17 +426,81 @@ public class Entity implements GeyserEntity { return 300; } + public String teamIdentifier() { + return uuid.toString(); + } + public void setDisplayName(EntityMetadata, ?> entityMetadata) { + // displayName is shown when always display name is enabled. Either with or without team. + // That's why there are both a displayName and a nametag variable. + // Displayname is ignored for players, and is always their username. Optional name = entityMetadata.getValue(); if (name.isPresent()) { - nametag = MessageTranslator.convertMessage(name.get(), session.locale()); - dirtyMetadata.put(EntityDataTypes.NAME, nametag); - } else if (!nametag.isEmpty()) { - // Clear nametag - dirtyMetadata.put(EntityDataTypes.NAME, ""); + String displayName = MessageTranslator.convertMessage(name.get(), session.locale()); + this.displayName = displayName; + setNametag(displayName, true); + return; } + + // if no displayName is set, use entity name (ENDER_DRAGON -> Ender Dragon) + // maybe we can/should use a translatable here instead? + this.displayName = standardDisplayName(); + setNametag(null, true); } + protected String standardDisplayName() { + return EntityUtils.translatedEntityName(definition.entityType(), session); + } + + protected void setNametag(@Nullable String nametag, boolean fromDisplayName) { + // ensure that the team format is used when nametag changes + if (nametag != null && fromDisplayName) { + var team = session.getWorldCache().getScoreboard().getTeamFor(teamIdentifier()); + if (team != null) { + updateNametag(team); + return; + } + } + + if (nametag == null) { + nametag = ""; + } + boolean changed = !Objects.equals(this.nametag, nametag); + this.nametag = nametag; + // we only update metadata if the value has changed + if (!changed) { + return; + } + + dirtyMetadata.put(EntityDataTypes.NAME, nametag); + // if nametag (player with team) is hidden for player, so should the score (belowname) + scoreVisibility(!nametag.isEmpty()); + } + + public void updateNametag(@Nullable Team team) { + // allow LivingEntity+ to have a different visibility check + updateNametag(team, true); + } + + protected void updateNametag(@Nullable Team team, boolean visible) { + if (team != null) { + String newNametag; + // (team) visibility is LivingEntity+, team displayName is Entity+ + if (visible) { + newNametag = team.displayName(getDisplayName()); + } else { + // The name is not visible to the session player; clear name + newNametag = ""; + } + setNametag(newNametag, false); + return; + } + // The name has reset, if it was previously something else + setNametag(null, false); + } + + protected void scoreVisibility(boolean show) {} + public void setDisplayNameVisible(BooleanEntityMetadata entityMetadata) { dirtyMetadata.put(EntityDataTypes.NAMETAG_ALWAYS_SHOW, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0)); } 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 266189e63..626ceca5c 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,6 +25,11 @@ 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; @@ -45,6 +50,7 @@ import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.AttributeUtils; @@ -65,12 +71,9 @@ 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.*; - @Getter @Setter public class LivingEntity extends Entity { - protected ItemData helmet = ItemData.AIR; protected ItemData chestplate = ItemData.AIR; protected ItemData leggings = ItemData.AIR; @@ -150,6 +153,16 @@ public class LivingEntity extends Entity { dirtyMetadata.put(EntityDataTypes.STRUCTURAL_INTEGRITY, 1); } + @Override + public void updateNametag(@Nullable Team team) { + // if name not visible, don't mark it as visible + updateNametag(team, team == null || team.isVisibleFor(session.getPlayerEntity().getUsername())); + } + + public void hideNametag() { + setNametag("", false); + } + public void setLivingEntityFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); 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 0a108be73..fbfc5d40a 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -32,11 +33,13 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.util.EntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.UUID; public class RabbitEntity extends AnimalEntity { + private boolean isKillerBunny; public RabbitEntity(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); @@ -46,7 +49,7 @@ public class RabbitEntity extends AnimalEntity { int variant = entityMetadata.getPrimitiveValue(); // Change the killer bunny to display as white since it only exists on Java Edition - boolean isKillerBunny = variant == 99; + isKillerBunny = variant == 99; if (isKillerBunny) { variant = 1; } @@ -56,6 +59,14 @@ public class RabbitEntity extends AnimalEntity { dirtyMetadata.put(EntityDataTypes.VARIANT, variant); } + @Override + protected String standardDisplayName() { + if (isKillerBunny) { + return EntityUtils.translatedEntityName(Key.key("killer_bunny"), session); + } + return super.standardDisplayName(); + } + @Override protected float getAdultSize() { return 0.55f; @@ -71,4 +82,4 @@ public class RabbitEntity extends AnimalEntity { protected ItemTag getFoodTag() { return ItemTag.RABBIT_FOOD; } -} \ No newline at end of file +} 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 b326f2e04..85905d716 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,6 +25,12 @@ 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; @@ -32,53 +38,35 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.Ability; import org.cloudburstmc.protocol.bedrock.data.AbilityLayer; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.PlayerPermission; import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataMap; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; -import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; +import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.ParrotEntity; -import org.geysermc.geyser.scoreboard.Objective; -import org.geysermc.geyser.scoreboard.Score; -import org.geysermc.geyser.scoreboard.Team; -import org.geysermc.geyser.scoreboard.UpdateType; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatColor; -import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.ChunkUtils; -import org.geysermc.mcprotocollib.protocol.codec.NbtComponentSerializer; -import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.BlankFormat; -import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.FixedFormat; -import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; -import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.StyledFormat; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.TimeUnit; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; @Getter @Setter public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { @@ -96,6 +84,9 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { private String username; + private String cachedScore = ""; + private boolean scoreVisible = true; + /** * The textures property from the GameProfile. */ @@ -123,6 +114,31 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { this.texturesProperty = texturesProperty; } + /** + * Do not use! For testing purposes only + */ + public PlayerEntity(GeyserSession session, long geyserId, UUID uuid, String username) { + super( + session, + -1, + geyserId, + uuid, + EntityDefinition.builder(null).type(EntityType.PLAYER).build(false), + Vector3f.ZERO, + Vector3f.ZERO, + 0, + 0, + 0 + ); + this.username = username; + this.nametag = username; + this.texturesProperty = null; + + // clear initial metadata + dirtyMetadata.apply(new EntityDataMap()); + setFlagsDirty(false); + } + @Override protected void initializeMetadata() { super.initializeMetadata(); @@ -132,17 +148,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { @Override public void spawnEntity() { - // Check to see if the player should have a belowname counterpart added - Objective objective = session.getWorldCache().getScoreboard().getObjectiveSlots().get(ScoreboardPosition.BELOW_NAME); - if (objective != null) { - setBelowNameText(objective); - } - - // Update in case this entity has been despawned, then respawned - this.nametag = this.username; - // The name can't be updated later (the entity metadata for it is ignored), so we need to check for this now - updateDisplayName(session.getWorldCache().getScoreboard().getTeamFor(username)); - AddPlayerPacket addPlayerPacket = new AddPlayerPacket(); addPlayerPacket.setUuid(uuid); addPlayerPacket.setUsername(username); @@ -177,6 +182,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { // Since we re-use player entities: Clear flags, held item, etc this.resetMetadata(); + this.nametag = username; this.hand = ItemData.AIR; this.offhand = ItemData.AIR; this.boots = ItemData.AIR; @@ -386,38 +392,30 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { } } + @Override + public String getDisplayName() { + return username; + } + @Override public void setDisplayName(EntityMetadata, ?> entityMetadata) { // Doesn't do anything for players } - //todo this will become common entity logic once UUID support is implemented for them - public void updateDisplayName(@Nullable Team team) { - boolean needsUpdate; - if (team != null) { - String newDisplayName; - if (team.isVisibleFor(session.getPlayerEntity().getUsername())) { - TeamColor color = team.getColor(); - String chatColor = MessageTranslator.toChatColor(color); - // We have to emulate what modern Java text already does for us and add the color to each section - String prefix = team.getCurrentData().getPrefix(); - String suffix = team.getCurrentData().getSuffix(); - newDisplayName = chatColor + prefix + chatColor + this.username + chatColor + suffix; - } else { - // The name is not visible to the session player; clear name - newDisplayName = ""; - } - needsUpdate = !newDisplayName.equals(this.nametag); - this.nametag = newDisplayName; - } else { - // The name has reset, if it was previously something else - needsUpdate = !this.nametag.equals(this.username); - this.nametag = this.username; - } + @Override + public String teamIdentifier() { + return username; + } - if (needsUpdate) { - dirtyMetadata.put(EntityDataTypes.NAME, this.nametag); + @Override + protected void setNametag(@Nullable String nametag, boolean fromDisplayName) { + // when fromDisplayName, LivingEntity will call scoreboard code. After that + // setNametag is called again with fromDisplayName on false + if (nametag == null && !fromDisplayName) { + // nametag = null means reset, so reset it back to username + nametag = username; } + super.setNametag(nametag, fromDisplayName); } @Override @@ -425,6 +423,33 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { // Doesn't do anything for players } + public void setBelowNameText(String text) { + if (text == null) { + text = ""; + } + + boolean changed = !Objects.equals(cachedScore, text); + cachedScore = text; + if (isScoreVisible() && changed) { + dirtyMetadata.put(EntityDataTypes.SCORE, text); + } + } + + @Override + protected void scoreVisibility(boolean show) { + boolean visibilityChanged = scoreVisible != show; + scoreVisible = show; + if (!visibilityChanged) { + return; + } + // if the player has no cachedScore, we never have to change the score. + // hide = set to "" (does nothing), show = change from "" (does nothing) + if (cachedScore.isEmpty()) { + return; + } + dirtyMetadata.put(EntityDataTypes.SCORE, show ? cachedScore : ""); + } + @Override protected void setDimensions(Pose pose) { float height; @@ -451,64 +476,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { setBoundingBoxHeight(height); } - public void setBelowNameText(Objective objective) { - if (objective != null && objective.getUpdateType() != UpdateType.REMOVE) { - Score score = objective.getScores().get(username); - String numberString; - NumberFormat numberFormat; - int amount; - if (score != null) { - amount = score.getScore(); - numberFormat = score.getNumberFormat(); - if (numberFormat == null) { - numberFormat = objective.getNumberFormat(); - } - } else { - amount = 0; - numberFormat = objective.getNumberFormat(); - } - - if (numberFormat instanceof BlankFormat) { - numberString = ""; - } else if (numberFormat instanceof FixedFormat fixedFormat) { - numberString = MessageTranslator.convertMessage(fixedFormat.getValue()); - } else if (numberFormat instanceof StyledFormat styledFormat) { - NbtMapBuilder styledAmount = styledFormat.getStyle().toBuilder(); - styledAmount.putString("text", String.valueOf(amount)); - - numberString = MessageTranslator.convertJsonMessage( - NbtComponentSerializer.tagComponentToJson(styledAmount.build()).toString(), session.locale()); - } else { - numberString = String.valueOf(amount); - } - - String displayString = numberString + " " + ChatColor.RESET + objective.getDisplayName(); - - if (valid) { - // Already spawned - we still need to run the rest of this code because the spawn packet will be - // providing the information - SetEntityDataPacket packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(geyserId); - packet.getMetadata().put(EntityDataTypes.SCORE, displayString); - session.sendUpstreamPacket(packet); - } else { - // Not spawned yet, store score value in dirtyMetadata to be picked up by #spawnEntity - dirtyMetadata.put(EntityDataTypes.SCORE, displayString); - } - } else { - if (valid) { - SetEntityDataPacket packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(geyserId); - packet.getMetadata().put(EntityDataTypes.SCORE, ""); - session.sendUpstreamPacket(packet); - } else { - // Not spawned yet, store score value in dirtyMetadata to be picked up by #spawnEntity - dirtyMetadata.put(EntityDataTypes.SCORE, ""); - } - } - - } - /** * @return the UUID that should be used when dealing with Bedrock's tab list. */ diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java index 6c1389ef5..f3b7f20d2 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java @@ -25,185 +25,100 @@ package org.geysermc.geyser.scoreboard; -import lombok.Getter; -import lombok.Setter; -import net.kyori.adventure.text.Component; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; - +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import org.geysermc.geyser.scoreboard.display.slot.DisplaySlot; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType; @Getter public final class Objective { private final Scoreboard scoreboard; - private final long id; - private boolean active = true; + private final List activeSlots = new ArrayList<>(); - @Setter - private UpdateType updateType = UpdateType.ADD; + private final String objectiveName; + private final Map scores = new ConcurrentHashMap<>(); - private String objectiveName; - private ScoreboardPosition displaySlot; - private String displaySlotName; - private String displayName = "unknown"; + private String displayName; private NumberFormat numberFormat; - private int type = 0; // 0 = integer, 1 = heart + private ScoreType type; - private Map scores = new ConcurrentHashMap<>(); - - private Objective(Scoreboard scoreboard) { - this.id = scoreboard.getNextId().getAndIncrement(); - this.scoreboard = scoreboard; - } - - /** - * /!\ This method is made for temporary objectives until the real objective is received - * - * @param scoreboard the scoreboard - * @param objectiveName the name of the objective - */ public Objective(Scoreboard scoreboard, String objectiveName) { - this(scoreboard); + this.scoreboard = scoreboard; this.objectiveName = objectiveName; - this.active = false; - } - - public Objective(Scoreboard scoreboard, String objectiveName, ScoreboardPosition displaySlot, String displayName, int type) { - this(scoreboard); - this.objectiveName = objectiveName; - this.displaySlot = displaySlot; - this.displaySlotName = translateDisplaySlot(displaySlot); - this.displayName = displayName; - this.type = type; - } - - private static String translateDisplaySlot(ScoreboardPosition displaySlot) { - return switch (displaySlot) { - case BELOW_NAME -> "belowname"; - case PLAYER_LIST -> "list"; - default -> "sidebar"; - }; } public void registerScore(String id, int score, Component displayName, NumberFormat numberFormat) { - if (!scores.containsKey(id)) { - long scoreId = scoreboard.getNextId().getAndIncrement(); - Score scoreObject = new Score(scoreId, id) - .setScore(score) - .setTeam(scoreboard.getTeamFor(id)) - .setDisplayName(displayName) - .setNumberFormat(numberFormat) - .setUpdateType(UpdateType.ADD); - scores.put(id, scoreObject); + if (scores.containsKey(id)) { + return; + } + var reference = new ScoreReference(scoreboard, id, score, displayName, numberFormat); + scores.put(id, reference); + + for (var slot : activeSlots) { + slot.addScore(reference); } } public void setScore(String id, int score, Component displayName, NumberFormat numberFormat) { - Score stored = scores.get(id); + ScoreReference stored = scores.get(id); if (stored != null) { - stored.setScore(score) - .setDisplayName(displayName) - .setNumberFormat(numberFormat) - .setUpdateType(UpdateType.UPDATE); + stored.updateProperties(scoreboard, score, displayName, numberFormat); return; } registerScore(id, score, displayName, numberFormat); } public void removeScore(String id) { - Score stored = scores.get(id); + ScoreReference stored = scores.remove(id); if (stored != null) { - stored.setUpdateType(UpdateType.REMOVE); + stored.markDeleted(); } } - /** - * Used internally to remove a score from the score map - */ - public void removeScore0(String id) { - scores.remove(id); - } + public void updateProperties(Component displayNameComponent, ScoreType type, NumberFormat format) { + String displayName = MessageTranslator.convertMessageRaw(displayNameComponent, scoreboard.session().locale()); + boolean changed = !Objects.equals(this.displayName, displayName) || this.type != type; - public Objective setDisplayName(String displayName) { this.displayName = displayName; - if (updateType == UpdateType.NOTHING) { - updateType = UpdateType.UPDATE; - } - return this; - } + this.type = type; - public Objective setNumberFormat(NumberFormat numberFormat) { - if (Objects.equals(this.numberFormat, numberFormat)) { - return this; - } - - this.numberFormat = numberFormat; - if (updateType == UpdateType.NOTHING) { - updateType = UpdateType.UPDATE; - } - - // Update the number format for scores that are following this objective's number format - for (Score score : scores.values()) { - if (score.getNumberFormat() == null) { - score.setUpdateType(UpdateType.UPDATE); + if (!Objects.equals(this.numberFormat, format)) { + this.numberFormat = format; + // update the number format for scores that are following this objective's number format, + // but only if the objective itself doesn't need to be updated. + // When the objective itself has to update all scores are updated anyway + if (!changed) { + for (ScoreReference score : scores.values()) { + if (score.numberFormat() == null) { + score.markChanged(); + } + } } } - return this; - } - - public Objective setType(int type) { - this.type = type; - if (updateType == UpdateType.NOTHING) { - updateType = UpdateType.UPDATE; - } - return this; - } - - public void setActive(ScoreboardPosition displaySlot) { - if (!active) { - active = true; - this.displaySlot = displaySlot; - displaySlotName = translateDisplaySlot(displaySlot); + if (changed) { + for (DisplaySlot slot : activeSlots) { + slot.markNeedsUpdate(); + } } } - /** - * The objective will be removed on the next update - */ - public void pendingRemove() { - updateType = UpdateType.REMOVE; + public boolean hasDisplaySlot() { + return !activeSlots.isEmpty(); } - public @Nullable TeamColor getTeamColor() { - return switch (displaySlot) { - case SIDEBAR_TEAM_RED -> TeamColor.RED; - case SIDEBAR_TEAM_AQUA -> TeamColor.AQUA; - case SIDEBAR_TEAM_BLUE -> TeamColor.BLUE; - case SIDEBAR_TEAM_GOLD -> TeamColor.GOLD; - case SIDEBAR_TEAM_GRAY -> TeamColor.GRAY; - case SIDEBAR_TEAM_BLACK -> TeamColor.BLACK; - case SIDEBAR_TEAM_GREEN -> TeamColor.GREEN; - case SIDEBAR_TEAM_WHITE -> TeamColor.WHITE; - case SIDEBAR_TEAM_YELLOW -> TeamColor.YELLOW; - case SIDEBAR_TEAM_DARK_RED -> TeamColor.DARK_RED; - case SIDEBAR_TEAM_DARK_AQUA -> TeamColor.DARK_AQUA; - case SIDEBAR_TEAM_DARK_BLUE -> TeamColor.DARK_BLUE; - case SIDEBAR_TEAM_DARK_GRAY -> TeamColor.DARK_GRAY; - case SIDEBAR_TEAM_DARK_GREEN -> TeamColor.DARK_GREEN; - case SIDEBAR_TEAM_DARK_PURPLE -> TeamColor.DARK_PURPLE; - case SIDEBAR_TEAM_LIGHT_PURPLE -> TeamColor.LIGHT_PURPLE; - default -> null; - }; + public void addDisplaySlot(DisplaySlot slot) { + activeSlots.add(slot); } - public void removed() { - active = false; - updateType = UpdateType.REMOVE; - scores = null; + public void removeDisplaySlot(DisplaySlot slot) { + activeSlots.remove(slot); } } diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java deleted file mode 100644 index 9a26b7f77..000000000 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java +++ /dev/null @@ -1,199 +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.scoreboard; - -import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.FixedFormat; -import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; -import net.kyori.adventure.text.Component; -import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; -import lombok.Getter; -import lombok.experimental.Accessors; -import org.geysermc.geyser.text.ChatColor; -import org.geysermc.geyser.translator.text.MessageTranslator; - -import java.util.Objects; - -@Getter -@Accessors(chain = true) -public final class Score { - private final long id; - private final String name; - private ScoreInfo cachedInfo; - - /** - * Changes that have been made since the last cached data. - */ - private final Score.ScoreData currentData; - /** - * The data that is currently displayed to the Bedrock client. - */ - private Score.ScoreData cachedData; - - public Score(long id, String name) { - this.id = id; - this.name = name; - this.currentData = new ScoreData(); - } - - public String getDisplayName() { - String displayName = cachedData.displayName; - if (displayName != null) { - return displayName; - } - Team team = cachedData.team; - if (team != null) { - return team.getDisplayName(name); - } - return name; - } - - public int getScore() { - return currentData.getScore(); - } - - public Score setScore(int score) { - currentData.score = score; - return this; - } - - public Team getTeam() { - return currentData.team; - } - - public Score setTeam(Team team) { - if (currentData.team != null && team != null) { - if (!currentData.team.equals(team)) { - currentData.team = team; - setUpdateType(UpdateType.UPDATE); - } - return this; - } - // simplified from (this.team != null && team == null) || (this.team == null && team != null) - if (currentData.team != null || team != null) { - currentData.team = team; - setUpdateType(UpdateType.UPDATE); - } - return this; - } - - public Score setDisplayName(Component displayName) { - if (currentData.displayName != null && displayName != null) { - String convertedDisplayName = MessageTranslator.convertMessage(displayName); - if (!currentData.displayName.equals(convertedDisplayName)) { - currentData.displayName = convertedDisplayName; - setUpdateType(UpdateType.UPDATE); - } - return this; - } - // simplified from (this.displayName != null && displayName == null) || (this.displayName == null && displayName != null) - if (currentData.displayName != null || displayName != null) { - currentData.displayName = MessageTranslator.convertMessage(displayName); - setUpdateType(UpdateType.UPDATE); - } - return this; - } - - public NumberFormat getNumberFormat() { - return currentData.numberFormat; - } - - public Score setNumberFormat(NumberFormat numberFormat) { - if (!Objects.equals(currentData.numberFormat, numberFormat)) { - currentData.numberFormat = numberFormat; - setUpdateType(UpdateType.UPDATE); - } - return this; - } - - public UpdateType getUpdateType() { - return currentData.updateType; - } - - public Score setUpdateType(UpdateType updateType) { - if (updateType != UpdateType.NOTHING) { - currentData.changed = true; - } - currentData.updateType = updateType; - return this; - } - - public boolean shouldUpdate() { - return cachedData == null || currentData.changed || - (currentData.team != null && currentData.team.shouldUpdate()); - } - - public void update(Objective objective) { - if (cachedData == null) { - cachedData = new ScoreData(); - cachedData.updateType = UpdateType.ADD; - if (currentData.updateType == UpdateType.REMOVE) { - cachedData.updateType = UpdateType.REMOVE; - } - } else { - cachedData.updateType = currentData.updateType; - } - - currentData.changed = false; - cachedData.team = currentData.team; - cachedData.score = currentData.score; - cachedData.displayName = currentData.displayName; - cachedData.numberFormat = currentData.numberFormat; - - String name = this.name; - if (cachedData.displayName != null) { - name = cachedData.displayName; - } else if (cachedData.team != null) { - cachedData.team.prepareUpdate(); - name = cachedData.team.getDisplayName(name); - } - - NumberFormat numberFormat = cachedData.numberFormat; - if (numberFormat == null) { - numberFormat = objective.getNumberFormat(); - } - if (numberFormat instanceof FixedFormat fixedFormat) { - name += " " + ChatColor.RESET + MessageTranslator.convertMessage(fixedFormat.getValue()); - } - - cachedInfo = new ScoreInfo(id, objective.getObjectiveName(), cachedData.score, name); - } - - @Getter - public static final class ScoreData { - private UpdateType updateType; - private boolean changed; - - private Team team; - private int score; - - private String displayName; - private NumberFormat numberFormat; - - private ScoreData() { - updateType = UpdateType.ADD; - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreReference.java b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreReference.java new file mode 100644 index 000000000..c26a59899 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreReference.java @@ -0,0 +1,132 @@ +/* + * 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.scoreboard; + +import java.util.Objects; +import net.kyori.adventure.text.Component; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; + +public final class ScoreReference { + public static final long LAST_UPDATE_DEFAULT = -1; + private static final long LAST_UPDATE_REMOVE = -2; + + private final String name; + private final boolean hidden; + + private String displayName; + private int score; + private NumberFormat numberFormat; + + private long lastUpdate; + + public ScoreReference( + Scoreboard scoreboard, String name, int score, Component displayName, NumberFormat format) { + this.name = name; + // hidden is a sidebar exclusive feature + this.hidden = name.startsWith("#"); + + updateProperties(scoreboard, score, displayName, format); + this.lastUpdate = LAST_UPDATE_DEFAULT; + } + + public String name() { + return name; + } + + public boolean hidden() { + return hidden; + } + + public String displayName() { + return displayName; + } + + public void displayName(Component displayName, Scoreboard scoreboard) { + if (this.displayName != null && displayName != null) { + String convertedDisplayName = MessageTranslator.convertMessage(displayName, scoreboard.session().locale()); + if (!this.displayName.equals(convertedDisplayName)) { + this.displayName = convertedDisplayName; + markChanged(); + } + return; + } + // simplified from (this.displayName != null && displayName == null) || (this.displayName == null && displayName != null) + if (this.displayName != null || displayName != null) { + this.displayName = MessageTranslator.convertMessage(displayName, scoreboard.session().locale()); + markChanged(); + } + } + + public int score() { + return score; + } + + private void score(int score) { + boolean changed = this.score != score; + this.score = score; + if (changed) { + markChanged(); + } + } + + public NumberFormat numberFormat() { + return numberFormat; + } + + private void numberFormat(NumberFormat numberFormat) { + if (Objects.equals(numberFormat(), numberFormat)) { + return; + } + this.numberFormat = numberFormat; + markChanged(); + } + + public void updateProperties(Scoreboard scoreboard, int score, Component displayName, NumberFormat numberFormat) { + score(score); + displayName(displayName, scoreboard); + numberFormat(numberFormat); + } + + public long lastUpdate() { + return lastUpdate; + } + + public boolean isRemoved() { + return lastUpdate == LAST_UPDATE_REMOVE; + } + + public void markChanged() { + if (lastUpdate == LAST_UPDATE_REMOVE) { + return; + } + lastUpdate = System.currentTimeMillis(); + } + + public void markDeleted() { + lastUpdate = -1; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java index acce86f4d..6e0867ddc 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java @@ -25,43 +25,72 @@ package org.geysermc.geyser.scoreboard; +import static org.geysermc.geyser.scoreboard.UpdateType.REMOVE; + import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.Collectors; import lombok.Getter; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumConstraint; -import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; -import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.scoreboard.display.slot.BelownameDisplaySlot; +import org.geysermc.geyser.scoreboard.display.slot.DisplaySlot; +import org.geysermc.geyser.scoreboard.display.slot.PlayerlistDisplaySlot; +import org.geysermc.geyser.scoreboard.display.slot.SidebarDisplaySlot; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import org.jetbrains.annotations.Contract; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static org.geysermc.geyser.scoreboard.UpdateType.*; - +/** + * Here follows some information about how scoreboards work in Java Edition, that is related to the workings of this + * class: + *

    + * Objectives can be divided in two states: inactive and active. + * Inactive objectives is the default state for objectives that have been created using the SetObjective packet. + * Scores can be added, updated and removed, but as long as they're inactive they aren't shown to the player. + * An objective becomes active when a SetDisplayObjective packet is received, which contains the slot that + * the objective should be displayed at. + *

    + * While Bedrock can handle showing one objective on multiple slots at the same time, we have to help Bedrock a bit + * for example by limiting the amount of sidebar scores to the amount of lines that can be shown + * (otherwise Bedrock may lag) and only showing online players in the playerlist (otherwise it's too cluttered.) + * This fact is the biggest contributor for the class being structured like it is. + */ public final class Scoreboard { private static final boolean SHOW_SCOREBOARD_LOGS = Boolean.parseBoolean(System.getProperty("Geyser.ShowScoreboardLogs", "true")); private static final boolean ADD_TEAM_SUGGESTIONS = Boolean.parseBoolean(System.getProperty("Geyser.AddTeamSuggestions", "true")); private final GeyserSession session; private final GeyserLogger logger; - @Getter private final AtomicLong nextId = new AtomicLong(0); private final Map objectives = new ConcurrentHashMap<>(); @Getter - private final Map objectiveSlots = new EnumMap<>(ScoreboardPosition.class); + private final Map objectiveSlots = Collections.synchronizedMap(new EnumMap<>(ScoreboardPosition.class)); + private final List removedSlots = Collections.synchronizedList(new ArrayList<>()); + private final Map teams = new ConcurrentHashMap<>(); // updated on multiple threads /** * Required to preserve vanilla behavior, which also uses a map. @@ -71,6 +100,7 @@ public final class Scoreboard { @Getter private final Map playerToTeam = new Object2ObjectOpenHashMap<>(); + private final AtomicBoolean updateLockActive = new AtomicBoolean(false); private int lastAddScoreCount = 0; private int lastRemoveScoreCount = 0; @@ -80,24 +110,22 @@ public final class Scoreboard { } public void removeScoreboard() { - Iterator iterator = objectives.values().iterator(); - while (iterator.hasNext()) { - Objective objective = iterator.next(); - iterator.remove(); + var copy = new HashMap<>(objectiveSlots); + objectiveSlots.clear(); - deleteObjective(objective, false); + for (DisplaySlot slot : copy.values()) { + slot.remove(); } } public @Nullable Objective registerNewObjective(String objectiveId) { Objective objective = objectives.get(objectiveId); if (objective != null) { - // we have no other choice, or we have to make a new map? - // if the objective hasn't been deleted, we have to force it - if (objective.getUpdateType() != REMOVE) { - return null; + // matches vanilla behaviour + if (SHOW_SCOREBOARD_LOGS) { + logger.warning("An objective with the same name '" + objectiveId + "' already exists! Ignoring new objective!"); } - deleteObjective(objective, true); + return null; } objective = new Objective(this, objectiveId); @@ -105,273 +133,162 @@ public final class Scoreboard { return objective; } - public void displayObjective(String objectiveId, ScoreboardPosition displaySlot) { + public void displayObjective(String objectiveId, ScoreboardPosition slot) { + if (objectiveId.isEmpty()) { + // matches vanilla behaviour + var display = objectiveSlots.get(slot); + if (display != null) { + removedSlots.add(display); + objectiveSlots.remove(slot, display); + var objective = display.objective(); + objective.removeDisplaySlot(display); + } + return; + } + Objective objective = objectives.get(objectiveId); if (objective == null) { return; } - if (!objective.isActive()) { - objective.setActive(displaySlot); - // for reactivated objectives - objective.setUpdateType(ADD); + var display = objectiveSlots.get(slot); + if (display != null && display.objective() != objective) { + removedSlots.add(display); } - Objective storedObjective = objectiveSlots.get(displaySlot); - if (storedObjective != null && storedObjective != objective) { - storedObjective.pendingRemove(); - } - objectiveSlots.put(displaySlot, objective); - - if (displaySlot == ScoreboardPosition.BELOW_NAME) { - // Display the below name score option to all players - // Of note: unlike Bedrock, if there is an objective in the below name slot, everyone has a display - for (PlayerEntity entity : session.getEntityCache().getAllPlayerEntities()) { - if (!entity.isValid()) { - // Player hasn't spawned yet - don't bother, it'll be done then - continue; - } - - entity.setBelowNameText(objective); - } - } + display = switch (DisplaySlot.slotCategory(slot)) { + case SIDEBAR -> new SidebarDisplaySlot(session, objective, slot); + case BELOW_NAME -> new BelownameDisplaySlot(session, objective); + case PLAYER_LIST -> new PlayerlistDisplaySlot(session, objective); + default -> throw new IllegalStateException("Unexpected value: " + slot); + }; + objectiveSlots.put(slot, display); + objective.addDisplaySlot(display); } - public Team registerNewTeam(String teamName, String[] players) { + public void registerNewTeam( + String teamName, + String[] players, + Component name, + Component prefix, + Component suffix, + NameTagVisibility visibility, + TeamColor color + ) { Team team = teams.get(teamName); if (team != null) { if (SHOW_SCOREBOARD_LOGS) { logger.info(GeyserLocale.getLocaleStringLog("geyser.network.translator.team.failed_overrides", teamName)); } - return team; + return; } - team = new Team(this, teamName); - team.addEntities(players); + team = new Team(this, teamName, players, name, prefix, suffix, visibility, color); teams.put(teamName, team); // Update command parameters - is safe to send even if the command enum doesn't exist on the client (as of 1.19.51) if (ADD_TEAM_SUGGESTIONS) { - session.addCommandEnum("Geyser_Teams", team.getId()); + session.addCommandEnum("Geyser_Teams", team.id()); } - return team; } public void onUpdate() { + // if an update is already running, let it finish + if (updateLockActive.getAndSet(true)) { + return; + } + List addScores = new ArrayList<>(lastAddScoreCount); List removeScores = new ArrayList<>(lastRemoveScoreCount); - List removedObjectives = new ArrayList<>(); Team playerTeam = getTeamFor(session.getPlayerEntity().getUsername()); - Objective correctSidebar = null; + DisplaySlot correctSidebarSlot = null; - for (Objective objective : objectives.values()) { - // objective has been deleted - if (objective.getUpdateType() == REMOVE) { - removedObjectives.add(objective); + for (DisplaySlot slot : objectiveSlots.values()) { + // slot has been removed + if (slot.updateType() == REMOVE) { continue; } - // there's nothing we can do with inactive objectives - // after checking if the objective has been deleted, - // except waiting for the objective to become activated (: - if (!objective.isActive()) { - continue; - } - - if (playerTeam != null && playerTeam.getColor() == objective.getTeamColor()) { - correctSidebar = objective; + if (playerTeam != null && playerTeam.color() == slot.teamColor()) { + correctSidebarSlot = slot; } } - if (correctSidebar == null) { - correctSidebar = objectiveSlots.get(ScoreboardPosition.SIDEBAR); + if (correctSidebarSlot == null) { + correctSidebarSlot = objectiveSlots.get(ScoreboardPosition.SIDEBAR); } - for (Objective objective : removedObjectives) { + var actualRemovedSlots = new ArrayList<>(removedSlots); + for (var slot : actualRemovedSlots) { // Deletion must be handled before the active objectives are handled - otherwise if a scoreboard display is changed before the current // scoreboard is removed, the client can crash - deleteObjective(objective, true); + slot.remove(); } + removedSlots.removeAll(actualRemovedSlots); - handleObjective(objectiveSlots.get(ScoreboardPosition.PLAYER_LIST), addScores, removeScores); - handleObjective(correctSidebar, addScores, removeScores); - handleObjective(objectiveSlots.get(ScoreboardPosition.BELOW_NAME), addScores, removeScores); - - Iterator teamIterator = teams.values().iterator(); - while (teamIterator.hasNext()) { - Team current = teamIterator.next(); - - switch (current.getCachedUpdateType()) { - case ADD, UPDATE -> current.markUpdated(); - case REMOVE -> teamIterator.remove(); - } - } + handleDisplaySlot(objectiveSlots.get(ScoreboardPosition.PLAYER_LIST), addScores, removeScores); + handleDisplaySlot(correctSidebarSlot, addScores, removeScores); + handleDisplaySlot(objectiveSlots.get(ScoreboardPosition.BELOW_NAME), addScores, removeScores); if (!removeScores.isEmpty()) { - SetScorePacket setScorePacket = new SetScorePacket(); - setScorePacket.setAction(SetScorePacket.Action.REMOVE); - setScorePacket.setInfos(removeScores); - session.sendUpstreamPacket(setScorePacket); + SetScorePacket packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(removeScores); + session.sendUpstreamPacket(packet); } if (!addScores.isEmpty()) { - SetScorePacket setScorePacket = new SetScorePacket(); - setScorePacket.setAction(SetScorePacket.Action.SET); - setScorePacket.setInfos(addScores); - session.sendUpstreamPacket(setScorePacket); + SetScorePacket packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(addScores); + session.sendUpstreamPacket(packet); } lastAddScoreCount = addScores.size(); lastRemoveScoreCount = removeScores.size(); + updateLockActive.set(false); } - private void handleObjective(Objective objective, List addScores, List removeScores) { - if (objective == null || objective.getUpdateType() == REMOVE) { - return; + private void handleDisplaySlot(DisplaySlot slot, List addScores, List removeScores) { + if (slot != null) { + slot.render(addScores, removeScores); } - - // hearts can't hold teams, so we treat them differently - if (objective.getType() == 1) { - for (Score score : objective.getScores().values()) { - boolean update = score.shouldUpdate(); - - if (update) { - score.update(objective); - } - - if (score.getUpdateType() != REMOVE && update) { - addScores.add(score.getCachedInfo()); - } - if (score.getUpdateType() != ADD && update) { - removeScores.add(score.getCachedInfo()); - } - } - return; - } - - boolean objectiveAdd = objective.getUpdateType() == ADD; - boolean objectiveUpdate = objective.getUpdateType() == UPDATE; - - for (Score score : objective.getScores().values()) { - if (score.getUpdateType() == REMOVE) { - ScoreInfo cachedInfo = score.getCachedInfo(); - // cachedInfo can be null here when ScoreboardUpdater is being used and a score is added and - // removed before a single update cycle is performed - if (cachedInfo != null) { - removeScores.add(cachedInfo); - } - // score is pending to be removed, so we can remove it from the objective - objective.removeScore0(score.getName()); - break; - } - - Team team = score.getTeam(); - - boolean add = objectiveAdd || objectiveUpdate; - - if (team != null) { - if (team.getUpdateType() == REMOVE || !team.hasEntity(score.getName())) { - score.setTeam(null); - add = true; - } - } - - if (score.shouldUpdate()) { - score.update(objective); - add = true; - } - - if (add) { - addScores.add(score.getCachedInfo()); - } - - // we need this as long as MCPE-143063 hasn't been fixed. - // the checks after 'add' are there to prevent removing scores that - // are going to be removed anyway / don't need to be removed - if (add && score.getUpdateType() != ADD && !(objectiveUpdate || objectiveAdd)) { - removeScores.add(score.getCachedInfo()); - } - - score.setUpdateType(NOTHING); - } - - if (objectiveUpdate) { - RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket(); - removeObjectivePacket.setObjectiveId(objective.getObjectiveName()); - session.sendUpstreamPacket(removeObjectivePacket); - } - - if (objectiveAdd || objectiveUpdate) { - SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket(); - displayObjectivePacket.setObjectiveId(objective.getObjectiveName()); - displayObjectivePacket.setDisplayName(objective.getDisplayName()); - displayObjectivePacket.setCriteria("dummy"); - displayObjectivePacket.setDisplaySlot(objective.getDisplaySlotName()); - displayObjectivePacket.setSortOrder(1); // 0 = ascending, 1 = descending - session.sendUpstreamPacket(displayObjectivePacket); - } - - objective.setUpdateType(NOTHING); - } - - /** - * @param remove if we should remove the objective from the objectives map. - */ - public void deleteObjective(Objective objective, boolean remove) { - if (remove) { - objectives.remove(objective.getObjectiveName()); - } - objectiveSlots.remove(objective.getDisplaySlot(), objective); - - objective.removed(); - - RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket(); - removeObjectivePacket.setObjectiveId(objective.getObjectiveName()); - session.sendUpstreamPacket(removeObjectivePacket); } public Objective getObjective(String objectiveName) { return objectives.get(objectiveName); } - public Collection getObjectives() { - return objectives.values(); - } - - public void unregisterObjective(String objectiveName) { - Objective objective = getObjective(objectiveName); - if (objective != null) { - objective.pendingRemove(); + public void removeObjective(Objective objective) { + objectives.remove(objective.getObjectiveName()); + for (DisplaySlot slot : objective.getActiveSlots()) { + objectiveSlots.remove(slot.position(), slot); + removedSlots.add(slot); } } - public Objective getSlot(ScoreboardPosition slot) { - return objectiveSlots.get(slot); + public void resetPlayerScores(String playerNameOrEntityUuid) { + for (Objective objective : objectives.values()) { + objective.removeScore(playerNameOrEntityUuid); + } } public Team getTeam(String teamName) { return teams.get(teamName); } - public Team getTeamFor(String entity) { - return playerToTeam.get(entity); + public Team getTeamFor(String playerNameOrEntityUuid) { + return playerToTeam.get(playerNameOrEntityUuid); } public void removeTeam(String teamName) { Team remove = teams.remove(teamName); - if (remove != null) { - remove.setUpdateType(REMOVE); - // We need to use the direct entities list here, so #refreshSessionPlayerDisplays also updates accordingly - // With the player's lack of a team in visibility checks - updateEntityNames(remove, remove.getEntities(), true); - for (String name : remove.getEntities()) { - // 1.19.3 Mojmap Scoreboard#removePlayerTeam(PlayerTeam) - playerToTeam.remove(name); - } - - session.removeCommandEnum("Geyser_Teams", remove.getId()); + if (remove == null) { + return; } + remove.remove(); + session.removeCommandEnum("Geyser_Teams", remove.id()); } @Contract("-> new") @@ -381,48 +298,46 @@ public final class Scoreboard { (o1, o2) -> o1, LinkedHashMap::new)); } - /** - * Updates the display names of all entities in a given team. - * @param teamChange the players have either joined or left the team. Used for optimizations when just the display name updated. - */ - public void updateEntityNames(Team team, boolean teamChange) { - Set names = new HashSet<>(team.getEntities()); - updateEntityNames(team, names, teamChange); + public void playerRegistered(PlayerEntity player) { + for (DisplaySlot slot : objectiveSlots.values()) { + slot.playerRegistered(player); + } } - /** - * Updates the display name of a set of entities within a given team. The team may also be null if the set is being removed - * from a team. - */ - public void updateEntityNames(@Nullable Team team, Set names, boolean teamChange) { - if (names.remove(session.getPlayerEntity().getUsername()) && teamChange) { - // If the player's team changed, then other entities' teams may modify their visibility based on team status - refreshSessionPlayerDisplays(); + public void playerRemoved(PlayerEntity player) { + for (DisplaySlot slot : objectiveSlots.values()) { + slot.playerRemoved(player); } - if (!names.isEmpty()) { - for (Entity entity : session.getEntityCache().getEntities().values()) { - // This more complex logic is for the future to iterate over all entities, not just players - if (entity instanceof PlayerEntity player && names.remove(player.getUsername())) { - player.updateDisplayName(team); - player.updateBedrockMetadata(); - if (names.isEmpty()) { - break; - } - } + } + + public void entityRegistered(Entity entity) { + var team = getTeamFor(entity.teamIdentifier()); + if (team != null) { + team.onEntitySpawn(entity); + } + } + + public void entityRemoved(Entity entity) { + var team = getTeamFor(entity.teamIdentifier()); + if (team != null) { + team.onEntityRemove(entity); + } + } + + public void setTeamFor(Team team, Set entities) { + for (DisplaySlot slot : objectiveSlots.values()) { + // only sidebar slots use teams + if (slot instanceof SidebarDisplaySlot sidebar) { + sidebar.setTeamFor(team, entities); } } } - /** - * If the team's player was refreshed, then we need to go through every entity and check... - */ - private void refreshSessionPlayerDisplays() { - for (Entity entity : session.getEntityCache().getEntities().values()) { - if (entity instanceof PlayerEntity player) { - Team playerTeam = session.getWorldCache().getScoreboard().getTeamFor(player.getUsername()); - player.updateDisplayName(playerTeam); - player.updateBedrockMetadata(); - } - } + public long nextId() { + return nextId.getAndIncrement(); + } + + public GeyserSession session() { + return session; } } diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java index 395eb9576..18a4bce39 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java @@ -173,7 +173,6 @@ public final class ScoreboardUpdater extends Thread { @Getter public static final class ScoreboardSession { private final GeyserSession session; - @SuppressWarnings("WriteOnlyObject") private final AtomicInteger pendingPacketsPerSecond = new AtomicInteger(0); private int packetsPerSecond; private long lastUpdate; diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java index cdf2e247e..d7c06ac4f 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java @@ -25,48 +25,66 @@ package org.geysermc.geyser.scoreboard; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.Accessors; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; - import java.util.HashSet; import java.util.Set; +import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; -@Getter -@Accessors(chain = true) public final class Team { + public static final long LAST_UPDATE_DEFAULT = -1; + private static final long LAST_UPDATE_REMOVE = -2; + private final Scoreboard scoreboard; private final String id; - @Getter(AccessLevel.PACKAGE) private final Set entities; + private final Set managedEntities; @NonNull private NameTagVisibility nameTagVisibility = NameTagVisibility.ALWAYS; - @Setter private TeamColor color; + private TeamColor color; - private final TeamData currentData; - private TeamData cachedData; + private String name; + private String prefix; + private String suffix; + private long lastUpdate; - private boolean updating; - - public Team(Scoreboard scoreboard, String id) { + public Team( + Scoreboard scoreboard, + String id, + String[] players, + Component name, + Component prefix, + Component suffix, + NameTagVisibility visibility, + TeamColor color + ) { this.scoreboard = scoreboard; this.id = id; - currentData = new TeamData(); - entities = new ObjectOpenHashSet<>(); + this.entities = new ObjectOpenHashSet<>(); + this.managedEntities = new ObjectOpenHashSet<>(); + this.lastUpdate = LAST_UPDATE_DEFAULT; + + // doesn't call entity update + updateProperties(name, prefix, suffix, visibility, color); + // calls entity update + addEntities(players); + lastUpdate = LAST_UPDATE_DEFAULT; } - public Set addEntities(String... names) { + public void addEntities(String... names) { Set added = new HashSet<>(); for (String name : names) { - if (entities.add(name)) { - added.add(name); + // go to next score if score is already present + if (!entities.add(name)) { + continue; } + added.add(name); scoreboard.getPlayerToTeam().compute(name, (player, oldTeam) -> { if (oldTeam != null) { // Remove old team from this map, and from the set of players of the old team. @@ -78,26 +96,15 @@ public final class Team { } if (added.isEmpty()) { - return added; + return; } - // we don't have to change the updateType, - // because the scores itself need updating, not the team - for (Objective objective : scoreboard.getObjectives()) { - for (String addedEntity : added) { - Score score = objective.getScores().get(addedEntity); - if (score != null) { - score.setTeam(this); - } - } - } - - return added; + // we don't have to change our updateType, + // because the scores themselves need updating, not the team + scoreboard.setTeamFor(this, added); + addAddedEntities(added); } - /** - * @return all removed entities from this team - */ - public Set removeEntities(String... names) { + public void removeEntities(String... names) { Set removed = new HashSet<>(); for (String name : names) { if (entities.remove(name)) { @@ -105,87 +112,22 @@ public final class Team { } scoreboard.getPlayerToTeam().remove(name, this); } - return removed; + removeRemovedEntities(removed); } public boolean hasEntity(String name) { return entities.contains(name); } - public Team setName(String name) { - currentData.name = name; - return this; - } - - public Team setPrefix(String prefix) { - // replace "null" to an empty string, - // we do this here to improve the performance of Score#getDisplayName - if (prefix.length() == 4 && "null".equals(prefix)) { - currentData.prefix = ""; - return this; + public String displayName(String score) { + String chatColor = ChatColor.chatColorFor(color); + // most sidebar plugins will use the reset color, because they don't want color + // skip the unneeded double reset color in that case + if (ChatColor.RESET.equals(chatColor)) { + chatColor = ""; } - currentData.prefix = prefix; - return this; - } - - public Team setSuffix(String suffix) { - // replace "null" to an empty string, - // we do this here to improve the performance of Score#getDisplayName - if (suffix.length() == 4 && "null".equals(suffix)) { - currentData.suffix = ""; - return this; - } - currentData.suffix = suffix; - return this; - } - - public String getDisplayName(String score) { - return cachedData != null ? - cachedData.getDisplayName(score) : - currentData.getDisplayName(score); - } - - public void markUpdated() { - updating = false; - } - - public boolean shouldUpdate() { - return updating || cachedData == null || currentData.changed; - } - - public void prepareUpdate() { - if (updating) { - return; - } - updating = true; - - if (cachedData == null) { - cachedData = new TeamData(); - cachedData.updateType = currentData.updateType != UpdateType.REMOVE ? UpdateType.ADD : UpdateType.REMOVE; - } else { - cachedData.updateType = currentData.updateType; - } - - currentData.changed = false; - cachedData.name = currentData.name; - cachedData.prefix = currentData.prefix; - cachedData.suffix = currentData.suffix; - } - - public UpdateType getUpdateType() { - return currentData.updateType; - } - - public UpdateType getCachedUpdateType() { - return cachedData != null ? cachedData.updateType : currentData.updateType; - } - - public Team setUpdateType(UpdateType updateType) { - if (updateType != UpdateType.NOTHING) { - currentData.changed = true; - } - currentData.updateType = updateType; - return this; + // also add reset because setting the color does not reset the formatting, unlike Java + return chatColor + prefix + ChatColor.RESET + chatColor + score + ChatColor.RESET + chatColor + suffix; } public boolean isVisibleFor(String entity) { @@ -201,34 +143,178 @@ public final class Team { }; } - public Team setNameTagVisibility(@Nullable NameTagVisibility nameTagVisibility) { - if (nameTagVisibility != null) { - // Null check like this (and this.nameTagVisibility defaults to ALWAYS) as of Java 1.19.4 - this.nameTagVisibility = nameTagVisibility; + public void updateProperties(Component name, Component prefix, Component suffix, NameTagVisibility visibility, TeamColor color) { + // this shouldn't happen but hey! + if (lastUpdate == LAST_UPDATE_REMOVE) { + return; } - return this; + + String oldName = this.name; + String oldPrefix = this.prefix; + String oldSuffix = this.suffix; + boolean oldVisible = isVisibleFor(playerName()); + var oldColor = this.color; + + this.name = MessageTranslator.convertMessageRaw(name, session().locale()); + this.prefix = MessageTranslator.convertMessageRaw(prefix, session().locale()); + this.suffix = MessageTranslator.convertMessageRaw(suffix, session().locale()); + // matches vanilla behaviour, the visibility is not reset (to ALWAYS) if it is null. + // instead the visibility is not altered + if (visibility != null) { + this.nameTagVisibility = visibility; + } + this.color = color; + + if (lastUpdate == LAST_UPDATE_DEFAULT) { + // addEntities is called after the initial updateProperties, so no need to do any entity updates here + if (this.color != TeamColor.RESET || !this.prefix.isEmpty() || !this.suffix.isEmpty()) { + markChanged(); + } + return; + } + + if (!this.name.equals(oldName) + || !this.prefix.equals(oldPrefix) + || !this.suffix.equals(oldSuffix) + || color != oldColor) { + markChanged(); + updateEntities(); + return; + } + + if (isVisibleFor(playerName()) != oldVisible) { + // if just the visibility changed, we only have to update the entities. + // We don't have to mark it as changed + updateEntities(); + } + } + + public boolean shouldRemove() { + return lastUpdate == LAST_UPDATE_REMOVE; + } + + public void markChanged() { + if (lastUpdate == LAST_UPDATE_REMOVE) { + return; + } + lastUpdate = System.currentTimeMillis(); + } + + public void remove() { + lastUpdate = LAST_UPDATE_REMOVE; + + for (String name : entities()) { + // 1.19.3 Mojmap Scoreboard#removePlayerTeam(PlayerTeam) + scoreboard.getPlayerToTeam().remove(name); + } + + if (entities().contains(playerName())) { + refreshAllEntities(); + return; + } + for (Entity entity : managedEntities) { + entity.updateNametag(null); + entity.updateBedrockMetadata(); + } + } + + private void updateEntities() { + for (Entity entity : managedEntities) { + entity.updateNametag(this); + entity.updateBedrockMetadata(); + } + } + + public void onEntitySpawn(Entity entity) { + // I've basically ported addAddedEntities + if (entities.contains(entity.teamIdentifier())) { + managedEntities.add(entity); + // onEntitySpawn includes all entities but players, so it cannot contain self + entity.updateNametag(this); + entity.updateBedrockMetadata(); + } + } + + public void onEntityRemove(Entity entity) { + // we don't have to update anything, since the player is removed. + managedEntities.remove(entity); + } + + private void addAddedEntities(Set names) { + // can't contain self if none are added + if (names.isEmpty()) { + return; + } + boolean containsSelf = names.contains(playerName()); + + for (Entity entity : session().getEntityCache().getEntities().values()) { + if (names.contains(entity.teamIdentifier())) { + managedEntities.add(entity); + if (!containsSelf) { + entity.updateNametag(this); + entity.updateBedrockMetadata(); + } + } + } + + if (containsSelf) { + refreshAllEntities(); + } + } + + private void removeRemovedEntities(Set names) { + boolean containsSelf = names.contains(playerName()); + + var iterator = managedEntities.iterator(); + while (iterator.hasNext()) { + var entity = iterator.next(); + if (names.contains(entity.teamIdentifier())) { + iterator.remove(); + if (!containsSelf) { + entity.updateNametag(null); + entity.updateBedrockMetadata(); + } + } + } + + if (containsSelf) { + refreshAllEntities(); + } + } + + private void refreshAllEntities() { + for (Entity entity : session().getEntityCache().getEntities().values()) { + entity.updateNametag(scoreboard.getTeamFor(entity.teamIdentifier())); + entity.updateBedrockMetadata(); + } + } + + private GeyserSession session() { + return scoreboard.session(); + } + + private String playerName() { + return session().getPlayerEntity().getUsername(); + } + + public String id() { + return id; + } + + public TeamColor color() { + return color; + } + + public long lastUpdate() { + return lastUpdate; + } + + public Set entities() { + return entities; } @Override public int hashCode() { return id.hashCode(); } - - @Getter - public static final class TeamData { - private UpdateType updateType; - private boolean changed; - - private String name; - private String prefix; - private String suffix; - - private TeamData() { - updateType = UpdateType.ADD; - } - - public String getDisplayName(String score) { - return prefix + score + suffix; - } - } } diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/BelownameDisplayScore.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/BelownameDisplayScore.java new file mode 100644 index 000000000..8e101d66a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/BelownameDisplayScore.java @@ -0,0 +1,56 @@ +/* + * 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.scoreboard.display.score; + +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.scoreboard.Objective; +import org.geysermc.geyser.scoreboard.ScoreReference; +import org.geysermc.geyser.scoreboard.display.slot.DisplaySlot; + +public class BelownameDisplayScore extends DisplayScore { + private final PlayerEntity player; + + public BelownameDisplayScore(DisplaySlot slot, long scoreId, ScoreReference reference, PlayerEntity player) { + super(slot, scoreId, reference); + this.player = player; + } + + @Override + public void update(Objective objective) {} + + public PlayerEntity player() { + return player; + } + + @Override + public void markUpdated() { + super.markUpdated(); + } + + public ScoreReference reference() { + return reference; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/DisplayScore.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/DisplayScore.java new file mode 100644 index 000000000..c6d70bb96 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/DisplayScore.java @@ -0,0 +1,70 @@ +/* + * 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.scoreboard.display.score; + +import org.geysermc.geyser.scoreboard.Objective; +import org.geysermc.geyser.scoreboard.ScoreReference; +import org.geysermc.geyser.scoreboard.display.slot.DisplaySlot; + +public abstract class DisplayScore { + protected final DisplaySlot slot; + protected final long id; + protected final ScoreReference reference; + + protected long lastTeamUpdate; + protected long lastUpdate; + + public DisplayScore(DisplaySlot slot, long scoreId, ScoreReference reference) { + this.slot = slot; + this.id = scoreId; + this.reference = reference; + } + + public boolean shouldUpdate() { + return reference.lastUpdate() != lastUpdate; + } + + public abstract void update(Objective objective); + + public String name() { + return reference.name(); + } + + public int score() { + return reference.score(); + } + + public boolean referenceRemoved() { + return reference.isRemoved(); + } + + protected void markUpdated() { + // with the last update (also for team) we rather have an old lastUpdate + // (and have to update again the next cycle) than potentially losing information + // by fetching the lastUpdate after update was performed + this.lastUpdate = reference.lastUpdate(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/PlayerlistDisplayScore.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/PlayerlistDisplayScore.java new file mode 100644 index 000000000..c4d8d91be --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/PlayerlistDisplayScore.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.scoreboard.display.score; + +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.geysermc.geyser.scoreboard.Objective; +import org.geysermc.geyser.scoreboard.ScoreReference; +import org.geysermc.geyser.scoreboard.display.slot.DisplaySlot; + +public final class PlayerlistDisplayScore extends DisplayScore { + private final long playerId; + private ScoreInfo cachedInfo; + + public PlayerlistDisplayScore(DisplaySlot slot, long scoreId, ScoreReference reference, long playerId) { + super(slot, scoreId, reference); + this.playerId = playerId; + } + + @Override + public boolean shouldUpdate() { + // for player references the player's name is shown, + // so we only have to update when the score has changed + return cachedInfo == null || cachedInfo.getScore() != reference.score(); + } + + @Override + public void update(Objective objective) { + cachedInfo = new ScoreInfo(id, slot.objectiveId(), reference.score(), ScoreInfo.ScorerType.PLAYER, playerId); + } + + public ScoreInfo cachedInfo() { + return cachedInfo; + } + + public boolean exists() { + return cachedInfo != null; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/SidebarDisplayScore.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/SidebarDisplayScore.java new file mode 100644 index 000000000..42c0dbbf7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/SidebarDisplayScore.java @@ -0,0 +1,139 @@ +/* + * 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.scoreboard.display.score; + +import java.util.Objects; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.geysermc.geyser.scoreboard.Objective; +import org.geysermc.geyser.scoreboard.ScoreReference; +import org.geysermc.geyser.scoreboard.Team; +import org.geysermc.geyser.scoreboard.display.slot.DisplaySlot; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.FixedFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; + +public final class SidebarDisplayScore extends DisplayScore { + private ScoreInfo cachedInfo; + private Team team; + private String order; + private boolean onlyScoreValueChanged; + + public SidebarDisplayScore(DisplaySlot slot, long scoreId, ScoreReference reference) { + super(slot, scoreId, reference); + team(slot.objective().getScoreboard().getTeamFor(reference.name())); + } + + @Override + public boolean shouldUpdate() { + return super.shouldUpdate() || shouldTeamUpdate(); + } + + private boolean shouldTeamUpdate() { + return team != null && team.lastUpdate() != lastTeamUpdate; + } + + @Override + public void update(Objective objective) { + markUpdated(); + + String finalName = reference.name(); + String displayName = reference.displayName(); + + if (displayName != null) { + finalName = displayName; + } else if (team != null) { + this.lastTeamUpdate = team.lastUpdate(); + finalName = team.displayName(reference.name()); + } + + NumberFormat numberFormat = reference.numberFormat(); + if (numberFormat == null) { + numberFormat = objective.getNumberFormat(); + } + if (numberFormat instanceof FixedFormat fixedFormat) { + finalName += " " + ChatColor.RESET + MessageTranslator.convertMessage(fixedFormat.getValue(), objective.getScoreboard().session().locale()); + } + + if (order != null) { + finalName = order + ChatColor.RESET + finalName; + } + + if (cachedInfo != null) { + onlyScoreValueChanged = finalName.equals(cachedInfo.getName()); + } + cachedInfo = new ScoreInfo(id, slot.objectiveId(), reference.score(), finalName); + } + + public String order() { + return order; + } + + public DisplayScore order(String order) { + if (Objects.equals(this.order, order)) { + return this; + } + this.order = order; + // this guarantees an update + requestUpdate(); + return this; + } + + public Team team() { + return team; + } + + public void team(Team team) { + if (this.team != null && team != null) { + if (!this.team.equals(team)) { + this.team = team; + requestUpdate(); + } + return; + } + // simplified from (this.team != null && team == null) || (this.team == null && team != null) + if (this.team != null || team != null) { + this.team = team; + requestUpdate(); + } + } + + private void requestUpdate() { + this.lastUpdate = 0; + } + + public ScoreInfo cachedInfo() { + return cachedInfo; + } + + public boolean exists() { + return cachedInfo != null; + } + + public boolean onlyScoreValueChanged() { + return onlyScoreValueChanged; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/BelownameDisplaySlot.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/BelownameDisplaySlot.java new file mode 100644 index 000000000..42a1e8c3f --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/BelownameDisplaySlot.java @@ -0,0 +1,182 @@ +/* + * 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.scoreboard.display.slot; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import java.util.List; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.scoreboard.Objective; +import org.geysermc.geyser.scoreboard.ScoreReference; +import org.geysermc.geyser.scoreboard.UpdateType; +import org.geysermc.geyser.scoreboard.display.score.BelownameDisplayScore; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.codec.NbtComponentSerializer; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.BlankFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.FixedFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat; +import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.StyledFormat; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; + +public class BelownameDisplaySlot extends DisplaySlot { + private final Long2ObjectMap displayScores = new Long2ObjectOpenHashMap<>(); + + public BelownameDisplaySlot(GeyserSession session, Objective objective) { + super(session, objective, ScoreboardPosition.BELOW_NAME); + } + + @Override + protected void render0(List addScores, List removeScores) { + // how belowname works is that if the player itself has belowname as a display slot, + // every player entity will show a score below their name. + // when the objective is added, updated or removed we thus have to update the belowname for every player + // when an individual score is updated (score or number format) we have to update the individual player + + // remove is handled in #remove() + if (updateType == UpdateType.ADD) { + for (PlayerEntity player : session.getEntityCache().getAllPlayerEntities()) { + playerRegistered(player); + } + return; + } + if (updateType == UpdateType.UPDATE) { + for (PlayerEntity player : session.getEntityCache().getAllPlayerEntities()) { + setBelowNameText(player, scoreFor(player.getUsername())); + } + updateType = UpdateType.NOTHING; + return; + } + + for (var score : displayScores.values()) { + // we don't have to worry about a score not existing, because that's handled by both + // this method when an objective is added and addScore/playerRegistered. + // we only have to update them, if they have changed + // (or delete them, if the score no longer exists) + if (!score.shouldUpdate()) { + continue; + } + + if (score.referenceRemoved()) { + clearBelowNameText(score.player()); + continue; + } + + score.markUpdated(); + setBelowNameText(score.player(), score.reference()); + } + } + + @Override + public void remove() { + updateType = UpdateType.REMOVE; + for (PlayerEntity player : session.getEntityCache().getAllPlayerEntities()) { + clearBelowNameText(player); + } + } + + @Override + public void addScore(ScoreReference reference) { + addDisplayScore(reference); + } + + @Override + public void playerRegistered(PlayerEntity player) { + var reference = scoreFor(player.getUsername()); + setBelowNameText(player, reference); + // keep track of score when the player is active + if (reference != null) { + // we already set the text, so we only have to update once the score does + addDisplayScore(player, reference).markUpdated(); + } + } + + @Override + public void playerRemoved(PlayerEntity player) { + displayScores.remove(player.getGeyserId()); + } + + private void addDisplayScore(ScoreReference reference) { + var players = session.getEntityCache().getPlayersByName(reference.name()); + for (PlayerEntity player : players) { + addDisplayScore(player, reference); + } + } + + private BelownameDisplayScore addDisplayScore(PlayerEntity player, ScoreReference reference) { + var score = new BelownameDisplayScore(this, objective.getScoreboard().nextId(), reference, player); + displayScores.put(player.getGeyserId(), score); + return score; + } + + private void setBelowNameText(PlayerEntity player, ScoreReference reference) { + player.setBelowNameText(calculateBelowNameText(reference)); + player.updateBedrockMetadata(); + } + + private void clearBelowNameText(PlayerEntity player) { + player.setBelowNameText(null); + player.updateBedrockMetadata(); + } + + private String calculateBelowNameText(ScoreReference reference) { + String numberString; + NumberFormat numberFormat = null; + // even if the player doesn't have a score, as long as belowname is on the client Java behaviour is + // to show them with a score of 0 + int score = 0; + if (reference != null) { + score = reference.score(); + numberFormat = reference.numberFormat(); + } + if (numberFormat == null) { + numberFormat = objective.getNumberFormat(); + } + + if (numberFormat instanceof BlankFormat) { + numberString = ""; + } else if (numberFormat instanceof FixedFormat fixedFormat) { + numberString = MessageTranslator.convertMessage(fixedFormat.getValue(), session.locale()); + } else if (numberFormat instanceof StyledFormat styledFormat) { + NbtMapBuilder styledAmount = styledFormat.getStyle().toBuilder(); + styledAmount.putString("text", String.valueOf(score)); + + numberString = MessageTranslator.convertJsonMessage( + NbtComponentSerializer.tagComponentToJson(styledAmount.build()).toString(), session.locale()); + } else { + numberString = String.valueOf(score); + } + + return numberString + " " + ChatColor.RESET + objective.getDisplayName(); + } + + private ScoreReference scoreFor(String username) { + return objective.getScores().get(username); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/DisplaySlot.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/DisplaySlot.java new file mode 100644 index 000000000..bac79e23e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/DisplaySlot.java @@ -0,0 +1,162 @@ +/* + * 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.scoreboard.display.slot; + +import java.util.List; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.scoreboard.Objective; +import org.geysermc.geyser.scoreboard.ScoreReference; +import org.geysermc.geyser.scoreboard.UpdateType; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; + +public abstract class DisplaySlot { + protected final GeyserSession session; + protected final Objective objective; + /** + * Use this instead of objective name because one objective can be shared in multiple slots, + * but each slot has its own logic and might not contain all scores + */ + protected final String objectiveId; + protected final ScoreboardPosition slot; + protected final TeamColor teamColor; + protected final String positionName; + + protected UpdateType updateType = UpdateType.ADD; + + public DisplaySlot(GeyserSession session, Objective objective, ScoreboardPosition slot) { + this.session = session; + this.objective = objective; + this.objectiveId = String.valueOf(objective.getScoreboard().nextId()); + this.slot = slot; + this.teamColor = teamColor(slot); + this.positionName = positionName(slot); + } + + public final void render(List addScores, List removeScores) { + if (updateType == UpdateType.REMOVE) { + return; + } + render0(addScores, removeScores); + } + + protected abstract void render0(List addScores, List removeScores); + + public abstract void addScore(ScoreReference reference); + + public abstract void playerRegistered(PlayerEntity player); + public abstract void playerRemoved(PlayerEntity player); + + public void remove() { + updateType = UpdateType.REMOVE; + sendRemoveObjective(); + } + + public void markNeedsUpdate() { + if (updateType == UpdateType.NOTHING) { + updateType = UpdateType.UPDATE; + } + } + + protected void sendDisplayObjective() { + SetDisplayObjectivePacket packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId(objectiveId()); + packet.setDisplayName(objective.getDisplayName()); + packet.setCriteria("dummy"); + packet.setDisplaySlot(positionName); + packet.setSortOrder(1); // 0 = ascending, 1 = descending + session.sendUpstreamPacket(packet); + } + + protected void sendRemoveObjective() { + RemoveObjectivePacket packet = new RemoveObjectivePacket(); + packet.setObjectiveId(objectiveId()); + session.sendUpstreamPacket(packet); + } + + public Objective objective() { + return objective; + } + + public String objectiveId() { + return objectiveId; + } + + public ScoreboardPosition position() { + return slot; + } + + public @Nullable TeamColor teamColor() { + return teamColor; + } + + public UpdateType updateType() { + return updateType; + } + + public static ScoreboardPosition slotCategory(ScoreboardPosition slot) { + return switch (slot) { + case BELOW_NAME -> ScoreboardPosition.BELOW_NAME; + case PLAYER_LIST -> ScoreboardPosition.PLAYER_LIST; + default -> ScoreboardPosition.SIDEBAR; + }; + } + + private static String positionName(ScoreboardPosition slot) { + return switch (slot) { + case BELOW_NAME -> "belowname"; + case PLAYER_LIST -> "list"; + default -> "sidebar"; + }; + } + + private static @Nullable TeamColor teamColor(ScoreboardPosition slot) { + return switch (slot) { + case SIDEBAR_TEAM_RED -> TeamColor.RED; + case SIDEBAR_TEAM_AQUA -> TeamColor.AQUA; + case SIDEBAR_TEAM_BLUE -> TeamColor.BLUE; + case SIDEBAR_TEAM_GOLD -> TeamColor.GOLD; + case SIDEBAR_TEAM_GRAY -> TeamColor.GRAY; + case SIDEBAR_TEAM_BLACK -> TeamColor.BLACK; + case SIDEBAR_TEAM_GREEN -> TeamColor.GREEN; + case SIDEBAR_TEAM_WHITE -> TeamColor.WHITE; + case SIDEBAR_TEAM_YELLOW -> TeamColor.YELLOW; + case SIDEBAR_TEAM_DARK_RED -> TeamColor.DARK_RED; + case SIDEBAR_TEAM_DARK_AQUA -> TeamColor.DARK_AQUA; + case SIDEBAR_TEAM_DARK_BLUE -> TeamColor.DARK_BLUE; + case SIDEBAR_TEAM_DARK_GRAY -> TeamColor.DARK_GRAY; + case SIDEBAR_TEAM_DARK_GREEN -> TeamColor.DARK_GREEN; + case SIDEBAR_TEAM_DARK_PURPLE -> TeamColor.DARK_PURPLE; + case SIDEBAR_TEAM_LIGHT_PURPLE -> TeamColor.LIGHT_PURPLE; + default -> null; + }; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/PlayerlistDisplaySlot.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/PlayerlistDisplaySlot.java new file mode 100644 index 000000000..6fd83ab8d --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/PlayerlistDisplaySlot.java @@ -0,0 +1,158 @@ +/* + * 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.scoreboard.display.slot; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.scoreboard.Objective; +import org.geysermc.geyser.scoreboard.ScoreReference; +import org.geysermc.geyser.scoreboard.UpdateType; +import org.geysermc.geyser.scoreboard.display.score.PlayerlistDisplayScore; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; + +public class PlayerlistDisplaySlot extends DisplaySlot { + private final Long2ObjectMap displayScores = + Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); + private final List removedScores = Collections.synchronizedList(new ArrayList<>()); + + public PlayerlistDisplaySlot(GeyserSession session, Objective objective) { + super(session, objective, ScoreboardPosition.PLAYER_LIST); + registerExisting(); + } + + @Override + protected void render0(List addScores, List removeScores) { + boolean objectiveAdd = updateType == UpdateType.ADD; + boolean objectiveUpdate = updateType == UpdateType.UPDATE; + boolean objectiveNothing = updateType == UpdateType.NOTHING; + + // if 'add' the scores aren't present, if 'update' the objective is re-added so the scores don't have to be + // manually removed, if 'remove' the scores are removed anyway + if (objectiveNothing) { + var removedScoresCopy = new ArrayList<>(removedScores); + for (var removedScore : removedScoresCopy) { + //todo idk if this if-statement is needed + if (removedScore.cachedInfo() != null) { + removeScores.add(removedScore.cachedInfo()); + } + } + removedScores.removeAll(removedScoresCopy); + } else { + removedScores.clear(); + } + + for (var score : displayScores.values()) { + if (score.referenceRemoved()) { + ScoreInfo cachedInfo = score.cachedInfo(); + // cachedInfo can be null here when ScoreboardUpdater is being used and a score is added and + // removed before a single update cycle is performed + if (cachedInfo != null) { + removeScores.add(cachedInfo); + } + continue; + } + + //todo does an animated title exist on tab? + boolean add = objectiveAdd || objectiveUpdate; + boolean exists = score.exists(); + + if (score.shouldUpdate()) { + score.update(objective); + add = true; + } + + if (add) { + addScores.add(score.cachedInfo()); + } + + // we need this as long as MCPE-143063 hasn't been fixed. + // the checks after 'add' are there to prevent removing scores that + // are going to be removed anyway / don't need to be removed + if (add && exists && objectiveNothing) { + removeScores.add(score.cachedInfo()); + } + } + + if (objectiveUpdate) { + sendRemoveObjective(); + } + + if (objectiveAdd || objectiveUpdate) { + sendDisplayObjective(); + } + + updateType = UpdateType.NOTHING; + } + + @Override + public void addScore(ScoreReference reference) { + // while it breaks a lot of stuff in Java, scoreboard do work fine with multiple players having + // the same username + var players = session.getEntityCache().getPlayersByName(reference.name()); + var selfPlayer = session.getPlayerEntity(); + if (reference.name().equals(selfPlayer.getUsername())) { + players.add(selfPlayer); + } + + for (PlayerEntity player : players) { + var score = + new PlayerlistDisplayScore(this, objective.getScoreboard().nextId(), reference, player.getGeyserId()); + displayScores.put(player.getGeyserId(), score); + } + } + + private void registerExisting() { + playerRegistered(session.getPlayerEntity()); + session.getEntityCache().getAllPlayerEntities().forEach(this::playerRegistered); + } + + @Override + public void playerRegistered(PlayerEntity player) { + var reference = objective.getScores().get(player.getUsername()); + if (reference == null) { + return; + } + var score = + new PlayerlistDisplayScore(this, objective.getScoreboard().nextId(), reference, player.getGeyserId()); + displayScores.put(player.getGeyserId(), score); + } + + @Override + public void playerRemoved(PlayerEntity player) { + var score = displayScores.remove(player.getGeyserId()); + if (score == null) { + return; + } + removedScores.add(score); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/SidebarDisplaySlot.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/SidebarDisplaySlot.java new file mode 100644 index 000000000..24cc81f78 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/slot/SidebarDisplaySlot.java @@ -0,0 +1,189 @@ +/* + * 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.scoreboard.display.slot; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.scoreboard.Objective; +import org.geysermc.geyser.scoreboard.ScoreReference; +import org.geysermc.geyser.scoreboard.Team; +import org.geysermc.geyser.scoreboard.UpdateType; +import org.geysermc.geyser.scoreboard.display.score.SidebarDisplayScore; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; + +public final class SidebarDisplaySlot extends DisplaySlot { + private static final int SCORE_DISPLAY_LIMIT = 15; + private static final Comparator SCORE_DISPLAY_ORDER = + Comparator.comparing(ScoreReference::score) + .reversed() + .thenComparing(ScoreReference::name, String.CASE_INSENSITIVE_ORDER); + + private List displayScores = new ArrayList<>(SCORE_DISPLAY_LIMIT); + + public SidebarDisplaySlot(GeyserSession session, Objective objective, ScoreboardPosition position) { + super(session, objective, position); + } + + @Override + protected void render0(List addScores, List removeScores) { + // while one could argue that we may not have to do this fancy Java filter when there are fewer scores than the + // line limit, we would lose the correct order of the scores if we don't + var newDisplayScores = + objective.getScores().values().stream() + .filter(score -> !score.hidden()) + .sorted(SCORE_DISPLAY_ORDER) + .limit(SCORE_DISPLAY_LIMIT) + .map(reference -> { + // pretty much an ArrayList#remove + var iterator = this.displayScores.iterator(); + while (iterator.hasNext()) { + var score = iterator.next(); + if (score.name().equals(reference.name())) { + iterator.remove(); + return score; + } + } + + // new score, so it should be added + return new SidebarDisplayScore(this, objective.getScoreboard().nextId(), reference); + }).collect(Collectors.toList()); + + // in newDisplayScores we removed the items that were already present from displayScores, + // meaning that the items that remain are items that are no longer displayed + for (var score : this.displayScores) { + removeScores.add(score.cachedInfo()); + } + + // preserves the new order + this.displayScores = newDisplayScores; + + // fixes ordering issues with multiple entries with same score + if (!this.displayScores.isEmpty()) { + SidebarDisplayScore lastScore = null; + int count = 0; + for (var score : this.displayScores) { + if (lastScore == null) { + lastScore = score; + continue; + } + + if (score.score() == lastScore.score()) { + // something to keep in mind is that Bedrock doesn't support some legacy color codes and adds some + // codes as well, so if the line limit is every increased keep that in mind + if (count == 0) { + lastScore.order(ChatColor.styleOrder(count++)); + } + score.order(ChatColor.styleOrder(count++)); + } else { + if (count == 0) { + lastScore.order(null); + } + count = 0; + } + lastScore = score; + } + + if (count == 0 && lastScore != null) { + lastScore.order(null); + } + } + + boolean objectiveAdd = updateType == UpdateType.ADD; + boolean objectiveUpdate = updateType == UpdateType.UPDATE; + + for (var score : this.displayScores) { + Team team = score.team(); + boolean add = objectiveAdd || objectiveUpdate; + boolean exists = score.exists(); + + if (team != null) { + // entities are mostly removed from teams without notifying the scores. + if (team.shouldRemove() || !team.hasEntity(score.name())) { + score.team(null); + add = true; + } + } + + if (score.shouldUpdate()) { + score.update(objective); + add = true; + } + + if (add) { + addScores.add(score.cachedInfo()); + } + + // we need this as long as MCPE-143063 hasn't been fixed. + // the checks after 'add' are there to prevent removing scores that + // are going to be removed anyway / don't need to be removed + if (add && exists && !(objectiveUpdate || objectiveAdd) && !score.onlyScoreValueChanged()) { + removeScores.add(score.cachedInfo()); + } + } + + if (objectiveUpdate) { + sendRemoveObjective(); + } + + if (objectiveAdd || objectiveUpdate) { + sendDisplayObjective(); + } + + updateType = UpdateType.NOTHING; + } + + @Override + public void addScore(ScoreReference reference) { + // we handle them a bit different: we sort the scores, and we add them ourselves + } + + @Override + public void playerRegistered(PlayerEntity player) { + + } + + @Override + public void playerRemoved(PlayerEntity player) { + + } + + public void setTeamFor(Team team, Set entities) { + // we only have to worry about scores that are currently displayed, + // because the constructor of the display score fetches the team + for (var score : displayScores) { + if (entities.contains(score.name())) { + score.team(team); + } + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java index 3affa12cf..a80ed3e3a 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java @@ -31,15 +31,18 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; import lombok.Getter; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; -import java.util.*; -import java.util.concurrent.atomic.AtomicLong; - /** * Each session has its own EntityCache in the occasion that an entity packet is sent specifically * for that player (e.g. seeing vanished players from /vanish) @@ -68,6 +71,10 @@ public class EntityCache { if (cacheEntity(entity)) { entity.spawnEntity(); + // start tracking newly spawned entities. + // This is however not called for players, that's done in addPlayerEntity + session.getWorldCache().getScoreboard().entityRegistered(entity); + if (entity instanceof Tickable) { // Start ticking it tickableEntities.add((Tickable) entity); @@ -86,21 +93,24 @@ public class EntityCache { } public void removeEntity(Entity entity) { + if (entity == null) { + return; + } + if (entity instanceof PlayerEntity player) { session.getPlayerWithCustomHeads().remove(player.getUuid()); } - if (entity != null) { - if (entity.isValid()) { - entity.despawnEntity(); - } + if (entity.isValid()) { + entity.despawnEntity(); + } + entities.remove(entityIdTranslations.remove(entity.getEntityId())); - long geyserId = entityIdTranslations.remove(entity.getEntityId()); - entities.remove(geyserId); + // don't track the entity anymore, now that it's removed + session.getWorldCache().getScoreboard().entityRemoved(entity); - if (entity instanceof Tickable) { - tickableEntities.remove(entity); - } + if (entity instanceof Tickable) { + tickableEntities.remove(entity); } } @@ -126,15 +136,39 @@ public class EntityCache { public void addPlayerEntity(PlayerEntity entity) { // putIfAbsent matches the behavior of playerInfoMap in Java as of 1.19.3 - playerEntities.putIfAbsent(entity.getUuid(), entity); + boolean exists = playerEntities.putIfAbsent(entity.getUuid(), entity) != null; + if (exists) { + return; + } + + // notify scoreboard for new entity + var scoreboard = session.getWorldCache().getScoreboard(); + scoreboard.playerRegistered(entity); + // spawnPlayer's entityRegistered is not called for players + scoreboard.entityRegistered(entity); } public PlayerEntity getPlayerEntity(UUID uuid) { return playerEntities.get(uuid); } + public List getPlayersByName(String name) { + var list = new ArrayList(); + for (PlayerEntity player : playerEntities.values()) { + if (name.equals(player.getUsername())) { + list.add(player); + } + } + return list; + } + public PlayerEntity removePlayerEntity(UUID uuid) { - return playerEntities.remove(uuid); + var player = playerEntities.remove(uuid); + if (player != null) { + // notify scoreboard + session.getWorldCache().getScoreboard().playerRemoved(player); + } + return player; } public Collection getAllPlayerEntities() { 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 86cb69314..5927963c0 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,6 +31,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.Setter; +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; @@ -49,7 +50,7 @@ public final class WorldCache { @Getter private final ScoreboardSession scoreboardSession; @Getter - private Scoreboard scoreboard; + private @NonNull Scoreboard scoreboard; @Getter @Setter private Difficulty difficulty = Difficulty.EASY; @@ -81,10 +82,8 @@ public final class WorldCache { } public void removeScoreboard() { - if (scoreboard != null) { - scoreboard.removeScoreboard(); - scoreboard = new Scoreboard(session); - } + scoreboard.removeScoreboard(); + scoreboard = new Scoreboard(session); } public int increaseAndGetScoreboardPacketsPerSecond() { diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatColor.java b/core/src/main/java/org/geysermc/geyser/text/ChatColor.java index 49178f033..22e553678 100644 --- a/core/src/main/java/org/geysermc/geyser/text/ChatColor.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatColor.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.text; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; + public class ChatColor { public static final String ANSI_RESET = (char) 0x1b + "[0m"; @@ -84,4 +86,58 @@ public class ChatColor { string = string.replace(WHITE, (char) 0x1b + "[37;1m"); return string; } -} \ No newline at end of file + + public static String styleOrder(int index) { + // https://bugs.mojang.com/browse/MCPE-41729 + // strikethrough and underlined do not exist on Bedrock + return switch (index) { + case 0 -> BLACK; + case 1 -> DARK_BLUE; + case 2 -> DARK_GREEN; + case 3 -> DARK_AQUA; + case 4 -> DARK_RED; + case 5 -> DARK_PURPLE; + case 6 -> GOLD; + case 7 -> GRAY; + case 8 -> DARK_GRAY; + case 9 -> BLUE; + case 10 -> GREEN; + case 11 -> AQUA; + case 12 -> RED; + case 13 -> LIGHT_PURPLE; + case 14 -> YELLOW; + case 15 -> WHITE; + case 16 -> OBFUSCATED; + case 17 -> BOLD; + default -> ITALIC; + }; + } + + public static String chatColorFor(TeamColor teamColor) { + // https://bugs.mojang.com/browse/MCPE-41729 + // strikethrough and underlined do not exist on Bedrock + return switch (teamColor) { + case BLACK -> BLACK; + case DARK_BLUE -> DARK_BLUE; + case DARK_GREEN -> DARK_GREEN; + case DARK_AQUA -> DARK_AQUA; + case DARK_RED -> DARK_RED; + case DARK_PURPLE -> DARK_PURPLE; + case GOLD -> GOLD; + case GRAY -> GRAY; + case DARK_GRAY -> DARK_GRAY; + case BLUE -> BLUE; + case GREEN -> GREEN; + case AQUA -> AQUA; + case RED -> RED; + case LIGHT_PURPLE -> LIGHT_PURPLE; + case YELLOW -> YELLOW; + case WHITE -> WHITE; + case OBFUSCATED -> OBFUSCATED; + case BOLD -> BOLD; + case STRIKETHROUGH, UNDERLINED -> ""; + case ITALIC -> ITALIC; + default -> RESET; + }; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java index e8d307c90..cf688bbfd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java @@ -32,40 +32,22 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundResetScorePacket; @Translator(packet = ClientboundResetScorePacket.class) public class JavaResetScorePacket extends PacketTranslator { - @Override public void translate(GeyserSession session, ClientboundResetScorePacket packet) { WorldCache worldCache = session.getWorldCache(); Scoreboard scoreboard = worldCache.getScoreboard(); int pps = worldCache.increaseAndGetScoreboardPacketsPerSecond(); - Objective belowName = scoreboard.getObjectiveSlots().get(ScoreboardPosition.BELOW_NAME); - if (packet.getObjective() == null) { // No objective name means all scores are reset for that player (/scoreboard players reset PLAYERNAME) - for (Objective otherObjective : scoreboard.getObjectives()) { - otherObjective.removeScore(packet.getOwner()); - } - - // as described below - if (belowName != null) { - JavaSetScoreTranslator.setBelowName(session, belowName, packet.getOwner()); - } + scoreboard.resetPlayerScores(packet.getOwner()); } else { Objective objective = scoreboard.getObjective(packet.getObjective()); objective.removeScore(packet.getOwner()); - - // If this is the objective that is in use to show the below name text, we need to update the player - // attached to this score. - if (objective == belowName) { - // Update the score on this player to now reflect 0 - JavaSetScoreTranslator.setBelowName(session, objective, packet.getOwner()); - } } // ScoreboardUpdater will handle it for us if the packets per second diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java index 85d93c0b5..0a7c6131f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java @@ -25,72 +25,45 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.scoreboard.Objective; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; -import org.geysermc.geyser.scoreboard.UpdateType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; @Translator(packet = ClientboundSetObjectivePacket.class) public class JavaSetObjectiveTranslator extends PacketTranslator { - private final GeyserLogger logger = GeyserImpl.getInstance().getLogger(); - @Override public void translate(GeyserSession session, ClientboundSetObjectivePacket packet) { WorldCache worldCache = session.getWorldCache(); Scoreboard scoreboard = worldCache.getScoreboard(); int pps = worldCache.increaseAndGetScoreboardPacketsPerSecond(); - Objective objective = scoreboard.getObjective(packet.getName()); - if (objective != null && objective.getUpdateType() != UpdateType.REMOVE && packet.getAction() == ObjectiveAction.ADD) { - // matches vanilla behaviour - logger.warning("An objective with the same name '" + packet.getName() + "' already exists! Ignoring packet"); + Objective objective; + if (packet.getAction() == ObjectiveAction.ADD) { + objective = scoreboard.registerNewObjective(packet.getName()); + } else { + objective = scoreboard.getObjective(packet.getName()); + } + + // matches vanilla + if (objective == null) { return; } - if ((objective == null || objective.getUpdateType() == UpdateType.REMOVE) && packet.getAction() != ObjectiveAction.REMOVE) { - objective = scoreboard.registerNewObjective(packet.getName()); - } - switch (packet.getAction()) { - case ADD, UPDATE -> { - objective.setDisplayName(MessageTranslator.convertMessage(packet.getDisplayName())) - .setNumberFormat(packet.getNumberFormat()) - .setType(packet.getType().ordinal()); - if (objective == scoreboard.getObjectiveSlots().get(ScoreboardPosition.BELOW_NAME)) { - // Update the score tag of all players - for (PlayerEntity entity : session.getEntityCache().getAllPlayerEntities()) { - if (entity.isValid()) { - entity.setBelowNameText(objective); - } - } - } - } - case REMOVE -> { - scoreboard.unregisterObjective(packet.getName()); - if (objective != null && objective == scoreboard.getObjectiveSlots().get(ScoreboardPosition.BELOW_NAME)) { - // Clear the score tag from all players - for (PlayerEntity entity : session.getEntityCache().getAllPlayerEntities()) { - // Other places we check for the entity being valid, - // but we must set the below name text as null for all players - // or else PlayerEntity#spawnEntity will find a null objective and not touch EntityData#SCORE_TAG - entity.setBelowNameText(null); - } - } - } + case ADD, UPDATE -> + objective.updateProperties(packet.getDisplayName(), packet.getType(), packet.getNumberFormat()); + case REMOVE -> scoreboard.removeObjective(objective); } - if (objective == null || !objective.isActive()) { + // Scoreboard#removeObjective doesn't touch the display slot(s) that were attached to it. + // So Objective#hasDisplaySlot will be true as long as it's currently present on the Bedrock client + if (!objective.hasDisplaySlot()) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java index 999edcc8c..3a1ee6373 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java @@ -25,23 +25,17 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; +import java.util.Arrays; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; import org.geysermc.geyser.scoreboard.Team; -import org.geysermc.geyser.scoreboard.UpdateType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.translator.text.MessageTranslator; - -import java.util.Arrays; -import java.util.Set; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; @Translator(packet = ClientboundSetPlayerTeamPacket.class) public class JavaSetPlayerTeamTranslator extends PacketTranslator { @@ -60,83 +54,45 @@ public class JavaSetPlayerTeamTranslator extends PacketTranslator { - team = scoreboard.registerNewTeam(packet.getTeamName(), packet.getPlayers()) - .setName(MessageTranslator.convertMessage(packet.getDisplayName())) - .setColor(packet.getColor()) - .setNameTagVisibility(packet.getNameTagVisibility()) - .setPrefix(MessageTranslator.convertMessage(packet.getPrefix(), session.locale())) - .setSuffix(MessageTranslator.convertMessage(packet.getSuffix(), session.locale())); - if (packet.getPlayers().length != 0) { - if ((team.getNameTagVisibility() != NameTagVisibility.ALWAYS && !team.isVisibleFor(session.getPlayerEntity().getUsername())) - || team.getColor() != TeamColor.RESET - || !team.getCurrentData().getPrefix().isEmpty() - || !team.getCurrentData().getSuffix().isEmpty()) { - // Something is here that would modify entity names - scoreboard.updateEntityNames(team, true); - } + if (packet.getAction() == TeamAction.CREATE) { + scoreboard.registerNewTeam( + packet.getTeamName(), + packet.getPlayers(), + packet.getDisplayName(), + packet.getPrefix(), + packet.getSuffix(), + packet.getNameTagVisibility(), + packet.getColor() + ); + } else { + Team team = scoreboard.getTeam(packet.getTeamName()); + if (team == null) { + if (logger.isDebug()) { + logger.debug("Error while translating Team Packet " + packet.getAction() + + "! Scoreboard Team " + packet.getTeamName() + " is not registered." + ); } + return; } - case UPDATE -> { - if (team == null) { - if (logger.isDebug()) { - logger.debug("Error while translating Team Packet " + packet.getAction() - + "! Scoreboard Team " + packet.getTeamName() + " is not registered." - ); - } - return; - } - TeamColor oldColor = team.getColor(); - NameTagVisibility oldVisibility = team.getNameTagVisibility(); - String oldPrefix = team.getCurrentData().getPrefix(); - String oldSuffix = team.getCurrentData().getSuffix(); - - team.setName(MessageTranslator.convertMessage(packet.getDisplayName())) - .setColor(packet.getColor()) - .setNameTagVisibility(packet.getNameTagVisibility()) - .setPrefix(MessageTranslator.convertMessage(packet.getPrefix(), session.locale())) - .setSuffix(MessageTranslator.convertMessage(packet.getSuffix(), session.locale())) - .setUpdateType(UpdateType.UPDATE); - - if (oldVisibility != team.getNameTagVisibility() - || oldColor != team.getColor() - || !oldPrefix.equals(team.getCurrentData().getPrefix()) - || !oldSuffix.equals(team.getCurrentData().getSuffix())) { - // Update entities attached to this team as something about their nameplates have changed - scoreboard.updateEntityNames(team, false); + switch (packet.getAction()) { + case UPDATE -> { + team.updateProperties( + packet.getDisplayName(), + packet.getPrefix(), + packet.getSuffix(), + packet.getNameTagVisibility(), + packet.getColor() + ); } + case ADD_PLAYER -> team.addEntities(packet.getPlayers()); + case REMOVE_PLAYER -> team.removeEntities(packet.getPlayers()); + case REMOVE -> scoreboard.removeTeam(packet.getTeamName()); } - case ADD_PLAYER -> { - if (team == null) { - if (logger.isDebug()) { - logger.debug("Error while translating Team Packet " + packet.getAction() - + "! Scoreboard Team " + packet.getTeamName() + " is not registered." - ); - } - return; - } - Set added = team.addEntities(packet.getPlayers()); - scoreboard.updateEntityNames(team, added, true); - } - case REMOVE_PLAYER -> { - if (team == null) { - if (logger.isDebug()) { - logger.debug("Error while translating Team Packet " + packet.getAction() - + "! Scoreboard Team " + packet.getTeamName() + " is not registered." - ); - } - return; - } - Set removed = team.removeEntities(packet.getPlayers()); - scoreboard.updateEntityNames(null, removed, true); - } - case REMOVE -> scoreboard.removeTeam(packet.getTeamName()); } + // ScoreboardUpdater will handle it for us if the packets per second // (for score and team packets) is higher than the first threshold if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java index d1645b496..989f0f2cb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java @@ -25,12 +25,8 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; -import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.scoreboard.Objective; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; @@ -39,6 +35,7 @@ import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; @Translator(packet = ClientboundSetScorePacket.class) public class JavaSetScoreTranslator extends PacketTranslator { @@ -63,16 +60,7 @@ public class JavaSetScoreTranslator extends PacketTranslator TEAM_COLORS = new EnumMap<>(TeamColor.class); - // Legacy formatting character private static final String BASE = "\u00a7"; @@ -81,31 +74,6 @@ public class MessageTranslator { private static final String RESET = BASE + "r"; static { - TEAM_COLORS.put(TeamColor.RESET, RESET); - - TEAM_COLORS.put(TeamColor.BLACK, BASE + "0"); - TEAM_COLORS.put(TeamColor.DARK_BLUE, BASE + "1"); - TEAM_COLORS.put(TeamColor.DARK_GREEN, BASE + "2"); - TEAM_COLORS.put(TeamColor.DARK_AQUA, BASE + "3"); - TEAM_COLORS.put(TeamColor.DARK_RED, BASE + "4"); - TEAM_COLORS.put(TeamColor.DARK_PURPLE, BASE + "5"); - TEAM_COLORS.put(TeamColor.GOLD, BASE + "6"); - TEAM_COLORS.put(TeamColor.GRAY, BASE + "7"); - TEAM_COLORS.put(TeamColor.DARK_GRAY, BASE + "8"); - TEAM_COLORS.put(TeamColor.BLUE, BASE + "9"); - TEAM_COLORS.put(TeamColor.GREEN, BASE + "a"); - TEAM_COLORS.put(TeamColor.AQUA, BASE + "b"); - TEAM_COLORS.put(TeamColor.RED, BASE + "c"); - TEAM_COLORS.put(TeamColor.LIGHT_PURPLE, BASE + "d"); - TEAM_COLORS.put(TeamColor.YELLOW, BASE + "e"); - TEAM_COLORS.put(TeamColor.WHITE, BASE + "f"); - - // Formats, not colors - TEAM_COLORS.put(TeamColor.OBFUSCATED, BASE + "k"); - TEAM_COLORS.put(TeamColor.BOLD, BASE + "l"); - TEAM_COLORS.put(TeamColor.STRIKETHROUGH, BASE + "m"); - TEAM_COLORS.put(TeamColor.ITALIC, BASE + "o"); - // Temporary fix for https://github.com/KyoriPowered/adventure/issues/447 - TODO resolve properly GsonComponentSerializer source = DefaultComponentSerializer.get() .toBuilder() @@ -157,13 +125,31 @@ public class MessageTranslator { } /** - * Convert a Java message to the legacy format ready for bedrock + * Convert a Java message to the legacy format ready for bedrock. Unlike + * {@link #convertMessageRaw(Component, String)} this adds a leading color reset. In Bedrock + * some places have build-in colors. * * @param message Java message * @param locale Locale to use for translation strings * @return Parsed and formatted message for bedrock */ public static String convertMessage(Component message, String locale) { + return convertMessage(message, locale, true); + } + + /** + * 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. + * + * @param message Java message + * @param locale Locale to use for translation strings + * @return Parsed and formatted message for bedrock + */ + public static String convertMessageRaw(Component message, String locale) { + return convertMessage(message, locale, false); + } + + private static String convertMessage(Component message, String locale, boolean addLeadingResetFormat) { try { // Translate any components that require it message = RENDERER.render(message, locale); @@ -172,7 +158,7 @@ public class MessageTranslator { StringBuilder finalLegacy = new StringBuilder(); char[] legacyChars = legacy.toCharArray(); - boolean lastFormatReset = false; + boolean lastFormatReset = !addLeadingResetFormat; for (int i = 0; i < legacyChars.length; i++) { char legacyChar = legacyChars[i]; if (legacyChar != ChatColor.ESCAPE || i >= legacyChars.length - 1) { @@ -185,7 +171,7 @@ public class MessageTranslator { char next = legacyChars[++i]; if (BEDROCK_COLORS.indexOf(next) != -1) { - // Append this color code, as well as a necessary reset code + // Unlike Java Edition, the ChatFormatting is not reset when a ChatColor is added if (!lastFormatReset) { finalLegacy.append(RESET); } @@ -378,16 +364,6 @@ public class MessageTranslator { session.sendUpstreamPacket(textPacket); } - /** - * Convert a team color to a chat color - * - * @param teamColor Color or format to convert - * @return The chat color character - */ - public static String toChatColor(TeamColor teamColor) { - return TEAM_COLORS.getOrDefault(teamColor, ""); - } - /** * Checks if the given message is over 256 characters (Java edition server chat limit) and sends a message to the user if it is * 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 53aefde1e..b7f4e7d76 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.util; +import net.kyori.adventure.key.Key; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -38,6 +39,8 @@ import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.entity.type.living.animal.horse.CamelEntity; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -290,6 +293,23 @@ public final class EntityUtils { }; } + private static String translatedEntityName(String namespace, String name, GeyserSession session) { + return MinecraftLocale.getLocaleString("entity." + namespace + "." + name, session.locale()); + } + + public static String translatedEntityName(Key type, GeyserSession session) { + return translatedEntityName(type.namespace(), type.value(), session); + } + + public static String translatedEntityName(EntityType type, GeyserSession session) { + if (type == EntityType.PLAYER) { + return "Player"; // the player's name is always shown instead + } + // this works at least with all 1.20.5 entities, except the killer bunny since that's not an entity type. + String typeName = type.name().toLowerCase(Locale.ROOT); + return translatedEntityName("minecraft", typeName, session); + } + private EntityUtils() { } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java new file mode 100644 index 000000000..523e4dca2 --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java @@ -0,0 +1,270 @@ +/* + * 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.scoreboard.network; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; + +import net.kyori.adventure.text.Component; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetPlayerTeamTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.CollisionRule; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; +import org.junit.jupiter.api.Test; + +public class NameVisibilityScoreboardTest { + @Test + void playerVisibilityNever() { + mockContextScoreboard(context -> { + var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); + + mockAndAddPlayerEntity(context, "player1", 2); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team1", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.NEVER, + CollisionRule.NEVER, + TeamColor.DARK_RED, + new String[]{"player1"} + ) + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, context); + }); + } + + @Test + void playerVisibilityHideForOtherTeam() { + mockContextScoreboard(context -> { + var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); + + mockAndAddPlayerEntity(context, "player1", 2); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team1", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.HIDE_FOR_OTHER_TEAMS, + CollisionRule.NEVER, + TeamColor.DARK_RED, + new String[]{"player1"} + ) + ); + // only hidden if session player (Tim203) is in a team as well + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); + return packet; + }, context); + assertNoNextPacket(context); + + // create another team and add Tim203 to it + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team2", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.NEVER, + CollisionRule.NEVER, + TeamColor.DARK_RED, + new String[]{"Tim203"} + ) + ); + // Tim203 is now in another team, so it should be hidden + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, context); + assertNoNextPacket(context); + + // add Tim203 to same team as player1, score should be visible again + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket("team1", TeamAction.ADD_PLAYER, new String[]{"Tim203"}) + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); + return packet; + }, context); + }); + } + + @Test + void playerVisibilityHideForOwnTeam() { + mockContextScoreboard(context -> { + var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); + + mockAndAddPlayerEntity(context, "player1", 2); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team1", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.HIDE_FOR_OWN_TEAM, + CollisionRule.NEVER, + TeamColor.DARK_RED, + new String[]{"player1"} + ) + ); + // Tim203 is not in a team (let alone the same team), so should be visible + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); + return packet; + }, context); + assertNoNextPacket(context); + + // Tim203 is now in the same team as player1, so should be hidden + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket("team1", TeamAction.ADD_PLAYER, new String[]{"Tim203"}) + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, context); + assertNoNextPacket(context); + + // create another team and add Tim203 to there, score should be visible again + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team2", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.NEVER, + CollisionRule.NEVER, + TeamColor.DARK_RED, + new String[]{"Tim203"} + ) + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); + return packet; + }, context); + }); + } + + @Test + void playerVisibilityAlways() { + mockContextScoreboard(context -> { + var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); + + mockAndAddPlayerEntity(context, "player1", 2); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team1", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.ALWAYS, + CollisionRule.NEVER, + TeamColor.DARK_RED, + new String[]{"player1"} + ) + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); + return packet; + }, context); + + // adding self to another team shouldn't make a difference + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team2", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.ALWAYS, + CollisionRule.NEVER, + TeamColor.DARK_RED, + new String[]{"Tim203"} + ) + ); + assertNoNextPacket(context); + + // adding self to player1 team shouldn't matter + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket("team1", TeamAction.ADD_PLAYER, new String[]{"Tim203"}) + ); + assertNoNextPacket(context); + }); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java new file mode 100644 index 000000000..5d8d8309f --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java @@ -0,0 +1,227 @@ +/* + * 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.scoreboard.network.belowname; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; +import org.junit.jupiter.api.Test; + +public class BasicBelownameScoreboardTests { + @Test + void displayWithNoPlayersAndRemove() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective") + ); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "") + ); + assertNoNextPacket(context); + }); + } + + @Test + void displayColorWithOnePlayer() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + + mockAndAddPlayerEntity(context, "player1", 2); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective", NamedTextColor.BLUE), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective") + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.SCORE, "0 §r§9objective"); + return packet; + }, context); + }); + } + + @Test + void displayWithOnePlayerAndRemove() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + + mockAndAddPlayerEntity(context, "player1", 2); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective") + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective"); + return packet; + }, context); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "") + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.SCORE, ""); + return packet; + }, context); + }); + } + + @Test + void overrideAndRemove() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + + mockAndAddPlayerEntity(context, "player1", 2); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective1", + ObjectiveAction.ADD, + Component.text("objective1"), + ScoreType.INTEGER, + null + ) + ); + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective2", + ObjectiveAction.ADD, + Component.text("objective2"), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective2") + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective2"); + return packet; + }, context); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective1") + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.SCORE, ""); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective1"); + return packet; + }, context); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "") + ); + assertNextPacket(() -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.SCORE, ""); + return packet; + }, context); + }); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java new file mode 100644 index 000000000..a3d4ad671 --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java @@ -0,0 +1,204 @@ +/* + * 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.scoreboard.network.playerlist; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; + +import java.util.List; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextDecoration; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetScoreTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; +import org.junit.jupiter.api.Test; + +/* +Identical to sidebar + */ +public class BasicPlayerlistScoreboardTests { + @Test + void display() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("list"); + packet.setSortOrder(1); + return packet; + }, context); + }); + } + + @Test + void displayNameColors() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective", Style.style(NamedTextColor.AQUA, TextDecoration.BOLD)), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("§b§lobjective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("list"); + packet.setSortOrder(1); + return packet; + }, context); + }); + } + + @Test + void overrideWithOneScore() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective1", + ObjectiveAction.ADD, + Component.text("objective1"), + ScoreType.INTEGER, + null + ) + ); + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective2", + ObjectiveAction.ADD, + Component.text("objective2"), + ScoreType.INTEGER, + null + ) + ); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("Tim203", "objective1", 1)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("Tim203", "objective2", 2)); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective2") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective2"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("list"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + // session player name is Tim203 + packet.setInfos(List.of(new ScoreInfo(1, "0", 2, ScoreInfo.ScorerType.PLAYER, 1))); + return packet; + }, context); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective1") + ); + assertNextPacket(() -> { + var packet = new RemoveObjectivePacket(); + packet.setObjectiveId("0"); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("2"); + packet.setDisplayName("objective1"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("list"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + // session player name is Tim203 + packet.setInfos(List.of(new ScoreInfo(3, "2", 1, ScoreInfo.ScorerType.PLAYER, 1))); + return packet; + }, context); + }); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java new file mode 100644 index 000000000..dd693022c --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java @@ -0,0 +1,756 @@ +/* + * 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.scoreboard.network.server; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; + +import java.util.List; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetPlayerTeamTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetScoreTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.CollisionRule; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; +import org.junit.jupiter.api.Test; + +public class CubecraftScoreboardTest { + @Test + void test() { + mockContextScoreboard(context -> { + var setTeamTranslator = new JavaSetPlayerTeamTranslator(); + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + + // unused + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("SB_NoName", Component.text("SB_NoName"), Component.empty(), Component.empty(), true, true, NameTagVisibility.NEVER, CollisionRule.NEVER, TeamColor.RESET, new String[0])); + assertNoNextPacket(context); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "sidebar", + ObjectiveAction.ADD, + Component.text("sidebar"), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "sidebar") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("sidebar"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + + + // Now they're going to create a bunch of teams and add players to those teams in a very inefficient way. + // Presumably this is a leftover from an old system, as these don't seem to do anything but hide their nametags. + // For which you could just use a single team. + + + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", Component.text("2i|1"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.RESET, new String[0])); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", Component.text("2i|1"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.DARK_GRAY)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", Component.text("2i|1"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.DARK_GRAY)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", Component.text("2i|1"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.DARK_GRAY)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", Component.text("2i|1"), Component.empty(), Component.empty(), false, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.DARK_GRAY)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", Component.text("2i|1"), Component.empty(), Component.empty(), false, false, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.DARK_GRAY)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", Component.text("2i|1"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.ALWAYS, TeamColor.DARK_GRAY)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", Component.text("2i|1"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.NEVER, TeamColor.DARK_GRAY)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "A_Player" })); + + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", Component.text("1y|11"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.RESET, new String[0])); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", Component.text("1y|11"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", Component.text("1y|11"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", Component.text("1y|11"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", Component.text("1y|11"), Component.empty(), Component.empty(), false, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", Component.text("1y|11"), Component.empty(), Component.empty(), false, false, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", Component.text("1y|11"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", Component.text("1y|11"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.NEVER, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", TeamAction.ADD_PLAYER, new String[] { "B_Player" })); + + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "C_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "D_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1y|11", TeamAction.ADD_PLAYER, new String[] { "E_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "F_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "G_Player" })); + + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", Component.text("2e|3"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.RESET, new String[0])); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", Component.text("2e|3"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.BLUE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", Component.text("2e|3"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.BLUE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", Component.text("2e|3"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.BLUE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", Component.text("2e|3"), Component.empty(), Component.empty(), false, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.BLUE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", Component.text("2e|3"), Component.empty(), Component.empty(), false, false, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.BLUE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", Component.text("2e|3"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.ALWAYS, TeamColor.BLUE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", Component.text("2e|3"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.NEVER, TeamColor.BLUE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", TeamAction.ADD_PLAYER, new String[] { "H_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "I_Player" })); + + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", Component.text("22|9"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.RESET, new String[0])); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", Component.text("22|9"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", Component.text("22|9"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", Component.text("22|9"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", Component.text("22|9"), Component.empty(), Component.empty(), false, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", Component.text("22|9"), Component.empty(), Component.empty(), false, false, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", Component.text("22|9"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", Component.text("22|9"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.NEVER, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("22|9", TeamAction.ADD_PLAYER, new String[] { "J_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "K_Player" })); + + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", Component.text("26|7"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.RESET, new String[0])); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", Component.text("26|7"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", Component.text("26|7"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", Component.text("26|7"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", Component.text("26|7"), Component.empty(), Component.empty(), false, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", Component.text("26|7"), Component.empty(), Component.empty(), false, false, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", Component.text("26|7"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.ALWAYS, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", Component.text("26|7"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.NEVER, TeamColor.AQUA)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("26|7", TeamAction.ADD_PLAYER, new String[] { "L_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2e|3", TeamAction.ADD_PLAYER, new String[] { "M_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "N_Player" })); + + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", Component.text("1u|13"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.RESET, new String[0])); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", Component.text("1u|13"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", Component.text("1u|13"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", Component.text("1u|13"), Component.empty(), Component.empty(), true, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", Component.text("1u|13"), Component.empty(), Component.empty(), false, true, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", Component.text("1u|13"), Component.empty(), Component.empty(), false, false, NameTagVisibility.ALWAYS, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", Component.text("1u|13"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.ALWAYS, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", Component.text("1u|13"), Component.empty(), Component.empty(), false, false, NameTagVisibility.NEVER, CollisionRule.NEVER, TeamColor.LIGHT_PURPLE)); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("1u|13", TeamAction.ADD_PLAYER, new String[] { "O_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "P_Player" })); + context.translate(setTeamTranslator, new ClientboundSetPlayerTeamPacket("2i|1", TeamAction.ADD_PLAYER, new String[] { "Q_Player" })); + + assertNoNextPacket(context); + + + // Now that those teams are created and people added to it, they set the final sidebar name and add the lines to it. + // They're also not doing this efficiently, because they don't add the players when the team is created. + // Instead, they send an additional packet. + + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "sidebar", + ObjectiveAction.UPDATE, + Component.empty() + .append(Component.text( + "CubeCraft", Style.style(NamedTextColor.WHITE, TextDecoration.BOLD))), + ScoreType.INTEGER, + null)); + assertNextPacket( + () -> { + var packet = new RemoveObjectivePacket(); + packet.setObjectiveId("0"); + return packet; + }, + context); + assertNextPacket( + () -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("§f§lCubeCraft"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-0", + Component.text("SB_l-0"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-0", TeamAction.ADD_PLAYER, new String[] {"§0§0"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-0", + Component.text("SB_l-0"), + Component.empty().append(Component.text("", Style.style(NamedTextColor.BLACK))), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§0", "sidebar", 10)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 10, "§r§0§0§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-1", + Component.text("SB_l-1"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-1", TeamAction.ADD_PLAYER, new String[] {"§0§1"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-1", + Component.text("SB_l-1"), + Component.empty() + .append(Component.textOfChildren( + Component.text("User: ", TextColor.color(0x3aa9ff)), + Component.text("Tim203", NamedTextColor.WHITE))), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§1", "sidebar", 9)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(2, "0", 9, "§bUser: §r§fTim203§r§0§1§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-2", + Component.text("SB_l-2"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-2", TeamAction.ADD_PLAYER, new String[] {"§0§2"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-2", + Component.text("SB_l-2"), + Component.empty() + .append(Component.textOfChildren( + Component.text("Rank: ", TextColor.color(0x3aa9ff)), + Component.text("\uE1AB ", NamedTextColor.WHITE))), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§2", "sidebar", 8)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(3, "0", 8, "§bRank: §r§f\uE1AB §r§0§2§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-3", + Component.text("SB_l-3"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-3", TeamAction.ADD_PLAYER, new String[] {"§0§3"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-3", + Component.text("SB_l-3"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§3", "sidebar", 7)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(4, "0", 7, "§r§0§3§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-4", + Component.text("SB_l-4"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-4", TeamAction.ADD_PLAYER, new String[] {"§0§4"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-4", + Component.text("SB_l-4"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§4", "sidebar", 6)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(5, "0", 6, "§r§0§4§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-5", + Component.text("SB_l-5"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-5", TeamAction.ADD_PLAYER, new String[] {"§0§5"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-5", + Component.text("SB_l-5"), + Component.empty().append(Component.text("", NamedTextColor.DARK_BLUE)), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§5", "sidebar", 5)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(6, "0", 5, "§r§0§5§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-6", + Component.text("SB_l-6"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-6", TeamAction.ADD_PLAYER, new String[] {"§0§6"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-6", + Component.text("SB_l-6"), + Component.empty() + .append(Component.textOfChildren( + Component.text("Lobby: ", TextColor.color(0x3aa9ff)), + Component.text("EU #10", NamedTextColor.WHITE))), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§6", "sidebar", 4)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(7, "0", 4, "§bLobby: §r§fEU #10§r§0§6§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-7", + Component.text("SB_l-7"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-7", TeamAction.ADD_PLAYER, new String[] {"§0§7"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-7", + Component.text("SB_l-7"), + Component.empty() + .append(Component.textOfChildren( + Component.text("Players: ", TextColor.color(0x3aa9ff)), + Component.text("783", NamedTextColor.WHITE))), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§7", "sidebar", 3)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(8, "0", 3, "§bPlayers: §r§f783§r§0§7§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-8", + Component.text("SB_l-8"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-8", TeamAction.ADD_PLAYER, new String[] {"§0§8"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-8", + Component.text("SB_l-8"), + Component.empty().append(Component.text("", NamedTextColor.DARK_GREEN)), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§8", "sidebar", 2)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(9, "0", 2, "§r§0§8§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-9", + Component.text("SB_l-9"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-9", TeamAction.ADD_PLAYER, new String[] {"§0§9"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-9", + Component.text("SB_l-9"), + Component.empty().append(Component.text("24/09/24 (g2208)", TextColor.color(0x777777))), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§9", "sidebar", 1)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(10, "0", 1, "§824/09/24 (g2208)§r§0§9§r"))); + return packet; + }, + context); + + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-10", + Component.text("SB_l-10"), + Component.empty(), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET, + new String[0])); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket("SB_l-10", TeamAction.ADD_PLAYER, new String[] {"§0§a"})); + context.translate( + setTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "SB_l-10", + Component.text("SB_l-10"), + Component.empty().append(Component.text("play.cubecraft.net", NamedTextColor.GOLD)), + Component.empty(), + true, + true, + NameTagVisibility.ALWAYS, + CollisionRule.ALWAYS, + TeamColor.RESET)); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§a", "sidebar", 0)); + assertNextPacket( + () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(11, "0", 0, "§6play.cubecraft.net§r§0§a§r"))); + return packet; + }, + context); + + // after this we get a ClientboundPlayerInfoUpdatePacket with the action UPDATE_DISPLAY_NAME, + // but that one is only shown in the tablist so we don't have to handle that. + // And after that we get each player's ClientboundPlayerInfoUpdatePacket with also a UPDATE_DISPLAY_NAME, + // which is also not interesting for us. + // CubeCraft seems to use two armor stands per player: 1 for the rank badge and 1 for the player name. + // So the only thing we have to verify is that the nametag is hidden + + mockAndAddPlayerEntity(context, "A_Player", 2); + assertNextPacket( + () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, + context); + + mockAndAddPlayerEntity(context, "B_Player", 3); + assertNextPacket( + () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(3); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, + context); + + mockAndAddPlayerEntity(context, "E_Player", 4); + assertNextPacket( + () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(4); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, + context); + + mockAndAddPlayerEntity(context, "H_Player", 5); + assertNextPacket( + () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(5); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, + context); + + mockAndAddPlayerEntity(context, "J_Player", 6); + assertNextPacket( + () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(6); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, + context); + + mockAndAddPlayerEntity(context, "K_Player", 7); + assertNextPacket( + () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(7); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, + context); + + mockAndAddPlayerEntity(context, "L_Player", 8); + assertNextPacket( + () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(8); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, + context); + + mockAndAddPlayerEntity(context, "O_Player", 9); + assertNextPacket( + () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(9); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }, + context); + }); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java new file mode 100644 index 000000000..b3999303e --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java @@ -0,0 +1,218 @@ +/* + * 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.scoreboard.network.sidebar; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; + +import java.util.List; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextDecoration; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetScoreTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; +import org.junit.jupiter.api.Test; + +/* +Identical to playerlist + */ +public class BasicSidebarScoreboardTests { + @Test + void displayAndRemove() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("list"); + packet.setSortOrder(1); + return packet; + }, context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "") + ); + assertNextPacket(() -> { + var packet = new RemoveObjectivePacket(); + packet.setObjectiveId("0"); + return packet; + }, context); + }); + } + + @Test + void displayNameColors() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective", Style.style(NamedTextColor.AQUA, TextDecoration.BOLD)), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("§b§lobjective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + }); + } + + @Test + void override() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective1", + ObjectiveAction.ADD, + Component.text("objective1"), + ScoreType.INTEGER, + null + ) + ); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective2", + ObjectiveAction.ADD, + Component.text("objective2"), + ScoreType.INTEGER, + null + ) + ); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("Tim203", "objective1", 1)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("Tim203", "objective2", 2)); + assertNoNextPacket(context); + + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective2") + ); + + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective2"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "Tim203"))); + return packet; + }, context); + assertNoNextPacket(context); + + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective1") + ); + + assertNextPacket(() -> { + var packet = new RemoveObjectivePacket(); + packet.setObjectiveId("0"); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("2"); + packet.setDisplayName("objective1"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(3, "2", 1, "Tim203"))); + return packet; + }, context); + }); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java new file mode 100644 index 000000000..3e0be1c02 --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java @@ -0,0 +1,533 @@ +/* + * 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.scoreboard.network.sidebar; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; + +import java.util.List; +import net.kyori.adventure.text.Component; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaResetScorePacket; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetPlayerTeamTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetScoreTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.CollisionRule; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundResetScorePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; +import org.junit.jupiter.api.Test; + +public class OrderAndLimitSidebarScoreboardTests { + @Test + void aboveDisplayLimit() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + var resetScoreTranslator = new JavaResetScorePacket(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + + // some are in an odd order to make sure that there is no bias for which score is send first, + // and to make sure that the score value also doesn't influence the order + context.translate(setScoreTranslator, new ClientboundSetScorePacket("a", "objective", 1)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("b", "objective", 2)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("c", "objective", 3)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("d", "objective", 5)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("e", "objective", 4)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("f", "objective", 6)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("g", "objective", 9)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("h", "objective", 8)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("i", "objective", 7)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("p", "objective", 10)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("o", "objective", 11)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("n", "objective", 12)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("m", "objective", 13)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("k", "objective", 14)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("l", "objective", 15)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("j", "objective", 16)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("q", "objective", 17)); + assertNoNextPacket(context); + + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(1, "0", 17, "q"), + new ScoreInfo(2, "0", 16, "j"), + new ScoreInfo(3, "0", 15, "l"), + new ScoreInfo(4, "0", 14, "k"), + new ScoreInfo(5, "0", 13, "m"), + new ScoreInfo(6, "0", 12, "n"), + new ScoreInfo(7, "0", 11, "o"), + new ScoreInfo(8, "0", 10, "p"), + new ScoreInfo(9, "0", 9, "g"), + new ScoreInfo(10, "0", 8, "h"), + new ScoreInfo(11, "0", 7, "i"), + new ScoreInfo(12, "0", 6, "f"), + new ScoreInfo(13, "0", 5, "d"), + new ScoreInfo(14, "0", 4, "e"), + new ScoreInfo(15, "0", 3, "c") + )); + return packet; + }, context); + assertNoNextPacket(context); + + // remove a score + context.translate( + resetScoreTranslator, + new ClientboundResetScorePacket("m", "objective") + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of(new ScoreInfo(5, "0", 13, "m"))); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); + return packet; + }, context); + + // add a score + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket("aa", "objective", 13) + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(17, "0", 13, "aa"))); + return packet; + }, context); + + // add score with same score value (after) + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket("ga", "objective", 9) + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of( + new ScoreInfo(15, "0", 3, "c"), + new ScoreInfo(9, "0", 9, "§0§rg") + )); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(9, "0", 9, "§0§rg"), + new ScoreInfo(18, "0", 9, "§1§rga") + )); + return packet; + }, context); + + // add another score with same score value (before all) + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket("ag", "objective", 9) + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of( + new ScoreInfo(14, "0", 4, "e"), + new ScoreInfo(9, "0", 9, "§1§rg"), + new ScoreInfo(18, "0", 9, "§2§rga") + )); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(19, "0", 9, "§0§rag"), + new ScoreInfo(9, "0", 9, "§1§rg"), + new ScoreInfo(18, "0", 9, "§2§rga") + )); + return packet; + }, context); + + // remove score with same value + context.translate( + resetScoreTranslator, + new ClientboundResetScorePacket("g", "objective") + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of( + new ScoreInfo(9, "0", 9, "§1§rg"), + new ScoreInfo(18, "0", 9, "§1§rga") + )); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(18, "0", 9, "§1§rga"), + new ScoreInfo(20, "0", 4, "e") + )); + return packet; + }, context); + + // remove the other score with the same value + context.translate( + resetScoreTranslator, + new ClientboundResetScorePacket("ga", "objective") + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of( + new ScoreInfo(18, "0", 9, "§1§rga"), + new ScoreInfo(19, "0", 9, "ag") + )); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(19, "0", 9, "ag"), + new ScoreInfo(21, "0", 3, "c") + )); + return packet; + }, context); + }); + } + + @Test + void aboveDisplayLimitWithTeam() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + var resetScoreTranslator = new JavaResetScorePacket(); + var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + + // some are in an odd order to make sure that there is no bias for which score is send first, + // and to make sure that the score value also doesn't influence the order + context.translate(setScoreTranslator, new ClientboundSetScorePacket("a", "objective", 1)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("b", "objective", 2)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("c", "objective", 3)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("d", "objective", 5)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("e", "objective", 4)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("f", "objective", 6)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("g", "objective", 9)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("h", "objective", 8)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("i", "objective", 7)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("p", "objective", 10)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("o", "objective", 11)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("n", "objective", 12)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("m", "objective", 13)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("k", "objective", 14)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("l", "objective", 15)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("j", "objective", 16)); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("q", "objective", 17)); + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team1", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.ALWAYS, + CollisionRule.NEVER, + TeamColor.DARK_RED, + new String[]{ "f", "o" } + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(1, "0", 17, "q"), + new ScoreInfo(2, "0", 16, "j"), + new ScoreInfo(3, "0", 15, "l"), + new ScoreInfo(4, "0", 14, "k"), + new ScoreInfo(5, "0", 13, "m"), + new ScoreInfo(6, "0", 12, "n"), + new ScoreInfo(7, "0", 11, "§4prefix§r§4o§r§4suffix"), + new ScoreInfo(8, "0", 10, "p"), + new ScoreInfo(9, "0", 9, "g"), + new ScoreInfo(10, "0", 8, "h"), + new ScoreInfo(11, "0", 7, "i"), + new ScoreInfo(12, "0", 6, "§4prefix§r§4f§r§4suffix"), + new ScoreInfo(13, "0", 5, "d"), + new ScoreInfo(14, "0", 4, "e"), + new ScoreInfo(15, "0", 3, "c") + )); + return packet; + }, context); + assertNoNextPacket(context); + + // remove a score + context.translate( + resetScoreTranslator, + new ClientboundResetScorePacket("m", "objective") + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of(new ScoreInfo(5, "0", 13, "m"))); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); + return packet; + }, context); + + // add a score + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket("aa", "objective", 13) + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(17, "0", 13, "aa"))); + return packet; + }, context); + + // add some teams for the upcoming score adds + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team2", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.ALWAYS, + CollisionRule.NEVER, + TeamColor.DARK_AQUA, + new String[]{ "oa" } + ) + ); + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "team3", + Component.text("displayName"), + Component.text("prefix"), + Component.text("suffix"), + false, + false, + NameTagVisibility.ALWAYS, + CollisionRule.NEVER, + TeamColor.DARK_PURPLE, + new String[]{ "ao" } + ) + ); + assertNoNextPacket(context); + + // add a score that on Java should be after 'o', but would be before on Bedrock without manual order + // due to the team color + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket("oa", "objective", 11) + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of( + new ScoreInfo(15, "0", 3, "c"), + new ScoreInfo(7, "0", 11, "§0§r§4prefix§r§4o§r§4suffix") + )); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(7, "0", 11, "§0§r§4prefix§r§4o§r§4suffix"), + new ScoreInfo(18, "0", 11, "§1§r§3prefix§r§3oa§r§3suffix") + )); + return packet; + }, context); + + // add a score that on Java should be before 'o', but would be after on Bedrock without manual order + // due to the team color + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket("ao", "objective", 11) + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of( + new ScoreInfo(14, "0", 4, "e"), + new ScoreInfo(7, "0", 11, "§1§r§4prefix§r§4o§r§4suffix"), + new ScoreInfo(18, "0", 11, "§2§r§3prefix§r§3oa§r§3suffix") + )); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(19, "0", 11, "§0§r§5prefix§r§5ao§r§5suffix"), + new ScoreInfo(7, "0", 11, "§1§r§4prefix§r§4o§r§4suffix"), + new ScoreInfo(18, "0", 11, "§2§r§3prefix§r§3oa§r§3suffix") + )); + return packet; + }, context); + + // remove original 'o' score + context.translate( + resetScoreTranslator, + new ClientboundResetScorePacket("o", "objective") + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of( + new ScoreInfo(7, "0", 11, "§1§r§4prefix§r§4o§r§4suffix"), + new ScoreInfo(18, "0", 11, "§1§r§3prefix§r§3oa§r§3suffix") + )); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(18, "0", 11, "§1§r§3prefix§r§3oa§r§3suffix"), + new ScoreInfo(20, "0", 4, "e") + )); + return packet; + }, context); + + // remove the other score with the same value as 'o' + context.translate( + resetScoreTranslator, + new ClientboundResetScorePacket("oa", "objective") + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of( + new ScoreInfo(18, "0", 11, "§1§r§3prefix§r§3oa§r§3suffix"), + new ScoreInfo(19, "0", 11, "§5prefix§r§5ao§r§5suffix") + )); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of( + new ScoreInfo(19, "0", 11, "§5prefix§r§5ao§r§5suffix"), + new ScoreInfo(21, "0", 3, "c") + )); + return packet; + }, context); + }); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java new file mode 100644 index 000000000..0a02a58d9 --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java @@ -0,0 +1,265 @@ +/* + * 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.scoreboard.network.sidebar; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; + +import java.util.List; +import net.kyori.adventure.text.Component; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; +import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetScoreTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; +import org.junit.jupiter.api.Test; + +public class VanillaSidebarScoreboardTests { + @Test + void displayAndAddScore() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 1)); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); + return packet; + }, context); + }); + } + + @Test + void displayAndChangeScoreValue() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 1)); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); + return packet; + }, context); + assertNoNextPacket(context); + + context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 2)); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "owner"))); + return packet; + }, context); + }); + } + + @Test + void displayAndChangeScoreDisplayName() { + // this ensures that MCPE-143063 is properly handled + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 1)); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); + return packet; + }, context); + assertNoNextPacket(context); + + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket("owner", "objective", 1).withDisplay(Component.text("hi")) + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "hi"))); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "hi"))); + return packet; + }, context); + }); + } + + @Test + void displayAndChangeScoreDisplayNameAndValue() { + // this ensures that MCPE-143063 is properly handled + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "objective", + ObjectiveAction.ADD, + Component.text("objective"), + ScoreType.INTEGER, + null + ) + ); + context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 1)); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") + ); + assertNextPacket(() -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("objective"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); + return packet; + }, context); + assertNoNextPacket(context); + + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket("owner", "objective", 2).withDisplay(Component.text("hi")) + ); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.REMOVE); + packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "hi"))); + return packet; + }, context); + assertNextPacket(() -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "hi"))); + return packet; + }, context); + }); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java new file mode 100644 index 000000000..770131325 --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java @@ -0,0 +1,52 @@ +/* + * 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.scoreboard.network.util; + +import java.util.Collections; +import java.util.function.Supplier; +import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +import org.junit.jupiter.api.Assertions; + +public class AssertUtils { + public static void assertContextEquals(Supplier expected, T actual) { + if (actual == null) { + Assertions.fail("Expected another packet! " + expected.get()); + } + Assertions.assertEquals(expected.get(), actual); + } + + public static void assertNextPacket(Supplier expected, GeyserMockContext context) { + assertContextEquals(expected, context.nextPacket()); + } + + public static void assertNoNextPacket(GeyserMockContext context) { + Assertions.assertEquals( + Collections.emptyList(), + context.packets(), + "Expected no remaining packets, got " + context.packetCount() + ); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/EmptyGeyserLogger.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/EmptyGeyserLogger.java new file mode 100644 index 000000000..f147e766d --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/EmptyGeyserLogger.java @@ -0,0 +1,75 @@ +/* + * 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.scoreboard.network.util; + +import org.geysermc.geyser.GeyserLogger; + +public class EmptyGeyserLogger implements GeyserLogger { + @Override + public void severe(String message) { + + } + + @Override + public void severe(String message, Throwable error) { + + } + + @Override + public void error(String message) { + + } + + @Override + public void error(String message, Throwable error) { + + } + + @Override + public void warning(String message) { + + } + + @Override + public void info(String message) { + + } + + @Override + public void debug(String message) { + + } + + @Override + public void setDebug(boolean debug) { + + } + + @Override + public boolean isDebug() { + return false; + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java new file mode 100644 index 000000000..72515d714 --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java @@ -0,0 +1,143 @@ +/* + * 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.scoreboard.network.util; + +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.configuration.GeyserConfiguration; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +public class GeyserMockContext { + private final List mocksAndSpies = new ArrayList<>(); + private final List storedObjects = new ArrayList<>(); + private final List packets = Collections.synchronizedList(new ArrayList<>()); + private MockedStatic geyserImplMock; + + public static void mockContext(Consumer geyserContext) { + var context = new GeyserMockContext(); + + var geyserImpl = context.mock(GeyserImpl.class); + var config = context.mock(GeyserConfiguration.class); + + when(config.getScoreboardPacketThreshold()).thenReturn(1_000); + + when(geyserImpl.getConfig()).thenReturn(config); + + var logger = context.storeObject(new EmptyGeyserLogger()); + when(geyserImpl.getLogger()).thenReturn(logger); + + try (var mocked = mockStatic(GeyserImpl.class)) { + mocked.when(GeyserImpl::getInstance).thenReturn(geyserImpl); + context.geyserImplMock = mocked; + geyserContext.accept(context); + } + } + + public static void mockContext(Runnable runnable) { + mockContext(context -> runnable.run()); + } + + public T mock(Class type) { + return addMockOrSpy(Mockito.mock(type)); + } + + public T spy(T object) { + return addMockOrSpy(Mockito.spy(object)); + } + + private T addMockOrSpy(T mockOrSpy) { + mocksAndSpies.add(mockOrSpy); + return mockOrSpy; + } + + public T storeObject(T object) { + storedObjects.add(object); + return object; + } + + /** + * Retries the mock or spy that is an instance of the specified type. + * This is only really intended for classes where you only need a single instance of. + */ + public T mockOrSpy(Class type) { + for (Object mock : mocksAndSpies) { + if (type.isInstance(mock)) { + return type.cast(mock); + } + } + return null; + } + + public T storedObject(Class type) { + for (Object storedObject : storedObjects) { + if (type.isInstance(storedObject)) { + return type.cast(storedObject); + } + } + return null; + } + + public GeyserSession session() { + return mockOrSpy(GeyserSession.class); + } + + void addPacket(BedrockPacket packet) { + packets.add(packet); + } + + public int packetCount() { + return packets.size(); + } + + public BedrockPacket nextPacket() { + if (packets.isEmpty()) { + return null; + } + return packets.remove(0); + } + + public List packets() { + return Collections.unmodifiableList(packets); + } + + public void translate(PacketTranslator translator, T packet) { + translator.translate(session(), packet); + } + + public MockedStatic geyserImplMock() { + return geyserImplMock; + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java new file mode 100644 index 000000000..36ceeb79b --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java @@ -0,0 +1,93 @@ +/* + * 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.scoreboard.network.util; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContext.mockContext; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import java.util.UUID; +import java.util.function.Consumer; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataMap; +import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.EntityCache; +import org.geysermc.geyser.session.cache.WorldCache; +import org.mockito.stubbing.Answer; + +public class GeyserMockContextScoreboard { + public static void mockContextScoreboard(Consumer geyserContext) { + mockContext(context -> { + createSessionSpy(context); + geyserContext.accept(context); + + assertNoNextPacket(context); + }); + } + + private static void createSessionSpy(GeyserMockContext context) { + // GeyserSession has so many dependencies, it's easier to just mock it + var session = context.mock(GeyserSession.class); + + when(session.locale()).thenReturn("en_US"); + doAnswer((Answer) invocation -> { + context.addPacket(invocation.getArgument(0, BedrockPacket.class)); + return null; + }).when(session).sendUpstreamPacket(any()); + + // SessionPlayerEntity loads stuff in like blocks, which is not what we want + var playerEntity = context.mock(SessionPlayerEntity.class); + when(playerEntity.getGeyserId()).thenReturn(1L); + when(playerEntity.getUsername()).thenReturn("Tim203"); + when(session.getPlayerEntity()).thenReturn(playerEntity); + + var entityCache = context.spy(new EntityCache(session)); + when(session.getEntityCache()).thenReturn(entityCache); + + var worldCache = context.spy(new WorldCache(session)); + when(session.getWorldCache()).thenReturn(worldCache); + + // disable global scoreboard updater + when(worldCache.increaseAndGetScoreboardPacketsPerSecond()).thenReturn(0); + } + + public static PlayerEntity mockAndAddPlayerEntity(GeyserMockContext context, String username, long geyserId) { + var playerEntity = spy(new PlayerEntity(context.session(), geyserId, UUID.randomUUID(), username)); + // fake the player being spawned + when(playerEntity.isValid()).thenReturn(true); + + var entityCache = context.mockOrSpy(EntityCache.class); + entityCache.addPlayerEntity(playerEntity); + // called when the player spawns + entityCache.cacheEntity(playerEntity); + return playerEntity; + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 70d6e915d..51c76803a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,7 @@ neoforge-minecraft = "21.1.1" mixin = "0.8.5" mixinextras = "0.3.5" minecraft = "1.21.1" +mockito = "5.+" # plugin versions indra = "3.1.3" @@ -133,6 +134,8 @@ protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-con math = { group = "org.cloudburstmc.math", name = "immutable", version = "2.0" } +mockito = { module = "org.mockito:mockito-core", version.ref = "mockito" } + # plugins lombok = { group = "io.freefair.gradle", name = "lombok-plugin", version.ref = "lombok" } indra = { group = "net.kyori", name = "indra-common", version.ref = "indra" } From 521df04ed9ac866feeb7ac13404dc82da6d78136 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 9 Oct 2024 11:39:16 +0200 Subject: [PATCH 387/897] Fix experience orbs after the scoreboard rework Fixes #5075 --- .../geyser/entity/EntityDefinition.java | 21 +-- .../geyser/entity/EntityDefinitions.java | 126 ++++++++++++++++-- .../geysermc/geyser/entity/type/Entity.java | 5 +- .../entity/type/player/PlayerEntity.java | 15 +-- .../org/geysermc/geyser/util/EntityUtils.java | 7 +- .../geyser/util/EnvironmentUtils.java | 41 ++++++ .../network/TeamIdentifierTest.java | 61 +++++++++ .../scoreboard/network/util/AssertUtils.java | 8 ++ .../util/GeyserMockContextScoreboard.java | 5 +- 9 files changed, 250 insertions(+), 39 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java create mode 100644 core/src/test/java/org/geysermc/geyser/scoreboard/network/TeamIdentifierTest.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java index f9b65a545..ea3950bd4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.entity; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; -import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.util.List; +import java.util.Locale; +import java.util.function.BiConsumer; import lombok.Setter; import lombok.experimental.Accessors; import org.geysermc.geyser.GeyserImpl; @@ -37,10 +37,10 @@ import org.geysermc.geyser.entity.properties.GeyserEntityProperties; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.entity.EntityMetadataTranslator; - -import java.util.List; -import java.util.Locale; -import java.util.function.BiConsumer; +import org.geysermc.geyser.util.EnvironmentUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; /** * Represents data for an entity. This includes properties such as height and width, as well as the list of entity @@ -146,8 +146,13 @@ public record EntityDefinition(EntityFactory factory, Entit return this; } + /** + * Build the given entity. If a testing environment has been discovered the entity is not registered, + * otherwise it is. This is to prevent all the registries from loading, which will fail (and should + * not be loaded) while testing + */ public EntityDefinition build() { - return build(true); + return build(!EnvironmentUtils.isUnitTesting); } /** 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 5932ecf41..39357eb60 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -25,34 +25,131 @@ package org.geysermc.geyser.entity; -import org.geysermc.geyser.entity.type.AbstractWindChargeEntity; -import org.geysermc.geyser.entity.factory.EntityFactory; -import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.geyser.entity.factory.EntityFactory; import org.geysermc.geyser.entity.properties.GeyserEntityProperties; -import org.geysermc.geyser.entity.type.*; -import org.geysermc.geyser.entity.type.living.*; -import org.geysermc.geyser.entity.type.living.animal.*; -import org.geysermc.geyser.entity.type.living.animal.horse.*; +import org.geysermc.geyser.entity.type.AbstractArrowEntity; +import org.geysermc.geyser.entity.type.AbstractWindChargeEntity; +import org.geysermc.geyser.entity.type.AreaEffectCloudEntity; +import org.geysermc.geyser.entity.type.ArrowEntity; +import org.geysermc.geyser.entity.type.BoatEntity; +import org.geysermc.geyser.entity.type.ChestBoatEntity; +import org.geysermc.geyser.entity.type.CommandBlockMinecartEntity; +import org.geysermc.geyser.entity.type.DisplayBaseEntity; +import org.geysermc.geyser.entity.type.EnderCrystalEntity; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.entity.type.EvokerFangsEntity; +import org.geysermc.geyser.entity.type.ExpOrbEntity; +import org.geysermc.geyser.entity.type.FallingBlockEntity; +import org.geysermc.geyser.entity.type.FireballEntity; +import org.geysermc.geyser.entity.type.FireworkEntity; +import org.geysermc.geyser.entity.type.FishingHookEntity; +import org.geysermc.geyser.entity.type.FurnaceMinecartEntity; +import org.geysermc.geyser.entity.type.InteractionEntity; +import org.geysermc.geyser.entity.type.ItemEntity; +import org.geysermc.geyser.entity.type.ItemFrameEntity; +import org.geysermc.geyser.entity.type.LeashKnotEntity; +import org.geysermc.geyser.entity.type.LightningEntity; +import org.geysermc.geyser.entity.type.LivingEntity; +import org.geysermc.geyser.entity.type.MinecartEntity; +import org.geysermc.geyser.entity.type.PaintingEntity; +import org.geysermc.geyser.entity.type.SpawnerMinecartEntity; +import org.geysermc.geyser.entity.type.TNTEntity; +import org.geysermc.geyser.entity.type.TextDisplayEntity; +import org.geysermc.geyser.entity.type.ThrowableEntity; +import org.geysermc.geyser.entity.type.ThrowableItemEntity; +import org.geysermc.geyser.entity.type.ThrownPotionEntity; +import org.geysermc.geyser.entity.type.TridentEntity; +import org.geysermc.geyser.entity.type.WitherSkullEntity; +import org.geysermc.geyser.entity.type.living.AbstractFishEntity; +import org.geysermc.geyser.entity.type.living.AgeableEntity; +import org.geysermc.geyser.entity.type.living.AllayEntity; +import org.geysermc.geyser.entity.type.living.ArmorStandEntity; +import org.geysermc.geyser.entity.type.living.BatEntity; +import org.geysermc.geyser.entity.type.living.DolphinEntity; +import org.geysermc.geyser.entity.type.living.GlowSquidEntity; +import org.geysermc.geyser.entity.type.living.IronGolemEntity; +import org.geysermc.geyser.entity.type.living.MagmaCubeEntity; +import org.geysermc.geyser.entity.type.living.MobEntity; +import org.geysermc.geyser.entity.type.living.SlimeEntity; +import org.geysermc.geyser.entity.type.living.SnowGolemEntity; +import org.geysermc.geyser.entity.type.living.SquidEntity; +import org.geysermc.geyser.entity.type.living.TadpoleEntity; +import org.geysermc.geyser.entity.type.living.animal.ArmadilloEntity; +import org.geysermc.geyser.entity.type.living.animal.AxolotlEntity; +import org.geysermc.geyser.entity.type.living.animal.BeeEntity; +import org.geysermc.geyser.entity.type.living.animal.ChickenEntity; +import org.geysermc.geyser.entity.type.living.animal.CowEntity; +import org.geysermc.geyser.entity.type.living.animal.FoxEntity; +import org.geysermc.geyser.entity.type.living.animal.FrogEntity; +import org.geysermc.geyser.entity.type.living.animal.GoatEntity; +import org.geysermc.geyser.entity.type.living.animal.HoglinEntity; +import org.geysermc.geyser.entity.type.living.animal.MooshroomEntity; +import org.geysermc.geyser.entity.type.living.animal.OcelotEntity; +import org.geysermc.geyser.entity.type.living.animal.PandaEntity; +import org.geysermc.geyser.entity.type.living.animal.PigEntity; +import org.geysermc.geyser.entity.type.living.animal.PolarBearEntity; +import org.geysermc.geyser.entity.type.living.animal.PufferFishEntity; +import org.geysermc.geyser.entity.type.living.animal.RabbitEntity; +import org.geysermc.geyser.entity.type.living.animal.SheepEntity; +import org.geysermc.geyser.entity.type.living.animal.SnifferEntity; +import org.geysermc.geyser.entity.type.living.animal.StriderEntity; +import org.geysermc.geyser.entity.type.living.animal.TropicalFishEntity; +import org.geysermc.geyser.entity.type.living.animal.TurtleEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.CamelEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.ChestedHorseEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.HorseEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.SkeletonHorseEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.TraderLlamaEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.ZombieHorseEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.ParrotEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.TameableEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.entity.type.living.merchant.AbstractMerchantEntity; import org.geysermc.geyser.entity.type.living.merchant.VillagerEntity; -import org.geysermc.geyser.entity.type.living.monster.*; +import org.geysermc.geyser.entity.type.living.monster.AbstractSkeletonEntity; +import org.geysermc.geyser.entity.type.living.monster.BasePiglinEntity; +import org.geysermc.geyser.entity.type.living.monster.BlazeEntity; +import org.geysermc.geyser.entity.type.living.monster.BoggedEntity; +import org.geysermc.geyser.entity.type.living.monster.BreezeEntity; +import org.geysermc.geyser.entity.type.living.monster.CreeperEntity; +import org.geysermc.geyser.entity.type.living.monster.ElderGuardianEntity; +import org.geysermc.geyser.entity.type.living.monster.EnderDragonEntity; +import org.geysermc.geyser.entity.type.living.monster.EnderDragonPartEntity; +import org.geysermc.geyser.entity.type.living.monster.EndermanEntity; +import org.geysermc.geyser.entity.type.living.monster.GhastEntity; +import org.geysermc.geyser.entity.type.living.monster.GiantEntity; +import org.geysermc.geyser.entity.type.living.monster.GuardianEntity; +import org.geysermc.geyser.entity.type.living.monster.MonsterEntity; +import org.geysermc.geyser.entity.type.living.monster.PhantomEntity; +import org.geysermc.geyser.entity.type.living.monster.PiglinEntity; +import org.geysermc.geyser.entity.type.living.monster.ShulkerEntity; +import org.geysermc.geyser.entity.type.living.monster.SkeletonEntity; +import org.geysermc.geyser.entity.type.living.monster.SpiderEntity; +import org.geysermc.geyser.entity.type.living.monster.VexEntity; +import org.geysermc.geyser.entity.type.living.monster.WardenEntity; +import org.geysermc.geyser.entity.type.living.monster.WitherEntity; +import org.geysermc.geyser.entity.type.living.monster.ZoglinEntity; +import org.geysermc.geyser.entity.type.living.monster.ZombieEntity; +import org.geysermc.geyser.entity.type.living.monster.ZombieVillagerEntity; +import org.geysermc.geyser.entity.type.living.monster.ZombifiedPiglinEntity; import org.geysermc.geyser.entity.type.living.monster.raid.PillagerEntity; import org.geysermc.geyser.entity.type.living.monster.raid.RaidParticipantEntity; +import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity; import org.geysermc.geyser.entity.type.living.monster.raid.SpellcasterIllagerEntity; import org.geysermc.geyser.entity.type.living.monster.raid.VindicatorEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.EnvironmentUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; public final class EntityDefinitions { public static final EntityDefinition ALLAY; @@ -1025,7 +1122,10 @@ public final class EntityDefinitions { .identifier("minecraft:armor_stand") // Emulated .build(false); // Never sent over the network - 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 + // causes the registries to load + if (!EnvironmentUtils.isUnitTesting) { + 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 + } } public static void init() { 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 983455da8..a016916f0 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 @@ -427,7 +427,10 @@ public class Entity implements GeyserEntity { } public String teamIdentifier() { - return uuid.toString(); + // experience orbs are the only known entities that do not send an uuid (even though they do have one), + // but to be safe in the future it's done in the entity class itself instead of the entity specific one. + // All entities without an uuid cannot show up in the scoreboard! + return uuid != null ? uuid.toString() : null; } public void setDisplayName(EntityMetadata, ?> entityMetadata) { 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 85905d716..4e0de44ea 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 @@ -53,7 +53,6 @@ import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; -import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.Entity; @@ -66,7 +65,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; @Getter @Setter public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { @@ -118,18 +116,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { * Do not use! For testing purposes only */ public PlayerEntity(GeyserSession session, long geyserId, UUID uuid, String username) { - super( - session, - -1, - geyserId, - uuid, - EntityDefinition.builder(null).type(EntityType.PLAYER).build(false), - Vector3f.ZERO, - Vector3f.ZERO, - 0, - 0, - 0 - ); + super(session, -1, geyserId, uuid, EntityDefinitions.PLAYER, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0); this.username = username; this.nametag = username; this.texturesProperty = null; 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 b7f4e7d76..9e365ab67 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.util; +import java.util.Locale; import net.kyori.adventure.key.Key; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameType; @@ -46,8 +47,6 @@ 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. @@ -294,6 +293,10 @@ public final class EntityUtils { } private static String translatedEntityName(String namespace, String name, GeyserSession session) { + // MinecraftLocale would otherwise invoke getBootstrap (which doesn't exist) and create some folders + if (EnvironmentUtils.isUnitTesting) { + return "entity." + namespace + "." + name; + } return MinecraftLocale.getLocaleString("entity." + namespace + "." + name, session.locale()); } diff --git a/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java b/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java new file mode 100644 index 000000000..909398bf4 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java @@ -0,0 +1,41 @@ +/* + * 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.util; + +public final class EnvironmentUtils { + public static final boolean isUnitTesting = isUnitTesting(); + + private EnvironmentUtils() {} + + private static boolean isUnitTesting() { + for (StackTraceElement element : Thread.currentThread().getStackTrace()) { + if (element.getClassName().startsWith("org.junit.")) { + return true; + } + } + return false; + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/TeamIdentifierTest.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/TeamIdentifierTest.java new file mode 100644 index 000000000..c7fa866e1 --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/TeamIdentifierTest.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.scoreboard.network; + +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketType; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket; +import org.geysermc.geyser.translator.protocol.java.entity.JavaRemoveEntitiesTranslator; +import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddExperienceOrbTranslator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRemoveEntitiesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; +import org.junit.jupiter.api.Test; + +public class TeamIdentifierTest { + @Test + void entityWithoutUuid() { + // experience orbs are the only known entities without an uuid, see Entity#teamIdentifier for more info + mockContextScoreboard(context -> { + var addExperienceOrbTranslator = new JavaAddExperienceOrbTranslator(); + var removeEntitiesTranslator = new JavaRemoveEntitiesTranslator(); + + // Entity#teamIdentifier used to throw because it returned uuid.toString where uuid could be null. + // this would result in both EntityCache#spawnEntity and EntityCache#removeEntity throwing an exception, + // because the entity would be registered and deregistered to the scoreboard. + assertDoesNotThrow(() -> { + context.translate(addExperienceOrbTranslator, new ClientboundAddExperienceOrbPacket(2, 0, 0, 0, 1)); + context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[] { 2 })); + }); + + // we know that spawning and removing the entity should be fine + assertNextPacketType(context, AddEntityPacket.class); + assertNextPacketType(context, RemoveEntityPacket.class); + }); + } +} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java index 770131325..b15994533 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java @@ -42,6 +42,14 @@ public class AssertUtils { assertContextEquals(expected, context.nextPacket()); } + public static void assertNextPacketType(GeyserMockContext context, Class type) { + var actual = context.nextPacket(); + if (actual == null) { + Assertions.fail("Expected another packet! " + type); + } + Assertions.assertEquals(type, actual.getClass()); + } + public static void assertNoNextPacket(GeyserMockContext context) { Assertions.assertEquals( Collections.emptyList(), diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java index 36ceeb79b..bc76a1b70 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java @@ -34,8 +34,8 @@ import static org.mockito.Mockito.when; import java.util.UUID; import java.util.function.Consumer; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataMap; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.session.GeyserSession; @@ -57,7 +57,10 @@ public class GeyserMockContextScoreboard { // GeyserSession has so many dependencies, it's easier to just mock it var session = context.mock(GeyserSession.class); + when(session.getGeyser()).thenReturn(context.mockOrSpy(GeyserImpl.class)); + when(session.locale()).thenReturn("en_US"); + doAnswer((Answer) invocation -> { context.addPacket(invocation.getArgument(0, BedrockPacket.class)); return null; From 123c5cc5d82807f364dc7bb1b195919ca74a0e7f Mon Sep 17 00:00:00 2001 From: Tim203 Date: Thu, 10 Oct 2024 14:18:35 +0200 Subject: [PATCH 388/897] Check whether the entity definition has a type Fixes #5078 --- .../org/geysermc/geyser/util/EntityUtils.java | 15 +++++--- ...ierTest.java => ScoreboardIssueTests.java} | 34 ++++++++++++++++++- 2 files changed, 44 insertions(+), 5 deletions(-) rename core/src/test/java/org/geysermc/geyser/scoreboard/network/{TeamIdentifierTest.java => ScoreboardIssueTests.java} (69%) 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 9e365ab67..8e5a57fae 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -27,6 +27,8 @@ 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; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -292,22 +294,27 @@ public final class EntityUtils { }; } - private static String translatedEntityName(String namespace, String name, GeyserSession session) { - // MinecraftLocale would otherwise invoke getBootstrap (which doesn't exist) and create some folders + private static String translatedEntityName(@NonNull String namespace, @NonNull String name, @NonNull GeyserSession session) { + // MinecraftLocale would otherwise invoke getBootstrap (which doesn't exist) and create some folders, + // so use the default fallback value as used in Minecraft Java if (EnvironmentUtils.isUnitTesting) { return "entity." + namespace + "." + name; } return MinecraftLocale.getLocaleString("entity." + namespace + "." + name, session.locale()); } - public static String translatedEntityName(Key type, GeyserSession session) { + public static String translatedEntityName(@NonNull Key type, @NonNull GeyserSession session) { return translatedEntityName(type.namespace(), type.value(), session); } - public static String translatedEntityName(EntityType type, GeyserSession session) { + public static String translatedEntityName(@Nullable EntityType type, @NonNull GeyserSession session) { if (type == EntityType.PLAYER) { return "Player"; // the player's name is always shown instead } + // default fallback value as used in Minecraft Java + if (type == null) { + return "entity.unregistered_sadface"; + } // this works at least with all 1.20.5 entities, except the killer bunny since that's not an entity type. String typeName = type.name().toLowerCase(Locale.ROOT); return translatedEntityName("minecraft", typeName, session); diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/TeamIdentifierTest.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java similarity index 69% rename from core/src/test/java/org/geysermc/geyser/scoreboard/network/TeamIdentifierTest.java rename to core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java index c7fa866e1..1ec245007 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/TeamIdentifierTest.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java @@ -28,16 +28,25 @@ package org.geysermc.geyser.scoreboard.network; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketType; 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 org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket; +import org.geysermc.geyser.entity.type.living.monster.EnderDragonPartEntity; +import org.geysermc.geyser.session.cache.EntityCache; import org.geysermc.geyser.translator.protocol.java.entity.JavaRemoveEntitiesTranslator; import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddExperienceOrbTranslator; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRemoveEntitiesPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; import org.junit.jupiter.api.Test; -public class TeamIdentifierTest { +/** + * Tests that don't fit in a larger system (e.g. sidebar objective) that were reported on GitHub + */ +public class ScoreboardIssueTests { + /** + * Test for #5075 + */ @Test void entityWithoutUuid() { // experience orbs are the only known entities without an uuid, see Entity#teamIdentifier for more info @@ -50,6 +59,10 @@ public class TeamIdentifierTest { // because the entity would be registered and deregistered to the scoreboard. assertDoesNotThrow(() -> { context.translate(addExperienceOrbTranslator, new ClientboundAddExperienceOrbPacket(2, 0, 0, 0, 1)); + + String displayName = context.mockOrSpy(EntityCache.class).getEntityByJavaId(2).getDisplayName(); + assertEquals("entity.minecraft.experience_orb", displayName); + context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[] { 2 })); }); @@ -58,4 +71,23 @@ public class TeamIdentifierTest { assertNextPacketType(context, RemoveEntityPacket.class); }); } + + /** + * Test for #5078 + */ + @Test + void entityWithoutType() { + // dragon entity parts are an entity in Geyser, but do not have an entity type + mockContextScoreboard(context -> { + // EntityUtils#translatedEntityName used to not take null EntityType's into account, + // so it used to throw an exception + assertDoesNotThrow(() -> { + // dragon entity parts are not spawned using a packet, so we manually create an instance + var dragonHeadPart = new EnderDragonPartEntity(context.session(), 2, 2, 1, 1); + + String displayName = dragonHeadPart.getDisplayName(); + assertEquals("entity.unregistered_sadface", displayName); + }); + }); + } } From 50de9d6867ac66184c459aef104195d10660dcb7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:27:49 -0400 Subject: [PATCH 389/897] Fix PROXY protocol support --- .../geyser/network/netty/LocalSession.java | 43 ++++++++++++------- gradle/libs.versions.toml | 2 +- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index d9e450c62..739c1c25e 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -27,7 +27,8 @@ package org.geysermc.geyser.network.netty; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; @@ -101,7 +102,7 @@ public final class LocalSession extends TcpSession { ChannelPipeline pipeline = channel.pipeline(); - initializeHAProxySupport(channel); + addHAProxySupport(pipeline); pipeline.addLast("read-timeout", new ReadTimeoutHandler(getFlag(BuiltinFlags.READ_TIMEOUT, 30))); pipeline.addLast("write-timeout", new WriteTimeoutHandler(getFlag(BuiltinFlags.WRITE_TIMEOUT, 0))); @@ -142,21 +143,33 @@ public final class LocalSession extends TcpSession { return (MinecraftCodecHelper) this.codecHelper; } - private void initializeHAProxySupport(Channel channel) { + // TODO duplicate code + private void addHAProxySupport(ChannelPipeline pipeline) { InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); - if (clientAddress == null) { - return; + if (clientAddress != null) { + pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() { + @Override + public void channelActive(@NonNull ChannelHandlerContext ctx) throws Exception { + HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6; + InetSocketAddress remoteAddress; + if (ctx.channel().remoteAddress() instanceof InetSocketAddress) { + remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); + } else { + remoteAddress = new InetSocketAddress(host, port); + } + ctx.channel().writeAndFlush(new HAProxyMessage( + HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol, + clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(), + clientAddress.getPort(), remoteAddress.getPort() + )); + ctx.pipeline().remove(this); + ctx.pipeline().remove("proxy-protocol-encoder"); + super.channelActive(ctx); + } + }); + pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE); + } } - - channel.pipeline().addLast("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE); - HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6; - InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress(); - channel.writeAndFlush(new HAProxyMessage( - HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol, - clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(), - clientAddress.getPort(), remoteAddress.getPort() - )).addListener(future -> channel.pipeline().remove("proxy-protocol-encoder")); - } /** * Should only be called when direct ByteBufs should be preferred. At this moment, this should only be called on BungeeCord. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 51c76803a..3a3831044 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20240916.181041-6" protocol-codec = "3.0.0.Beta5-20240916.181041-6" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21-20241008.134549-23" +mcprotocollib = "1.21-20241010.155958-24" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From d64c0b38dadb2d9d6c9712af18013af4daa056eb Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 13 Oct 2024 01:12:58 +0800 Subject: [PATCH 390/897] Fix: Extension command arg parsing (#5081) * Fix: No args being parsed as 1 arg, and don't try to localize extension command's descriptions * add comment --- .../geyser/extension/command/GeyserExtensionCommand.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java b/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java index 0b22a8b8e..0dc49f5c1 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java +++ b/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java @@ -38,6 +38,7 @@ import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.incendo.cloud.CommandManager; import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.description.CommandDescription; import java.util.ArrayList; import java.util.List; @@ -193,11 +194,17 @@ public abstract class GeyserExtensionCommand extends GeyserCommand { .handler(this::execute)); } + @Override + protected org.incendo.cloud.Command.Builder.Applicable meta() { + // We don't want to localize the extension command description + return builder -> builder.commandDescription(CommandDescription.commandDescription(description)); + } + @SuppressWarnings("unchecked") @Override public void execute(CommandContext context) { GeyserCommandSource source = context.sender(); - String[] args = context.getOrDefault("args", "").split(" "); + String[] args = context.getOrDefault("args", " ").split(" "); if (sourceType.isInstance(source)) { executor.execute((T) source, this, args); From e2f40569f8e07b7ec4502a056ad64454e26c8952 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 19 Oct 2024 22:38:04 -0400 Subject: [PATCH 391/897] Get some bits going --- .../geyser/entity/type/LivingEntity.java | 31 +- .../type/living/animal/horse/CamelEntity.java | 2 +- .../type/player/SessionPlayerEntity.java | 4 +- .../entity/vehicle/VehicleComponent.java | 4 +- .../geyser/inventory/item/Potion.java | 2 +- .../java/org/geysermc/geyser/item/Items.java | 214 +- .../geysermc/geyser/level/block/Blocks.java | 3502 +++++++++-------- .../level/block/property/Properties.java | 2 + .../geyser/level/physics/CollisionResult.java | 34 + .../geyser/session/GeyserSession.java | 5 +- .../inventory/InventoryTranslator.java | 8 +- .../JavaClientboundRecipesTranslator.java | 82 - ....java => JavaLoginFinishedTranslator.java} | 12 +- .../java/JavaRecipeBookAddTranslator.java | 81 + .../java/JavaUpdateRecipesTranslator.java | 913 +++-- ...or.java => JavaSetHeldSlotTranslator.java} | 8 +- .../JavaContainerSetSlotTranslator.java | 4 +- gradle/libs.versions.toml | 2 +- 18 files changed, 2528 insertions(+), 2382 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundRecipesTranslator.java rename core/src/main/java/org/geysermc/geyser/translator/protocol/java/{JavaGameProfileTranslator.java => JavaLoginFinishedTranslator.java} (91%) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookAddTranslator.java rename core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/{JavaSetCarriedItemTranslator.java => JavaSetHeldSlotTranslator.java} (86%) 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/animal/horse/CamelEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java index 3c0bf1a70..b83a85bfb 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 @@ -141,7 +141,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/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index f427b001a..a8b0765f3 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 @@ -247,9 +247,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..4f4a46dc9 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(); 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/item/Items.java b/core/src/main/java/org/geysermc/geyser/item/Items.java index 462e98d19..ba4b37ff5 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 LEATHER_HORSE_ARMOR = register(new DyeableArmorItem("leather_horse_armor", ArmorMaterial.LEATHER, 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 Item("leather_horse_armor", 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/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/CollisionResult.java b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java new file mode 100644 index 000000000..8ba5f895b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java @@ -0,0 +1,34 @@ +/* + * 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.level.physics; + +import org.cloudburstmc.math.vector.Vector3d; + +/** + * Holds the result of a collision check. + */ +public record CollisionResult(Vector3d correctedMovement, boolean horizontalCollision) { +} 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 9c20e9909..db802439f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -191,7 +191,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; @@ -207,8 +206,6 @@ 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; @@ -1275,7 +1272,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { 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(), + ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(), false, //FIXME position.getX(), position.getY(), position.getZ()); sendDownstreamGamePacket(packet); } 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..f051885d4 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 @@ -729,10 +729,10 @@ public abstract class InventoryTranslator { if (ingRemaining == 0) { while (++ingredientIndex < ingredients.length) { - if (ingredients[ingredientIndex].getOptions().length != 0) { - ingRemaining = timesCrafted; - break; - } +// if (ingredients[ingredientIndex].getOptions().length != 0) { +// ingRemaining = timesCrafted; +// break; +// } } } 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/JavaClientboundRecipesTranslator.java deleted file mode 100644 index 9eb69183d..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundRecipesTranslator.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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 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 java.util.ArrayList; -import java.util.List; - -@Translator(packet = ClientboundRecipePacket.class) -public class JavaClientboundRecipesTranslator 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); - } - } - session.sendUpstreamPacket(recipesPacket); - } - - private List getBedrockRecipes(GeyserSession session, String[] javaRecipeIdentifiers) { - List recipes = new ArrayList<>(); - for (String javaIdentifier : javaRecipeIdentifiers) { - 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. - if (bedrockRecipes != null) { - recipes.addAll(bedrockRecipes); - } - } - return recipes; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginFinishedTranslator.java similarity index 91% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginFinishedTranslator.java index 47d1cff08..cebf71efd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginFinishedTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java; -import org.geysermc.mcprotocollib.auth.GameProfile; import net.kyori.adventure.key.Key; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.PlayerEntity; @@ -34,17 +33,18 @@ import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.PluginMessageUtils; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; -import org.geysermc.mcprotocollib.protocol.packet.login.clientbound.ClientboundGameProfilePacket; +import org.geysermc.mcprotocollib.protocol.packet.login.clientbound.ClientboundLoginFinishedPacket; /** - * ClientboundGameProfilePacket triggers protocol change LOGIN -> 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..74fb11814 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookAddTranslator.java @@ -0,0 +1,81 @@ +/* + * 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 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.ClientboundRecipeBookAddPacket; + +@Translator(packet = ClientboundRecipeBookAddPacket.class) +public class JavaRecipeBookAddTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundRecipeBookAddPacket packet) { + UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket(); + recipesPacket.setAction(packet.isReplace() ? UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED : UnlockedRecipesPacket.ActionType.NEWLY_UNLOCKED); +// List recipes = getBedrockRecipes(session, packet.getEntries()); +// if (recipes.isEmpty() && !packet.isReplace()) { +// // Sending an empty list here packet will crash the client as of 1.20.60 +// return; +// } +// switch (packet.getAction()) { +// case INIT -> { +// recipesPacket.setAction(UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED); +// recipesPacket.getUnlockedRecipes().addAll(getBedrockRecipes(session, packet.getAlreadyKnownRecipes())); +// } +// case ADD -> { +// +// 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); +// } +// } +// session.sendUpstreamPacket(recipesPacket); + } + +// private List getBedrockRecipes(GeyserSession session, List entry) { +// List recipes = new ArrayList<>(); +// for (String javaIdentifier : javaRecipeIdentifiers) { +// 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. +// if (bedrockRecipes != null) { +// recipes.addAll(bedrockRecipes); +// } +// } +// return recipes; +// } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 689e0448a..e6e875791 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -25,61 +25,18 @@ package org.geysermc.geyser.translator.protocol.java; -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.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; -import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; -import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.RecipeUnlockingRequirement; +import net.kyori.adventure.key.Key; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.MultiRecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData; -import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTrimRecipeData; -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.TrimDataPacket; -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.inventory.recipe.GeyserStonecutterData; -import org.geysermc.geyser.inventory.recipe.TrimRecipe; -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.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.Recipe; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapedRecipeData; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapelessRecipeData; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.SmithingTransformRecipeData; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.StoneCuttingRecipeData; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; @@ -121,437 +78,443 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator> recipeIDs = session.getJavaToBedrockRecipeIds(); - recipeIDs.clear(); - Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(); - Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); - 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) { - // BDS sends armor trim templates and materials before the CraftingDataPacket - TrimDataPacket trimDataPacket = new TrimDataPacket(); - trimDataPacket.getPatterns().addAll(session.getRegistryCache().trimPatterns().values()); - trimDataPacket.getMaterials().addAll(session.getRegistryCache().trimMaterials().values()); - session.sendUpstreamPacket(trimDataPacket); - - // Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the - // approach of using many default-descriptors (which we do for smithing_transform) - craftingDataPacket.getCraftingData().add(SmithingTrimRecipeData.of(TrimRecipe.ID, - TrimRecipe.BASE, TrimRecipe.ADDITION, TrimRecipe.TEMPLATE, "smithing_table", session.getLastRecipeNetId().getAndIncrement())); - } else { - // manually add recipes for the upgrade template (workaround), since Java pre-1.20 doesn't - craftingDataPacket.getCraftingData().addAll(getSmithingTransformRecipes(session)); - } - session.setOldSmithingTable(!sendTrimRecipes); - session.sendUpstreamPacket(craftingDataPacket); - session.setCraftingRecipes(recipeMap); - session.setStonecutterRecipes(stonecutterRecipeMap); - } - - //TODO: rewrite - /** - * The Java server sends an array of items for each ingredient you can use per slot in the crafting grid. - * Bedrock recipes take only one ingredient per crafting grid slot. - * - * @return the Java ingredient list as an array that Bedrock can understand - */ - private static ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) { - boolean empty = true; - Map, 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); - 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(); - - String recipeTag = RECIPE_TAGS.get(groupedItem.id.getIdentifier()); - if (recipeTag != null && ingredients.length > 1) { - optionSet.add(new ItemDescriptorWithCount(new ItemTagDescriptor(recipeTag), groupedItem.count)); - continue; - } - - 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); - } - } - 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; - } - } - 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; - } - - private List getSmithingTransformRecipes(GeyserSession session) { - List recipes = new ArrayList<>(); - 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", - getDescriptorFromId(session, template.getBedrockIdentifier()), - getDescriptorFromId(session, identifier.replace("netherite", "diamond")), - getDescriptorFromId(session, "minecraft:netherite_ingot"), - ItemData.builder().definition(Objects.requireNonNull(session.getItemMappings().getDefinition(identifier))).count(1).build(), - "smithing_table", - session.getLastRecipeNetId().getAndIncrement())); - } - return recipes; - } - - private ItemDescriptorWithCount getDescriptorFromId(GeyserSession session, String bedrockId) { - ItemDefinition bedrockDefinition = session.getItemMappings().getDefinition(bedrockId); - if (bedrockDefinition != null) { - return ItemDescriptorWithCount.fromItem(ItemData.builder().definition(bedrockDefinition).count(1).build()); - } - GeyserImpl.getInstance().getLogger().debug("Unable to find item with identifier " + bedrockId); - return ItemDescriptorWithCount.EMPTY; - } - - @EqualsAndHashCode - @AllArgsConstructor - private static class GroupedItem { - ItemDefinition id; - int count; - } - - private static final class RecipeContext { - private final GeyserSession session; - private final CraftingDataPacket packet; - private final Int2ObjectMap 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++; - } + // :( } +// boolean sendTrimRecipes = false; +// Map> recipeIDs = session.getJavaToBedrockRecipeIds(); +// recipeIDs.clear(); +// Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(); +// Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); +// 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) { +// // BDS sends armor trim templates and materials before the CraftingDataPacket +// TrimDataPacket trimDataPacket = new TrimDataPacket(); +// trimDataPacket.getPatterns().addAll(session.getRegistryCache().trimPatterns().values()); +// trimDataPacket.getMaterials().addAll(session.getRegistryCache().trimMaterials().values()); +// session.sendUpstreamPacket(trimDataPacket); +// +// // Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the +// // approach of using many default-descriptors (which we do for smithing_transform) +// craftingDataPacket.getCraftingData().add(SmithingTrimRecipeData.of(TrimRecipe.ID, +// TrimRecipe.BASE, TrimRecipe.ADDITION, TrimRecipe.TEMPLATE, "smithing_table", session.getLastRecipeNetId().getAndIncrement())); +// } else { +// // manually add recipes for the upgrade template (workaround), since Java pre-1.20 doesn't +// craftingDataPacket.getCraftingData().addAll(getSmithingTransformRecipes(session)); +// } +// session.setOldSmithingTable(!sendTrimRecipes); +// session.sendUpstreamPacket(craftingDataPacket); +// session.setCraftingRecipes(recipeMap); +// session.setStonecutterRecipes(stonecutterRecipeMap); +// } +// +// //TODO: rewrite +// /** +// * The Java server sends an array of items for each ingredient you can use per slot in the crafting grid. +// * Bedrock recipes take only one ingredient per crafting grid slot. +// * +// * @return the Java ingredient list as an array that Bedrock can understand +// */ +// private static ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) { +// boolean empty = true; +// Map, 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); +// 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(); +// +// String recipeTag = RECIPE_TAGS.get(groupedItem.id.getIdentifier()); +// if (recipeTag != null && ingredients.length > 1) { +// optionSet.add(new ItemDescriptorWithCount(new ItemTagDescriptor(recipeTag), groupedItem.count)); +// continue; +// } +// +// 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); +// } +// } +// 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; +// } +// } +// 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; +// } +// +// private List getSmithingTransformRecipes(GeyserSession session) { +// List recipes = new ArrayList<>(); +// 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", +// getDescriptorFromId(session, template.getBedrockIdentifier()), +// getDescriptorFromId(session, identifier.replace("netherite", "diamond")), +// getDescriptorFromId(session, "minecraft:netherite_ingot"), +// ItemData.builder().definition(Objects.requireNonNull(session.getItemMappings().getDefinition(identifier))).count(1).build(), +// "smithing_table", +// session.getLastRecipeNetId().getAndIncrement())); +// } +// return recipes; +// } +// +// private ItemDescriptorWithCount getDescriptorFromId(GeyserSession session, String bedrockId) { +// ItemDefinition bedrockDefinition = session.getItemMappings().getDefinition(bedrockId); +// if (bedrockDefinition != null) { +// return ItemDescriptorWithCount.fromItem(ItemData.builder().definition(bedrockDefinition).count(1).build()); +// } +// GeyserImpl.getInstance().getLogger().debug("Unable to find item with identifier " + bedrockId); +// return ItemDescriptorWithCount.EMPTY; +// } +// +// @EqualsAndHashCode +// @AllArgsConstructor +// private static class GroupedItem { +// ItemDefinition id; +// int count; +// } +// +// private static final class RecipeContext { +// private final GeyserSession session; +// private final CraftingDataPacket packet; +// private final Int2ObjectMap 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/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 9b5d95afe..ed3abdfe4 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 @@ -59,7 +59,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator Date: Mon, 21 Oct 2024 00:36:02 +0800 Subject: [PATCH 392/897] Fix: Late Geyser response to ClientboundSelectKnownPacks packet (#5090) --- .../protocol/java/JavaSelectKnownPacksTranslator.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java index 6b1c8c645..9192beacf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java @@ -59,4 +59,9 @@ public class JavaSelectKnownPacksTranslator extends PacketTranslator Date: Sun, 20 Oct 2024 14:54:27 -0400 Subject: [PATCH 393/897] Boat changes applied --- .../geyser/entity/EntityDefinitions.java | 92 +++++++++++++++---- .../geyser/entity/type/BoatEntity.java | 46 +++++++--- .../geyser/entity/type/ChestBoatEntity.java | 10 +- .../BedrockEntityPickRequestTranslator.java | 25 +---- ...BedrockInventoryTransactionTranslator.java | 5 +- .../BedrockMoveEntityAbsoluteTranslator.java | 3 +- .../bedrock/BedrockPlayerInputTranslator.java | 16 ++-- .../player/BedrockActionTranslator.java | 1 + .../player/BedrockInteractTranslator.java | 14 +-- .../player/BedrockMovePlayerTranslator.java | 5 +- .../BedrockLevelSoundEventTranslator.java | 1 + .../java/level/JavaCooldownTranslator.java | 2 +- .../org/geysermc/geyser/util/EntityUtils.java | 44 +++++---- .../geysermc/geyser/util/InventoryUtils.java | 13 +-- 14 files changed, 178 insertions(+), 99 deletions(-) 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 39357eb60..1443a9443 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -152,29 +152,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; @@ -213,14 +221,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; @@ -251,6 +265,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; @@ -309,23 +325,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) @@ -568,6 +567,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) @@ -1128,6 +1166,22 @@ public final class EntityDefinitions { } } + 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..9312d83f5 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,11 +32,12 @@ 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 java.util.UUID; @@ -63,16 +64,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 +128,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) { @@ -212,6 +207,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 +218,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/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..7ed4ac72c 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 @@ -296,6 +296,7 @@ public class BedrockInventoryTransactionTranslator 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/BedrockMovePlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java index ee80cac16..c4cb10127 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/BedrockMovePlayerTranslator.java @@ -84,7 +84,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator 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 a0bd5a4c7..11ed17872 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -485,7 +485,7 @@ public class InventoryUtils { } for (int i = 0; i < data.ingredients().length; i++) { Ingredient ingredient = data.ingredients()[i]; - for (ItemStack itemStack : ingredient.getOptions()) { + for (int item : ingredient.getValues().getHolders()) { // FIXME boolean inventoryHasItem = false; // Iterate only over the crafting table to find this item crafting: @@ -493,11 +493,11 @@ public class InventoryUtils { 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; + inventoryHasItem = item == 0; if (inventoryHasItem) { break crafting; } - } else if (itemStack.equals(geyserItemStack.getItemStack(1))) { + } else if (item == geyserItemStack.getJavaId()) { inventoryHasItem = true; break crafting; } @@ -522,14 +522,15 @@ public class InventoryUtils { 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) { + int[] items = ingredient.getValues().getHolders(); // FIXME + if (items.length == 0) { if (!geyserItemStack.isEmpty()) { return false; } } else { boolean inventoryHasItem = false; - for (ItemStack item : ingredient.getOptions()) { - if (Objects.equals(geyserItemStack.getItemStack(1), item)) { + for (int item : items) { + if (geyserItemStack.getJavaId() == item) { inventoryHasItem = true; break; } From 04128907b452af7880113878b5f98509af4353ae Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:19:18 -0400 Subject: [PATCH 394/897] More progress --- .../player/JavaPlayerPositionTranslator.java | 22 ++++---- .../java/level/JavaExplodeTranslator.java | 55 +++++-------------- .../level/JavaLevelParticlesTranslator.java | 9 +-- .../java/level/JavaSetTimeTranslator.java | 16 ++---- 4 files changed, 37 insertions(+), 65 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java index 413833acf..5fc7f7200 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java @@ -53,7 +53,7 @@ public class JavaPlayerPositionTranslator extends PacketTranslator 32 && !session.isEmulatePost1_13Logic()) { // See DimensionUtils for an explanation @@ -92,23 +92,23 @@ public class JavaPlayerPositionTranslator 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 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(); // TEST 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()); } } } From aaf95effc4b7c6ab3b8bdc9a29f4e4e7ae6b096e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:50:41 -0400 Subject: [PATCH 395/897] IT BOOOOOOOOOTS --- .../registry/loader/RecipeRegistryLoader.java | 8 ++- .../populator/BlockRegistryPopulator.java | 2 +- .../populator/ItemRegistryPopulator.java | 3 +- .../geyser/session/GeyserSession.java | 3 +- .../JavaEntityPositionSyncTranslator.java | 52 +++++++++++++++++++ .../entity/JavaTeleportEntityTranslator.java | 14 +---- .../player/JavaPlayerPositionTranslator.java | 22 ++++---- .../JavaContainerSetSlotTranslator.java | 5 +- 8 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityPositionSyncTranslator.java 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..1af6a8661 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 @@ -49,6 +49,7 @@ import java.io.DataInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Base64; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -60,6 +61,9 @@ public final class RecipeRegistryLoader implements RegistryLoader> load(String input) { + if (true) { + return Collections.emptyMap(); + } Map> deserializedRecipes = new Object2ObjectOpenHashMap<>(); List recipes; @@ -96,7 +100,7 @@ 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)); } @@ -121,7 +125,7 @@ public final class RecipeRegistryLoader implements RegistryLoader { + + @Override + public void translate(GeyserSession session, ClientboundEntityPositionSyncPacket packet) { + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getId()); + if (entity == null) return; + + Vector3d pos = packet.getPosition(); + + if (entity instanceof ClientVehicle clientVehicle) { + clientVehicle.getVehicleComponent().moveAbsolute(pos.getX(), pos.getY(), pos.getZ()); + } + + entity.teleport(pos.toFloat(), packet.getXRot(), packet.getYRot(), 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/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java index 5fc7f7200..e73e25a93 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; +import org.cloudburstmc.math.vector.Vector3d; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PositionElement; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket; @@ -50,14 +51,15 @@ public class JavaPlayerPositionTranslator extends PacketTranslator Date: Tue, 22 Oct 2024 12:25:13 +0700 Subject: [PATCH 396/897] Protocol Update 1.21.40 (#5091) Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../standalone/src/main/resources/log4j2.xml | 5 +- .../geyser/impl/camera/CameraDefinitions.java | 14 +- .../updater/AnvilInventoryUpdater.java | 8 +- .../updater/ChestInventoryUpdater.java | 2 + .../updater/ContainerInventoryUpdater.java | 2 + .../updater/CrafterInventoryUpdater.java | 3 + .../updater/HorseInventoryUpdater.java | 2 + .../inventory/updater/InventoryUpdater.java | 2 + .../inventory/updater/UIInventoryUpdater.java | 3 + .../geyser/level/block/type/BlockState.java | 2 +- .../geyser/network/CodecProcessor.java | 25 +- .../geysermc/geyser/network/GameProtocol.java | 14 +- .../geyser/network/UpstreamPacketHandler.java | 2 +- .../populator/BlockRegistryPopulator.java | 21 + .../populator/ItemRegistryPopulator.java | 2 + .../inventory/OldSmithingTableTranslator.java | 1 + .../inventory/PlayerInventoryTranslator.java | 6 + .../ChestedHorseInventoryTranslator.java | 2 + .../entity/SkullBlockEntityTranslator.java | 5 +- .../entity/JavaEntityEventTranslator.java | 2 + .../JavaContainerSetSlotTranslator.java | 2 + .../geysermc/geyser/util/InventoryUtils.java | 1 + .../resources/bedrock/biome_definitions.dat | Bin 41832 -> 37653 bytes .../bedrock/block_palette.1_21_40.nbt | Bin 0 -> 181156 bytes .../bedrock/creative_items.1_21_40.json | 6262 +++++++++++++++ .../bedrock/runtime_item_states.1_21_40.json | 6994 +++++++++++++++++ gradle/libs.versions.toml | 6 +- 27 files changed, 13367 insertions(+), 21 deletions(-) create mode 100644 core/src/main/resources/bedrock/block_palette.1_21_40.nbt create mode 100644 core/src/main/resources/bedrock/creative_items.1_21_40.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_21_40.json diff --git a/bootstrap/standalone/src/main/resources/log4j2.xml b/bootstrap/standalone/src/main/resources/log4j2.xml index 54f6f9528..bf361a851 100644 --- a/bootstrap/standalone/src/main/resources/log4j2.xml +++ b/bootstrap/standalone/src/main/resources/log4j2.xml @@ -20,6 +20,9 @@ + + + - \ No newline at end of file + diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java b/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java index 1cf6a794e..ee20c14a2 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java @@ -43,13 +43,13 @@ public class CameraDefinitions { static { CAMERA_PRESETS = List.of( - new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null), - new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null), - new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null), - new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null), - new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(false), null), - new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null), - new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null)); + new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), + new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), + new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), + new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), + new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(false), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), + new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), + new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty())); SimpleDefinitionRegistry.Builder builder = SimpleDefinitionRegistry.builder(); for (int i = 0; i < CAMERA_PRESETS.size(); i++) { 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 2e0c75708..cc98d0ae5 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 @@ -27,7 +27,6 @@ package org.geysermc.geyser.inventory.updater; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import java.util.stream.IntStream; import net.kyori.adventure.text.Component; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -41,8 +40,8 @@ import org.geysermc.geyser.inventory.AnvilContainer; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.item.BedrockEnchantment; -import org.geysermc.geyser.item.enchantment.Enchantment; 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; @@ -57,6 +56,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S import java.util.Map; import java.util.Objects; +import java.util.stream.IntStream; public class AnvilInventoryUpdater extends InventoryUpdater { public static final AnvilInventoryUpdater INSTANCE = new AnvilInventoryUpdater(); @@ -81,6 +81,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(bedrockSlot); slotPacket.setItem(inventory.getItem(i).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } } @@ -102,6 +103,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } else if (lastTargetSlot != javaSlot) { // Update the previous target slot to remove repair cost changes @@ -110,6 +112,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(lastTargetSlot)); slotPacket.setItem(inventory.getItem(lastTargetSlot).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } @@ -174,6 +177,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(slot)); slotPacket.setItem(itemData); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java index 9f3d00c57..b28bd23d1 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java @@ -64,6 +64,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(bedrockItems); contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); } @@ -77,6 +78,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java index 3d372c083..224b7d4c9 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java @@ -52,6 +52,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); } @@ -65,6 +66,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java index 315b84c6d..d3135c97e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java @@ -59,6 +59,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater { contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); // inventory and hotbar @@ -71,6 +72,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater { contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); // Crafter result - it doesn't come after the grid, as explained elsewhere. @@ -93,6 +95,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater { packet.setSlot(translator.javaSlotToBedrock(javaSlot)); packet.setItem(inventory.getItem(javaSlot).getItemData(session)); packet.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + packet.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(packet); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java index 1a46fc02a..657c91604 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java @@ -52,6 +52,7 @@ public class HorseInventoryUpdater extends InventoryUpdater { contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); } @@ -65,6 +66,7 @@ public class HorseInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java index b7ef4720f..c57f59bfd 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java @@ -48,6 +48,7 @@ public class InventoryUpdater { contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); } @@ -58,6 +59,7 @@ public class InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java index f4f40d6ce..23cfc79f5 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.inventory.updater; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.session.GeyserSession; @@ -49,6 +50,7 @@ public class UIInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(bedrockSlot); slotPacket.setItem(inventory.getItem(i).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } } @@ -63,6 +65,7 @@ public class UIInventoryUpdater extends InventoryUpdater { slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 2513e3ceb..32aa2fd3f 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -63,7 +63,7 @@ public final class BlockState { return null; } //noinspection unchecked - return (T) get(property); + return (T) value; } public > T getValue(Property property, T def) { 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 741369c46..cdbeef143 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -44,6 +44,8 @@ import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventorySlotSeri import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.MobArmorEquipmentSerializer_v712; import org.cloudburstmc.protocol.bedrock.codec.v729.serializer.InventoryContentSerializer_v729; import org.cloudburstmc.protocol.bedrock.codec.v729.serializer.InventorySlotSerializer_v729; +import org.cloudburstmc.protocol.bedrock.codec.v748.serializer.InventoryContentSerializer_v748; +import org.cloudburstmc.protocol.bedrock.codec.v748.serializer.InventorySlotSerializer_v748; import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.cloudburstmc.protocol.bedrock.packet.BossEventPacket; @@ -140,6 +142,13 @@ class CodecProcessor { } }; + private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V748 = new InventoryContentSerializer_v748() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { + throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!"); + } + }; + private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V729 = new InventoryContentSerializer_v729() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { @@ -174,6 +183,13 @@ class CodecProcessor { } }; + private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER_V748 = new InventorySlotSerializer_v748() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { + throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!"); + } + }; + /** * Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client. */ @@ -262,11 +278,14 @@ class CodecProcessor { @SuppressWarnings("unchecked") static BedrockCodec processCodec(BedrockCodec codec) { + boolean is748OrAbove = codec.getProtocolVersion() >= 748; boolean is729OrAbove = codec.getProtocolVersion() >= 729; boolean is712OrAbove = codec.getProtocolVersion() >= 712; BedrockPacketSerializer inventoryContentSerializer; - if (is729OrAbove) { + if (is748OrAbove) { + inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V748; + } else if (is729OrAbove) { inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V729; } else if (is712OrAbove) { inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V712; @@ -275,7 +294,9 @@ class CodecProcessor { } BedrockPacketSerializer inventorySlotSerializer; - if (is729OrAbove) { + if (is748OrAbove) { + inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V748; + } else if (is729OrAbove) { inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V729; } else if (is712OrAbove) { inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V712; diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index c188e92bb..c76958777 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -32,6 +32,7 @@ import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; import org.cloudburstmc.protocol.bedrock.codec.v686.Bedrock_v686; 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.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; @@ -50,8 +51,8 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v729.CODEC.toBuilder() - .minecraftVersion("1.21.31") + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() + .minecraftVersion("1.21.40") .build()); /** @@ -78,8 +79,11 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder() .minecraftVersion("1.21.20 - 1.21.23") .build())); + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v729.CODEC.toBuilder() + .minecraftVersion("1.21.30/1.21.31") + .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.30/1.21.31") + .minecraftVersion("1.21.40") .build()); } @@ -107,6 +111,10 @@ public final class GameProtocol { return session.getUpstream().getProtocolVersion() < Bedrock_v686.CODEC.getProtocolVersion(); } + public static boolean isPre1_21_40(GeyserSession session) { + return session.getUpstream().getProtocolVersion() < Bedrock_v748.CODEC.getProtocolVersion(); + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * 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 5c48df1f9..48f1dee5f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -209,7 +209,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { ResourcePackManifest.Header header = pack.manifest().header(); resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry( header.uuid().toString(), header.version().toString(), codec.size(), pack.contentKey(), - "", header.uuid().toString(), false, false, false)); + "", header.uuid().toString(), false, false, false, "")); } resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks()); session.sendUpstreamPacket(resourcePacksInfo); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index bface58da..b95da4f8f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -48,6 +48,7 @@ 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.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -60,6 +61,7 @@ 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.level.block.type.FlowerPotBlock; +import org.geysermc.geyser.level.block.type.SkullBlock; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -129,6 +131,16 @@ public final class BlockRegistryPopulator { .put(ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), Conversion712_685::remapBlock) .put(ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), Conversion729_712::remapBlock) .put(ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), tag -> { + final String name = tag.getString("name"); + if (name.endsWith("_wood") && tag.getCompound("states").containsKey("stripped_bit")) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("stripped_bit"); + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + return tag; + }) .build(); // We can keep this strong as nothing should be garbage collected @@ -262,6 +274,15 @@ public final class BlockRegistryPopulator { NbtMap originalBedrockTag = buildBedrockState(blockState, entry); NbtMap bedrockTag = stateMapper.remap(originalBedrockTag); + // FIXME TEMPORARY + if (blockState.block() instanceof SkullBlock && palette.valueInt() >= Bedrock_v748.CODEC.getProtocolVersion()) { + // The flattening must be a very interesting process. + String skullName = blockState.block().javaIdentifier().asString().replace("_wall", ""); + bedrockTag = bedrockTag.toBuilder() + .putString("name", skullName) + .build(); + } + GeyserBedrockBlock vanillaBedrockDefinition = blockStateOrderedMap.get(bedrockTag); GeyserBedrockBlock bedrockDefinition; diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index bea213aa4..12b5ebb0e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -43,6 +43,7 @@ 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.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; @@ -95,6 +96,7 @@ public class ItemRegistryPopulator { 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())); + paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java index 685d51fc0..125614e77 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java @@ -141,6 +141,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator slotPacket.setSlot(53); slotPacket.setItem(UPGRADE_TEMPLATE.apply(session.getUpstream().getProtocolVersion())); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index a276e4750..65fd87c83 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -85,6 +85,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } inventoryContentPacket.setContents(Arrays.asList(contents)); inventoryContentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + inventoryContentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(inventoryContentPacket); // Armor @@ -102,6 +103,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } armorContentPacket.setContents(Arrays.asList(contents)); armorContentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + armorContentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(armorContentPacket); // Offhand @@ -109,6 +111,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { offhandPacket.setContainerId(ContainerId.OFFHAND); offhandPacket.setContents(Collections.singletonList(inventory.getItem(45).getItemData(session))); offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + offhandPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(offhandPacket); } @@ -131,6 +134,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } } @@ -168,12 +172,14 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } slotPacket.setItem(bedrockItem); slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); offhandPacket.setContents(Collections.singletonList(bedrockItem)); offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + offhandPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(offhandPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java index ba3b7285e..363761e47 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java @@ -96,6 +96,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); ItemData[] horseItems = new ItemData[chestSize + 1]; @@ -110,6 +111,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven horseContentsPacket.setContainerId(inventory.getBedrockId()); horseContentsPacket.setContents(Arrays.asList(horseItems)); horseContentsPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); + horseContentsPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(horseContentsPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index c2d457202..77f58f5d6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -36,6 +36,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.SkullBlock; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.skin.SkinProvider; @@ -57,7 +58,9 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements // Could be a wall skull block otherwise, which has rotation in its Bedrock state bedrockNbt.putFloat("Rotation", rotation * 22.5f); } - bedrockNbt.putByte("SkullType", (byte) (blockState.block() instanceof SkullBlock skull ? skull.skullType().bedrockId() : 0)); + if (GameProtocol.isPre1_21_40(session)) { + bedrockNbt.putByte("SkullType", (byte) (blockState.block() instanceof SkullBlock skull ? skull.skullType().bedrockId() : 0)); + } if (blockState.getValue(Properties.POWERED)) { bedrockNbt.putBoolean("MouthMoving", true); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index 3195a6536..a37ba88b3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -32,6 +32,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; @@ -170,6 +171,7 @@ public class JavaEntityEventTranslator extends PacketTranslatorUX6guI5KC#H(D7rSWviu#&Q`35 z1*&{uNfm~e#VtBE^|H9=9C1HPmf#Y%WZC|i%ZAC8DT~>b?2j4u-o5X=vHo?>cfWJK z^PPKMf4QDCekSRBT{4>c3}eL{#*>4@lu|%rgoimGbssETBO-nSE^~1-rM)b0v5*!Z zyVKV#qrn}e7S$>a*_r8huT+6lg&(7euf)42aKkR(I{fgc17*ri5q}ejjMgRjgIH9# zXdG78CcksWf@y;de(frhu9%{@LK6^TGNVah!naojh+o?%b-`g#x03H7jM>a9Vr2nS z;OgoCw(7h~un~-9xp`Y!81)yRGOr@{^%_>lk==*yvv=a&J|kW+Y>-+ZcMYQ7`ka39 zYmSYv8%+Dj?g$KD-bO^4ed_p`{e3(oYXE0^qjw@Co#TEi=ewi;| zE$e%6Z+#=hq9rksx8Z4;B)m9E`(d_=bLVT!*(0QWV-71ivndGsGnZ&$wZn{UWmc&} zd{K6ZPKa#oM#;11nV@<(9xvZ0bIz65QkQEhKE)$jKBAnNO&soT=_Zlq;*to5ZI!$6 zb>+vD@MYBta)FkulK6`fMiw1&|Ly1P?W5%A4zIkx`85GDTeD<=&2@w1vpTa(usHXS zi_Sbb*0~Roi*A0OgxCJlW0Pe7VM6Y@%?SID`5{Du@$I1(1Gg*UZsuAM=}r%4`WS)?i%JJZ)5P_Ini-C zx&~b2)_|G05|%H1I0H4&y}TMrVAv2@H)vwcauZpYIO2wSh_1UJdSqCS`6073CjLr? zoku_5Eim(rSP0+6+Gs=J;cA&@9ARq_RvTa)Et2uGqaHeniue$IiZ{@_g)|*v$6S1@ zh30rAokIM$UCvoO)+E+9@dJ=+ky=bXOfPa1L0m{Q3uo4|3ceFPA|C`@F5yrv< z6BW$Q*^M|k>4Net_T{mGWa3nK4c?zLVfj=Z98>kQ;hR$)Qguo!I6fUf&T00aJ9~OW SmDbzd5%77MUvGbi{{98b;aB?r delta 5474 zcmai2TWl0n7-qYa-k=xC_O|UJC|ho&Tx=~M7EHi^fS}Ssp*_y-p1shyY-eV>U0Nu# zM5Lt__`{PC5EBv-Vt@$-Mam^A@E```iw{J^2QUyte1Hcm&dhGR=WO@5`~H3ZWxoIW z|FcI}W4L<20gnDm=(4sK6@)nz%kRsa zs029~i|&Zm>#W!QwpLlE5)6eD1M&xWUeS3fVP!@qg99#Sv?L^@*y3DF!LDT6Vz3JMCAXUeYs_n=igf$2 zEJu(}mfEA=cDUOCkMnA+z0QET0^xrcw2KAf zEn_JpH|9jMm^+i1pKC*5OA@Hc1$L5@)0WopY5A+BL93df0JQUqYfC( zHh6ZkIBpcV9R$Z@feV;~+9~iZ^w2S%ek)YFU$wfM=O-4=1;pMJ%>2P9Y2JlzqOXf?y~x z8N9Nz1B)o0!qalr;A?FawHC@eOa?yGio={N5FFn*b~4J)R!nu%+Auld;jg`VtUT5i856U0TE%Huz%^t-2_3M0Eozq5oAEBP<-RErsiLCk!@j zhsN^RaJgnZwOPgt{hV5+f{)i;NQMn!t~DyZ;qD69wIUNfd2MzI8Jc<7>W(GjlLPHo zHZ}26oye-Ie(_oAc!;mY+$F101@B+7DWA~Nct7TObM%LoTuVNHFtqe*YH9**j07np z>WfH>7JuQ5iE!fe03%^7d)YzS?F@z>Pr$_LeiaA67_?f!}@R!YmGS7#;MS~)wiXk8&xyiDY$JNH{=S-dOf;-X zxL6518u3xXeon31$I794z0*pGF2)geKVuj>H-=aQe{Gy;r8a+zARa$j$Ffa5EQ+B` z>GbmCv5#{{(3n~Lts&Kgr>$?Sv{30J*}<^6gOLhkZ`n#+cDjxFiG9+$<;@gYfahE2 zwI*<)Ig3aMb3)J@<499oDwYRLjg+7S%z31+i8f4S$JPZY7_@s^AJOwA=uJiOOY>3l zXRIb1Xt_mQm~kYr6pagWH)36w+6#2oLV1dS70&dOe>tX!ZFkY#H!#R0N8H#%8cKZV zVk!~2Lur(hO}K6;D&|5aK_j1g*vmZac`yAo;XF1Sb%N0)P4*30sohV8L*^x-!{@@b zR)s+Uw_52()UU1fSf0$i|1+OX-^zlnP+5`$6i|3hjNa`}1({*nKJkZXgyYx}&`9y? z4@XmG?@ArXIkX$n3JbMs;wNflo5ZM9JJRN-_dVhDj{bZ&y)zqX6xO4!g5;78?j%1t}Z}&Uf8R%1BOVR0+)YhJBZx zQo-C^CAtcn@UXWG@_d;vw9}a?i<#Z@&R0Y!96<^%1!H%^aQ8c@IQH&N=#3QO6@Bqc$|Fk9j&D?Q>Bl+$bX%iaRZ08vW z2o2DEBmXkFJ-}RsZ6DK*oG2`Q-PD->j8qLQ0^eW}D|Xl5W@-*qKSo$LYvYmoWDqf6 z+J=L6dWR=G==UFD-G=b|5S_M;495M(h}&^^pfc&-G4<(LVShlyNdFskoca3?X+09% diff --git a/core/src/main/resources/bedrock/block_palette.1_21_40.nbt b/core/src/main/resources/bedrock/block_palette.1_21_40.nbt new file mode 100644 index 0000000000000000000000000000000000000000..f7d3ace9aca01fe633ec7c90f358245bfde4af75 GIT binary patch literal 181156 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�F%BP4tuMZB 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 Ik{MwB5BVQ@8UO$Q literal 0 HcmV?d00001 diff --git a/core/src/main/resources/bedrock/creative_items.1_21_40.json b/core/src/main/resources/bedrock/creative_items.1_21_40.json new file mode 100644 index 000000000..e4a15d9c6 --- /dev/null +++ b/core/src/main/resources/bedrock/creative_items.1_21_40.json @@ -0,0 +1,6262 @@ +{ + "items": [ + { + "id": "minecraft:oak_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19wbGFua3MECQBuYW1lX2hhc2ilMDLR92rQ4wMKAG5ldHdvcmtfaWS2GotyCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:spruce_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAwAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9wbGFua3MECQBuYW1lX2hhc2iumBkmFGFE8gMKAG5ldHdvcmtfaWSo8TFgCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:birch_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3BsYW5rcwQJAG5hbWVfaGFzaLrrAKJqV2WFAwoAbmV0d29ya19pZL+e3ZAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:jungle_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAwAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9wbGFua3MECQBuYW1lX2hhc2iBM3k4T3FAugMKAG5ldHdvcmtfaWSXUmBCCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:acacia_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAwAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9wbGFua3MECQBuYW1lX2hhc2g60edJxO5/aAMKAG5ldHdvcmtfaWTUXozECgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dark_oak_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3BsYW5rcwQJAG5hbWVfaGFzaAr64wkQ9cA7AwoAbmV0d29ya19pZFbMeR0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mangrove_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3BsYW5rcwQJAG5hbWVfaGFzaPvLtcEA0F8xAwoAbmV0d29ya19pZEvnlCYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cherry_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9wbGFua3MECQBuYW1lX2hhc2hNIvVh/lVW7gMKAG5ldHdvcmtfaWQTXpRoCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bamboo_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19wbGFua3MECQBuYW1lX2hhc2gYnjNz7SCCjgMKAG5ldHdvcmtfaWTi8ySSCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bamboo_mosaic", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWMECQBuYW1lX2hhc2izSEgiMKOp/AMKAG5ldHdvcmtfaWQZ/p8xCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:crimson_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fcGxhbmtzBAkAbmFtZV9oYXNoJc5IKqNXJnwDCgBuZXR3b3JrX2lkwtJDdQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:warped_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9wbGFua3MECQBuYW1lX2hhc2g3yGXEWhe6LgMKAG5ldHdvcmtfaWStTABvCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSLY2XwCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mossy_cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKBAAACAQAbmFtZSAAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2gHUQMwwFQeNQMKAG5ldHdvcmtfaWRzPhG8CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:granite_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLBAAACAQAbmFtZRYAbWluZWNyYWZ0OmdyYW5pdGVfd2FsbAQJAG5hbWVfaGFzaE1GmM5AU0qUAwoAbmV0d29ya19pZE/UoPUKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:diorite_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMBAAACAQAbmFtZRYAbWluZWNyYWZ0OmRpb3JpdGVfd2FsbAQJAG5hbWVfaGFzaF27l0QvdM8xAwoAbmV0d29ya19pZJe7jOwKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:andesite_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNBAAACAQAbmFtZRcAbWluZWNyYWZ0OmFuZGVzaXRlX3dhbGwECQBuYW1lX2hhc2gAL1Vay0kZjQMKAG5ldHdvcmtfaWRJGxdvCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:sandstone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOBAAACAQAbmFtZRgAbWluZWNyYWZ0OnNhbmRzdG9uZV93YWxsBAkAbmFtZV9oYXNoYL2gu8a6HfgDCgBuZXR3b3JrX2lkHrhRjgoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_sandstone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVBAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfd2FsbAQJAG5hbWVfaGFzaLAUUdOlo24MAwoAbmV0d29ya19pZI66BqAKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:stone_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQBAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3dhbGwECQBuYW1lX2hhc2hQegufuP6vjAMKAG5ldHdvcmtfaWS4AsOKCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mossy_stone_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRBAAACAQAbmFtZSAAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3dhbGwECQBuYW1lX2hhc2i680zzUekp+wMKAG5ldHdvcmtfaWTQTaHPCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJyaWNrX3dhbGwECQBuYW1lX2hhc2gGJFLNjfgSCAMKAG5ldHdvcmtfaWSc5iUZCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:nether_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTSBAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl9icmlja193YWxsBAkAbmFtZV9oYXNoAxb5f2yQ5MYDCgBuZXR3b3JrX2lkAECPDAoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_nether_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWBAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBOtwkokUt3cAwoAbmV0d29ya19pZJykmZUKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:end_stone_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTBAAACAQAbmFtZR4AbWluZWNyYWZ0OmVuZF9zdG9uZV9icmlja193YWxsBAkAbmFtZV9oYXNoOsr1L9kJIAMDCgBuZXR3b3JrX2lkjuYlYgoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:prismarine_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUBAAACAQAbmFtZRkAbWluZWNyYWZ0OnByaXNtYXJpbmVfd2FsbAQJAG5hbWVfaGFzaDO5IGrYZu1/AwoAbmV0d29ya19pZB4nLYYKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:blackstone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaMP8XppUSU1RAwoAbmV0d29ya19pZMbeBBsKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_blackstone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaP6SwV08YwzAAwoAbmV0d29ya19pZAJLsz8KBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_blackstone_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBBIDZbHxiEzAwoAbmV0d29ya19pZEbLV8cKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cobbled_deepslate_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3dhbGwECQBuYW1lX2hhc2iECY5oKxeT+gMKAG5ldHdvcmtfaWRCnPrFCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:deepslate_tile_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3dhbGwECQBuYW1lX2hhc2jz7N+PeuEXgQMKAG5ldHdvcmtfaWTqw4s4CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:polished_deepslate_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV93YWxsBAkAbmFtZV9oYXNoHxjTdj9pevMDCgBuZXR3b3JrX2lkIvBYYwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:deepslate_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja193YWxsBAkAbmFtZV9oYXNoEs3EQrjroyEDCgBuZXR3b3JrX2lkwlrCGwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:tuff_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAwAACAQAbmFtZRMAbWluZWNyYWZ0OnR1ZmZfd2FsbAQJAG5hbWVfaGFzaMyeeu1IRf03AwoAbmV0d29ya19pZDkIrosKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:tuff_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AwAACAQAbmFtZRkAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaIL0IyNCOsonAwoAbmV0d29ya19pZJW4T5UKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_tuff_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfd2FsbAQJAG5hbWVfaGFzaJVZj6QYWXUrAwoAbmV0d29ya19pZLU7dooKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mud_brick_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja193YWxsBAkAbmFtZV9oYXNov9b98ATpUSwDCgBuZXR3b3JrX2lkH/1WZQoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:oak_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAAAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZDvPEXcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:spruce_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAwAACAQAbmFtZRYAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZQQJAG5hbWVfaGFzaPQCm+aX1ZQeAwoAbmV0d29ya19pZD1QUEoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:birch_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AwAACAQAbmFtZRUAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlBAkAbmFtZV9oYXNo6CJ2ATpANfgDCgBuZXR3b3JrX2lkmCUV2QoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:jungle_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAwAACAQAbmFtZRYAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZQQJAG5hbWVfaGFzaOX4cD9uAmsdAwoAbmV0d29ya19pZHz1VxkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:acacia_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AwAACAQAbmFtZRYAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZQQJAG5hbWVfaGFzaGjn+RlKVDH6AwoAbmV0d29ya19pZNVGubwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dark_oak_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAwAACAQAbmFtZRgAbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlBAkAbmFtZV9oYXNoGPj0gCgM0c0DCgBuZXR3b3JrX2lk2w+gEwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mangrove_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlBAkAbmFtZV9oYXNowwAd7tPu9bsDCgBuZXR3b3JrX2lkKEcd0goGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cherry_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAwAACAQAbmFtZRYAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZQQJAG5hbWVfaGFzaFmtUfHfTxcxAwoAbmV0d29ya19pZPCBxAIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:bamboo_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19mZW5jZQQJAG5hbWVfaGFzaCKRbxfXsfkiAwoAbmV0d29ya19pZJNXKFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:nether_brick_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAAAACAQAbmFtZRwAbWluZWNyYWZ0Om5ldGhlcl9icmlja19mZW5jZQQJAG5hbWVfaGFzaA6030ngawxcAwoAbmV0d29ya19pZLnjLF4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crimson_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2UECQBuYW1lX2hhc2jhUhKv1HGj9AMKAG5ldHdvcmtfaWR3OH3OCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:warped_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9mZW5jZQQJAG5hbWVfaGFzaJfb3/YuKmOWAwoAbmV0d29ya19pZCpaGC8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAAAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWR+T9kTCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:spruce_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AAAACAQAbmFtZRsAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoanTVB84HRbkDCgBuZXR3b3JrX2lkEnw5egoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:birch_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2jmfPklI8azSwMKAG5ldHdvcmtfaWQL77/BCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:jungle_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS5AAAACAQAbmFtZRsAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNobYVQkfBomIcDCgBuZXR3b3JrX2lkA1zgtgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:acacia_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS7AAAACAQAbmFtZRsAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoZnrLUx/XSekDCgBuZXR3b3JrX2lkHg/kTgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dark_oak_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS6AAAACAQAbmFtZR0AbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2j2PTvdJJHcVQMKAG5ldHdvcmtfaWTwjOCeCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mangrove_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2i/kOhBKiI/dAMKAG5ldHdvcmtfaWSfweCSCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAELAGluX3dhbGxfYml0AAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cherry_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAwAACAQAbmFtZRsAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoKWLgCk0z+PsDCgBuZXR3b3JrX2lk/9bTZQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:bamboo_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJhbWJvb19mZW5jZV9nYXRlBAkAbmFtZV9oYXNopH1JrUgwdIADCgBuZXR3b3JrX2lkzIpPywoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crimson_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2VfZ2F0ZQQJAG5hbWVfaGFzaHE3Gfd0Z2d2AwoAbmV0d29ya19pZDQzVbEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQsAaW5fd2FsbF9iaXQAAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:warped_fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoy0oIBjDIG4kDCgBuZXR3b3JrX2lkkf+/3QoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCwBpbl93YWxsX2JpdAABCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:normal_stone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAQAACAQAbmFtZR0AbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hAEktZZOkGIwMKAG5ldHdvcmtfaWQeH1ALCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZDcCv+MKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mossy_cobblestone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSyAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3N0YWlycwQJAG5hbWVfaGFzaMVSTq5z9n1RAwoAbmV0d29ya19pZFIfrhkKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:oak_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19zdGFpcnMECQBuYW1lX2hhc2jk/HFzdXy0FQMKAG5ldHdvcmtfaWQJjyzBCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:spruce_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9zdGFpcnMECQBuYW1lX2hhc2iznygw7uBPBQMKAG5ldHdvcmtfaWTv+is3CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:birch_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3N0YWlycwQJAG5hbWVfaGFzaPfhbL619a3GAwoAbmV0d29ya19pZFyPlHAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:jungle_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9zdGFpcnMECQBuYW1lX2hhc2jodJsHUbOVxQMKAG5ldHdvcmtfaWR0z5d4CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:acacia_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9zdGFpcnMECQBuYW1lX2hhc2h3x1NmD43IqQMKAG5ldHdvcmtfaWS7Jwz6CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dark_oak_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3N0YWlycwQJAG5hbWVfaGFzaMfwkbYPbNmAAwoAbmV0d29ya19pZCmBYKAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mangrove_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3N0YWlycwQJAG5hbWVfaGFzaNpUDY+uGMpyAwoAbmV0d29ya19pZChzUAsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cherry_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9zdGFpcnMECQBuYW1lX2hhc2jMtr0v9JY4zwMKAG5ldHdvcmtfaWRQwq31CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bamboo_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19zdGFpcnMECQBuYW1lX2hhc2jFOzWL8PalKwMKAG5ldHdvcmtfaWTVPh42CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bamboo_mosaic_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc3RhaXJzBAkAbmFtZV9oYXNoNLPiveSHPaoDCgBuZXR3b3JrX2lk44PHjgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:stone_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAAAACAQAbmFtZRwAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaN6tQViRo5cwAwoAbmV0d29ya19pZDMyMgIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mossy_stone_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaIB/Zv5YBPuYAwoAbmV0d29ya19pZANTOsMKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:sandstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAAAACAQAbmFtZRoAbWluZWNyYWZ0OnNhbmRzdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hOyA0BoYUOPQMKAG5ldHdvcmtfaWSV/834CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:smooth_sandstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSwAQAACAQAbmFtZSEAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoB+CuCd8Ruz8DCgBuZXR3b3JrX2lksR+m8QoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:red_sandstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS0AAAACAQAbmFtZR4AbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoPs0LpHPL24YDCgBuZXR3b3JrX2lkLYVt3woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:smooth_red_sandstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAQAACAQAbmFtZSUAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3N0YWlycwQJAG5hbWVfaGFzaBvjtQv5pf+MAwoAbmV0d29ya19pZMHNND8KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:granite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAQAACAQAbmFtZRgAbWluZWNyYWZ0OmdyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNoGzpvtoqKQjgDCgBuZXR3b3JrX2lkPkcB1goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_granite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNo3PvbSfEQklIDCgBuZXR3b3JrX2lkMmEm3AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:diorite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAQAACAQAbmFtZRgAbWluZWNyYWZ0OmRpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoi73T8VQuZmcDCgBuZXR3b3JrX2lk6i6nBQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_diorite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoFKRJd5Wk5L0DCgBuZXR3b3JrX2lkbt2ioAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:andesite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaO5w2FKBw76EAwoAbmV0d29ya19pZKhXEgUKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:polished_andesite_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAQAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaNcZZ/zmLInIAwoAbmV0d29ya19pZJTHrlEKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJyaWNrX3N0YWlycwQJAG5hbWVfaGFzaMyt+cRDk5O2AwoAbmV0d29ya19pZNeMh58KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:nether_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAAAACAQAbmFtZR0AbWluZWNyYWZ0Om5ldGhlcl9icmlja19zdGFpcnMECQBuYW1lX2hhc2jRqIoOXgifBAMKAG5ldHdvcmtfaWQDiw5yCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_nether_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AQAACAQAbmFtZSEAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNogQvosSbcj7kDCgBuZXR3b3JrX2lkx2IMtAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:end_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSxAQAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2hmlAk+QhsUsQMKAG5ldHdvcmtfaWTN7KFaCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:quartz_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAAAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9zdGFpcnMECQBuYW1lX2hhc2hmvpvOqGi6egMKAG5ldHdvcmtfaWRmUTh7CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:smooth_quartz_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AQAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc3RhaXJzBAkAbmFtZV9oYXNoNZZ9rX0qZOsDCgBuZXR3b3JrX2lkzsgQyQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:purpur_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAAAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9zdGFpcnMECQBuYW1lX2hhc2ifwDxeezXD7gMKAG5ldHdvcmtfaWTT+rxiCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:prismarine_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAQAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfc3RhaXJzBAkAbmFtZV9oYXNooTHSZ+IrYtcDCgBuZXR3b3JrX2lkxTJfeAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dark_prismarine_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAQAACAQAbmFtZSAAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zdGFpcnMECQBuYW1lX2hhc2hIciLmam4o4AMKAG5ldHdvcmtfaWTVu7TCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:prismarine_bricks_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAQAACAQAbmFtZSIAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzX3N0YWlycwQJAG5hbWVfaGFzaNIjq1oBlZMMAwoAbmV0d29ya19pZGEFwLYKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crimson_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fc3RhaXJzBAkAbmFtZV9oYXNoZJqIzCBpCq4DCgBuZXR3b3JrX2lktXE00AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:warped_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9zdGFpcnMECQBuYW1lX2hhc2hOkY27jLD4RQMKAG5ldHdvcmtfaWQ+E5VrCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:blackstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNokdoUb76p9McDCgBuZXR3b3JrX2lk5fWI5goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_blackstone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNolCFtFIE8MmADCgBuZXR3b3JrX2lkGTf7sgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_blackstone_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAgAACAQAbmFtZSoAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNonks6UlfpOmkDCgBuZXR3b3JrX2lkgYeOdAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cobbled_deepslate_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AgAACAQAbmFtZSIAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3N0YWlycwQJAG5hbWVfaGFzaPIfa+TpyJcIAwoAbmV0d29ya19pZJUvOYIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:deepslate_tile_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3N0YWlycwQJAG5hbWVfaGFzaGFRFzB72mN2AwoAbmV0d29ya19pZJEOgIsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:polished_deepslate_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAgAACAQAbmFtZSMAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zdGFpcnMECQBuYW1lX2hhc2iNCYxVik9sGAMKAG5ldHdvcmtfaWSRVPnYCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:deepslate_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zdGFpcnMECQBuYW1lX2hhc2hIasOahEf83wMKAG5ldHdvcmtfaWQ1qEDCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:tuff_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAwAACAQAbmFtZRUAbWluZWNyYWZ0OnR1ZmZfc3RhaXJzBAkAbmFtZV9oYXNoKjyNUBjcfZsDCgBuZXR3b3JrX2lk+LsycgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_tuff_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfc3RhaXJzBAkAbmFtZV9oYXNo8yuah8QI1dcDCgBuZXR3b3JrX2lkjLoU4AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:tuff_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT0AwAACAQAbmFtZRsAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNoWJpkAurUfKwDCgBuZXR3b3JrX2lkUMcjiwoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mud_brick_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAgAACAQAbmFtZRoAbWluZWNyYWZ0Om11ZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2gt3qxK1NWajAMKAG5ldHdvcmtfaWSm9N3MCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAgAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoHfoAXYq5G3MDCgBuZXR3b3JrX2lkeetf7woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:exposed_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAgAACAQAbmFtZSMAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2howneQGtZ9cgMKAG5ldHdvcmtfaWSg73zdCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:weathered_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAgAACAQAbmFtZSUAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaP+R5loXxrVgAwoAbmV0d29ya19pZOnbRf4KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:oxidized_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAgAACAQAbmFtZSQAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNo6Jeoq5rsPxsDCgBuZXR3b3JrX2lkmRjDnQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAgAACAQAbmFtZSEAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoh07CQj0/SR8DCgBuZXR3b3JrX2lkmYqoqAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_exposed_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2guVct1ilmxTwMKAG5ldHdvcmtfaWQgCPROCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_weathered_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAgAACAQAbmFtZSsAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaPXC8Sz/phCpAwoAbmV0d29ya19pZHlwHVsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS/AgAACAQAbmFtZSoAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoaqGdkuhxVZUDCgBuZXR3b3JrX2lkYQXzzgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:wooden_door" + }, + { + "id": "minecraft:spruce_door" + }, + { + "id": "minecraft:birch_door" + }, + { + "id": "minecraft:jungle_door" + }, + { + "id": "minecraft:acacia_door" + }, + { + "id": "minecraft:dark_oak_door" + }, + { + "id": "minecraft:mangrove_door" + }, + { + "id": "minecraft:cherry_door" + }, + { + "id": "minecraft:bamboo_door" + }, + { + "id": "minecraft:iron_door" + }, + { + "id": "minecraft:crimson_door" + }, + { + "id": "minecraft:warped_door" + }, + { + "id": "minecraft:copper_door" + }, + { + "id": "minecraft:exposed_copper_door" + }, + { + "id": "minecraft:weathered_copper_door" + }, + { + "id": "minecraft:oxidized_copper_door" + }, + { + "id": "minecraft:waxed_copper_door" + }, + { + "id": "minecraft:waxed_exposed_copper_door" + }, + { + "id": "minecraft:waxed_weathered_copper_door" + }, + { + "id": "minecraft:waxed_oxidized_copper_door" + }, + { + "id": "minecraft:trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAAAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkyTAWkAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:spruce_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAQAACAQAbmFtZRkAbWluZWNyYWZ0OnNwcnVjZV90cmFwZG9vcgQJAG5hbWVfaGFzaOwlfbgBkUW4AwoAbmV0d29ya19pZPHy1K0KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:birch_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAQAACAQAbmFtZRgAbWluZWNyYWZ0OmJpcmNoX3RyYXBkb29yBAkAbmFtZV9oYXNoSLtLweOLJ7wDCgBuZXR3b3JrX2lkeJWDfgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:jungle_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAQAACAQAbmFtZRkAbWluZWNyYWZ0Omp1bmdsZV90cmFwZG9vcgQJAG5hbWVfaGFzaDP/TnM9wyCIAwoAbmV0d29ya19pZEy2fJoKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:acacia_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFjYWNpYV90cmFwZG9vcgQJAG5hbWVfaGFzaMj8xi3vmEKOAwoAbmV0d29ya19pZOHj8E8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dark_oak_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAQAACAQAbmFtZRsAbWluZWNyYWZ0OmRhcmtfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNomB2GGJQ2aOMDCgBuZXR3b3JrX2lko5ZHTwoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:mangrove_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAgAACAQAbmFtZRsAbWluZWNyYWZ0Om1hbmdyb3ZlX3RyYXBkb29yBAkAbmFtZV9oYXNooV3kQsQUUmkDCgBuZXR3b3JrX2lkkF/mxAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cherry_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoZXJyeV90cmFwZG9vcgQJAG5hbWVfaGFzaH/PefpfdHgtAwoAbmV0d29ya19pZOA7eNgKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:bamboo_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJhbWJvb190cmFwZG9vcgQJAG5hbWVfaGFzaJrEOpsTwtKCAwoAbmV0d29ya19pZLvbPz8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:iron_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAAAACAQAbmFtZRcAbWluZWNyYWZ0Omlyb25fdHJhcGRvb3IECQBuYW1lX2hhc2gwA+IumsEiGQMKAG5ldHdvcmtfaWTvSVl/CgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crimson_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AQAACAQAbmFtZRoAbWluZWNyYWZ0OmNyaW1zb25fdHJhcGRvb3IECQBuYW1lX2hhc2jHXufTnwUkYgMKAG5ldHdvcmtfaWQLjMYVCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:warped_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AQAACAQAbmFtZRkAbWluZWNyYWZ0OndhcnBlZF90cmFwZG9vcgQJAG5hbWVfaGFzaA20wG/+vkd6AwoAbmV0d29ya19pZHKR/hYKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXBAAACAQAbmFtZRkAbWluZWNyYWZ0OmNvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaO9fXio+svKVAwoAbmV0d29ya19pZMCoRjEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:exposed_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYBAAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX3RyYXBkb29yBAkAbmFtZV9oYXNoYhDFUysN7qUDCgBuZXR3b3JrX2lkMzwGJgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:weathered_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZBAAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfdHJhcGRvb3IECQBuYW1lX2hhc2hFnEC282a1tgMKAG5ldHdvcmtfaWTk70oiCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:oxidized_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQaBAAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaOJpG/XFexVwAwoAbmV0d29ya19pZPhi0J4KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbBAAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaO0JUKUHqNU6AwoAbmV0d29ya19pZJC3ZuMKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_exposed_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcBAAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX3RyYXBkb29yBAkAbmFtZV9oYXNoBHHxCpkUzpgDCgBuZXR3b3JrX2lkw2XBGQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_weathered_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQdBAAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfdHJhcGRvb3IECQBuYW1lX2hhc2gH9Fi3JCF4egMKAG5ldHdvcmtfaWRkGU6TCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_oxidized_copper_trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeBAAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaNA/q9qAy6Z9AwoAbmV0d29ya19pZDgExS8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:iron_bars", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAAAACAQAbmFtZRMAbWluZWNyYWZ0Omlyb25fYmFycwQJAG5hbWVfaGFzaPuefWSNAe56AwoAbmV0d29ya19pZN2LB5IKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lk0hdLNwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:white_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAAAACAQAbmFtZR0AbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iHubqoMbu9fAMKAG5ldHdvcmtfaWRndBrUCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:light_gray_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaKKa+LrRsHQhAwoAbmV0d29ya19pZEv2giYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:gray_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAwAACAQAbmFtZRwAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaIETy7Y/HZREAwoAbmV0d29ya19pZDomVrUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:black_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iV6BCwpfDMmwMKAG5ldHdvcmtfaWSV7doJCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brown_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2igsEiq5np8JgMKAG5ldHdvcmtfaWRMzE/lCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAwAACAQAbmFtZRsAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoCa2J12/lQoIDCgBuZXR3b3JrX2lk283lWAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:orange_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAwAACAQAbmFtZR4AbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNozgjAuvzhxGsDCgBuZXR3b3JrX2lkW5CkhQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:yellow_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAwAACAQAbmFtZR4AbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNo7EbHMd5WVugDCgBuZXR3b3JrX2lkkdDyXQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:lime_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAwAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBtZA1nZtwcFAwoAbmV0d29ya19pZDxX85UKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:green_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAwAACAQAbmFtZR0AbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2h91ptDgbehWwMKAG5ldHdvcmtfaWTlDhnECgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cyan_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAwAACAQAbmFtZRwAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBkIYQ8nQLqbAwoAbmV0d29ya19pZOL1lHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:light_blue_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaLt05n1G0fiSAwoAbmV0d29ya19pZNbwulIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:blue_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaPhLocSfzduRAwoAbmV0d29ya19pZENsjFwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:purple_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAwAACAQAbmFtZR4AbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoJk0DhRO0szUDCgBuZXR3b3JrX2lkD98ZxgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:magenta_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAwAACAQAbmFtZR8AbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaFEDeFiJj3zSAwoAbmV0d29ya19pZG+iFRoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:pink_stained_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaDijTX87ywxhAwoAbmV0d29ya19pZKdEricKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:tinted_glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAgAACAQAbmFtZRYAbWluZWNyYWZ0OnRpbnRlZF9nbGFzcwQJAG5hbWVfaGFzaAFZWSamk6KdAwoAbmV0d29ya19pZGSvWX8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWRGwixuCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:white_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAAAACAQAbmFtZSIAbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaHgxQmgJVtRrAwoAbmV0d29ya19pZBEr/DYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:light_gray_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNon0aQw9lNkSEDCgBuZXR3b3JrX2lk9dp5VgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:gray_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAwAACAQAbmFtZSEAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNors74IIw+2MMDCgBuZXR3b3JrX2lkmrGO5woGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:black_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaOK/5ZRRd+M1AwoAbmV0d29ya19pZDv++oQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:brown_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaLHeGJyRFTIWAwoAbmV0d29ya19pZMz9L0wKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:red_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAwAACAQAbmFtZSAAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2gGr4x6JheAywMKAG5ldHdvcmtfaWQBjCTmCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:orange_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAwAACAQAbmFtZSMAbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hbHxPD2gEbEAMKAG5ldHdvcmtfaWSt/7a5CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:yellow_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAwAACAQAbmFtZSMAbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2g9tl4aOCyZBwMKAG5ldHdvcmtfaWTXRAS7CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:lime_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAwAACAQAbmFtZSEAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3CtUyLwoGegDCgBuZXR3b3JrX2lkYJDnggoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:green_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAwAACAQAbmFtZSIAbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaJo6YP7IMy9SAwoAbmV0d29ya19pZHOnixoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cyan_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAwAACAQAbmFtZSEAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoti97c6QrbLQDCgBuZXR3b3JrX2lkUqFUeQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:light_blue_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNovDg/gQle104DCgBuZXR3b3JrX2lkFuy4MQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:blue_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAwAACAQAbmFtZSEAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoGc57tiexbQMDCgBuZXR3b3JrX2lk1eBLUAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:purple_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAwAACAQAbmFtZSMAbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hDJHYdd0FdfQMKAG5ldHdvcmtfaWSNsdK5CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:magenta_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAwAACAQAbmFtZSQAbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3pcOw5bs5XoDCgBuZXR3b3JrX2lkVbOR7AoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:pink_stained_glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAwAACAQAbmFtZSEAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoWRhSACMWgswDCgBuZXR3b3JrX2lkIR92xwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:ladder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxhZGRlcgQJAG5hbWVfaGFzaKBhqheJVOz+AwoAbmV0d29ya19pZCgvzlsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:scaffolding", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNjYWZmb2xkaW5nBAkAbmFtZV9oYXNoYrkevrqcljwDCgBuZXR3b3JrX2lkD13mlAoGAHN0YXRlcwMJAHN0YWJpbGl0eQAAAAABDwBzdGFiaWxpdHlfY2hlY2sAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brick_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAAAACAQAbmFtZRUAbWluZWNyYWZ0OmJyaWNrX2Jsb2NrBAkAbmFtZV9oYXNo5Qc2E005S3oDCgBuZXR3b3JrX2lkqeGWRgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:smooth_stone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRsAbWluZWNyYWZ0OnNtb290aF9zdG9uZV9zbGFiBAkAbmFtZV9oYXNon5I1yVw74uMDCgBuZXR3b3JrX2lkqvjcBQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:normal_stone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCBAAACAQAbmFtZRsAbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zbGFiBAkAbmFtZV9oYXNoIvsjJLQdolcDCgBuZXR3b3JrX2lkC1zqRQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cobblestone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoBAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3NsYWIECQBuYW1lX2hhc2h5CXtW7vlQVgMKAG5ldHdvcmtfaWRDGyj2CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mossy_cobblestone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR3BAAACAQAbmFtZSAAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3NsYWIECQBuYW1lX2hhc2ijm1BCwB82VgMKAG5ldHdvcmtfaWR7ByMGCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:oak_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha19zbGFiBAkAbmFtZV9oYXNoJp1Cp1M4jlwDCgBuZXR3b3JrX2lkZH6+owoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:spruce_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV9zbGFiBAkAbmFtZV9oYXNodQi70jB238cDCgBuZXR3b3JrX2lkrriOYQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:birch_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3NsYWIECQBuYW1lX2hhc2gZPpfMxoOsTAMKAG5ldHdvcmtfaWThR9jyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:jungle_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV9zbGFiBAkAbmFtZV9oYXNo6gLs79NXak4DCgBuZXR3b3JrX2lk5ZiKgwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:acacia_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV9zbGFiBAkAbmFtZV9oYXNomSdFmDnv4OUDCgBuZXR3b3JrX2lkHttaXAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dark_oak_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3NsYWIECQBuYW1lX2hhc2hJjTohRFyhIQMKAG5ldHdvcmtfaWRMzDTyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mangrove_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3NsYWIECQBuYW1lX2hhc2jYCcmhJPeNMwMKAG5ldHdvcmtfaWQx6U1yCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cherry_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV9zbGFiBAkAbmFtZV9oYXNoTt0MmVn/mqoDCgBuZXR3b3JrX2lk2VVsZQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:bamboo_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJhbWJvb19zbGFiBAkAbmFtZV9oYXNoo1xuFqINeLYDCgBuZXR3b3JrX2lkVC+0twoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:bamboo_mosaic_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc2xhYgQJAG5hbWVfaGFzaNbVRBZ/ChI3AwoAbmV0d29ya19pZOLZHFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stone_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqBAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3NsYWIECQBuYW1lX2hhc2js6EexuKuzrQMKAG5ldHdvcmtfaWRSsMxaCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mossy_stone_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZSAAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3NsYWIECQBuYW1lX2hhc2hiA4kFUl4tHAMKAG5ldHdvcmtfaWS6joSOCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:sandstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnBAAACAQAbmFtZRgAbWluZWNyYWZ0OnNhbmRzdG9uZV9zbGFiBAkAbmFtZV9oYXNo/GMI0MZnrhsDCgBuZXR3b3JrX2lkFP8WmwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cut_sandstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDBAAACAQAbmFtZRwAbWluZWNyYWZ0OmN1dF9zYW5kc3RvbmVfc2xhYgQJAG5hbWVfaGFzaE+zxVQweViJAwoAbmV0d29ya19pZHsu74YKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:smooth_sandstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4BAAACAQAbmFtZR8AbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc2xhYgQJAG5hbWVfaGFzaIkmsO1gw3gnAwoAbmV0d29ya19pZFSiwP0KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_sandstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc2xhYgQJAG5hbWVfaGFzaEyDjeWlUHItAwoAbmV0d29ya19pZIT4rmwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cut_red_sandstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEBAAACAQAbmFtZSAAbWluZWNyYWZ0OmN1dF9yZWRfc2FuZHN0b25lX3NsYWIECQBuYW1lX2hhc2hTVRS++snU3wMKAG5ldHdvcmtfaWSvIAviCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:smooth_red_sandstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6BAAACAQAbmFtZSMAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3NsYWIECQBuYW1lX2hhc2i9iN2UK272tgMKAG5ldHdvcmtfaWRUZrwJCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:granite_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/BAAACAQAbmFtZRYAbWluZWNyYWZ0OmdyYW5pdGVfc2xhYgQJAG5hbWVfaGFzaL0HprlAhhZwAwoAbmV0d29ya19pZIcIdc8KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_granite_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSABAAACAQAbmFtZR8AbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc2xhYgQJAG5hbWVfaGFzaP6bXk5w2dGrAwoAbmV0d29ya19pZCsRy1cKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:diorite_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9BAAACAQAbmFtZRYAbWluZWNyYWZ0OmRpb3JpdGVfc2xhYgQJAG5hbWVfaGFzaM3ppS8v55sNAwoAbmV0d29ya19pZB+Pv9oKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_diorite_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+BAAACAQAbmFtZR8AbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc2xhYgQJAG5hbWVfaGFzaLZlyJLkMPhyAwoAbmV0d29ya19pZFM0HYwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:andesite_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8BAAACAQAbmFtZRcAbWluZWNyYWZ0OmFuZGVzaXRlX3NsYWIECQBuYW1lX2hhc2icIrtuy/aosAMKAG5ldHdvcmtfaWTtXTtYCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_andesite_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7BAAACAQAbmFtZSAAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3NsYWIECQBuYW1lX2hhc2j56zJOfCF+3wMKAG5ldHdvcmtfaWRBs69FCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJyaWNrX3NsYWIECQBuYW1lX2hhc2hO/Da4jU2v4wMKAG5ldHdvcmtfaWRG/qphCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:nether_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsBAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl9icmlja19zbGFiBAkAbmFtZV9oYXNonymoa2zbbqMDCgBuZXR3b3JrX2lkquvR1QoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:red_nether_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5BAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaG89ujUk3Y64AwoAbmV0d29ya19pZEZIunAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:end_stone_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZR4AbWluZWNyYWZ0OmVuZF9zdG9uZV9icmlja19zbGFiBAkAbmFtZV9oYXNo4tkxQtl+IyQDCgBuZXR3b3JrX2lkhByH/woGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:quartz_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrBAAACAQAbmFtZRUAbWluZWNyYWZ0OnF1YXJ0el9zbGFiBAkAbmFtZV9oYXNo9JMj3upfsbwDCgBuZXR3b3JrX2lkn2g2VAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:smooth_quartz_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBBAAACAQAbmFtZRwAbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc2xhYgQJAG5hbWVfaGFzaHOSJv8ve0nmAwoAbmV0d29ya19pZFMk/JsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:purpur_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRzBAAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnB1cl9zbGFiBAkAbmFtZV9oYXNo4XeWbKpx2ScDCgBuZXR3b3JrX2lkRkga5goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:prismarine_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0BAAACAQAbmFtZRkAbWluZWNyYWZ0OnByaXNtYXJpbmVfc2xhYgQJAG5hbWVfaGFzaI9x+1fY8QRfAwoAbmV0d29ya19pZBTUZhwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dark_prismarine_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR1BAAACAQAbmFtZR4AbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zbGFiBAkAbmFtZV9oYXNoSsZGDkEL5ZUDCgBuZXR3b3JrX2lkNLQ8VwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:prismarine_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR2BAAACAQAbmFtZR8AbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaB1FSbVi97xJAwoAbmV0d29ya19pZEBwwFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:crimson_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc2xhYgQJAG5hbWVfaGFzaKZ+EfP0ZYOZAwoAbmV0d29ya19pZAxRUWAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:warped_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zbGFiBAkAbmFtZV9oYXNo/AT0e/Z9W7UDCgBuZXR3b3JrX2lk1yq11AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:blackstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaF/DD4ZUlNgtAwoAbmV0d29ya19pZGy1DjwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_blackstone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaDYnuUs86EWfAwoAbmV0d29ya19pZJj2bXIKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_blackstone_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaKySLqvHc4xXAwoAbmV0d29ya19pZOyWX94KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cobbled_deepslate_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3NsYWIECQBuYW1lX2hhc2gwJIVWK1TM2QMKAG5ldHdvcmtfaWTYAoX5CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_deepslate_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zbGFiBAkAbmFtZV9oYXNoC/Adiz8k6RYDCgBuZXR3b3JrX2lkuFYMAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:deepslate_tile_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3NsYWIECQBuYW1lX2hhc2hPydV6emzIXAMKAG5ldHdvcmtfaWQwlbFCCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:deepslate_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zbGFiBAkAbmFtZV9oYXNoSv62V7iw10UDCgBuZXR3b3JrX2lkWMoragoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:tuff_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAwAACAQAbmFtZRMAbWluZWNyYWZ0OnR1ZmZfc2xhYgQJAG5hbWVfaGFzaIhCGdlIsnMUAwoAbmV0d29ya19pZN1dUL4KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_tuff_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfc2xhYgQJAG5hbWVfaGFzaLXdb48YvAsHAwoAbmV0d29ya19pZAnJ7W0KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:tuff_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAwAACAQAbmFtZRkAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaLqPMjVCv5dIAwoAbmV0d29ya19pZOmeRhcKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:mud_brick_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja19zbGFiBAkAbmFtZV9oYXNoq/tGBQWkv08DCgBuZXR3b3JrX2lkl4nnMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAgAACAQAbmFtZRkAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaDsNpb2qs4iBAwoAbmV0d29ya19pZOTm2nsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:exposed_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNoahQ5OwIQb7kDCgBuZXR3b3JrX2lkrUlZLwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:weathered_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2hBIuGIOVVXogMKAG5ldHdvcmtfaWQgnaDiCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:oxidized_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaOptj9ycfpaDAwoAbmV0d29ya19pZMzFSRgKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaAlx6DZOCTHzAwoAbmV0d29ya19pZFRBvDAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_exposed_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNo3KqS5OnhtRIDCgBuZXR3b3JrX2lkHTGcTgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_weathered_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2gzZ1oX0HCFtwMKAG5ldHdvcmtfaWSgJR+XCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTAAgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaMjjTnLu1KcqAwoAbmV0d29ya19pZIxsnFYKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2JyaWNrcwQJAG5hbWVfaGFzaGAiQu8VWVJRAwoAbmV0d29ya19pZH2DjXUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mossy_stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjBAAACAQAbmFtZRwAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaIZBO00MONRIAwoAbmV0d29ya19pZL2WDrAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cracked_stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkBAAACAQAbmFtZR4AbWluZWNyYWZ0OmNyYWNrZWRfc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNocIkAp6riMz4DCgBuZXR3b3JrX2lkTWGeCwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:chiseled_stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlBAAACAQAbmFtZR8AbWluZWNyYWZ0OmNoaXNlbGVkX3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaMB2FPLLADkEAwoAbmV0d29ya19pZOIPn0IKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:smooth_stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AQAACAQAbmFtZRYAbWluZWNyYWZ0OnNtb290aF9zdG9uZQQJAG5hbWVfaGFzaMwf87/JaTNvAwoAbmV0d29ya19pZLkZICEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:end_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAAAACAQAbmFtZRQAbWluZWNyYWZ0OmVuZF9icmlja3MECQBuYW1lX2hhc2hIUFfxNLZaFgMKAG5ldHdvcmtfaWQ/vDihCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_blackstone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoIHgsgIdzKXcDCgBuZXR3b3JrX2lkUw9b3woGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cracked_polished_blackstone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAgAACAQAbmFtZSwAbWluZWNyYWZ0OmNyYWNrZWRfcG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3MECQBuYW1lX2hhc2jQIO1GQDk80AMKAG5ldHdvcmtfaWQ3UlRYCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:gilded_blackstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAgAACAQAbmFtZRsAbWluZWNyYWZ0OmdpbGRlZF9ibGFja3N0b25lBAkAbmFtZV9oYXNoNoWt1ocG0HEDCgBuZXR3b3JrX2lktL8gUwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:chiseled_polished_blackstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAgAACAQAbmFtZSYAbWluZWNyYWZ0OmNoaXNlbGVkX3BvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2gzFa+kEjCJgAMKAG5ldHdvcmtfaWR2NJX2CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:deepslate_tiles", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlcwQJAG5hbWVfaGFzaGcLLx3NXAFvAwoAbmV0d29ya19pZI/G/xYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cracked_deepslate_tiles", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAgAACAQAbmFtZSEAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX3RpbGVzBAkAbmFtZV9oYXNo9zWgkFuMM1QDCgBuZXR3b3JrX2lkGwY6OgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:deepslate_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja3MECQBuYW1lX2hhc2gucvFmPdZxigMKAG5ldHdvcmtfaWSH4HDPCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:tuff_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAwAACAQAbmFtZRUAbWluZWNyYWZ0OnR1ZmZfYnJpY2tzBAkAbmFtZV9oYXNo/hbQ+mXSK7wDCgBuZXR3b3JrX2lk6gmIwQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cracked_deepslate_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAgAACAQAbmFtZSIAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX2JyaWNrcwQJAG5hbWVfaGFzaN40aqhh9WqHAwoAbmV0d29ya19pZO9GPBQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:chiseled_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaEU7/uRG8HSBAwoAbmV0d29ya19pZEqmI0EKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:chiseled_tuff", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoaXNlbGVkX3R1ZmYECQBuYW1lX2hhc2iVliOT8OTQ9AMKAG5ldHdvcmtfaWTLNKOiCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:chiseled_tuff_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AwAACAQAbmFtZR4AbWluZWNyYWZ0OmNoaXNlbGVkX3R1ZmZfYnJpY2tzBAkAbmFtZV9oYXNo3oQw6gmxYuADCgBuZXR3b3JrX2lkm3D8AgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cobblestone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYmJsZXN0b25lBAkAbmFtZV9oYXNoPoK7mGlSUz4DCgBuZXR3b3JrX2lkLm7RZwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mossy_cobblestone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAAAACAQAbmFtZRsAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoGJ67FCbkChMDCgBuZXR3b3JrX2lk/pYs1AoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cobbled_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AgAACAQAbmFtZRsAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoLUz9Y/ywmLwDCgBuZXR3b3JrX2lkNwzZ+AoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZPsXMaQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:chiseled_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvBAAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX3NhbmRzdG9uZQQJAG5hbWVfaGFzaPEkxMvZmemgAwoAbmV0d29ya19pZGI5NB4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cut_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSwBAAACAQAbmFtZRcAbWluZWNyYWZ0OmN1dF9zYW5kc3RvbmUECQBuYW1lX2hhc2ichLQc71njnQMKAG5ldHdvcmtfaWSmBLkRCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:smooth_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSxBAAACAQAbmFtZRoAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmUECQBuYW1lX2hhc2huR7XTwISyCAMKAG5ldHdvcmtfaWSzWj3UCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWRXRYxZCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:chiseled_red_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS7BAAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX3JlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2gh5sX+ON054wMKAG5ldHdvcmtfaWT6Pw1PCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cut_red_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS8BAAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9yZWRfc2FuZHN0b25lBAkAbmFtZV9oYXNoaOtka4NrQ1EDCgBuZXR3b3JrX2lk3r/JPAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:smooth_red_sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS9BAAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lBAkAbmFtZV9oYXNoqsNl8x36ju4DCgBuZXR3b3JrX2lk7x5DTwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:coal_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvYWxfYmxvY2sECQBuYW1lX2hhc2jH8QQP3t5PiAMKAG5ldHdvcmtfaWRo+sR+CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dried_kelp_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAQAACAQAbmFtZRoAbWluZWNyYWZ0OmRyaWVkX2tlbHBfYmxvY2sECQBuYW1lX2hhc2iRoucexkrl8wMKAG5ldHdvcmtfaWQQCCrvCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:copper_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZIiUodwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:weathered_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAgAACAQAbmFtZRoAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2hJCQXbvobv+gMKAG5ldHdvcmtfaWQwM0lJCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:exposed_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAgAACAQAbmFtZRgAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoQH3Fukmu3CEDCgBuZXR3b3JrX2lk72jFIwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:oxidized_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMDtJqR0G5Y7AwoAbmV0d29ya19pZGjN8bUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAgAACAQAbmFtZRYAbWluZWNyYWZ0OndheGVkX2NvcHBlcgQJAG5hbWVfaGFzaPF+FG6Eh5fsAwoAbmV0d29ya19pZIjtz/0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_exposed_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAgAACAQAbmFtZR4AbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoig8IOc+SCikDCgBuZXR3b3JrX2lklz8yWQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_weathered_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAgAACAQAbmFtZSAAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2gjtPq8MOdvKgMKAG5ldHdvcmtfaWSQ9Ln9CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_oxidized_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS9AgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMaORhsO+LzjAwoAbmV0d29ya19pZJhGfLEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AwAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaC/JEFOWnmEcAwoAbmV0d29ya19pZC6YiiMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:exposed_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQABAAACAQAbmFtZR4AbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX2dyYXRlBAkAbmFtZV9oYXNolFIBYLYU0IcDCgBuZXR3b3JrX2lk4UqptAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:weathered_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBBAAACAQAbmFtZSAAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfZ3JhdGUECQBuYW1lX2hhc2jB3o8enlv1RgMKAG5ldHdvcmtfaWRih2pOCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:oxidized_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCBAAACAQAbmFtZR8AbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaBRfNhyndve7AwoAbmV0d29ya19pZKY2cnEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDBAAACAQAbmFtZRwAbWluZWNyYWZ0OndheGVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaDmC92M2RO+HAwoAbmV0d29ya19pZH4og2AKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_exposed_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEBAAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX2dyYXRlBAkAbmFtZV9oYXNoWmd6B+hWwiEDCgBuZXR3b3JrX2lk8d4ZQwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_weathered_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFBAAACAQAbmFtZSYAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfZ3JhdGUECQBuYW1lX2hhc2hXfilVFDAiYQMKAG5ldHdvcmtfaWQqTGC1CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_oxidized_copper_grate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGBAAACAQAbmFtZSUAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaEbeMT605GP4AwoAbmV0d29ya19pZOZjpkkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAgAACAQAbmFtZRQAbWluZWNyYWZ0OmN1dF9jb3BwZXIECQBuYW1lX2hhc2hAfN3NGax3eAMKAG5ldHdvcmtfaWTnFBtYCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:exposed_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAgAACAQAbmFtZRwAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaA85G3yv/w6pAwoAbmV0d29ya19pZMQhr0QKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:weathered_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAgAACAQAbmFtZR4AbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoVgRV0fBaz88DCgBuZXR3b3JrX2lk/0cYugoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:oxidized_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAgAACAQAbmFtZR0AbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2iP8WmFWOkriwMKAG5ldHdvcmtfaWQPdce7CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWReAgAACAQAbmFtZRoAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2jumiwOZIqv2AMKAG5ldHdvcmtfaWQvuxx9CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_exposed_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAgAACAQAbmFtZSIAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaPE/OfK6IoVMAwoAbmV0d29ya19pZHy5HkcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_weathered_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoCA1xDp11bnwDCgBuZXR3b3JrX2lkDyEDVQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS+AgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2i1pZAsZYHLDAMKAG5ldHdvcmtfaWQ/wSkCCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT3AwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaIsW5pmpJEuQAwoAbmV0d29ya19pZHetwrkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:exposed_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT4AwAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY2hpc2VsZWRfY29wcGVyBAkAbmFtZV9oYXNoOvrLJ0UowbgDCgBuZXR3b3JrX2lkZj7cPwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:weathered_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT5AwAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jaGlzZWxlZF9jb3BwZXIECQBuYW1lX2hhc2hh+42XlsWvGAMKAG5ldHdvcmtfaWS7Cy59CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:oxidized_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT6AwAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaLpTIsnfluiCAwoAbmV0d29ya19pZB9/jS8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AwAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaFnXvXY5OinzAwoAbmV0d29ya19pZAcKtHsKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_exposed_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AwAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY2hpc2VsZWRfY29wcGVyBAkAbmFtZV9oYXNoHJdq+Pph6hMDCgBuZXR3b3JrX2lkdge7IAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_oxidized_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AwAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaMj49OvlTpgCAwoAbmV0d29ya19pZN/r+roKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_weathered_chiseled_copper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AwAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jaGlzZWxlZF9jb3BwZXIECQBuYW1lX2hhc2hzuO+Sg9LYQwMKAG5ldHdvcmtfaWQ7AN7iCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHBAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcHBlcl9idWxiBAkAbmFtZV9oYXNo41TimHOsMWcDCgBuZXR3b3JrX2lkJnZvAgoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:exposed_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIBAAACAQAbmFtZR0AbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX2J1bGIECQBuYW1lX2hhc2g++f1wYLLCrAMKAG5ldHdvcmtfaWRLdMmGCgYAc3RhdGVzAQMAbGl0AAELAHBvd2VyZWRfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:weathered_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQJBAAACAQAbmFtZR8AbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfYnVsYgQJAG5hbWVfaGFzaMEtsYfwRTXlAwoAbmV0d29ya19pZAp51LQKBgBzdGF0ZXMBAwBsaXQAAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:oxidized_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKBAAACAQAbmFtZR4AbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNovnrBQZs8nDIDCgBuZXR3b3JrX2lkPsj0AAoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLBAAACAQAbmFtZRsAbWluZWNyYWZ0OndheGVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNoGTg6TYllMiIDCgBuZXR3b3JrX2lk9m0WhgoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waxed_exposed_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMBAAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX2J1bGIECQBuYW1lX2hhc2gI6xkPcvBDVwMKAG5ldHdvcmtfaWR7BRcACgYAc3RhdGVzAQMAbGl0AAELAHBvd2VyZWRfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:waxed_weathered_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNBAAACAQAbmFtZSUAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfYnVsYgQJAG5hbWVfaGFzaMsUnmp3/VqVAwoAbmV0d29ya19pZEoworoKBgBzdGF0ZXMBAwBsaXQAAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:waxed_oxidized_copper_bulb", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOBAAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNoBFKxY3fjVq4DCgBuZXR3b3JrX2lkzrJ6aAoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:iron_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAAAACAQAbmFtZRQAbWluZWNyYWZ0Omlyb25fYmxvY2sECQBuYW1lX2hhc2jYINmJQbvV/gMKAG5ldHdvcmtfaWRf7AbICgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:gold_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdvbGRfYmxvY2sECQBuYW1lX2hhc2iYLshvjtXzFwMKAG5ldHdvcmtfaWTDJGBcCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:emerald_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAAAACAQAbmFtZRcAbWluZWNyYWZ0OmVtZXJhbGRfYmxvY2sECQBuYW1lX2hhc2hK6QunqJznNAMKAG5ldHdvcmtfaWRk5+otCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:diamond_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AAAACAQAbmFtZRcAbWluZWNyYWZ0OmRpYW1vbmRfYmxvY2sECQBuYW1lX2hhc2iGKrxuvkytFQMKAG5ldHdvcmtfaWQQeQZXCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:lapis_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxhcGlzX2Jsb2NrBAkAbmFtZV9oYXNoDZ44xdb2zVoDCgBuZXR3b3JrX2lktVy0BAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:raw_copper_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAgAACAQAbmFtZRoAbWluZWNyYWZ0OnJhd19jb3BwZXJfYmxvY2sECQBuYW1lX2hhc2hw1KG0TNUGgwMKAG5ldHdvcmtfaWS1vGo/CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:raw_iron_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19pcm9uX2Jsb2NrBAkAbmFtZV9oYXNo9XyzNIQXxvwDCgBuZXR3b3JrX2lknms1QAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:raw_gold_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19nb2xkX2Jsb2NrBAkAbmFtZV9oYXNo6YuwuLwfOBwDCgBuZXR3b3JrX2lkLiQ5gQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:quartz_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZE2axGsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:quartz_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9icmlja3MECQBuYW1lX2hhc2jSZO590dd8sAMKAG5ldHdvcmtfaWSc5xCLCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:quartz_pillar", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS5BAAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9waWxsYXIECQBuYW1lX2hhc2igp62HI+PuSwMKAG5ldHdvcmtfaWS9SGXLCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:chiseled_quartz_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4BAAACAQAbmFtZR8AbWluZWNyYWZ0OmNoaXNlbGVkX3F1YXJ0el9ibG9jawQJAG5hbWVfaGFzaAftJM9mCAvaAwoAbmV0d29ya19pZFwy0s0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:smooth_quartz", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS6BAAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9xdWFydHoECQBuYW1lX2hhc2hIVzzgiItGagMKAG5ldHdvcmtfaWTVWgU2CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:prismarine", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWQnuuW1CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:prismarine_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzBAAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzBAkAbmFtZV9oYXNozeGe3/7s5fcDCgBuZXR3b3JrX2lkj/iBnAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dark_prismarine", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSyBAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZQQJAG5hbWVfaGFzaK+rhxsgkzplAwoAbmV0d29ya19pZIdA0I0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:slime", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnNsaW1lBAkAbmFtZV9oYXNoHJiEEJx+JlkDCgBuZXR3b3JrX2lkfgfVzAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:honey_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAQAACAQAbmFtZRUAbWluZWNyYWZ0OmhvbmV5X2Jsb2NrBAkAbmFtZV9oYXNo9zLYSUlelywDCgBuZXR3b3JrX2lko+dyWgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:honeycomb_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAQAACAQAbmFtZRkAbWluZWNyYWZ0OmhvbmV5Y29tYl9ibG9jawQJAG5hbWVfaGFzaASIPuOCYd1oAwoAbmV0d29ya19pZKys4n4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:hay_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAAAACAQAbmFtZRMAbWluZWNyYWZ0OmhheV9ibG9jawQJAG5hbWVfaGFzaIB2VxKxX8EpAwoAbmV0d29ya19pZKuQSloKBgBzdGF0ZXMDCgBkZXByZWNhdGVkAAAAAAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bone_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAAAACAQAbmFtZRQAbWluZWNyYWZ0OmJvbmVfYmxvY2sECQBuYW1lX2hhc2i4ZX576W9AWgMKAG5ldHdvcmtfaWTWGacQCgYAc3RhdGVzAwoAZGVwcmVjYXRlZAAAAAAICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:nether_brick", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAAAACAQAbmFtZRYAbWluZWNyYWZ0Om5ldGhlcl9icmljawQJAG5hbWVfaGFzaMxcRiheU+nXAwoAbmV0d29ya19pZMkmzloKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:red_nether_brick", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAAAACAQAbmFtZRoAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2sECQBuYW1lX2hhc2j8pRO4LfoECAMKAG5ldHdvcmtfaWRpdF0YCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:chiseled_nether_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX25ldGhlcl9icmlja3MECQBuYW1lX2hhc2g31SBPTcUK1QMKAG5ldHdvcmtfaWS8TJ+TCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cracked_nether_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAgAACAQAbmFtZR8AbWluZWNyYWZ0OmNyYWNrZWRfbmV0aGVyX2JyaWNrcwQJAG5hbWVfaGFzaAdC6eKzXT5tAwoAbmV0d29ya19pZIUSejwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:netherite_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcml0ZV9ibG9jawQJAG5hbWVfaGFzaMghh6Zib/ZKAwoAbmV0d29ya19pZIz0mq0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:lodestone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAQAACAQAbmFtZRMAbWluZWNyYWZ0OmxvZGVzdG9uZQQJAG5hbWVfaGFzaJ2gmHOTlXv8AwoAbmV0d29ya19pZEfgB4wKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:white_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAAAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWSO8paQCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:light_gray_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfd29vbAQJAG5hbWVfaGFzaOpdQ1a2v4b3AwoAbmV0d29ya19pZIqZCYEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:gray_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAwAACAQAbmFtZRMAbWluZWNyYWZ0OmdyYXlfd29vbAQJAG5hbWVfaGFzaLsc1Lp1xdIOAwoAbmV0d29ya19pZFUs+HgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:black_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrX3dvb2wECQBuYW1lX2hhc2hP2HC6o0X4HAMKAG5ldHdvcmtfaWRUbORcCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brown_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJyb3duX3dvb2wECQBuYW1lX2hhc2ig5IW89PrREwMKAG5ldHdvcmtfaWRjT9j8CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAwAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF93b29sBAkAbmFtZV9oYXNoY4TBDq+mFgUDCgBuZXR3b3JrX2lktn9lcAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:orange_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAwAACAQAbmFtZRUAbWluZWNyYWZ0Om9yYW5nZV93b29sBAkAbmFtZV9oYXNoFstfrTZfSCgDCgBuZXR3b3JrX2lk+rqywwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:yellow_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAwAACAQAbmFtZRUAbWluZWNyYWZ0OnllbGxvd193b29sBAkAbmFtZV9oYXNoTFyus2RHegcDCgBuZXR3b3JrX2lkkKBhXAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:lime_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAwAACAQAbmFtZRMAbWluZWNyYWZ0OmxpbWVfd29vbAQJAG5hbWVfaGFzaNVnnzKiMxmeAwoAbmV0d29ya19pZG9b32kKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:green_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAwAACAQAbmFtZRQAbWluZWNyYWZ0OmdyZWVuX3dvb2wECQBuYW1lX2hhc2i3mElRYHIcSQMKAG5ldHdvcmtfaWSssprwCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cyan_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAwAACAQAbmFtZRMAbWluZWNyYWZ0OmN5YW5fd29vbAQJAG5hbWVfaGFzaBNDfvHn8dqFAwoAbmV0d29ya19pZK0hAbgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:light_blue_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfd29vbAQJAG5hbWVfaGFzaLWFAUfyxFPNAwoAbmV0d29ya19pZL2oEugKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:blue_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAwAACAQAbmFtZRMAbWluZWNyYWZ0OmJsdWVfd29vbAQJAG5hbWVfaGFzaLjHyxxbTWCLAwoAbmV0d29ya19pZPaLdFQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:purple_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAwAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnBsZV93b29sBAkAbmFtZV9oYXNojvFtqzjAf/4DCgBuZXR3b3JrX2lklqASNQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:magenta_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AwAACAQAbmFtZRYAbWluZWNyYWZ0Om1hZ2VudGFfd29vbAQJAG5hbWVfaGFzaGuOHvf+Pd4yAwoAbmV0d29ya19pZI4UoDQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:pink_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AwAACAQAbmFtZRMAbWluZWNyYWZ0OnBpbmtfd29vbAQJAG5hbWVfaGFzaPiVA2pFeoFLAwoAbmV0d29ya19pZOZRO6oKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:white_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAAAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZEahDFcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:light_gray_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0BAkAbmFtZV9oYXNoHPw6ArBAsP0DCgBuZXR3b3JrX2lkQoAeUAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:gray_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FycGV0BAkAbmFtZV9oYXNoZVR0OI+1VRADCgBuZXR3b3JrX2lkETF4WwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:black_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhcnBldAQJAG5hbWVfaGFzaOk7LP9NptyhAwoAbmV0d29ya19pZFjmXtIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:brown_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhcnBldAQJAG5hbWVfaGFzaNaXFyOsAvIvAwoAbmV0d29ya19pZHPjFuoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:red_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAwAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYXJwZXQECQBuYW1lX2hhc2i9eSKBf6SO3wMKAG5ldHdvcmtfaWQuhI/KCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:orange_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAwAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQECQBuYW1lX2hhc2hIUkO4HlAdygMKAG5ldHdvcmtfaWSyKV9OCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:yellow_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAwAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYXJwZXQECQBuYW1lX2hhc2hSDKX3scCamwMKAG5ldHdvcmtfaWT8nq+ECgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:lime_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAwAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FycGV0BAkAbmFtZV9oYXNo+6KFOpzsib4DCgBuZXR3b3JrX2lkT+DS4woGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:green_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAwAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhcnBldAQJAG5hbWVfaGFzaCHPMP9ltqFJAwoAbmV0d29ya19pZBgwAvAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cyan_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAwAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FycGV0BAkAbmFtZV9oYXNobXf62dQBJj8DCgBuZXR3b3JrX2lkKVppLgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:light_blue_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0BAkAbmFtZV9oYXNo20l4oktdZ3sDCgBuZXR3b3JrX2lkjdeMiwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:blue_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWReAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FycGV0BAkAbmFtZV9oYXNo3p3lsW0eQwsDCgBuZXR3b3JrX2lkAovdPQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:purple_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAwAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQECQBuYW1lX2hhc2jwIA9pW/qp7QMKAG5ldHdvcmtfaWTqJqhjCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:magenta_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAwAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0BAkAbmFtZV9oYXNoFXT36YNNZhMDCgBuZXR3b3JrX2lk+tqsGAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:pink_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FycGV0BAkAbmFtZV9oYXNoHll72oqk+OoDCgBuZXR3b3JrX2lkrnBYDwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:white_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTtAAAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZJPZY8AKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:light_gray_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo7EUk30hmUtYDCgBuZXR3b3JrX2lkh8jVIwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:gray_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmdyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoW77af6WihdwDCgBuZXR3b3JrX2lkSsqC1woGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:black_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTSAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaAfWYp0xtgcfAwoAbmV0d29ya19pZMWTC8EKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:brown_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaB74EeiLO46XAwoAbmV0d29ya19pZEDHKqwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:red_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAwAACAQAbmFtZR0AbWluZWNyYWZ0OnJlZF9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gjFut6Z/VH1gMKAG5ldHdvcmtfaWSvcmwYCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:orange_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAwAACAQAbmFtZSAAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gADDj2IJiw+gMKAG5ldHdvcmtfaWTHph0FCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:yellow_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAwAACAQAbmFtZSAAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iy6qKNn3ob5wMKAG5ldHdvcmtfaWQZAI39CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:lime_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAwAACAQAbmFtZR4AbWluZWNyYWZ0OmxpbWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo4dYIPslbXPUDCgBuZXR3b3JrX2lk2O8X0AoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:green_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAwAACAQAbmFtZR8AbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaM/c9x2aJh3HAwoAbmV0d29ya19pZA0VfBMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cyan_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAwAACAQAbmFtZR4AbWluZWNyYWZ0OmN5YW5fY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNok+xKAe7XXjoDCgBuZXR3b3JrX2lkmkn6uwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:light_blue_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNogScpIQceyAEDCgBuZXR3b3JrX2lkOmVSbgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:blue_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoFp7mmeL86r0DCgBuZXR3b3JrX2lkS3b3RQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:purple_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAwAACAQAbmFtZSAAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iYcVU04hoStwMKAG5ldHdvcmtfaWQXimEjCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:magenta_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAwAACAQAbmFtZSEAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoy/70q6VPsWgDCgBuZXR3b3JrX2lkf9mxQwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:pink_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBpbmtfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoVikSAf8DwV0DCgBuZXR3b3JrX2lku2MivwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:white_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAAAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lk3MAYQAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:light_gray_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGUECQBuYW1lX2hhc2hEtet5wuDIKAMKAG5ldHdvcmtfaWQISs02CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:gray_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AwAACAQAbmFtZRcAbWluZWNyYWZ0OmdyYXlfY29uY3JldGUECQBuYW1lX2hhc2j92INnb0a83AMKAG5ldHdvcmtfaWQj8RHwCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:black_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAwAACAQAbmFtZRgAbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlBAkAbmFtZV9oYXNo2X7NDIQmZ70DCgBuZXR3b3JrX2lk2uiVDQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:brown_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AwAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlBAkAbmFtZV9oYXNoeka02BwXf6oDCgBuZXR3b3JrX2lkYf+xDQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:red_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAwAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9jb25jcmV0ZQQJAG5hbWVfaGFzaPWmNowLGubqAwoAbmV0d29ya19pZKwyx58KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:orange_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRzAwAACAQAbmFtZRkAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZQQJAG5hbWVfaGFzaAgE8XmaAi6+AwoAbmV0d29ya19pZMDQNz8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:yellow_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR2AwAACAQAbmFtZRkAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZQQJAG5hbWVfaGFzaE6ONfJPBd0+AwoAbmV0d29ya19pZMarutwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:lime_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR3AwAACAQAbmFtZRcAbWluZWNyYWZ0OmxpbWVfY29uY3JldGUECQBuYW1lX2hhc2gnd8JW6wmJcAMKAG5ldHdvcmtfaWTd47aoCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:green_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AwAACAQAbmFtZRgAbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlBAkAbmFtZV9oYXNokbFxRKchQZkDCgBuZXR3b3JrX2lkmhZWUgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cyan_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AwAACAQAbmFtZRcAbWluZWNyYWZ0OmN5YW5fY29uY3JldGUECQBuYW1lX2hhc2hFRrWJ33qj1wMKAG5ldHdvcmtfaWQbi5b8CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:light_blue_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR1AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGUECQBuYW1lX2hhc2gHAe0kl0SE4AMKAG5ldHdvcmtfaWRL/GbSCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:blue_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AwAACAQAbmFtZRcAbWluZWNyYWZ0OmJsdWVfY29uY3JldGUECQBuYW1lX2hhc2hiay301nnj1wMKAG5ldHdvcmtfaWRMvFXNCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:purple_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AwAACAQAbmFtZRkAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZQQJAG5hbWVfaGFzaHBHflsPIwdXAwoAbmV0d29ya19pZCyKA5gKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:magenta_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AwAACAQAbmFtZRoAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGUECQBuYW1lX2hhc2gN7LuB/OvdZAMKAG5ldHdvcmtfaWTc6ZOdCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:pink_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpbmtfY29uY3JldGUECQBuYW1lX2hhc2ii2G5F0u3SOAMKAG5ldHdvcmtfaWSszGgrCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:hardened_clay", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAAAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRBCOrrCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:white_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAAAACAQAbmFtZRoAbWluZWNyYWZ0OndoaXRlX3RlcnJhY290dGEECQBuYW1lX2hhc2j3RSdgmnAIewMKAG5ldHdvcmtfaWSimKw+CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:light_gray_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAz1Ri3wIxomAwoAbmV0d29ya19pZH5qgOcKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:gray_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAwAACAQAbmFtZRkAbWluZWNyYWZ0OmdyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAXdSLAaNZ9vAwoAbmV0d29ya19pZM1QDV0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:black_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsYWNrX3RlcnJhY290dGEECQBuYW1lX2hhc2jxssdv5vlbpgMKAG5ldHdvcmtfaWRE3Ru/CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brown_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJyb3duX3RlcnJhY290dGEECQBuYW1lX2hhc2gG4kPenmOF9gMKAG5ldHdvcmtfaWQ/i0iNCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAwAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo7fX56HXFejEDCgBuZXR3b3JrX2lk8tTF8QoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:orange_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAwAACAQAbmFtZRsAbWluZWNyYWZ0Om9yYW5nZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo0Hjmql3sruMDCgBuZXR3b3JrX2lklmqmkAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:yellow_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAwAACAQAbmFtZRsAbWluZWNyYWZ0OnllbGxvd190ZXJyYWNvdHRhBAkAbmFtZV9oYXNoqkyKKrmA3VcDCgBuZXR3b3JrX2lkaM/orAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:lime_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpbWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaANjADFOF9v7AwoAbmV0d29ya19pZJt0XsgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:green_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyZWVuX3RlcnJhY290dGEECQBuYW1lX2hhc2j5Ybq36yYwRQMKAG5ldHdvcmtfaWQ8kGdHCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cyan_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAwAACAQAbmFtZRkAbWluZWNyYWZ0OmN5YW5fdGVycmFjb3R0YQQJAG5hbWVfaGFzaN09COzMuHwAAwoAbmV0d29ya19pZIWPCzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:light_blue_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaOMytez7cOZiAwoAbmV0d29ya19pZFHK1UsKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:blue_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaF6inyTK5RpAAwoAbmV0d29ya19pZF5mVZIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:purple_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAwAACAQAbmFtZRsAbWluZWNyYWZ0OnB1cnBsZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoKF7YG61yTbEDCgBuZXR3b3JrX2lkhtRDlwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:magenta_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAwAACAQAbmFtZRwAbWluZWNyYWZ0Om1hZ2VudGFfdGVycmFjb3R0YQQJAG5hbWVfaGFzaLWvtpAVtztyAwoAbmV0d29ya19pZN5SoakKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:pink_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAwAACAQAbmFtZRkAbWluZWNyYWZ0OnBpbmtfdGVycmFjb3R0YQQJAG5hbWVfaGFzaJ7mzvyzSQZTAwoAbmV0d29ya19pZDJWe4YKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:white_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAAAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkIlj9AAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:silver_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAAAACAQAbmFtZSIAbWluZWNyYWZ0OnNpbHZlcl9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAVsA0CnhzA4AwoAbmV0d29ya19pZPnxtJEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:gray_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAAAACAQAbmFtZSAAbWluZWNyYWZ0OmdyYXlfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2jvLZt9u/lF/AMKAG5ldHdvcmtfaWQVU8eFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:black_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJsYWNrX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoe8I4xAXbO5UDCgBuZXR3b3JrX2lk2Icb9AoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brown_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJyb3duX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoSiNZOobbpjoDCgBuZXR3b3JrX2lkJy0jwgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaBdWFGLmCLFVAwoAbmV0d29ya19pZMYBJSEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:orange_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAAAACAQAbmFtZSIAbWluZWNyYWZ0Om9yYW5nZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaMyJMrnPr7szAwoAbmV0d29ya19pZN6+7TUKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:yellow_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAAAACAQAbmFtZSIAbWluZWNyYWZ0OnllbGxvd19nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaN6NaIhf6m0uAwoAbmV0d29ya19pZKRHXeoKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:lime_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAAAACAQAbmFtZSAAbWluZWNyYWZ0OmxpbWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2iF3E68/rB2EAMKAG5ldHdvcmtfaWSP7qQWCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:green_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAAAACAQAbmFtZSEAbWluZWNyYWZ0OmdyZWVuX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNow5mo8aQDFboDCgBuZXR3b3JrX2lkoF11kgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:cyan_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAAAACAQAbmFtZSAAbWluZWNyYWZ0OmN5YW5fZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gnNB+cCFRJhwMKAG5ldHdvcmtfaWT9buMtCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:light_blue_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAAAACAQAbmFtZSYAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gladnCDBKCigMKAG5ldHdvcmtfaWS5CszFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:blue_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAAAACAQAbmFtZSAAbWluZWNyYWZ0OmJsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2giOZK+2nB1igMKAG5ldHdvcmtfaWR+e22CCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:purple_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAAAACAQAbmFtZSIAbWluZWNyYWZ0OnB1cnBsZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaIQU03txeAfHAwoAbmV0d29ya19pZLKbSE4KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:magenta_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAAAACAQAbmFtZSMAbWluZWNyYWZ0Om1hZ2VudGFfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2i/SNqDJbfjMgMKAG5ldHdvcmtfaWQKf9UvCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:pink_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAAAACAQAbmFtZSAAbWluZWNyYWZ0OnBpbmtfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2hik8DVt4g+twMKAG5ldHdvcmtfaWTKzav2CgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:purpur_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZGCZ+4UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:purpur_pillar", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2BAAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9waWxsYXIECQBuYW1lX2hhc2iFcSsdykO+jgMKAG5ldHdvcmtfaWQe0+geCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:packed_mud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9tdWQECQBuYW1lX2hhc2gHOMa121h4FgMKAG5ldHdvcmtfaWTUb6LyCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:mud_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAgAACAQAbmFtZRQAbWluZWNyYWZ0Om11ZF9icmlja3MECQBuYW1lX2hhc2iDL/SVl/PewQMKAG5ldHdvcmtfaWSkBjaDCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:nether_wart_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9XGS4GNnlV4DCgBuZXR3b3JrX2lkh3apIgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:warped_wart_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAQAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9IqDS9yUPJoDCgBuZXR3b3JrX2lkMpKAbAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:shroomlight", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNocm9vbWxpZ2h0BAkAbmFtZV9oYXNoZHCHcHX/HYADCgBuZXR3b3JrX2lkLG2JiwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:crimson_nylium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fbnlsaXVtBAkAbmFtZV9oYXNoOr6DJYW2bFYDCgBuZXR3b3JrX2lkuWpRDgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:warped_nylium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9ueWxpdW0ECQBuYW1lX2hhc2g0Zf89cfr3rwMKAG5ldHdvcmtfaWSu/kekCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:netherrack", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAAAACAQAbmFtZRQAbWluZWNyYWZ0Om5ldGhlcnJhY2sECQBuYW1lX2hhc2i/r5ZyRsvPyQMKAG5ldHdvcmtfaWTAiTOACgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:soul_soil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAQAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc29pbAQJAG5hbWVfaGFzaC1/87ccutuTAwoAbmV0d29ya19pZKc63SMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:grass_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXNzX2Jsb2NrBAkAbmFtZV9oYXNojPyGp3/CSZwDCgBuZXR3b3JrX2lktCgx3goGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:podzol", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTzAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBvZHpvbAQJAG5hbWVfaGFzaBzqokRjH4Z1AwoAbmV0d29ya19pZPPS/GUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mycelium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAAAACAQAbmFtZRIAbWluZWNyYWZ0Om15Y2VsaXVtBAkAbmFtZV9oYXNojTN09cKickIDCgBuZXR3b3JrX2lkLNPxXQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:grass_path", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdyYXNzX3BhdGgECQBuYW1lX2hhc2i0/KZV8Qsy+gMKAG5ldHdvcmtfaWT7CcdzCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dirt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWSG706CCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:coarse_dirt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTBBAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYXJzZV9kaXJ0BAkAbmFtZV9oYXNosd+cah7WSmoDCgBuZXR3b3JrX2lkgS5RcAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dirt_with_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRpcnRfd2l0aF9yb290cwQJAG5hbWVfaGFzaLCNDYPviDCIAwoAbmV0d29ya19pZNCkwzoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:farmland", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AAAACAQAbmFtZRIAbWluZWNyYWZ0OmZhcm1sYW5kBAkAbmFtZV9oYXNoxyQ5ag7LolADCgBuZXR3b3JrX2lkX618FQoGAHN0YXRlcwMSAG1vaXN0dXJpemVkX2Ftb3VudAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAgAACAQAbmFtZQ0AbWluZWNyYWZ0Om11ZAQJAG5hbWVfaGFzaPb/3P+uLy+9AwoAbmV0d29ya19pZPIUlUkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:clay", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmNsYXkECQBuYW1lX2hhc2j/S6sKXRcpzwMKAG5ldHdvcmtfaWRmsb8nCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:iron_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAAAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lk3loneQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:gold_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAAAACAQAbmFtZRIAbWluZWNyYWZ0OmdvbGRfb3JlBAkAbmFtZV9oYXNoC5Y+DUGXLC4DCgBuZXR3b3JrX2lkNhvMfwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:diamond_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AAAACAQAbmFtZRUAbWluZWNyYWZ0OmRpYW1vbmRfb3JlBAkAbmFtZV9oYXNokUOJ2wZZrGQDCgBuZXR3b3JrX2lk/dChVAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:lapis_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAAAACAQAbmFtZRMAbWluZWNyYWZ0OmxhcGlzX29yZQQJAG5hbWVfaGFzaMrmrUrSzb7qAwoAbmV0d29ya19pZMg+qK4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:redstone_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZHN0b25lX29yZQQJAG5hbWVfaGFzaFHVnp8Wc4JbAwoAbmV0d29ya19pZKDYvQoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:coal_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAAAACAQAbmFtZRIAbWluZWNyYWZ0OmNvYWxfb3JlBAkAbmFtZV9oYXNo1OjA+Iuy51oDCgBuZXR3b3JrX2lk+R/aKAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:copper_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcHBlcl9vcmUECQBuYW1lX2hhc2iSZduSntOzOwMKAG5ldHdvcmtfaWQtIuCnCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:emerald_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVtZXJhbGRfb3JlBAkAbmFtZV9oYXNoJTovr+VgINsDCgBuZXR3b3JrX2lknbkqCgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:quartz_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAAAACAQAbmFtZRQAbWluZWNyYWZ0OnF1YXJ0el9vcmUECQBuYW1lX2hhc2g0yNHLMK9TaQMKAG5ldHdvcmtfaWSzN7nzCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:nether_gold_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcl9nb2xkX29yZQQJAG5hbWVfaGFzaEJZ7segIBgBAwoAbmV0d29ya19pZNI9pDgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:ancient_debris", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFuY2llbnRfZGVicmlzBAkAbmFtZV9oYXNoNrbxMc9AwKcDCgBuZXR3b3JrX2lkrSNjEAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:deepslate_iron_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9pcm9uX29yZQQJAG5hbWVfaGFzaB/fDL9pgvXXAwoAbmV0d29ya19pZFA0bz4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:deepslate_gold_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9nb2xkX29yZQQJAG5hbWVfaGFzaF9G7WYhKFinAwoAbmV0d29ya19pZHQTfBUKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:deepslate_diamond_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9kaWFtb25kX29yZQQJAG5hbWVfaGFzaEUH5USh+iD3AwoAbmV0d29ya19pZHP6VzAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:deepslate_lapis_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV9sYXBpc19vcmUECQBuYW1lX2hhc2j+yFxU/KZs1gMKAG5ldHdvcmtfaWRKINzICgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:deepslate_redstone_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9yZWRzdG9uZV9vcmUECQBuYW1lX2hhc2iVgM3wWWD6ugMKAG5ldHdvcmtfaWReBdYRCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:deepslate_emerald_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9lbWVyYWxkX29yZQQJAG5hbWVfaGFzaNlfo5HTwS6wAwoAbmV0d29ya19pZNeie6sKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:deepslate_coal_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb2FsX29yZQQJAG5hbWVfaGFzaIjikmcbRrPPAwoAbmV0d29ya19pZD9TiygKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:deepslate_copper_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb3BwZXJfb3JlBAkAbmFtZV9oYXNottjV4Ev5LAQDCgBuZXR3b3JrX2lkP23rgQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkIQ4xgAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:granite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAwAACAQAbmFtZREAbWluZWNyYWZ0OmdyYW5pdGUECQBuYW1lX2hhc2iq+Dur2pw4AwMKAG5ldHdvcmtfaWT2NMfJCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:diorite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAwAACAQAbmFtZREAbWluZWNyYWZ0OmRpb3JpdGUECQBuYW1lX2hhc2iaFsq2iinZBQMKAG5ldHdvcmtfaWQqGE6XCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:andesite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAwAACAQAbmFtZRIAbWluZWNyYWZ0OmFuZGVzaXRlBAkAbmFtZV9oYXNosaLIEnQQoSYDCgBuZXR3b3JrX2lkEApRZAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:blackstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrc3RvbmUECQBuYW1lX2hhc2iMFYziD80D6QMKAG5ldHdvcmtfaWSrUryHCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AgAACAQAbmFtZRMAbWluZWNyYWZ0OmRlZXBzbGF0ZQQJAG5hbWVfaGFzaKX5pAblxz8TAwoAbmV0d29ya19pZOJoQjsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:tuff", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAgAACAQAbmFtZQ4AbWluZWNyYWZ0OnR1ZmYECQBuYW1lX2hhc2h1Rwc1XYsBGwMKAG5ldHdvcmtfaWRwQGn0CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:basalt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhc2FsdAQJAG5hbWVfaGFzaH+UQO2yWodiAwoAbmV0d29ya19pZBPNSV4KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_granite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGUECQBuYW1lX2hhc2iLiEfys8pFIAMKAG5ldHdvcmtfaWTCxxcHCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_diorite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGUECQBuYW1lX2hhc2hTxY4fKmNmlAMKAG5ldHdvcmtfaWTmtjdRCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_andesite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAwAACAQAbmFtZRsAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlBAkAbmFtZV9oYXNovl28uFk4HuQDCgBuZXR3b3JrX2lklFjuCwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:polished_blackstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAgAACAQAbmFtZR0AbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2jT9fHCl6vWQQMKAG5ldHdvcmtfaWR/Ho6oCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaHC1edoaWF3uAwoAbmV0d29ya19pZCPeQsEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:polished_tuff", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmYECQBuYW1lX2hhc2hyaLe/KEVZ0gMKAG5ldHdvcmtfaWTcX3NrCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_basalt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAQAACAQAbmFtZRkAbWluZWNyYWZ0OnBvbGlzaGVkX2Jhc2FsdAQJAG5hbWVfaGFzaMS+L0gMnRcBAwoAbmV0d29ya19pZF+/mHwKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:smooth_basalt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AgAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9iYXNhbHQECQBuYW1lX2hhc2jKPUdz89kuNAMKAG5ldHdvcmtfaWTkb/oVCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:gravel", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAAAACAQAbmFtZRAAbWluZWNyYWZ0OmdyYXZlbAQJAG5hbWVfaGFzaOFxz8XJd2r/AwoAbmV0d29ya19pZBpfI1sKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:sand", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWRjeUMICgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:red_sand", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS0BAAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF9zYW5kBAkAbmFtZV9oYXNoCiarI69JQCkDCgBuZXR3b3JrX2lkU8UD/AoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cactus", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAAAACAQAbmFtZRAAbWluZWNyYWZ0OmNhY3R1cwQJAG5hbWVfaGFzaCG9zL0N4wvGAwoAbmV0d29ya19pZDeCERAKBgBzdGF0ZXMDAwBhZ2UAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAAAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWQjfjoxCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQJAQAACAQAbmFtZRoAbWluZWNyYWZ0OnN0cmlwcGVkX29ha19sb2cECQBuYW1lX2hhc2h8dqh+OOHU4wMKAG5ldHdvcmtfaWSYKjdrCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:spruce_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AwAACAQAbmFtZRQAbWluZWNyYWZ0OnNwcnVjZV9sb2cECQBuYW1lX2hhc2hZ03qaLoF3WgMKAG5ldHdvcmtfaWRlFD8eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_spruce_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV9sb2cECQBuYW1lX2hhc2iNrhKjS5IyrgMKAG5ldHdvcmtfaWRQcEC3CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:birch_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AwAACAQAbmFtZRMAbWluZWNyYWZ0OmJpcmNoX2xvZwQJAG5hbWVfaGFzaBUzT3NxsZAnAwoAbmV0d29ya19pZBKN3VQKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:stripped_birch_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAQAACAQAbmFtZRwAbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX2xvZwQJAG5hbWVfaGFzaCFKS4AeuSidAwoAbmV0d29ya19pZN0IONIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:jungle_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AwAACAQAbmFtZRQAbWluZWNyYWZ0Omp1bmdsZV9sb2cECQBuYW1lX2hhc2gkwW0KNulqDgMKAG5ldHdvcmtfaWQaziU/CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_jungle_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV9sb2cECQBuYW1lX2hhc2hAwMsgOk02JAMKAG5ldHdvcmtfaWQvls0eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:acacia_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAAAACAQAbmFtZRQAbWluZWNyYWZ0OmFjYWNpYV9sb2cECQBuYW1lX2hhc2iV48VpYhjoYQMKAG5ldHdvcmtfaWRxEqe0CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_acacia_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV9sb2cECQBuYW1lX2hhc2hJb0lQqnEqlgMKAG5ldHdvcmtfaWRg3IdRCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dark_oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AwAACAQAbmFtZRYAbWluZWNyYWZ0OmRhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaIWfVRd0XUo3AwoAbmV0d29ya19pZPMM7LYKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:stripped_dark_oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaPFTdxRdPwkOAwoAbmV0d29ya19pZDIzenIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mangrove_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaHZe6DzPZBobAwoAbmV0d29ya19pZG6DuYkKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:stripped_mangrove_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaLqIBo4hwA//AwoAbmV0d29ya19pZPtRn7UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cherry_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAwAACAQAbmFtZRQAbWluZWNyYWZ0OmNoZXJyeV9sb2cECQBuYW1lX2hhc2hwFlaioppB1wMKAG5ldHdvcmtfaWS2sdXECgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_cherry_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAwAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV9sb2cECQBuYW1lX2hhc2i85H6G+WhXaAMKAG5ldHdvcmtfaWRjzoglCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crimson_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAQAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc3RlbQQJAG5hbWVfaGFzaM0FzfL0UTKZAwoAbmV0d29ya19pZKvzID0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:stripped_crimson_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25fc3RlbQQJAG5hbWVfaGFzaDlA6nood57EAwoAbmV0d29ya19pZHrIqjIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:warped_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAQAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zdGVtBAkAbmFtZV9oYXNon7cKfPZxdrUDCgBuZXR3b3JrX2lkerWyMwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stripped_warped_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAQAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9zdGVtBAkAbmFtZV9oYXNoEw+y0dDPSd8DCgBuZXR3b3JrX2lkIQ9vBAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha193b29kBAkAbmFtZV9oYXNoqQIkuVPyJX0DCgBuZXR3b3JrX2lku2G1YAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stripped_oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyBAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0cmlwcGVkX29ha193b29kBAkAbmFtZV9oYXNovW6KCv+VZnsDCgBuZXR3b3JrX2lkkhWGegoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:spruce_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV93b29kBAkAbmFtZV9oYXNoTrIJ5TAQ+OgDCgBuZXR3b3JrX2lkaXLxCwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stripped_spruce_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzBAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV93b29kBAkAbmFtZV9oYXNoMnuUk4Xo6icDCgBuZXR3b3JrX2lkes2ydAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:birch_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3dvb2QECQBuYW1lX2hhc2iqVjG4xt0cKQMKAG5ldHdvcmtfaWS06c5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_birch_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0BAAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX3dvb2QECQBuYW1lX2hhc2hm88R604TKbAMKAG5ldHdvcmtfaWRleEMJCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:jungle_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV93b29kBAkAbmFtZV9oYXNo9bYW29ORWCoDCgBuZXR3b3JrX2lkyFyKLQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stripped_jungle_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV93b29kBAkAbmFtZV9oYXNoUVs6KsZQRBoDCgBuZXR3b3JrX2lk92k8HQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:acacia_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV93b29kBAkAbmFtZV9oYXNoKkDfgzlJUcIDCgBuZXR3b3JrX2lkuTWlcgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stripped_acacia_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV93b29kBAkAbmFtZV9oYXNo/kOPN2bCJhUDCgBuZXR3b3JrX2lktl6LwQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dark_oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2jaKv4ORLadAAMKAG5ldHdvcmtfaWSDrNQ8CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_dark_oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3BAAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2h2jFDfKVFgfAMKAG5ldHdvcmtfaWTgZQ5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mangrove_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2iXVxG0JG2fVAMKAG5ldHdvcmtfaWSkqJ4cCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_mangrove_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2h7CkbaBF7/WAMKAG5ldHdvcmtfaWQLAX88CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cherry_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV93b29kBAkAbmFtZV9oYXNoAW8srlmpBM8DCgBuZXR3b3JrX2lkLPsAwgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stripped_cherry_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAwAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV93b29kBAkAbmFtZV9oYXNo/e7KXv+CB38DCgBuZXR3b3JrX2lkg5aVtQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:crimson_hyphae", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNouRmKmfSqEWADCgBuZXR3b3JrX2lk+Tm5rQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stripped_crimson_hyphae", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAgAACAQAbmFtZSEAbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNoFffwmABq4LUDCgBuZXR3b3JrX2lkZAlUbgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:warped_hyphae", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2hn8plQUr6pmQMKAG5ldHdvcmtfaWRU2AIBCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:stripped_warped_hyphae", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2irKq+HYPSgjQMKAG5ldHdvcmtfaWSbrOPDCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:bamboo_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19ibG9jawQJAG5hbWVfaGFzaAbDeur6stIBAwoAbmV0d29ya19pZCJAwn0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:stripped_bamboo_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAwAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2JhbWJvb19ibG9jawQJAG5hbWVfaGFzaJpwytpZOZM9AwoAbmV0d29ya19pZKuRbNEKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:oak_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19sZWF2ZXMECQBuYW1lX2hhc2h6O4xGqA2oKgMKAG5ldHdvcmtfaWT98c59CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:spruce_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfBAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9sZWF2ZXMECQBuYW1lX2hhc2i9x1CtNAuqZwMKAG5ldHdvcmtfaWSzF7pTCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:birch_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgBAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2xlYXZlcwQJAG5hbWVfaGFzaBlAGHaoaLZSAwoAbmV0d29ya19pZOjtvWcKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:jungle_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhBAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9sZWF2ZXMECQBuYW1lX2hhc2iW1uAH07zGhgMKAG5ldHdvcmtfaWSA5KX0CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:acacia_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9sZWF2ZXMECQBuYW1lX2hhc2iZJf8dAgDRNQMKAG5ldHdvcmtfaWQ/G7VuCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dark_oak_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiBAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2xlYXZlcwQJAG5hbWVfaGFzaCk7rDipWFSjAwoAbmV0d29ya19pZJ2AkbYKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:mangrove_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2xlYXZlcwQJAG5hbWVfaGFzaKyI/dWvhEG8AwoAbmV0d29ya19pZPQxCZ8KBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cherry_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9sZWF2ZXMECQBuYW1lX2hhc2giTs9ChhYBlQMKAG5ldHdvcmtfaWR8bPpwCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:azalea_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAgAACAQAbmFtZRcAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXMECQBuYW1lX2hhc2iXFhD57wFS7AMKAG5ldHdvcmtfaWTNB/9ECgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:azalea_leaves_flowered", + "block_state_b64": "CgAAAwgAYmxvY2tfaWREAgAACAQAbmFtZSAAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXNfZmxvd2VyZWQECQBuYW1lX2hhc2gs8jxlS/pMrwMKAG5ldHdvcmtfaWQ7W4PyCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:oak_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZRUAbWluZWNyYWZ0Om9ha19zYXBsaW5nBAkAbmFtZV9oYXNoogXcT9QfjiUDCgBuZXR3b3JrX2lkG22C+AoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:spruce_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4BAAACAQAbmFtZRgAbWluZWNyYWZ0OnNwcnVjZV9zYXBsaW5nBAkAbmFtZV9oYXNoe8hz4uYP0FcDCgBuZXR3b3JrX2lkUQmhaQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:birch_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5BAAACAQAbmFtZRcAbWluZWNyYWZ0OmJpcmNoX3NhcGxpbmcECQBuYW1lX2hhc2h348iJQ/tK4wMKAG5ldHdvcmtfaWQ2Uh53CgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:jungle_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6BAAACAQAbmFtZRgAbWluZWNyYWZ0Omp1bmdsZV9zYXBsaW5nBAkAbmFtZV9oYXNo7tyTOdSrxaADCgBuZXR3b3JrX2lkXmBAdAoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:acacia_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7BAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjYWNpYV9zYXBsaW5nBAkAbmFtZV9oYXNo99sg15uoX7ADCgBuZXR3b3JrX2lkPXX1KgoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dark_oak_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8BAAACAQAbmFtZRoAbWluZWNyYWZ0OmRhcmtfb2FrX3NhcGxpbmcECQBuYW1lX2hhc2jnVzFplW7cHgMKAG5ldHdvcmtfaWTD4giHCgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mangrove_propagule", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hbmdyb3ZlX3Byb3BhZ3VsZQQJAG5hbWVfaGFzaJGeox6hkfLFAwoAbmV0d29ya19pZAIpvpYKBgBzdGF0ZXMBBwBoYW5naW5nAAMPAHByb3BhZ3VsZV9zdGFnZQAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cherry_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAwAACAQAbmFtZRgAbWluZWNyYWZ0OmNoZXJyeV9zYXBsaW5nBAkAbmFtZV9oYXNoGrPpNMf1LtcDCgBuZXR3b3JrX2lkypakXQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bee_nest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJlZV9uZXN0BAkAbmFtZV9oYXNo2R2WBxUHEZIDCgBuZXR3b3JrX2lkiXWLEAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAADCwBob25leV9sZXZlbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:wheat_seeds" + }, + { + "id": "minecraft:pumpkin_seeds" + }, + { + "id": "minecraft:melon_seeds" + }, + { + "id": "minecraft:beetroot_seeds" + }, + { + "id": "minecraft:torchflower_seeds" + }, + { + "id": "minecraft:pitcher_pod" + }, + { + "id": "minecraft:wheat" + }, + { + "id": "minecraft:beetroot" + }, + { + "id": "minecraft:potato" + }, + { + "id": "minecraft:poisonous_potato" + }, + { + "id": "minecraft:carrot" + }, + { + "id": "minecraft:golden_carrot" + }, + { + "id": "minecraft:apple" + }, + { + "id": "minecraft:golden_apple" + }, + { + "id": "minecraft:enchanted_golden_apple" + }, + { + "id": "minecraft:melon_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1lbG9uX2Jsb2NrBAkAbmFtZV9oYXNoXxSm0iYpAx8DCgBuZXR3b3JrX2lkC9rqygoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:melon_slice" + }, + { + "id": "minecraft:glistering_melon_slice" + }, + { + "id": "minecraft:sweet_berries" + }, + { + "id": "minecraft:glow_berries" + }, + { + "id": "minecraft:pumpkin", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAAAACAQAbmFtZREAbWluZWNyYWZ0OnB1bXBraW4ECQBuYW1lX2hhc2gc8A3jaSzWbgMKAG5ldHdvcmtfaWRFGA+xCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:carved_pumpkin", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNhcnZlZF9wdW1wa2luBAkAbmFtZV9oYXNoPu1T0MJuG90DCgBuZXR3b3JrX2lkXNNn5QoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:lit_pumpkin", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxpdF9wdW1wa2luBAkAbmFtZV9oYXNo7gWtEm2uPL0DCgBuZXR3b3JrX2lki8sU4AoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:honeycomb" + }, + { + "id": "minecraft:fern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPBAAACAQAbmFtZQ4AbWluZWNyYWZ0OmZlcm4ECQBuYW1lX2hhc2iHbj3yXFn4owMKAG5ldHdvcmtfaWQKC6u7CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:large_fern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgBAAACAQAbmFtZRQAbWluZWNyYWZ0OmxhcmdlX2Zlcm4ECQBuYW1lX2hhc2gnE9sd0LzHtQMKAG5ldHdvcmtfaWTS9hG4CgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:short_grass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNob3J0X2dyYXNzBAkAbmFtZV9oYXNobWQghLH0bLcDCgBuZXR3b3JrX2lkJWOOqAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:tall_grass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfBAAACAQAbmFtZRQAbWluZWNyYWZ0OnRhbGxfZ3Jhc3MECQBuYW1lX2hhc2ii5MyZJpv4sgMKAG5ldHdvcmtfaWRRfeH4CgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:nether_sprouts" + }, + { + "id": "minecraft:fire_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAwAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWS9vF0UCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brain_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWREAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJyYWluX2NvcmFsBAkAbmFtZV9oYXNoRiWlLCwA2ycDCgBuZXR3b3JrX2lkrjAuhgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:bubble_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbAQJAG5hbWVfaGFzaJz6rWnl+v2qAwoAbmV0d29ya19pZImIWy0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:tube_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1YmVfY29yYWwECQBuYW1lX2hhc2iYa8oO/tgk7wMKAG5ldHdvcmtfaWRTfND5CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:horn_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAwAACAQAbmFtZRQAbWluZWNyYWZ0Omhvcm5fY29yYWwECQBuYW1lX2hhc2iZnRHjZbnLPgMKAG5ldHdvcmtfaWR+GGp8CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dead_fire_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbAQJAG5hbWVfaGFzaEPU6tFy/latAwoAbmV0d29ya19pZNMa7V4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dead_brain_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAwAACAQAbmFtZRoAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWwECQBuYW1lX2hhc2j5L6QJCISvzwMKAG5ldHdvcmtfaWQkKzeiCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dead_bubble_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAwAACAQAbmFtZRsAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsBAkAbmFtZV9oYXNoSTOZ/8wpeNYDCgBuZXR3b3JrX2lka6w9DAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dead_tube_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbAQJAG5hbWVfaGFzaJGjNWhlaIJeAwoAbmV0d29ya19pZO3Z0ygKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dead_horn_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbAQJAG5hbWVfaGFzaJBkz3qt+g2cAwoAbmV0d29ya19pZBAN+eYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:fire_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJBAAACAQAbmFtZRgAbWluZWNyYWZ0OmZpcmVfY29yYWxfZmFuBAkAbmFtZV9oYXNosOTxYYxsDLgDCgBuZXR3b3JrX2lkFKxbEgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brain_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHBAAACAQAbmFtZRkAbWluZWNyYWZ0OmJyYWluX2NvcmFsX2ZhbgQJAG5hbWVfaGFzaAi5uHizSNcqAwoAbmV0d29ya19pZFtLjNwKBgBzdGF0ZXMDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:bubble_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIBAAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hy/rX2on17DgMKAG5ldHdvcmtfaWQof60VCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:tube_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRgAbWluZWNyYWZ0OnR1YmVfY29yYWxfZmFuBAkAbmFtZV9oYXNo9pbJbo+PphIDCgBuZXR3b3JrX2lkenDTYgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:horn_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKBAAACAQAbmFtZRgAbWluZWNyYWZ0Omhvcm5fY29yYWxfZmFuBAkAbmFtZV9oYXNoA+ri6NPDkbUDCgBuZXR3b3JrX2lkezoHNwoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dead_fire_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNBAAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hpQO02NDxPvwMKAG5ldHdvcmtfaWTaOJgLCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dead_brain_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLBAAACAQAbmFtZR4AbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWxfZmFuBAkAbmFtZV9oYXNoI9/+Z4YqMhIDCgBuZXR3b3JrX2lkqYXxYgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dead_bubble_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsX2ZhbgQJAG5hbWVfaGFzaBNECtIM6VIOAwoAbmV0d29ya19pZLrNtBEKBgBzdGF0ZXMDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dead_tube_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hbBBM9jFKWvQMKAG5ldHdvcmtfaWSkJKUWCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dead_horn_coral_fan", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROBAAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbF9mYW4ECQBuYW1lX2hhc2hObElFrHfPygMKAG5ldHdvcmtfaWQ1ZxvmCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crimson_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fcm9vdHMECQBuYW1lX2hhc2j1fWgQLViv5QMKAG5ldHdvcmtfaWRLh5DXCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:warped_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAQAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9yb290cwQJAG5hbWVfaGFzaBc3WvbJOLlkAwoAbmV0d29ya19pZNLgDnAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dandelion", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRhbmRlbGlvbgQJAG5hbWVfaGFzaBJ3bEUi+Nn/AwoAbmV0d29ya19pZBjjC44KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:poppy", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnBvcHB5BAkAbmFtZV9oYXNocMF8pITMbkcDCgBuZXR3b3JrX2lk8im6ywoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:blue_orchid", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9BAAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfb3JjaGlkBAkAbmFtZV9oYXNoBjz2MsgB21EDCgBuZXR3b3JrX2lk/iLsSwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:allium", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+BAAACAQAbmFtZRAAbWluZWNyYWZ0OmFsbGl1bQQJAG5hbWVfaGFzaDCGQBHNDTkcAwoAbmV0d29ya19pZD9Dgr0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:azure_bluet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/BAAACAQAbmFtZRUAbWluZWNyYWZ0OmF6dXJlX2JsdWV0BAkAbmFtZV9oYXNo9N5egqMT2QcDCgBuZXR3b3JrX2lkwIgDnwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:red_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRABAAACAQAbmFtZRMAbWluZWNyYWZ0OnJlZF90dWxpcAQJAG5hbWVfaGFzaAjMi9Rd+6rhAwoAbmV0d29ya19pZAZCnt8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:orange_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBBAAACAQAbmFtZRYAbWluZWNyYWZ0Om9yYW5nZV90dWxpcAQJAG5hbWVfaGFzaP+NjxMBZ8vAAwoAbmV0d29ya19pZPYatsMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:white_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCBAAACAQAbmFtZRUAbWluZWNyYWZ0OndoaXRlX3R1bGlwBAkAbmFtZV9oYXNo5vbU4VRPh3ADCgBuZXR3b3JrX2lkok+4rQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:pink_tulip", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDBAAACAQAbmFtZRQAbWluZWNyYWZ0OnBpbmtfdHVsaXAECQBuYW1lX2hhc2hxDHZa6OaNXAMKAG5ldHdvcmtfaWTiOT+VCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:oxeye_daisy", + "block_state_b64": "CgAAAwgAYmxvY2tfaWREBAAACAQAbmFtZRUAbWluZWNyYWZ0Om94ZXllX2RhaXN5BAkAbmFtZV9oYXNoXwxsqNQTN9gDCgBuZXR3b3JrX2lkw7R7dwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cornflower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFBAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcm5mbG93ZXIECQBuYW1lX2hhc2gnhyC3EeqHgAMKAG5ldHdvcmtfaWR4VrvACgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:lily_of_the_valley", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGBAAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbHlfb2ZfdGhlX3ZhbGxleQQJAG5hbWVfaGFzaI64TJSf9mgQAwoAbmV0d29ya19pZFE9+nwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:sunflower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRMAbWluZWNyYWZ0OnN1bmZsb3dlcgQJAG5hbWVfaGFzaAMxYQLoqlZ0AwoAbmV0d29ya19pZA10iSoKBgBzdGF0ZXMBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:lilac", + "block_state_b64": "CgAAAwgAYmxvY2tfaWReBAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxpbGFjBAkAbmFtZV9oYXNoD3nrQJuo7NkDCgBuZXR3b3JrX2lk5W+uFAoGAHN0YXRlcwEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:rose_bush", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhBAAACAQAbmFtZRMAbWluZWNyYWZ0OnJvc2VfYnVzaAQJAG5hbWVfaGFzaLoiFk8LVpGKAwoAbmV0d29ya19pZMZPv48KBgBzdGF0ZXMBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:peony", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiBAAACAQAbmFtZQ8AbWluZWNyYWZ0OnBlb255BAkAbmFtZV9oYXNoR4dYc4QquPADCgBuZXR3b3JrX2lkrTe7RwoGAHN0YXRlcwEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:pitcher_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpdGNoZXJfcGxhbnQECQBuYW1lX2hhc2hRJHzsbDH+SQMKAG5ldHdvcmtfaWRnY76VCgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:pink_petals", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfcGV0YWxzBAkAbmFtZV9oYXNo6DQwN9SwV3QDCgBuZXR3b3JrX2lkNWneGgoGAHN0YXRlcwMGAGdyb3d0aAAAAAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:wither_rose", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAQAACAQAbmFtZRUAbWluZWNyYWZ0OndpdGhlcl9yb3NlBAkAbmFtZV9oYXNoaSKxl3I516gDCgBuZXR3b3JrX2lkATXLPwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:torchflower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AwAACAQAbmFtZRUAbWluZWNyYWZ0OnRvcmNoZmxvd2VyBAkAbmFtZV9oYXNoL+mHtElwbqQDCgBuZXR3b3JrX2lkI34O+AoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:white_dye" + }, + { + "id": "minecraft:light_gray_dye" + }, + { + "id": "minecraft:gray_dye" + }, + { + "id": "minecraft:black_dye" + }, + { + "id": "minecraft:brown_dye" + }, + { + "id": "minecraft:red_dye" + }, + { + "id": "minecraft:orange_dye" + }, + { + "id": "minecraft:yellow_dye" + }, + { + "id": "minecraft:lime_dye" + }, + { + "id": "minecraft:green_dye" + }, + { + "id": "minecraft:cyan_dye" + }, + { + "id": "minecraft:light_blue_dye" + }, + { + "id": "minecraft:blue_dye" + }, + { + "id": "minecraft:purple_dye" + }, + { + "id": "minecraft:magenta_dye" + }, + { + "id": "minecraft:pink_dye" + }, + { + "id": "minecraft:ink_sac" + }, + { + "id": "minecraft:glow_ink_sac" + }, + { + "id": "minecraft:cocoa_beans" + }, + { + "id": "minecraft:lapis_lazuli" + }, + { + "id": "minecraft:bone_meal" + }, + { + "id": "minecraft:vine", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnZpbmUECQBuYW1lX2hhc2j0Sj8/XeXOLAMKAG5ldHdvcmtfaWSUkDtbCgYAc3RhdGVzAxMAdmluZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:weeping_vines", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAQAACAQAbmFtZRcAbWluZWNyYWZ0OndlZXBpbmdfdmluZXMECQBuYW1lX2hhc2jrLgLHkQygiwMKAG5ldHdvcmtfaWQ8NHSJCgYAc3RhdGVzAxEAd2VlcGluZ192aW5lc19hZ2UAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:twisting_vines", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAgAACAQAbmFtZRgAbWluZWNyYWZ0OnR3aXN0aW5nX3ZpbmVzBAkAbmFtZV9oYXNoDYR5QgVUQJADCgBuZXR3b3JrX2lk5kYVIQoGAHN0YXRlcwMSAHR3aXN0aW5nX3ZpbmVzX2FnZQAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:waterlily", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAAAACAQAbmFtZRMAbWluZWNyYWZ0OndhdGVybGlseQQJAG5hbWVfaGFzaEHgC4c1SXg0AwoAbmV0d29ya19pZOOerp8KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:seagrass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAQAACAQAbmFtZRIAbWluZWNyYWZ0OnNlYWdyYXNzBAkAbmFtZV9oYXNoHSBFtoHdWxIDCgBuZXR3b3JrX2lkd3lhEAoGAHN0YXRlcwgOAHNlYV9ncmFzc190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:kelp" + }, + { + "id": "minecraft:deadbush", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAAAACAQAbmFtZRIAbWluZWNyYWZ0OmRlYWRidXNoBAkAbmFtZV9oYXNoPFODe4IScnYDCgBuZXR3b3JrX2lkVfnl+goGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:bamboo", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhbWJvbwQJAG5hbWVfaGFzaBgpGmyzhedCAwoAbmV0d29ya19pZIZv1nYKBgBzdGF0ZXMBBwBhZ2VfYml0AAgQAGJhbWJvb19sZWFmX3NpemUJAG5vX2xlYXZlcwgWAGJhbWJvb19zdGFsa190aGlja25lc3MEAHRoaW4AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:snow", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNub3cECQBuYW1lX2hhc2gVHr5XXdETWAMKAG5ldHdvcmtfaWQ0zCeHCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:ice", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAAAACAQAbmFtZQ0AbWluZWNyYWZ0OmljZQQJAG5hbWVfaGFzaNF26f+uUT29AwoAbmV0d29ya19pZOUMaQYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:packed_ice", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAAAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9pY2UECQBuYW1lX2hhc2hk4bu123ZrFgMKAG5ldHdvcmtfaWTr/ooaCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:blue_ice", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJsdWVfaWNlBAkAbmFtZV9oYXNo+EKxYgFhKcgDCgBuZXR3b3JrX2lkxfsA8goGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:snow_layer", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAAAACAQAbmFtZRQAbWluZWNyYWZ0OnNub3dfbGF5ZXIECQBuYW1lX2hhc2hXka6atMYUCQMKAG5ldHdvcmtfaWRCrIPcCgYAc3RhdGVzAQsAY292ZXJlZF9iaXQAAwYAaGVpZ2h0AAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:pointed_dripstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvaW50ZWRfZHJpcHN0b25lBAkAbmFtZV9oYXNoJMISzmHQgt8DCgBuZXR3b3JrX2lkbWrtYgoGAHN0YXRlcwgTAGRyaXBzdG9uZV90aGlja25lc3MDAHRpcAEHAGhhbmdpbmcBAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dripstone_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRyaXBzdG9uZV9ibG9jawQJAG5hbWVfaGFzaIIXnEqY77YsAwoAbmV0d29ya19pZMZi2kwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:moss_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vc3NfY2FycGV0BAkAbmFtZV9oYXNo/NEDxRPTshYDCgBuZXR3b3JrX2lkaGG3QwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:moss_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AgAACAQAbmFtZRQAbWluZWNyYWZ0Om1vc3NfYmxvY2sECQBuYW1lX2hhc2iovcsPUYX2tgMKAG5ldHdvcmtfaWT3JSbfCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:hanging_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AgAACAQAbmFtZRcAbWluZWNyYWZ0Omhhbmdpbmdfcm9vdHMECQBuYW1lX2hhc2jaXn+Y5UZpDAMKAG5ldHdvcmtfaWRU4c2vCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:mangrove_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNoa786PzQGZ6kDCgBuZXR3b3JrX2lklA0AHgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:muddy_mangrove_roots", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAgAACAQAbmFtZR4AbWluZWNyYWZ0Om11ZGR5X21hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNo9YApdHpo1RkDCgBuZXR3b3JrX2lkH0Oc4woGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:big_dripleaf", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpZ19kcmlwbGVhZgQJAG5hbWVfaGFzaGBEhXjo6qSdAwoAbmV0d29ya19pZMETsb8KBgBzdGF0ZXMBEQBiaWdfZHJpcGxlYWZfaGVhZAEIEQBiaWdfZHJpcGxlYWZfdGlsdAQAbm9uZQgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:small_dripleaf_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtYWxsX2RyaXBsZWFmX2Jsb2NrBAkAbmFtZV9oYXNojxRAgXP9uWADCgBuZXR3b3JrX2lkozbVPwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24EAGVhc3QBDwB1cHBlcl9ibG9ja19iaXQBAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:spore_blossom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwb3JlX2Jsb3Nzb20ECQBuYW1lX2hhc2il3U72Gbco2gMKAG5ldHdvcmtfaWSbbbgcCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:azalea", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAgAACAQAbmFtZRAAbWluZWNyYWZ0OmF6YWxlYQQJAG5hbWVfaGFzaNyUl+BW9JrBAwoAbmV0d29ya19pZO/XZtQKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:flowering_azalea", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAgAACAQAbmFtZRoAbWluZWNyYWZ0OmZsb3dlcmluZ19hemFsZWEECQBuYW1lX2hhc2ie9r33wz8kiwMKAG5ldHdvcmtfaWQ3ij0VCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:glow_lichen", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAgAACAQAbmFtZRUAbWluZWNyYWZ0Omdsb3dfbGljaGVuBAkAbmFtZV9oYXNobyPUrIYlo44DCgBuZXR3b3JrX2lkCh8lSAoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHM/AAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:amethyst_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFtZXRoeXN0X2Jsb2NrBAkAbmFtZV9oYXNob+JK1iiAthcDCgBuZXR3b3JrX2lk8HtpzgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:budding_amethyst", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAgAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1ZGRpbmdfYW1ldGh5c3QECQBuYW1lX2hhc2gJvAwfI14fxgMKAG5ldHdvcmtfaWTQYqfACgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:amethyst_cluster", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAgAACAQAbmFtZRoAbWluZWNyYWZ0OmFtZXRoeXN0X2NsdXN0ZXIECQBuYW1lX2hhc2jK82S88Jgm8wMKAG5ldHdvcmtfaWSCPMPGCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:large_amethyst_bud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAgAACAQAbmFtZRwAbWluZWNyYWZ0OmxhcmdlX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaAHhdpWD+sd5AwoAbmV0d29ya19pZKkQxOcKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:medium_amethyst_bud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1lZGl1bV9hbWV0aHlzdF9idWQECQBuYW1lX2hhc2g5lBGtC0DzZQMKAG5ldHdvcmtfaWSYiP4gCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:small_amethyst_bud", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAgAACAQAbmFtZRwAbWluZWNyYWZ0OnNtYWxsX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaEnb4+q9PO4YAwoAbmV0d29ya19pZGWzxrQKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:calcite", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAgAACAQAbmFtZREAbWluZWNyYWZ0OmNhbGNpdGUECQBuYW1lX2hhc2ixKLu8ZIdzDQMKAG5ldHdvcmtfaWQlSbJDCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:chicken" + }, + { + "id": "minecraft:porkchop" + }, + { + "id": "minecraft:beef" + }, + { + "id": "minecraft:mutton" + }, + { + "id": "minecraft:rabbit" + }, + { + "id": "minecraft:cod" + }, + { + "id": "minecraft:salmon" + }, + { + "id": "minecraft:tropical_fish" + }, + { + "id": "minecraft:pufferfish" + }, + { + "id": "minecraft:brown_mushroom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAAAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkLh1OXAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:red_mushroom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9tdXNocm9vbQQJAG5hbWVfaGFzaPpzJua7669xAwoAbmV0d29ya19pZCvWPYkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crimson_fungus", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fZnVuZ3VzBAkAbmFtZV9oYXNolIcCUuFM2u0DCgBuZXR3b3JrX2lkD2NN0QoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:warped_fungus", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9mdW5ndXMECQBuYW1lX2hhc2gq8bSnRVTAFgMKAG5ldHdvcmtfaWTkwS+rCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brown_mushroom_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkdOMhDAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw4AAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:red_mushroom_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9tdXNocm9vbV9ibG9jawQJAG5hbWVfaGFzaJTTyJbth9M9AwoAbmV0d29ya19pZM+AyboKBgBzdGF0ZXMDEgBodWdlX211c2hyb29tX2JpdHMOAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:mushroom_stem", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvBAAACAQAbmFtZRcAbWluZWNyYWZ0Om11c2hyb29tX3N0ZW0ECQBuYW1lX2hhc2i2SozhK9NLpgMKAG5ldHdvcmtfaWTTVND+CgYAc3RhdGVzAxIAaHVnZV9tdXNocm9vbV9iaXRzDwAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:egg" + }, + { + "id": "minecraft:sugar_cane" + }, + { + "id": "minecraft:sugar" + }, + { + "id": "minecraft:rotten_flesh" + }, + { + "id": "minecraft:bone" + }, + { + "id": "minecraft:web", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAAAACAQAbmFtZQ0AbWluZWNyYWZ0OndlYgQJAG5hbWVfaGFzaA4GKQCvG4i9AwoAbmV0d29ya19pZApt+jgKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:spider_eye" + }, + { + "id": "minecraft:mob_spawner", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vYl9zcGF3bmVyBAkAbmFtZV9oYXNoNwGrCV/Fkh8DCgBuZXR3b3JrX2lkM1wTmgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:trial_spawner", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AgAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaWFsX3NwYXduZXIECQBuYW1lX2hhc2iNLRPB4ACz+QMKAG5ldHdvcmtfaWTWFYHGCgYAc3RhdGVzAQcAb21pbm91cwADEwB0cmlhbF9zcGF3bmVyX3N0YXRlAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:vault", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AgAACAQAbmFtZQ8AbWluZWNyYWZ0OnZhdWx0BAkAbmFtZV9oYXNoCAp9n3IAyqcDCgBuZXR3b3JrX2lk6/P+vwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQcAb21pbm91cwAICwB2YXVsdF9zdGF0ZQgAaW5hY3RpdmUAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:end_portal_frame", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9wb3J0YWxfZnJhbWUECQBuYW1lX2hhc2gqofyUIjGOpQMKAG5ldHdvcmtfaWRbGHf8CgYAc3RhdGVzARIAZW5kX3BvcnRhbF9leWVfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:infested_stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRgAbWluZWNyYWZ0OmluZmVzdGVkX3N0b25lBAkAbmFtZV9oYXNoxnRcHDu4zqQDCgBuZXR3b3JrX2lkpfcnsgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:infested_cobblestone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZBAAACAQAbmFtZR4AbWluZWNyYWZ0OmluZmVzdGVkX2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoy+LVCKG2kVMDCgBuZXR3b3JrX2lkpn+icAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:infested_stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaBAAACAQAbmFtZR8AbWluZWNyYWZ0OmluZmVzdGVkX3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaBMnals7a32CAwoAbmV0d29ya19pZNHi2UYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:infested_mossy_stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbBAAACAQAbmFtZSUAbWluZWNyYWZ0OmluZmVzdGVkX21vc3N5X3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaAmJk+HmVq0rAwoAbmV0d29ya19pZAVH8/sKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:infested_cracked_stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcBAAACAQAbmFtZScAbWluZWNyYWZ0OmluZmVzdGVkX2NyYWNrZWRfc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoMyc60XcfcyoDCgBuZXR3b3JrX2lkaW+kbQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:infested_chiseled_stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdBAAACAQAbmFtZSgAbWluZWNyYWZ0OmluZmVzdGVkX2NoaXNlbGVkX3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaNUvNIIg9dZbAwoAbmV0d29ya19pZCajGicKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:infested_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAgAACAQAbmFtZRwAbWluZWNyYWZ0OmluZmVzdGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaICF2VYccxF1AwoAbmV0d29ya19pZDa/624KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dragon_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AAAACAQAbmFtZRQAbWluZWNyYWZ0OmRyYWdvbl9lZ2cECQBuYW1lX2hhc2inMzXrV+/e1wMKAG5ldHdvcmtfaWTgO1yRCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:turtle_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1cnRsZV9lZ2cECQBuYW1lX2hhc2iwSRcxOJIJ9gMKAG5ldHdvcmtfaWSIRNUhCgYAc3RhdGVzCA0AY3JhY2tlZF9zdGF0ZQkAbm9fY3JhY2tzCBAAdHVydGxlX2VnZ19jb3VudAcAb25lX2VnZwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:sniffer_egg", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAwAACAQAbmFtZRUAbWluZWNyYWZ0OnNuaWZmZXJfZWdnBAkAbmFtZV9oYXNoY1lozc8lPcYDCgBuZXR3b3JrX2lk7yb/2QoGAHN0YXRlcwgNAGNyYWNrZWRfc3RhdGUJAG5vX2NyYWNrcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:frog_spawn", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAgAACAQAbmFtZRQAbWluZWNyYWZ0OmZyb2dfc3Bhd24ECQBuYW1lX2hhc2iWmd7idp3ZZwMKAG5ldHdvcmtfaWRFzJudCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:pearlescent_froglight", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAgAACAQAbmFtZR8AbWluZWNyYWZ0OnBlYXJsZXNjZW50X2Zyb2dsaWdodAQJAG5hbWVfaGFzaKkcFRyycYGyAwoAbmV0d29ya19pZJqYakAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:verdant_froglight", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAgAACAQAbmFtZRsAbWluZWNyYWZ0OnZlcmRhbnRfZnJvZ2xpZ2h0BAkAbmFtZV9oYXNoA+eXuTBohrQDCgBuZXR3b3JrX2lkDIVnsQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:ochre_froglight", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om9jaHJlX2Zyb2dsaWdodAQJAG5hbWVfaGFzaMY59kjPe+c3AwoAbmV0d29ya19pZO2TD50KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:chicken_spawn_egg" + }, + { + "id": "minecraft:bee_spawn_egg" + }, + { + "id": "minecraft:cow_spawn_egg" + }, + { + "id": "minecraft:pig_spawn_egg" + }, + { + "id": "minecraft:sheep_spawn_egg" + }, + { + "id": "minecraft:wolf_spawn_egg" + }, + { + "id": "minecraft:polar_bear_spawn_egg" + }, + { + "id": "minecraft:ocelot_spawn_egg" + }, + { + "id": "minecraft:cat_spawn_egg" + }, + { + "id": "minecraft:mooshroom_spawn_egg" + }, + { + "id": "minecraft:bat_spawn_egg" + }, + { + "id": "minecraft:parrot_spawn_egg" + }, + { + "id": "minecraft:rabbit_spawn_egg" + }, + { + "id": "minecraft:llama_spawn_egg" + }, + { + "id": "minecraft:horse_spawn_egg" + }, + { + "id": "minecraft:donkey_spawn_egg" + }, + { + "id": "minecraft:mule_spawn_egg" + }, + { + "id": "minecraft:skeleton_horse_spawn_egg" + }, + { + "id": "minecraft:zombie_horse_spawn_egg" + }, + { + "id": "minecraft:tropical_fish_spawn_egg" + }, + { + "id": "minecraft:cod_spawn_egg" + }, + { + "id": "minecraft:pufferfish_spawn_egg" + }, + { + "id": "minecraft:salmon_spawn_egg" + }, + { + "id": "minecraft:dolphin_spawn_egg" + }, + { + "id": "minecraft:turtle_spawn_egg" + }, + { + "id": "minecraft:panda_spawn_egg" + }, + { + "id": "minecraft:fox_spawn_egg" + }, + { + "id": "minecraft:creeper_spawn_egg" + }, + { + "id": "minecraft:enderman_spawn_egg" + }, + { + "id": "minecraft:silverfish_spawn_egg" + }, + { + "id": "minecraft:skeleton_spawn_egg" + }, + { + "id": "minecraft:wither_skeleton_spawn_egg" + }, + { + "id": "minecraft:stray_spawn_egg" + }, + { + "id": "minecraft:slime_spawn_egg" + }, + { + "id": "minecraft:spider_spawn_egg" + }, + { + "id": "minecraft:zombie_spawn_egg" + }, + { + "id": "minecraft:zombie_pigman_spawn_egg" + }, + { + "id": "minecraft:husk_spawn_egg" + }, + { + "id": "minecraft:drowned_spawn_egg" + }, + { + "id": "minecraft:squid_spawn_egg" + }, + { + "id": "minecraft:glow_squid_spawn_egg" + }, + { + "id": "minecraft:cave_spider_spawn_egg" + }, + { + "id": "minecraft:witch_spawn_egg" + }, + { + "id": "minecraft:guardian_spawn_egg" + }, + { + "id": "minecraft:elder_guardian_spawn_egg" + }, + { + "id": "minecraft:endermite_spawn_egg" + }, + { + "id": "minecraft:magma_cube_spawn_egg" + }, + { + "id": "minecraft:strider_spawn_egg" + }, + { + "id": "minecraft:hoglin_spawn_egg" + }, + { + "id": "minecraft:piglin_spawn_egg" + }, + { + "id": "minecraft:zoglin_spawn_egg" + }, + { + "id": "minecraft:piglin_brute_spawn_egg" + }, + { + "id": "minecraft:goat_spawn_egg" + }, + { + "id": "minecraft:axolotl_spawn_egg" + }, + { + "id": "minecraft:warden_spawn_egg" + }, + { + "id": "minecraft:allay_spawn_egg" + }, + { + "id": "minecraft:frog_spawn_egg" + }, + { + "id": "minecraft:tadpole_spawn_egg" + }, + { + "id": "minecraft:trader_llama_spawn_egg" + }, + { + "id": "minecraft:camel_spawn_egg" + }, + { + "id": "minecraft:ghast_spawn_egg" + }, + { + "id": "minecraft:blaze_spawn_egg" + }, + { + "id": "minecraft:shulker_spawn_egg" + }, + { + "id": "minecraft:vindicator_spawn_egg" + }, + { + "id": "minecraft:evoker_spawn_egg" + }, + { + "id": "minecraft:vex_spawn_egg" + }, + { + "id": "minecraft:villager_spawn_egg" + }, + { + "id": "minecraft:wandering_trader_spawn_egg" + }, + { + "id": "minecraft:zombie_villager_spawn_egg" + }, + { + "id": "minecraft:phantom_spawn_egg" + }, + { + "id": "minecraft:pillager_spawn_egg" + }, + { + "id": "minecraft:ravager_spawn_egg" + }, + { + "id": "minecraft:iron_golem_spawn_egg" + }, + { + "id": "minecraft:snow_golem_spawn_egg" + }, + { + "id": "minecraft:sniffer_spawn_egg" + }, + { + "id": "minecraft:breeze_spawn_egg" + }, + { + "id": "minecraft:armadillo_spawn_egg" + }, + { + "id": "minecraft:bogged_spawn_egg" + }, + { + "id": "minecraft:obsidian", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2lkaWFuBAkAbmFtZV9oYXNoiz4qrb8QjyEDCgBuZXR3b3JrX2lkuqnPpQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:crying_obsidian", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAgAACAQAbmFtZRkAbWluZWNyYWZ0OmNyeWluZ19vYnNpZGlhbgQJAG5hbWVfaGFzaKT0JlA7Z1K+AwoAbmV0d29ya19pZCjbPV4KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:bedrock", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAAAACAQAbmFtZREAbWluZWNyYWZ0OmJlZHJvY2sECQBuYW1lX2hhc2hWfFrh4LVtxwMKAG5ldHdvcmtfaWT7fKz1CgYAc3RhdGVzAQ4AaW5maW5pYnVybl9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:soul_sand", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc2FuZAQJAG5hbWVfaGFzaMaf+bccu+KTAwoAbmV0d29ya19pZBQSHrMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:magma", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAAAACAQAbmFtZQ8AbWluZWNyYWZ0Om1hZ21hBAkAbmFtZV9oYXNoqyTjKaIsWfYDCgBuZXR3b3JrX2lkyfWAZgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:nether_wart" + }, + { + "id": "minecraft:end_stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AAAACAQAbmFtZRMAbWluZWNyYWZ0OmVuZF9zdG9uZQQJAG5hbWVfaGFzaH1J9jA39GJNAwoAbmV0d29ya19pZFeFQ7UKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:chorus_flower", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAAAACAQAbmFtZRcAbWluZWNyYWZ0OmNob3J1c19mbG93ZXIECQBuYW1lX2hhc2iMpSodli5uawMKAG5ldHdvcmtfaWRnd1ZWCgYAc3RhdGVzAwMAYWdlAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:chorus_plant", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAAAACAQAbmFtZRYAbWluZWNyYWZ0OmNob3J1c19wbGFudAQJAG5hbWVfaGFzaJhSrmNGKwaMAwoAbmV0d29ya19pZA3uVqMKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:chorus_fruit" + }, + { + "id": "minecraft:popped_chorus_fruit" + }, + { + "id": "minecraft:sponge", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZNmQW/oKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:wet_sponge", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXBAAACAQAbmFtZRQAbWluZWNyYWZ0OndldF9zcG9uZ2UECQBuYW1lX2hhc2htp6nKpSHcAgMKAG5ldHdvcmtfaWQaW+fCCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:tube_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRoAbWluZWNyYWZ0OnR1YmVfY29yYWxfYmxvY2sECQBuYW1lX2hhc2iGkaiR7Eot4wMKAG5ldHdvcmtfaWQPNJ6sCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:brain_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQBAAACAQAbmFtZRsAbWluZWNyYWZ0OmJyYWluX2NvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoeDNAK18yUo4DCgBuZXR3b3JrX2lkloN1vgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:bubble_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRBAAACAQAbmFtZRwAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaAI2mwMlvcNbAwoAbmV0d29ya19pZBlkxKIKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:fire_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSBAAACAQAbmFtZRoAbWluZWNyYWZ0OmZpcmVfY29yYWxfYmxvY2sECQBuYW1lX2hhc2gg1gLeXLmKaAMKAG5ldHdvcmtfaWSp3W57CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:horn_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTBAAACAQAbmFtZRoAbWluZWNyYWZ0Omhvcm5fY29yYWxfYmxvY2sECQBuYW1lX2hhc2hnZSLRWUwGhAMKAG5ldHdvcmtfaWRSK6ccCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dead_tube_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaB9+lY3hAkNNAwoAbmV0d29ya19pZF0hKKYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dead_brain_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVBAAACAQAbmFtZSAAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWxfYmxvY2sECQBuYW1lX2hhc2iHyDn52AO8uwMKAG5ldHdvcmtfaWQw7yCaCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dead_bubble_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWBAAACAQAbmFtZSEAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsX2Jsb2NrBAkAbmFtZV9oYXNotwkk/ITrsjADCgBuZXR3b3JrX2lk56mXUgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dead_fire_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaG0qHxbIrBEyAwoAbmV0d29ya19pZFvnH88KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:dead_horn_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaL7D8bu4Fm+0AwoAbmV0d29ya19pZEALRLoKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:sculk", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lkyqUPPgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:sculk_vein", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNjdWxrX3ZlaW4ECQBuYW1lX2hhc2gJUdhVooV4zwMKAG5ldHdvcmtfaWSUfn1XCgYAc3RhdGVzAxkAbXVsdGlfZmFjZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:sculk_catalyst", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX2NhdGFseXN0BAkAbmFtZV9oYXNo+gCpbrCHST4DCgBuZXR3b3JrX2lkMJ2n/woGAHN0YXRlcwEFAGJsb29tAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:sculk_shrieker", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX3Nocmlla2VyBAkAbmFtZV9oYXNo5OXtyObniQ4DCgBuZXR3b3JrX2lkxapoNAoGAHN0YXRlcwEGAGFjdGl2ZQABCgBjYW5fc3VtbW9uAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:sculk_sensor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNjdWxrX3NlbnNvcgQJAG5hbWVfaGFzaCkmHreeTgNnAwoAbmV0d29ya19pZLj2WPcKBgBzdGF0ZXMDEgBzY3Vsa19zZW5zb3JfcGhhc2UAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:calibrated_sculk_sensor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAwAACAQAbmFtZSEAbWluZWNyYWZ0OmNhbGlicmF0ZWRfc2N1bGtfc2Vuc29yBAkAbmFtZV9oYXNoffAcXXN/iJUDCgBuZXR3b3JrX2lkwOx3QQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAxIAc2N1bGtfc2Vuc29yX3BoYXNlAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:reinforced_deepslate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlaW5mb3JjZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoldDmj91EapQDCgBuZXR3b3JrX2lkHIt+aQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:leather_helmet" + }, + { + "id": "minecraft:chainmail_helmet" + }, + { + "id": "minecraft:iron_helmet" + }, + { + "id": "minecraft:golden_helmet" + }, + { + "id": "minecraft:diamond_helmet" + }, + { + "id": "minecraft:netherite_helmet" + }, + { + "id": "minecraft:leather_chestplate" + }, + { + "id": "minecraft:chainmail_chestplate" + }, + { + "id": "minecraft:iron_chestplate" + }, + { + "id": "minecraft:golden_chestplate" + }, + { + "id": "minecraft:diamond_chestplate" + }, + { + "id": "minecraft:netherite_chestplate" + }, + { + "id": "minecraft:leather_leggings" + }, + { + "id": "minecraft:chainmail_leggings" + }, + { + "id": "minecraft:iron_leggings" + }, + { + "id": "minecraft:golden_leggings" + }, + { + "id": "minecraft:diamond_leggings" + }, + { + "id": "minecraft:netherite_leggings" + }, + { + "id": "minecraft:leather_boots" + }, + { + "id": "minecraft:chainmail_boots" + }, + { + "id": "minecraft:iron_boots" + }, + { + "id": "minecraft:golden_boots" + }, + { + "id": "minecraft:diamond_boots" + }, + { + "id": "minecraft:netherite_boots" + }, + { + "id": "minecraft:wooden_sword" + }, + { + "id": "minecraft:stone_sword" + }, + { + "id": "minecraft:iron_sword" + }, + { + "id": "minecraft:golden_sword" + }, + { + "id": "minecraft:diamond_sword" + }, + { + "id": "minecraft:netherite_sword" + }, + { + "id": "minecraft:wooden_axe" + }, + { + "id": "minecraft:stone_axe" + }, + { + "id": "minecraft:iron_axe" + }, + { + "id": "minecraft:golden_axe" + }, + { + "id": "minecraft:diamond_axe" + }, + { + "id": "minecraft:netherite_axe" + }, + { + "id": "minecraft:wooden_pickaxe" + }, + { + "id": "minecraft:stone_pickaxe" + }, + { + "id": "minecraft:iron_pickaxe" + }, + { + "id": "minecraft:golden_pickaxe" + }, + { + "id": "minecraft:diamond_pickaxe" + }, + { + "id": "minecraft:netherite_pickaxe" + }, + { + "id": "minecraft:wooden_shovel" + }, + { + "id": "minecraft:stone_shovel" + }, + { + "id": "minecraft:iron_shovel" + }, + { + "id": "minecraft:golden_shovel" + }, + { + "id": "minecraft:diamond_shovel" + }, + { + "id": "minecraft:netherite_shovel" + }, + { + "id": "minecraft:wooden_hoe" + }, + { + "id": "minecraft:stone_hoe" + }, + { + "id": "minecraft:iron_hoe" + }, + { + "id": "minecraft:golden_hoe" + }, + { + "id": "minecraft:diamond_hoe" + }, + { + "id": "minecraft:netherite_hoe" + }, + { + "id": "minecraft:bow" + }, + { + "id": "minecraft:crossbow" + }, + { + "id": "minecraft:mace" + }, + { + "id": "minecraft:arrow" + }, + { + "id": "minecraft:arrow", + "damage": 6 + }, + { + "id": "minecraft:arrow", + "damage": 7 + }, + { + "id": "minecraft:arrow", + "damage": 8 + }, + { + "id": "minecraft:arrow", + "damage": 9 + }, + { + "id": "minecraft:arrow", + "damage": 10 + }, + { + "id": "minecraft:arrow", + "damage": 11 + }, + { + "id": "minecraft:arrow", + "damage": 12 + }, + { + "id": "minecraft:arrow", + "damage": 13 + }, + { + "id": "minecraft:arrow", + "damage": 14 + }, + { + "id": "minecraft:arrow", + "damage": 15 + }, + { + "id": "minecraft:arrow", + "damage": 16 + }, + { + "id": "minecraft:arrow", + "damage": 17 + }, + { + "id": "minecraft:arrow", + "damage": 18 + }, + { + "id": "minecraft:arrow", + "damage": 19 + }, + { + "id": "minecraft:arrow", + "damage": 20 + }, + { + "id": "minecraft:arrow", + "damage": 21 + }, + { + "id": "minecraft:arrow", + "damage": 22 + }, + { + "id": "minecraft:arrow", + "damage": 23 + }, + { + "id": "minecraft:arrow", + "damage": 24 + }, + { + "id": "minecraft:arrow", + "damage": 25 + }, + { + "id": "minecraft:arrow", + "damage": 26 + }, + { + "id": "minecraft:arrow", + "damage": 27 + }, + { + "id": "minecraft:arrow", + "damage": 28 + }, + { + "id": "minecraft:arrow", + "damage": 29 + }, + { + "id": "minecraft:arrow", + "damage": 30 + }, + { + "id": "minecraft:arrow", + "damage": 31 + }, + { + "id": "minecraft:arrow", + "damage": 32 + }, + { + "id": "minecraft:arrow", + "damage": 33 + }, + { + "id": "minecraft:arrow", + "damage": 34 + }, + { + "id": "minecraft:arrow", + "damage": 35 + }, + { + "id": "minecraft:arrow", + "damage": 36 + }, + { + "id": "minecraft:arrow", + "damage": 37 + }, + { + "id": "minecraft:arrow", + "damage": 38 + }, + { + "id": "minecraft:arrow", + "damage": 39 + }, + { + "id": "minecraft:arrow", + "damage": 40 + }, + { + "id": "minecraft:arrow", + "damage": 41 + }, + { + "id": "minecraft:arrow", + "damage": 42 + }, + { + "id": "minecraft:arrow", + "damage": 43 + }, + { + "id": "minecraft:arrow", + "damage": 44 + }, + { + "id": "minecraft:arrow", + "damage": 45 + }, + { + "id": "minecraft:arrow", + "damage": 46 + }, + { + "id": "minecraft:arrow", + "damage": 47 + }, + { + "id": "minecraft:shield" + }, + { + "id": "minecraft:cooked_chicken" + }, + { + "id": "minecraft:cooked_porkchop" + }, + { + "id": "minecraft:cooked_beef" + }, + { + "id": "minecraft:cooked_mutton" + }, + { + "id": "minecraft:cooked_rabbit" + }, + { + "id": "minecraft:cooked_cod" + }, + { + "id": "minecraft:cooked_salmon" + }, + { + "id": "minecraft:bread" + }, + { + "id": "minecraft:mushroom_stew" + }, + { + "id": "minecraft:beetroot_soup" + }, + { + "id": "minecraft:rabbit_stew" + }, + { + "id": "minecraft:baked_potato" + }, + { + "id": "minecraft:cookie" + }, + { + "id": "minecraft:pumpkin_pie" + }, + { + "id": "minecraft:cake" + }, + { + "id": "minecraft:dried_kelp" + }, + { + "id": "minecraft:fishing_rod" + }, + { + "id": "minecraft:carrot_on_a_stick" + }, + { + "id": "minecraft:warped_fungus_on_a_stick" + }, + { + "id": "minecraft:snowball" + }, + { + "id": "minecraft:wind_charge" + }, + { + "id": "minecraft:shears" + }, + { + "id": "minecraft:flint_and_steel" + }, + { + "id": "minecraft:lead" + }, + { + "id": "minecraft:clock" + }, + { + "id": "minecraft:compass" + }, + { + "id": "minecraft:recovery_compass" + }, + { + "id": "minecraft:goat_horn" + }, + { + "id": "minecraft:goat_horn", + "damage": 1 + }, + { + "id": "minecraft:goat_horn", + "damage": 2 + }, + { + "id": "minecraft:goat_horn", + "damage": 3 + }, + { + "id": "minecraft:goat_horn", + "damage": 4 + }, + { + "id": "minecraft:goat_horn", + "damage": 5 + }, + { + "id": "minecraft:goat_horn", + "damage": 6 + }, + { + "id": "minecraft:goat_horn", + "damage": 7 + }, + { + "id": "minecraft:empty_map" + }, + { + "id": "minecraft:empty_map", + "damage": 2 + }, + { + "id": "minecraft:saddle" + }, + { + "id": "minecraft:bundle" + }, + { + "id": "minecraft:white_bundle" + }, + { + "id": "minecraft:light_gray_bundle" + }, + { + "id": "minecraft:gray_bundle" + }, + { + "id": "minecraft:black_bundle" + }, + { + "id": "minecraft:brown_bundle" + }, + { + "id": "minecraft:red_bundle" + }, + { + "id": "minecraft:orange_bundle" + }, + { + "id": "minecraft:yellow_bundle" + }, + { + "id": "minecraft:lime_bundle" + }, + { + "id": "minecraft:green_bundle" + }, + { + "id": "minecraft:cyan_bundle" + }, + { + "id": "minecraft:light_blue_bundle" + }, + { + "id": "minecraft:blue_bundle" + }, + { + "id": "minecraft:purple_bundle" + }, + { + "id": "minecraft:magenta_bundle" + }, + { + "id": "minecraft:pink_bundle" + }, + { + "id": "minecraft:leather_horse_armor" + }, + { + "id": "minecraft:iron_horse_armor" + }, + { + "id": "minecraft:golden_horse_armor" + }, + { + "id": "minecraft:diamond_horse_armor" + }, + { + "id": "minecraft:wolf_armor" + }, + { + "id": "minecraft:trident" + }, + { + "id": "minecraft:turtle_helmet" + }, + { + "id": "minecraft:elytra" + }, + { + "id": "minecraft:totem_of_undying" + }, + { + "id": "minecraft:glass_bottle" + }, + { + "id": "minecraft:experience_bottle" + }, + { + "id": "minecraft:potion" + }, + { + "id": "minecraft:potion", + "damage": 1 + }, + { + "id": "minecraft:potion", + "damage": 2 + }, + { + "id": "minecraft:potion", + "damage": 3 + }, + { + "id": "minecraft:potion", + "damage": 4 + }, + { + "id": "minecraft:potion", + "damage": 5 + }, + { + "id": "minecraft:potion", + "damage": 6 + }, + { + "id": "minecraft:potion", + "damage": 7 + }, + { + "id": "minecraft:potion", + "damage": 8 + }, + { + "id": "minecraft:potion", + "damage": 9 + }, + { + "id": "minecraft:potion", + "damage": 10 + }, + { + "id": "minecraft:potion", + "damage": 11 + }, + { + "id": "minecraft:potion", + "damage": 12 + }, + { + "id": "minecraft:potion", + "damage": 13 + }, + { + "id": "minecraft:potion", + "damage": 14 + }, + { + "id": "minecraft:potion", + "damage": 15 + }, + { + "id": "minecraft:potion", + "damage": 16 + }, + { + "id": "minecraft:potion", + "damage": 17 + }, + { + "id": "minecraft:potion", + "damage": 18 + }, + { + "id": "minecraft:potion", + "damage": 19 + }, + { + "id": "minecraft:potion", + "damage": 20 + }, + { + "id": "minecraft:potion", + "damage": 21 + }, + { + "id": "minecraft:potion", + "damage": 22 + }, + { + "id": "minecraft:potion", + "damage": 23 + }, + { + "id": "minecraft:potion", + "damage": 24 + }, + { + "id": "minecraft:potion", + "damage": 25 + }, + { + "id": "minecraft:potion", + "damage": 26 + }, + { + "id": "minecraft:potion", + "damage": 27 + }, + { + "id": "minecraft:potion", + "damage": 28 + }, + { + "id": "minecraft:potion", + "damage": 29 + }, + { + "id": "minecraft:potion", + "damage": 30 + }, + { + "id": "minecraft:potion", + "damage": 31 + }, + { + "id": "minecraft:potion", + "damage": 32 + }, + { + "id": "minecraft:potion", + "damage": 33 + }, + { + "id": "minecraft:potion", + "damage": 34 + }, + { + "id": "minecraft:potion", + "damage": 35 + }, + { + "id": "minecraft:potion", + "damage": 36 + }, + { + "id": "minecraft:potion", + "damage": 37 + }, + { + "id": "minecraft:potion", + "damage": 38 + }, + { + "id": "minecraft:potion", + "damage": 39 + }, + { + "id": "minecraft:potion", + "damage": 40 + }, + { + "id": "minecraft:potion", + "damage": 41 + }, + { + "id": "minecraft:potion", + "damage": 42 + }, + { + "id": "minecraft:potion", + "damage": 43 + }, + { + "id": "minecraft:potion", + "damage": 44 + }, + { + "id": "minecraft:potion", + "damage": 45 + }, + { + "id": "minecraft:potion", + "damage": 46 + }, + { + "id": "minecraft:splash_potion" + }, + { + "id": "minecraft:splash_potion", + "damage": 1 + }, + { + "id": "minecraft:splash_potion", + "damage": 2 + }, + { + "id": "minecraft:splash_potion", + "damage": 3 + }, + { + "id": "minecraft:splash_potion", + "damage": 4 + }, + { + "id": "minecraft:splash_potion", + "damage": 5 + }, + { + "id": "minecraft:splash_potion", + "damage": 6 + }, + { + "id": "minecraft:splash_potion", + "damage": 7 + }, + { + "id": "minecraft:splash_potion", + "damage": 8 + }, + { + "id": "minecraft:splash_potion", + "damage": 9 + }, + { + "id": "minecraft:splash_potion", + "damage": 10 + }, + { + "id": "minecraft:splash_potion", + "damage": 11 + }, + { + "id": "minecraft:splash_potion", + "damage": 12 + }, + { + "id": "minecraft:splash_potion", + "damage": 13 + }, + { + "id": "minecraft:splash_potion", + "damage": 14 + }, + { + "id": "minecraft:splash_potion", + "damage": 15 + }, + { + "id": "minecraft:splash_potion", + "damage": 16 + }, + { + "id": "minecraft:splash_potion", + "damage": 17 + }, + { + "id": "minecraft:splash_potion", + "damage": 18 + }, + { + "id": "minecraft:splash_potion", + "damage": 19 + }, + { + "id": "minecraft:splash_potion", + "damage": 20 + }, + { + "id": "minecraft:splash_potion", + "damage": 21 + }, + { + "id": "minecraft:splash_potion", + "damage": 22 + }, + { + "id": "minecraft:splash_potion", + "damage": 23 + }, + { + "id": "minecraft:splash_potion", + "damage": 24 + }, + { + "id": "minecraft:splash_potion", + "damage": 25 + }, + { + "id": "minecraft:splash_potion", + "damage": 26 + }, + { + "id": "minecraft:splash_potion", + "damage": 27 + }, + { + "id": "minecraft:splash_potion", + "damage": 28 + }, + { + "id": "minecraft:splash_potion", + "damage": 29 + }, + { + "id": "minecraft:splash_potion", + "damage": 30 + }, + { + "id": "minecraft:splash_potion", + "damage": 31 + }, + { + "id": "minecraft:splash_potion", + "damage": 32 + }, + { + "id": "minecraft:splash_potion", + "damage": 33 + }, + { + "id": "minecraft:splash_potion", + "damage": 34 + }, + { + "id": "minecraft:splash_potion", + "damage": 35 + }, + { + "id": "minecraft:splash_potion", + "damage": 36 + }, + { + "id": "minecraft:splash_potion", + "damage": 37 + }, + { + "id": "minecraft:splash_potion", + "damage": 38 + }, + { + "id": "minecraft:splash_potion", + "damage": 39 + }, + { + "id": "minecraft:splash_potion", + "damage": 40 + }, + { + "id": "minecraft:splash_potion", + "damage": 41 + }, + { + "id": "minecraft:splash_potion", + "damage": 42 + }, + { + "id": "minecraft:splash_potion", + "damage": 43 + }, + { + "id": "minecraft:splash_potion", + "damage": 44 + }, + { + "id": "minecraft:splash_potion", + "damage": 45 + }, + { + "id": "minecraft:splash_potion", + "damage": 46 + }, + { + "id": "minecraft:lingering_potion" + }, + { + "id": "minecraft:lingering_potion", + "damage": 1 + }, + { + "id": "minecraft:lingering_potion", + "damage": 2 + }, + { + "id": "minecraft:lingering_potion", + "damage": 3 + }, + { + "id": "minecraft:lingering_potion", + "damage": 4 + }, + { + "id": "minecraft:lingering_potion", + "damage": 5 + }, + { + "id": "minecraft:lingering_potion", + "damage": 6 + }, + { + "id": "minecraft:lingering_potion", + "damage": 7 + }, + { + "id": "minecraft:lingering_potion", + "damage": 8 + }, + { + "id": "minecraft:lingering_potion", + "damage": 9 + }, + { + "id": "minecraft:lingering_potion", + "damage": 10 + }, + { + "id": "minecraft:lingering_potion", + "damage": 11 + }, + { + "id": "minecraft:lingering_potion", + "damage": 12 + }, + { + "id": "minecraft:lingering_potion", + "damage": 13 + }, + { + "id": "minecraft:lingering_potion", + "damage": 14 + }, + { + "id": "minecraft:lingering_potion", + "damage": 15 + }, + { + "id": "minecraft:lingering_potion", + "damage": 16 + }, + { + "id": "minecraft:lingering_potion", + "damage": 17 + }, + { + "id": "minecraft:lingering_potion", + "damage": 18 + }, + { + "id": "minecraft:lingering_potion", + "damage": 19 + }, + { + "id": "minecraft:lingering_potion", + "damage": 20 + }, + { + "id": "minecraft:lingering_potion", + "damage": 21 + }, + { + "id": "minecraft:lingering_potion", + "damage": 22 + }, + { + "id": "minecraft:lingering_potion", + "damage": 23 + }, + { + "id": "minecraft:lingering_potion", + "damage": 24 + }, + { + "id": "minecraft:lingering_potion", + "damage": 25 + }, + { + "id": "minecraft:lingering_potion", + "damage": 26 + }, + { + "id": "minecraft:lingering_potion", + "damage": 27 + }, + { + "id": "minecraft:lingering_potion", + "damage": 28 + }, + { + "id": "minecraft:lingering_potion", + "damage": 29 + }, + { + "id": "minecraft:lingering_potion", + "damage": 30 + }, + { + "id": "minecraft:lingering_potion", + "damage": 31 + }, + { + "id": "minecraft:lingering_potion", + "damage": 32 + }, + { + "id": "minecraft:lingering_potion", + "damage": 33 + }, + { + "id": "minecraft:lingering_potion", + "damage": 34 + }, + { + "id": "minecraft:lingering_potion", + "damage": 35 + }, + { + "id": "minecraft:lingering_potion", + "damage": 36 + }, + { + "id": "minecraft:lingering_potion", + "damage": 37 + }, + { + "id": "minecraft:lingering_potion", + "damage": 38 + }, + { + "id": "minecraft:lingering_potion", + "damage": 39 + }, + { + "id": "minecraft:lingering_potion", + "damage": 40 + }, + { + "id": "minecraft:lingering_potion", + "damage": 41 + }, + { + "id": "minecraft:lingering_potion", + "damage": 42 + }, + { + "id": "minecraft:lingering_potion", + "damage": 43 + }, + { + "id": "minecraft:lingering_potion", + "damage": 44 + }, + { + "id": "minecraft:lingering_potion", + "damage": 45 + }, + { + "id": "minecraft:lingering_potion", + "damage": 46 + }, + { + "id": "minecraft:ominous_bottle" + }, + { + "id": "minecraft:ominous_bottle", + "damage": 1 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 2 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 3 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 4 + }, + { + "id": "minecraft:spyglass" + }, + { + "id": "minecraft:brush" + }, + { + "id": "minecraft:stick" + }, + { + "id": "minecraft:bed" + }, + { + "id": "minecraft:bed", + "damage": 8 + }, + { + "id": "minecraft:bed", + "damage": 7 + }, + { + "id": "minecraft:bed", + "damage": 15 + }, + { + "id": "minecraft:bed", + "damage": 12 + }, + { + "id": "minecraft:bed", + "damage": 14 + }, + { + "id": "minecraft:bed", + "damage": 1 + }, + { + "id": "minecraft:bed", + "damage": 4 + }, + { + "id": "minecraft:bed", + "damage": 5 + }, + { + "id": "minecraft:bed", + "damage": 13 + }, + { + "id": "minecraft:bed", + "damage": 9 + }, + { + "id": "minecraft:bed", + "damage": 3 + }, + { + "id": "minecraft:bed", + "damage": 11 + }, + { + "id": "minecraft:bed", + "damage": 10 + }, + { + "id": "minecraft:bed", + "damage": 2 + }, + { + "id": "minecraft:bed", + "damage": 6 + }, + { + "id": "minecraft:torch", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnRvcmNoBAkAbmFtZV9oYXNoagn7rmDBzisDCgBuZXR3b3JrX2lk+BwwuQoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:soul_torch", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNvdWxfdG9yY2gECQBuYW1lX2hhc2huixOT04BRdQMKAG5ldHdvcmtfaWShbFILCgYAc3RhdGVzCBYAdG9yY2hfZmFjaW5nX2RpcmVjdGlvbgcAdW5rbm93bgADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:sea_pickle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAQAACAQAbmFtZRQAbWluZWNyYWZ0OnNlYV9waWNrbGUECQBuYW1lX2hhc2iONEfZJB+glgMKAG5ldHdvcmtfaWSINWQyCgYAc3RhdGVzAw0AY2x1c3Rlcl9jb3VudAAAAAABCABkZWFkX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:lantern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAQAACAQAbmFtZREAbWluZWNyYWZ0OmxhbnRlcm4ECQBuYW1lX2hhc2hMw44VI2HWygMKAG5ldHdvcmtfaWRkjQvzCgYAc3RhdGVzAQcAaGFuZ2luZwAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:soul_lantern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNvdWxfbGFudGVybgQJAG5hbWVfaGFzaGjIpjxk9z+RAwoAbmV0d29ya19pZGfoP8cKBgBzdGF0ZXMBBwBoYW5naW5nAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZHsBMA0KBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:white_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhbmRsZQQJAG5hbWVfaGFzaN1EG5Q1mHiEAwoAbmV0d29ya19pZKN1mmgKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:orange_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSdAgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYW5kbGUECQBuYW1lX2hhc2jySEVWHgUIHQMKAG5ldHdvcmtfaWSfVz82CgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:magenta_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FuZGxlBAkAbmFtZV9oYXNoG0u6YIOoBSEDCgBuZXR3b3JrX2lk9xGNkQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:light_blue_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FuZGxlBAkAbmFtZV9oYXNocXGeK0zgrG0DCgBuZXR3b3JrX2lk2m1y8goGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:yellow_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYW5kbGUECQBuYW1lX2hhc2i00dtusU3CqQMKAG5ldHdvcmtfaWR9LTmpCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:lime_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FuZGxlBAkAbmFtZV9oYXNokcmrw5xvz7ADCgBuZXR3b3JrX2lkIAUu6QoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:pink_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FuZGxlBAkAbmFtZV9oYXNoQJdEY4sZ0dwDCgBuZXR3b3JrX2lk23Rn5AoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:gray_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FuZGxlBAkAbmFtZV9oYXNoS5poSo9wBDEDCgBuZXR3b3JrX2lk3trRCAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:light_gray_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FuZGxlBAkAbmFtZV9oYXNo9ruTZLBNMasDCgBuZXR3b3JrX2lkb6DOegoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cyan_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FuZGxlBAkAbmFtZV9oYXNoc/M8PNVcjOwDCgBuZXR3b3JrX2lkZoIQOQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:purple_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYW5kbGUECQBuYW1lX2hhc2jaI3xUW0/myQMKAG5ldHdvcmtfaWSnLI2BCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:blue_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FuZGxlBAkAbmFtZV9oYXNoAASSPW6TgQADCgBuZXR3b3JrX2lkrxrjQAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:brown_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhbmRsZQQJAG5hbWVfaGFzaDia0l6s1+WYAwoAbmV0d29ya19pZKSkBXYKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:green_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhbmRsZQQJAG5hbWVfaGFzaLeFPO1l+fIoAwoAbmV0d29ya19pZBkznDsKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:red_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYW5kbGUECQBuYW1lX2hhc2jjAQpGf59ZdwMKAG5ldHdvcmtfaWRbb88GCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:black_candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhbmRsZQQJAG5hbWVfaGFzaB+wRDpOqREKAwoAbmV0d29ya19pZNnOnuEKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crafting_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AAAACAQAbmFtZRgAbWluZWNyYWZ0OmNyYWZ0aW5nX3RhYmxlBAkAbmFtZV9oYXNoe76VAmjvbpYDCgBuZXR3b3JrX2lkwCxwaAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cartography_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAQAACAQAbmFtZRsAbWluZWNyYWZ0OmNhcnRvZ3JhcGh5X3RhYmxlBAkAbmFtZV9oYXNomaWiiD/znP8DCgBuZXR3b3JrX2lkI6FzMwoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:fletching_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAQAACAQAbmFtZRkAbWluZWNyYWZ0OmZsZXRjaGluZ190YWJsZQQJAG5hbWVfaGFzaPFibh8unKyUAwoAbmV0d29ya19pZJ2mW0oKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:smithing_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAQAACAQAbmFtZRgAbWluZWNyYWZ0OnNtaXRoaW5nX3RhYmxlBAkAbmFtZV9oYXNo4tFES2xOXEYDCgBuZXR3b3JrX2lkXWMBzQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:beehive", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAQAACAQAbmFtZREAbWluZWNyYWZ0OmJlZWhpdmUECQBuYW1lX2hhc2hCcqn12UbNpwMKAG5ldHdvcmtfaWR/idcaCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAMLAGhvbmV5X2xldmVsAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:suspicious_sand", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAwAACAQAbmFtZRkAbWluZWNyYWZ0OnN1c3BpY2lvdXNfc2FuZAQJAG5hbWVfaGFzaL67QsuvLP00AwoAbmV0d29ya19pZKnkaIAKBgBzdGF0ZXMDEABicnVzaGVkX3Byb2dyZXNzAAAAAAEHAGhhbmdpbmcBAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:suspicious_gravel", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AwAACAQAbmFtZRsAbWluZWNyYWZ0OnN1c3BpY2lvdXNfZ3JhdmVsBAkAbmFtZV9oYXNoJSVbGNk7C3oDCgBuZXR3b3JrX2lkvIEJAAoGAHN0YXRlcwMQAGJydXNoZWRfcHJvZ3Jlc3MAAAAAAQcAaGFuZ2luZwEAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:campfire" + }, + { + "id": "minecraft:soul_campfire" + }, + { + "id": "minecraft:furnace", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AAAACAQAbmFtZREAbWluZWNyYWZ0OmZ1cm5hY2UECQBuYW1lX2hhc2ioOQrludYY8wMKAG5ldHdvcmtfaWRZxnDOCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:blast_furnace", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAQAACAQAbmFtZRcAbWluZWNyYWZ0OmJsYXN0X2Z1cm5hY2UECQBuYW1lX2hhc2ivDbnjkpGm5QMKAG5ldHdvcmtfaWTcEbV/CgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:smoker", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAQAACAQAbmFtZRAAbWluZWNyYWZ0OnNtb2tlcgQJAG5hbWVfaGFzaJd1rDMkRWomAwoAbmV0d29ya19pZGWswMwKBgBzdGF0ZXMIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:respawn_anchor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlc3Bhd25fYW5jaG9yBAkAbmFtZV9oYXNoZOdcjW05qigDCgBuZXR3b3JrX2lkmhMcaQoGAHN0YXRlcwMVAHJlc3Bhd25fYW5jaG9yX2NoYXJnZQAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:brewing_stand" + }, + { + "id": "minecraft:anvil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkqXzNjwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:chipped_anvil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS+BAAACAQAbmFtZRcAbWluZWNyYWZ0OmNoaXBwZWRfYW52aWwECQBuYW1lX2hhc2ge+QY3vlS/eQMKAG5ldHdvcmtfaWRJ15iUCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:damaged_anvil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWS/BAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhbWFnZWRfYW52aWwECQBuYW1lX2hhc2imJ12Be2V8+AMKAG5ldHdvcmtfaWRh5SHkCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:grindstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAQAACAQAbmFtZRQAbWluZWNyYWZ0OmdyaW5kc3RvbmUECQBuYW1lX2hhc2id56zc0nk99wMKAG5ldHdvcmtfaWS4Es07CgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:enchanting_table", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuY2hhbnRpbmdfdGFibGUECQBuYW1lX2hhc2jgIx24VLvMvwMKAG5ldHdvcmtfaWRliFFJCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bookshelf", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAAAACAQAbmFtZRMAbWluZWNyYWZ0OmJvb2tzaGVsZgQJAG5hbWVfaGFzaDU04DrgJCS9AwoAbmV0d29ya19pZBcWwIwKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:chiseled_bookshelf", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAwAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2Jvb2tzaGVsZgQJAG5hbWVfaGFzaNXDBnsIsywYAwoAbmV0d29ya19pZIprt5IKBgBzdGF0ZXMDDABib29rc19zdG9yZWQAAAAAAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:lectern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTBAQAACAQAbmFtZREAbWluZWNyYWZ0OmxlY3Rlcm4ECQBuYW1lX2hhc2j5Z4Mmi/1QxAMKAG5ldHdvcmtfaWR4JfDHCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cauldron" + }, + { + "id": "minecraft:composter", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvbXBvc3RlcgQJAG5hbWVfaGFzaPAADHptzeWJAwoAbmV0d29ya19pZHIL6i4KBgBzdGF0ZXMDFABjb21wb3N0ZXJfZmlsbF9sZXZlbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:chest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AAAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkDkOFvAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:trapped_chest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyYXBwZWRfY2hlc3QECQBuYW1lX2hhc2g2qpF9stsEjgMKAG5ldHdvcmtfaWTjJWYxCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAbm9ydGgAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:ender_chest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVuZGVyX2NoZXN0BAkAbmFtZV9oYXNohEZzOFdg0WUDCgBuZXR3b3JrX2lkx4jiSQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:barrel", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhcnJlbAQJAG5hbWVfaGFzaHDkRPGymiRqAwoAbmV0d29ya19pZPnxzgsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:undyed_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAAAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZJ8rxp0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:white_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAAAACAQAbmFtZRsAbWluZWNyYWZ0OndoaXRlX3NodWxrZXJfYm94BAkAbmFtZV9oYXNosK79m1rPUBwDCgBuZXR3b3JrX2lkjrET6goGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:light_gray_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iBe5zq7PxHmgMKAG5ldHdvcmtfaWSCVJv0CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:gray_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2ga2s8ctjHUhgMKAG5ldHdvcmtfaWS3WMsWCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:black_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoPm03OZphrp8DCgBuZXR3b3JrX2lkXHztNAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:brown_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJyb3duX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoT3DD6qAL9cADCgBuZXR3b3JrX2lkaXxpYQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:red_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAwAACAQAbmFtZRkAbWluZWNyYWZ0OnJlZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaMIlKSCzqSZoAwoAbmV0d29ya19pZNrf+icKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:orange_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAwAACAQAbmFtZRwAbWluZWNyYWZ0Om9yYW5nZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaG2MAXU67wGrAwoAbmV0d29ya19pZGoO05gKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:yellow_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAwAACAQAbmFtZRwAbWluZWNyYWZ0OnllbGxvd19zaHVsa2VyX2JveAQJAG5hbWVfaGFzaIsLwQHYjcIEAwoAbmV0d29ya19pZBCBSiYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:lime_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAwAACAQAbmFtZRoAbWluZWNyYWZ0OmxpbWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hUwBkg+faUGAMKAG5ldHdvcmtfaWRJeKqqCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:green_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAwAACAQAbmFtZRsAbWluZWNyYWZ0OmdyZWVuX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoZgUeT3LupLUDCgBuZXR3b3JrX2lkzJiohQoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:cyan_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAwAACAQAbmFtZRoAbWluZWNyYWZ0OmN5YW5fc2h1bGtlcl9ib3gECQBuYW1lX2hhc2gSfbjteXg5yAMKAG5ldHdvcmtfaWTHeliECgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:light_blue_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2h0VFCX0qsRxQMKAG5ldHdvcmtfaWQXD8U0CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:blue_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hn9gS0XIe6rAMKAG5ldHdvcmtfaWTO4PJaCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:purple_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAwAACAQAbmFtZRwAbWluZWNyYWZ0OnB1cnBsZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaEV/lkNPxRDdAwoAbmV0d29ya19pZFK25GAKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:magenta_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAwAACAQAbmFtZR0AbWluZWNyYWZ0Om1hZ2VudGFfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iqWM7IJHxcFgMKAG5ldHdvcmtfaWTyyudTCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:pink_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBpbmtfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2in1tkJ1GNcZgMKAG5ldHdvcmtfaWQOEGXjCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:armor_stand" + }, + { + "id": "minecraft:noteblock", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAAAACAQAbmFtZRMAbWluZWNyYWZ0Om5vdGVibG9jawQJAG5hbWVfaGFzaHPA8dBBH0UaAwoAbmV0d29ya19pZH1U5QkKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:jukebox", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAAAACAQAbmFtZREAbWluZWNyYWZ0Omp1a2Vib3gECQBuYW1lX2hhc2ieAIPExf/ZfgMKAG5ldHdvcmtfaWSmR7JfCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:music_disc_13" + }, + { + "id": "minecraft:music_disc_cat" + }, + { + "id": "minecraft:music_disc_blocks" + }, + { + "id": "minecraft:music_disc_chirp" + }, + { + "id": "minecraft:music_disc_far" + }, + { + "id": "minecraft:music_disc_mall" + }, + { + "id": "minecraft:music_disc_mellohi" + }, + { + "id": "minecraft:music_disc_stal" + }, + { + "id": "minecraft:music_disc_strad" + }, + { + "id": "minecraft:music_disc_ward" + }, + { + "id": "minecraft:music_disc_11" + }, + { + "id": "minecraft:music_disc_wait" + }, + { + "id": "minecraft:music_disc_otherside" + }, + { + "id": "minecraft:music_disc_5" + }, + { + "id": "minecraft:music_disc_pigstep" + }, + { + "id": "minecraft:music_disc_relic" + }, + { + "id": "minecraft:music_disc_creator" + }, + { + "id": "minecraft:music_disc_creator_music_box" + }, + { + "id": "minecraft:music_disc_precipice" + }, + { + "id": "minecraft:disc_fragment_5" + }, + { + "id": "minecraft:glowstone_dust" + }, + { + "id": "minecraft:glowstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAAAACAQAbmFtZRMAbWluZWNyYWZ0Omdsb3dzdG9uZQQJAG5hbWVfaGFzaFYqXNkefIlPAwoAbmV0d29ya19pZGT7WYYKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:redstone_lamp", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZHN0b25lX2xhbXAECQBuYW1lX2hhc2hJ9V80caPvEgMKAG5ldHdvcmtfaWRvNPwnCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:sea_lantern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNlYV9sYW50ZXJuBAkAbmFtZV9oYXNoLPsv1TX9M+QDCgBuZXR3b3JrX2lk1PPVyAoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:oak_sign" + }, + { + "id": "minecraft:spruce_sign" + }, + { + "id": "minecraft:birch_sign" + }, + { + "id": "minecraft:jungle_sign" + }, + { + "id": "minecraft:acacia_sign" + }, + { + "id": "minecraft:dark_oak_sign" + }, + { + "id": "minecraft:mangrove_sign" + }, + { + "id": "minecraft:cherry_sign" + }, + { + "id": "minecraft:bamboo_sign" + }, + { + "id": "minecraft:crimson_sign" + }, + { + "id": "minecraft:warped_sign" + }, + { + "id": "minecraft:oak_hanging_sign" + }, + { + "id": "minecraft:spruce_hanging_sign" + }, + { + "id": "minecraft:birch_hanging_sign" + }, + { + "id": "minecraft:jungle_hanging_sign" + }, + { + "id": "minecraft:acacia_hanging_sign" + }, + { + "id": "minecraft:dark_oak_hanging_sign" + }, + { + "id": "minecraft:mangrove_hanging_sign" + }, + { + "id": "minecraft:cherry_hanging_sign" + }, + { + "id": "minecraft:bamboo_hanging_sign" + }, + { + "id": "minecraft:crimson_hanging_sign" + }, + { + "id": "minecraft:warped_hanging_sign" + }, + { + "id": "minecraft:painting" + }, + { + "id": "minecraft:frame" + }, + { + "id": "minecraft:glow_frame" + }, + { + "id": "minecraft:honey_bottle" + }, + { + "id": "minecraft:flower_pot" + }, + { + "id": "minecraft:bowl" + }, + { + "id": "minecraft:bucket" + }, + { + "id": "minecraft:milk_bucket" + }, + { + "id": "minecraft:water_bucket" + }, + { + "id": "minecraft:lava_bucket" + }, + { + "id": "minecraft:cod_bucket" + }, + { + "id": "minecraft:salmon_bucket" + }, + { + "id": "minecraft:tropical_fish_bucket" + }, + { + "id": "minecraft:pufferfish_bucket" + }, + { + "id": "minecraft:powder_snow_bucket" + }, + { + "id": "minecraft:axolotl_bucket" + }, + { + "id": "minecraft:tadpole_bucket" + }, + { + "id": "minecraft:player_head", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGBAAACAQAbmFtZRUAbWluZWNyYWZ0OnBsYXllcl9oZWFkBAkAbmFtZV9oYXNonFwZb7CL8EYDCgBuZXR3b3JrX2lkZeAXqAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:zombie_head", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFBAAACAQAbmFtZRUAbWluZWNyYWZ0OnpvbWJpZV9oZWFkBAkAbmFtZV9oYXNoixuENYuaGgEDCgBuZXR3b3JrX2lk0NsHDgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:creeper_head", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHBAAACAQAbmFtZRYAbWluZWNyYWZ0OmNyZWVwZXJfaGVhZAQJAG5hbWVfaGFzaCvAGFMS/RqVAwoAbmV0d29ya19pZEfskXYKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dragon_head", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIBAAACAQAbmFtZRUAbWluZWNyYWZ0OmRyYWdvbl9oZWFkBAkAbmFtZV9oYXNozjh6bGRaa5UDCgBuZXR3b3JrX2lk/zjetgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:skeleton_skull", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAAAACAQAbmFtZRgAbWluZWNyYWZ0OnNrZWxldG9uX3NrdWxsBAkAbmFtZV9oYXNo3+kbzeMgg4kDCgBuZXR3b3JrX2lk/RqWbwoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:wither_skeleton_skull", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEBAAACAQAbmFtZR8AbWluZWNyYWZ0OndpdGhlcl9za2VsZXRvbl9za3VsbAQJAG5hbWVfaGFzaEcZrUyy9cfRAwoAbmV0d29ya19pZJZ2G/oKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:piglin_head", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJBAAACAQAbmFtZRUAbWluZWNyYWZ0OnBpZ2xpbl9oZWFkBAkAbmFtZV9oYXNo+jUCKgb5DskDCgBuZXR3b3JrX2lkQ1ETVwoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:beacon", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAAAACAQAbmFtZRAAbWluZWNyYWZ0OmJlYWNvbgQJAG5hbWVfaGFzaACwhhfSkdkHAwoAbmV0d29ya19pZF8jfiEKBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:bell", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAQAACAQAbmFtZQ4AbWluZWNyYWZ0OmJlbGwECQBuYW1lX2hhc2iPqsgDXRcsxAMKAG5ldHdvcmtfaWT7zhOoCgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAQoAdG9nZ2xlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:conduit", + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAQAACAQAbmFtZREAbWluZWNyYWZ0OmNvbmR1aXQECQBuYW1lX2hhc2jqxKAxq2EaWQMKAG5ldHdvcmtfaWTWcBVnCgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stonecutter_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lY3V0dGVyX2Jsb2NrBAkAbmFtZV9oYXNoQAXTbAM3MeYDCgBuZXR3b3JrX2lkWS4RjAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:coal" + }, + { + "id": "minecraft:charcoal" + }, + { + "id": "minecraft:diamond" + }, + { + "id": "minecraft:iron_nugget" + }, + { + "id": "minecraft:raw_iron" + }, + { + "id": "minecraft:raw_gold" + }, + { + "id": "minecraft:raw_copper" + }, + { + "id": "minecraft:copper_ingot" + }, + { + "id": "minecraft:iron_ingot" + }, + { + "id": "minecraft:netherite_scrap" + }, + { + "id": "minecraft:netherite_ingot" + }, + { + "id": "minecraft:gold_nugget" + }, + { + "id": "minecraft:gold_ingot" + }, + { + "id": "minecraft:emerald" + }, + { + "id": "minecraft:quartz" + }, + { + "id": "minecraft:clay_ball" + }, + { + "id": "minecraft:brick" + }, + { + "id": "minecraft:netherbrick" + }, + { + "id": "minecraft:prismarine_shard" + }, + { + "id": "minecraft:amethyst_shard" + }, + { + "id": "minecraft:prismarine_crystals" + }, + { + "id": "minecraft:nautilus_shell" + }, + { + "id": "minecraft:heart_of_the_sea" + }, + { + "id": "minecraft:turtle_scute" + }, + { + "id": "minecraft:armadillo_scute" + }, + { + "id": "minecraft:phantom_membrane" + }, + { + "id": "minecraft:string" + }, + { + "id": "minecraft:feather" + }, + { + "id": "minecraft:flint" + }, + { + "id": "minecraft:gunpowder" + }, + { + "id": "minecraft:leather" + }, + { + "id": "minecraft:rabbit_hide" + }, + { + "id": "minecraft:rabbit_foot" + }, + { + "id": "minecraft:fire_charge" + }, + { + "id": "minecraft:blaze_rod" + }, + { + "id": "minecraft:breeze_rod" + }, + { + "id": "minecraft:heavy_core", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AgAACAQAbmFtZRQAbWluZWNyYWZ0OmhlYXZ5X2NvcmUECQBuYW1lX2hhc2hhz/uNCtrC2QMKAG5ldHdvcmtfaWRaFu+8CgYAc3RhdGVzAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:blaze_powder" + }, + { + "id": "minecraft:magma_cream" + }, + { + "id": "minecraft:fermented_spider_eye" + }, + { + "id": "minecraft:echo_shard" + }, + { + "id": "minecraft:dragon_breath" + }, + { + "id": "minecraft:shulker_shell" + }, + { + "id": "minecraft:ghast_tear" + }, + { + "id": "minecraft:slime_ball" + }, + { + "id": "minecraft:ender_pearl" + }, + { + "id": "minecraft:ender_eye" + }, + { + "id": "minecraft:nether_star" + }, + { + "id": "minecraft:end_rod", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAAAACAQAbmFtZREAbWluZWNyYWZ0OmVuZF9yb2QECQBuYW1lX2hhc2jx/q5cEA0hmQMKAG5ldHdvcmtfaWQ2eM8kCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:lightning_rod", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpZ2h0bmluZ19yb2QECQBuYW1lX2hhc2ioXQF1xvfHNQMKAG5ldHdvcmtfaWRLuHyACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:end_crystal" + }, + { + "id": "minecraft:paper" + }, + { + "id": "minecraft:book" + }, + { + "id": "minecraft:writable_book" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:oak_boat" + }, + { + "id": "minecraft:spruce_boat" + }, + { + "id": "minecraft:birch_boat" + }, + { + "id": "minecraft:jungle_boat" + }, + { + "id": "minecraft:acacia_boat" + }, + { + "id": "minecraft:dark_oak_boat" + }, + { + "id": "minecraft:mangrove_boat" + }, + { + "id": "minecraft:cherry_boat" + }, + { + "id": "minecraft:bamboo_raft" + }, + { + "id": "minecraft:oak_chest_boat" + }, + { + "id": "minecraft:spruce_chest_boat" + }, + { + "id": "minecraft:birch_chest_boat" + }, + { + "id": "minecraft:jungle_chest_boat" + }, + { + "id": "minecraft:acacia_chest_boat" + }, + { + "id": "minecraft:dark_oak_chest_boat" + }, + { + "id": "minecraft:mangrove_chest_boat" + }, + { + "id": "minecraft:cherry_chest_boat" + }, + { + "id": "minecraft:bamboo_chest_raft" + }, + { + "id": "minecraft:rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWR+Sp6YCgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:golden_rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdvbGRlbl9yYWlsBAkAbmFtZV9oYXNoOoV5MaKipoUDCgBuZXR3b3JrX2lkfAcxLwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:detector_rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAAAACAQAbmFtZRcAbWluZWNyYWZ0OmRldGVjdG9yX3JhaWwECQBuYW1lX2hhc2gVUk31qOysUQMKAG5ldHdvcmtfaWRVW/aICgYAc3RhdGVzAQ0AcmFpbF9kYXRhX2JpdAADDgByYWlsX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:activator_rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjdGl2YXRvcl9yYWlsBAkAbmFtZV9oYXNosIL91qriCRkDCgBuZXR3b3JrX2lkZfckmwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:minecart" + }, + { + "id": "minecraft:chest_minecart" + }, + { + "id": "minecraft:hopper_minecart" + }, + { + "id": "minecraft:tnt_minecart" + }, + { + "id": "minecraft:redstone" + }, + { + "id": "minecraft:redstone_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX2Jsb2NrBAkAbmFtZV9oYXNoRhULL0r8o0sDCgBuZXR3b3JrX2lklayOHgoGAHN0YXRlcwADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:redstone_torch", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX3RvcmNoBAkAbmFtZV9oYXNoizFRjpYMIDgDCgBuZXR3b3JrX2lkuHz7yAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:lever", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxldmVyBAkAbmFtZV9oYXNoGMJeLJsUMLYDCgBuZXR3b3JrX2lkEF/GuAoGAHN0YXRlcwgPAGxldmVyX2RpcmVjdGlvbg4AZG93bl9lYXN0X3dlc3QBCABvcGVuX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:wooden_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAAAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWSU07kYCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:spruce_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAQAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9idXR0b24ECQBuYW1lX2hhc2jBW9Z8aYE7YQMKAG5ldHdvcmtfaWTkUIGuCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:birch_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAQAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2J1dHRvbgQJAG5hbWVfaGFzaJXYgGuSHbTwAwoAbmV0d29ya19pZGWp3yoKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:jungle_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAQAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9idXR0b24ECQBuYW1lX2hhc2iCgNANcJs+BQMKAG5ldHdvcmtfaWT9fImWCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:acacia_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAQAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9idXR0b24ECQBuYW1lX2hhc2gVvmcT7LTO0wMKAG5ldHdvcmtfaWRQnxIJCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dark_oak_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAQAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaIV10ZGGrCIEAwoAbmV0d29ya19pZN5vAmIKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mangrove_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2J1dHRvbgQJAG5hbWVfaGFzaNzeYYKLgOzJAwoAbmV0d29ya19pZAFEGQ0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cherry_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9idXR0b24ECQBuYW1lX2hhc2j2/IHjeAbUcwMKAG5ldHdvcmtfaWRJ1irQCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bamboo_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19idXR0b24ECQBuYW1lX2hhc2j7AddMi+6nsgMKAG5ldHdvcmtfaWSa9w4/CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stone_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2J1dHRvbgQJAG5hbWVfaGFzaM4ejMctmvohAwoAbmV0d29ya19pZMw+aC0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:crimson_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fYnV0dG9uBAkAbmFtZV9oYXNofnjYHaYIeWgDCgBuZXR3b3JrX2lk+n1vyQoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:warped_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9idXR0b24ECQBuYW1lX2hhc2jwkV2EU6Cn1QMKAG5ldHdvcmtfaWTnHnk1CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:polished_blackstone_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnV0dG9uBAkAbmFtZV9oYXNojmxzQKS0S/EDCgBuZXR3b3JrX2lkDtQ95woGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:tripwire_hook", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaXB3aXJlX2hvb2sECQBuYW1lX2hhc2gQdp+oGZLNnAMKAG5ldHdvcmtfaWSy+1KJCgYAc3RhdGVzAQwAYXR0YWNoZWRfYml0AAMJAGRpcmVjdGlvbgAAAAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:wooden_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAAAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZDRzPNwKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:spruce_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAQAACAQAbmFtZR8AbWluZWNyYWZ0OnNwcnVjZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNmwuq549fJKAwoAbmV0d29ya19pZLQMCw0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:birch_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAQAACAQAbmFtZR4AbWluZWNyYWZ0OmJpcmNoX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNorQkT9kDdlTwDCgBuZXR3b3JrX2lkH0G97AoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:jungle_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAQAACAQAbmFtZR8AbWluZWNyYWZ0Omp1bmdsZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaJ7DcteCkb8/AwoAbmV0d29ya19pZLdPBSAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:acacia_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAQAACAQAbmFtZR8AbWluZWNyYWZ0OmFjYWNpYV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaC2frZtfoYqCAwoAbmV0d29ya19pZIDdI18KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:dark_oak_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAQAACAQAbmFtZSEAbWluZWNyYWZ0OmRhcmtfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoHUCJsTy52pwDCgBuZXR3b3JrX2lkKpi8rAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:mangrove_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hbmdyb3ZlX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoiDsTfJaX100DCgBuZXR3b3JrX2lkuwWDyQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:cherry_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAwAACAQAbmFtZR8AbWluZWNyYWZ0OmNoZXJyeV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaALMqYEZDUQHAwoAbmV0d29ya19pZPNT+r0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:bamboo_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJhbWJvb19wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNvxJ7NIAaqlAwoAbmV0d29ya19pZIZ8XnYKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:crimson_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNyaW1zb25fcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2hqBDVDAd31/gMKAG5ldHdvcmtfaWRmV18LCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:warped_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAgAACAQAbmFtZR8AbWluZWNyYWZ0OndhcnBlZF9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaBxFoQksWtYUAwoAbmV0d29ya19pZJVRoIcKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:stone_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0b25lX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNounJuTBUTrU8DCgBuZXR3b3JrX2lkjDydwQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:light_weighted_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAAAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoOyOJkNxLtkEDCgBuZXR3b3JrX2lkrr2AjgoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:heavy_weighted_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAAAACAQAbmFtZScAbWluZWNyYWZ0OmhlYXZ5X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoltgDmDvTajUDCgBuZXR3b3JrX2lkFxVKuQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:polished_blackstone_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAgAACAQAbmFtZSwAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2h65Ci6/CeGqwMKAG5ldHdvcmtfaWTaSW5xCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:observer", + "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2VydmVyBAkAbmFtZV9oYXNoYhlh1lpmHTgDCgBuZXR3b3JrX2lkQEh55goGAHN0YXRlcwgaAG1pbmVjcmFmdDpmYWNpbmdfZGlyZWN0aW9uBABkb3duAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:daylight_detector", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAAAACAQAbmFtZRsAbWluZWNyYWZ0OmRheWxpZ2h0X2RldGVjdG9yBAkAbmFtZV9oYXNoV0F0s7B7PVgDCgBuZXR3b3JrX2lkri5afQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:repeater" + }, + { + "id": "minecraft:comparator" + }, + { + "id": "minecraft:hopper" + }, + { + "id": "minecraft:dropper", + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AAAACAQAbmFtZREAbWluZWNyYWZ0OmRyb3BwZXIECQBuYW1lX2hhc2joXP7XqU0l3QMKAG5ldHdvcmtfaWQfQN6zCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgMAAAABDQB0cmlnZ2VyZWRfYml0AAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:dispenser", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRpc3BlbnNlcgQJAG5hbWVfaGFzaP1RR+zAbYP2AwoAbmV0d29ya19pZGAayD0KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAwAAAAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:crafter", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AgAACAQAbmFtZREAbWluZWNyYWZ0OmNyYWZ0ZXIECQBuYW1lX2hhc2iLCT/rJmRN8QMKAG5ldHdvcmtfaWTPTbvrCgYAc3RhdGVzAQgAY3JhZnRpbmcACAsAb3JpZW50YXRpb24JAGRvd25fZWFzdAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24BKBUBAA==" + }, + { + "id": "minecraft:piston", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBpc3RvbgQJAG5hbWVfaGFzaDs3AFh1fL0uAwoAbmV0d29ya19pZLD/5XQKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAQAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:sticky_piston", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQdAAAACAQAbmFtZRcAbWluZWNyYWZ0OnN0aWNreV9waXN0b24ECQBuYW1lX2hhc2hPFJFJSiJ0ZQMKAG5ldHdvcmtfaWT/MzCJCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgEAAAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:tnt", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAAAACAQAbmFtZQ0AbWluZWNyYWZ0OnRudAQJAG5hbWVfaGFzaEYOHwCvJH29AwoAbmV0d29ya19pZAXzHyUKBgBzdGF0ZXMBCwBleHBsb2RlX2JpdAAAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:name_tag" + }, + { + "id": "minecraft:loom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAQAACAQAbmFtZQ4AbWluZWNyYWZ0Omxvb20ECQBuYW1lX2hhc2i7DKjAXNq8TAMKAG5ldHdvcmtfaWR/49HXCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:banner", + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 8, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 7, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 15, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 12, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 14, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 1, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 4, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 5, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 13, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 9, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 3, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 11, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 10, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 2, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 6, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 15, + "nbt_b64": "CgAAAwQAVHlwZQEAAAAA" + }, + { + "id": "minecraft:creeper_banner_pattern" + }, + { + "id": "minecraft:skull_banner_pattern" + }, + { + "id": "minecraft:flower_banner_pattern" + }, + { + "id": "minecraft:mojang_banner_pattern" + }, + { + "id": "minecraft:field_masoned_banner_pattern" + }, + { + "id": "minecraft:bordure_indented_banner_pattern" + }, + { + "id": "minecraft:piglin_banner_pattern" + }, + { + "id": "minecraft:globe_banner_pattern" + }, + { + "id": "minecraft:flow_banner_pattern" + }, + { + "id": "minecraft:guster_banner_pattern" + }, + { + "id": "minecraft:angler_pottery_sherd" + }, + { + "id": "minecraft:archer_pottery_sherd" + }, + { + "id": "minecraft:arms_up_pottery_sherd" + }, + { + "id": "minecraft:blade_pottery_sherd" + }, + { + "id": "minecraft:brewer_pottery_sherd" + }, + { + "id": "minecraft:burn_pottery_sherd" + }, + { + "id": "minecraft:danger_pottery_sherd" + }, + { + "id": "minecraft:explorer_pottery_sherd" + }, + { + "id": "minecraft:flow_pottery_sherd" + }, + { + "id": "minecraft:friend_pottery_sherd" + }, + { + "id": "minecraft:guster_pottery_sherd" + }, + { + "id": "minecraft:heart_pottery_sherd" + }, + { + "id": "minecraft:heartbreak_pottery_sherd" + }, + { + "id": "minecraft:howl_pottery_sherd" + }, + { + "id": "minecraft:miner_pottery_sherd" + }, + { + "id": "minecraft:mourner_pottery_sherd" + }, + { + "id": "minecraft:plenty_pottery_sherd" + }, + { + "id": "minecraft:prize_pottery_sherd" + }, + { + "id": "minecraft:scrape_pottery_sherd" + }, + { + "id": "minecraft:sheaf_pottery_sherd" + }, + { + "id": "minecraft:shelter_pottery_sherd" + }, + { + "id": "minecraft:skull_pottery_sherd" + }, + { + "id": "minecraft:snort_pottery_sherd" + }, + { + "id": "minecraft:netherite_upgrade_smithing_template" + }, + { + "id": "minecraft:sentry_armor_trim_smithing_template" + }, + { + "id": "minecraft:vex_armor_trim_smithing_template" + }, + { + "id": "minecraft:wild_armor_trim_smithing_template" + }, + { + "id": "minecraft:coast_armor_trim_smithing_template" + }, + { + "id": "minecraft:dune_armor_trim_smithing_template" + }, + { + "id": "minecraft:wayfinder_armor_trim_smithing_template" + }, + { + "id": "minecraft:shaper_armor_trim_smithing_template" + }, + { + "id": "minecraft:raiser_armor_trim_smithing_template" + }, + { + "id": "minecraft:host_armor_trim_smithing_template" + }, + { + "id": "minecraft:ward_armor_trim_smithing_template" + }, + { + "id": "minecraft:silence_armor_trim_smithing_template" + }, + { + "id": "minecraft:tide_armor_trim_smithing_template" + }, + { + "id": "minecraft:snout_armor_trim_smithing_template" + }, + { + "id": "minecraft:rib_armor_trim_smithing_template" + }, + { + "id": "minecraft:eye_armor_trim_smithing_template" + }, + { + "id": "minecraft:spire_armor_trim_smithing_template" + }, + { + "id": "minecraft:flow_armor_trim_smithing_template" + }, + { + "id": "minecraft:bolt_armor_trim_smithing_template" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_star", + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 8, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 7, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 15, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 12, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 14, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 1, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 4, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 5, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 13, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 9, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 3, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 11, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 10, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 2, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 6, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" + }, + { + "id": "minecraft:chain" + }, + { + "id": "minecraft:target", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAQAACAQAbmFtZRAAbWluZWNyYWZ0OnRhcmdldAQJAG5hbWVfaGFzaJc66SVbYlaxAwoAbmV0d29ya19pZPBozs0KBgBzdGF0ZXMAAwcAdmVyc2lvbgEoFQEA" + }, + { + "id": "minecraft:decorated_pot", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAwAACAQAbmFtZRcAbWluZWNyYWZ0OmRlY29yYXRlZF9wb3QECQBuYW1lX2hhc2jjQgckn8VTvwMKAG5ldHdvcmtfaWRwvkUUCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uASgVAQA=" + }, + { + "id": "minecraft:trial_key" + }, + { + "id": "minecraft:ominous_trial_key" + }, + { + "id": "minecraft:lodestone_compass" + }, + { + "id": "minecraft:wither_spawn_egg" + }, + { + "id": "minecraft:ender_dragon_spawn_egg" + } + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_21_40.json b/core/src/main/resources/bedrock/runtime_item_states.1_21_40.json new file mode 100644 index 000000000..9ad93dd09 --- /dev/null +++ b/core/src/main/resources/bedrock/runtime_item_states.1_21_40.json @@ -0,0 +1,6994 @@ +[ + { + "name": "minecraft:acacia_boat", + "id": 405 + }, + { + "name": "minecraft:acacia_button", + "id": -140 + }, + { + "name": "minecraft:acacia_chest_boat", + "id": 678 + }, + { + "name": "minecraft:acacia_door", + "id": 589 + }, + { + "name": "minecraft:acacia_double_slab", + "id": -812 + }, + { + "name": "minecraft:acacia_fence", + "id": -575 + }, + { + "name": "minecraft:acacia_fence_gate", + "id": 187 + }, + { + "name": "minecraft:acacia_hanging_sign", + "id": -504 + }, + { + "name": "minecraft:acacia_leaves", + "id": 161 + }, + { + "name": "minecraft:acacia_log", + "id": 162 + }, + { + "name": "minecraft:acacia_planks", + "id": -742 + }, + { + "name": "minecraft:acacia_pressure_plate", + "id": -150 + }, + { + "name": "minecraft:acacia_sapling", + "id": -828 + }, + { + "name": "minecraft:acacia_sign", + "id": 612 + }, + { + "name": "minecraft:acacia_slab", + "id": -807 + }, + { + "name": "minecraft:acacia_stairs", + "id": 163 + }, + { + "name": "minecraft:acacia_standing_sign", + "id": -190 + }, + { + "name": "minecraft:acacia_trapdoor", + "id": -145 + }, + { + "name": "minecraft:acacia_wall_sign", + "id": -191 + }, + { + "name": "minecraft:acacia_wood", + "id": -817 + }, + { + "name": "minecraft:activator_rail", + "id": 126 + }, + { + "name": "minecraft:agent_spawn_egg", + "id": 515 + }, + { + "name": "minecraft:air", + "id": -158 + }, + { + "name": "minecraft:allay_spawn_egg", + "id": 667 + }, + { + "name": "minecraft:allium", + "id": -831 + }, + { + "name": "minecraft:allow", + "id": 210 + }, + { + "name": "minecraft:amethyst_block", + "id": -327 + }, + { + "name": "minecraft:amethyst_cluster", + "id": -329 + }, + { + "name": "minecraft:amethyst_shard", + "id": 660 + }, + { + "name": "minecraft:ancient_debris", + "id": -271 + }, + { + "name": "minecraft:andesite", + "id": -594 + }, + { + "name": "minecraft:andesite_double_slab", + "id": -920 + }, + { + "name": "minecraft:andesite_slab", + "id": -893 + }, + { + "name": "minecraft:andesite_stairs", + "id": -171 + }, + { + "name": "minecraft:andesite_wall", + "id": -974 + }, + { + "name": "minecraft:angler_pottery_sherd", + "id": 692 + }, + { + "name": "minecraft:anvil", + "id": 145 + }, + { + "name": "minecraft:apple", + "id": 278 + }, + { + "name": "minecraft:archer_pottery_sherd", + "id": 693 + }, + { + "name": "minecraft:armadillo_scute", + "id": 739 + }, + { + "name": "minecraft:armadillo_spawn_egg", + "id": 738 + }, + { + "name": "minecraft:armor_stand", + "id": 585 + }, + { + "name": "minecraft:arms_up_pottery_sherd", + "id": 694 + }, + { + "name": "minecraft:arrow", + "id": 325 + }, + { + "name": "minecraft:axolotl_bucket", + "id": 394 + }, + { + "name": "minecraft:axolotl_spawn_egg", + "id": 530 + }, + { + "name": "minecraft:azalea", + "id": -337 + }, + { + "name": "minecraft:azalea_leaves", + "id": -324 + }, + { + "name": "minecraft:azalea_leaves_flowered", + "id": -325 + }, + { + "name": "minecraft:azure_bluet", + "id": -832 + }, + { + "name": "minecraft:baked_potato", + "id": 303 + }, + { + "name": "minecraft:balloon", + "id": 634 + }, + { + "name": "minecraft:bamboo", + "id": -163 + }, + { + "name": "minecraft:bamboo_block", + "id": -527 + }, + { + "name": "minecraft:bamboo_button", + "id": -511 + }, + { + "name": "minecraft:bamboo_chest_raft", + "id": 690 + }, + { + "name": "minecraft:bamboo_door", + "id": -517 + }, + { + "name": "minecraft:bamboo_double_slab", + "id": -521 + }, + { + "name": "minecraft:bamboo_fence", + "id": -515 + }, + { + "name": "minecraft:bamboo_fence_gate", + "id": -516 + }, + { + "name": "minecraft:bamboo_hanging_sign", + "id": -522 + }, + { + "name": "minecraft:bamboo_mosaic", + "id": -509 + }, + { + "name": "minecraft:bamboo_mosaic_double_slab", + "id": -525 + }, + { + "name": "minecraft:bamboo_mosaic_slab", + "id": -524 + }, + { + "name": "minecraft:bamboo_mosaic_stairs", + "id": -523 + }, + { + "name": "minecraft:bamboo_planks", + "id": -510 + }, + { + "name": "minecraft:bamboo_pressure_plate", + "id": -514 + }, + { + "name": "minecraft:bamboo_raft", + "id": 689 + }, + { + "name": "minecraft:bamboo_sapling", + "id": -164 + }, + { + "name": "minecraft:bamboo_sign", + "id": 688 + }, + { + "name": "minecraft:bamboo_slab", + "id": -513 + }, + { + "name": "minecraft:bamboo_stairs", + "id": -512 + }, + { + "name": "minecraft:bamboo_standing_sign", + "id": -518 + }, + { + "name": "minecraft:bamboo_trapdoor", + "id": -520 + }, + { + "name": "minecraft:bamboo_wall_sign", + "id": -519 + }, + { + "name": "minecraft:banner", + "id": 600 + }, + { + "name": "minecraft:banner_pattern", + "id": 787 + }, + { + "name": "minecraft:barrel", + "id": -203 + }, + { + "name": "minecraft:barrier", + "id": -161 + }, + { + "name": "minecraft:basalt", + "id": -234 + }, + { + "name": "minecraft:bat_spawn_egg", + "id": 480 + }, + { + "name": "minecraft:beacon", + "id": 138 + }, + { + "name": "minecraft:bed", + "id": 444 + }, + { + "name": "minecraft:bedrock", + "id": 7 + }, + { + "name": "minecraft:bee_nest", + "id": -218 + }, + { + "name": "minecraft:bee_spawn_egg", + "id": 522 + }, + { + "name": "minecraft:beef", + "id": 295 + }, + { + "name": "minecraft:beehive", + "id": -219 + }, + { + "name": "minecraft:beetroot", + "id": 307 + }, + { + "name": "minecraft:beetroot_seeds", + "id": 317 + }, + { + "name": "minecraft:beetroot_soup", + "id": 308 + }, + { + "name": "minecraft:bell", + "id": -206 + }, + { + "name": "minecraft:big_dripleaf", + "id": -323 + }, + { + "name": "minecraft:birch_boat", + "id": 402 + }, + { + "name": "minecraft:birch_button", + "id": -141 + }, + { + "name": "minecraft:birch_chest_boat", + "id": 675 + }, + { + "name": "minecraft:birch_door", + "id": 587 + }, + { + "name": "minecraft:birch_double_slab", + "id": -810 + }, + { + "name": "minecraft:birch_fence", + "id": -576 + }, + { + "name": "minecraft:birch_fence_gate", + "id": 184 + }, + { + "name": "minecraft:birch_hanging_sign", + "id": -502 + }, + { + "name": "minecraft:birch_leaves", + "id": -801 + }, + { + "name": "minecraft:birch_log", + "id": -570 + }, + { + "name": "minecraft:birch_planks", + "id": -740 + }, + { + "name": "minecraft:birch_pressure_plate", + "id": -151 + }, + { + "name": "minecraft:birch_sapling", + "id": -826 + }, + { + "name": "minecraft:birch_sign", + "id": 610 + }, + { + "name": "minecraft:birch_slab", + "id": -805 + }, + { + "name": "minecraft:birch_stairs", + "id": 135 + }, + { + "name": "minecraft:birch_standing_sign", + "id": -186 + }, + { + "name": "minecraft:birch_trapdoor", + "id": -146 + }, + { + "name": "minecraft:birch_wall_sign", + "id": -187 + }, + { + "name": "minecraft:birch_wood", + "id": -815 + }, + { + "name": "minecraft:black_bundle", + "id": 257 + }, + { + "name": "minecraft:black_candle", + "id": -428 + }, + { + "name": "minecraft:black_candle_cake", + "id": -445 + }, + { + "name": "minecraft:black_carpet", + "id": -611 + }, + { + "name": "minecraft:black_concrete", + "id": -642 + }, + { + "name": "minecraft:black_concrete_powder", + "id": -723 + }, + { + "name": "minecraft:black_dye", + "id": 421 + }, + { + "name": "minecraft:black_glazed_terracotta", + "id": 235 + }, + { + "name": "minecraft:black_shulker_box", + "id": -627 + }, + { + "name": "minecraft:black_stained_glass", + "id": -687 + }, + { + "name": "minecraft:black_stained_glass_pane", + "id": -657 + }, + { + "name": "minecraft:black_terracotta", + "id": -738 + }, + { + "name": "minecraft:black_wool", + "id": -554 + }, + { + "name": "minecraft:blackstone", + "id": -273 + }, + { + "name": "minecraft:blackstone_double_slab", + "id": -283 + }, + { + "name": "minecraft:blackstone_slab", + "id": -282 + }, + { + "name": "minecraft:blackstone_stairs", + "id": -276 + }, + { + "name": "minecraft:blackstone_wall", + "id": -277 + }, + { + "name": "minecraft:blade_pottery_sherd", + "id": 695 + }, + { + "name": "minecraft:blast_furnace", + "id": -196 + }, + { + "name": "minecraft:blaze_powder", + "id": 456 + }, + { + "name": "minecraft:blaze_rod", + "id": 449 + }, + { + "name": "minecraft:blaze_spawn_egg", + "id": 483 + }, + { + "name": "minecraft:bleach", + "id": 632 + }, + { + "name": "minecraft:blue_bundle", + "id": 258 + }, + { + "name": "minecraft:blue_candle", + "id": -424 + }, + { + "name": "minecraft:blue_candle_cake", + "id": -441 + }, + { + "name": "minecraft:blue_carpet", + "id": -607 + }, + { + "name": "minecraft:blue_concrete", + "id": -638 + }, + { + "name": "minecraft:blue_concrete_powder", + "id": -719 + }, + { + "name": "minecraft:blue_dye", + "id": 425 + }, + { + "name": "minecraft:blue_glazed_terracotta", + "id": 231 + }, + { + "name": "minecraft:blue_ice", + "id": -11 + }, + { + "name": "minecraft:blue_orchid", + "id": -830 + }, + { + "name": "minecraft:blue_shulker_box", + "id": -623 + }, + { + "name": "minecraft:blue_stained_glass", + "id": -683 + }, + { + "name": "minecraft:blue_stained_glass_pane", + "id": -653 + }, + { + "name": "minecraft:blue_terracotta", + "id": -734 + }, + { + "name": "minecraft:blue_wool", + "id": -563 + }, + { + "name": "minecraft:boat", + "id": 785 + }, + { + "name": "minecraft:bogged_spawn_egg", + "id": 490 + }, + { + "name": "minecraft:bolt_armor_trim_smithing_template", + "id": 734 + }, + { + "name": "minecraft:bone", + "id": 441 + }, + { + "name": "minecraft:bone_block", + "id": 216 + }, + { + "name": "minecraft:bone_meal", + "id": 437 + }, + { + "name": "minecraft:book", + "id": 413 + }, + { + "name": "minecraft:bookshelf", + "id": 47 + }, + { + "name": "minecraft:border_block", + "id": 212 + }, + { + "name": "minecraft:bordure_indented_banner_pattern", + "id": 619 + }, + { + "name": "minecraft:bow", + "id": 324 + }, + { + "name": "minecraft:bowl", + "id": 346 + }, + { + "name": "minecraft:brain_coral", + "id": -581 + }, + { + "name": "minecraft:brain_coral_block", + "id": -849 + }, + { + "name": "minecraft:brain_coral_fan", + "id": -840 + }, + { + "name": "minecraft:brain_coral_wall_fan", + "id": -904 + }, + { + "name": "minecraft:bread", + "id": 283 + }, + { + "name": "minecraft:breeze_rod", + "id": 274 + }, + { + "name": "minecraft:breeze_spawn_egg", + "id": 529 + }, + { + "name": "minecraft:brewer_pottery_sherd", + "id": 696 + }, + { + "name": "minecraft:brewing_stand", + "id": 458 + }, + { + "name": "minecraft:brick", + "id": 409 + }, + { + "name": "minecraft:brick_block", + "id": 45 + }, + { + "name": "minecraft:brick_double_slab", + "id": -880 + }, + { + "name": "minecraft:brick_slab", + "id": -874 + }, + { + "name": "minecraft:brick_stairs", + "id": 108 + }, + { + "name": "minecraft:brick_wall", + "id": -976 + }, + { + "name": "minecraft:brown_bundle", + "id": 259 + }, + { + "name": "minecraft:brown_candle", + "id": -425 + }, + { + "name": "minecraft:brown_candle_cake", + "id": -442 + }, + { + "name": "minecraft:brown_carpet", + "id": -608 + }, + { + "name": "minecraft:brown_concrete", + "id": -639 + }, + { + "name": "minecraft:brown_concrete_powder", + "id": -720 + }, + { + "name": "minecraft:brown_dye", + "id": 424 + }, + { + "name": "minecraft:brown_glazed_terracotta", + "id": 232 + }, + { + "name": "minecraft:brown_mushroom", + "id": 39 + }, + { + "name": "minecraft:brown_mushroom_block", + "id": 99 + }, + { + "name": "minecraft:brown_shulker_box", + "id": -624 + }, + { + "name": "minecraft:brown_stained_glass", + "id": -684 + }, + { + "name": "minecraft:brown_stained_glass_pane", + "id": -654 + }, + { + "name": "minecraft:brown_terracotta", + "id": -735 + }, + { + "name": "minecraft:brown_wool", + "id": -555 + }, + { + "name": "minecraft:brush", + "id": 715 + }, + { + "name": "minecraft:bubble_column", + "id": -160 + }, + { + "name": "minecraft:bubble_coral", + "id": -582 + }, + { + "name": "minecraft:bubble_coral_block", + "id": -850 + }, + { + "name": "minecraft:bubble_coral_fan", + "id": -841 + }, + { + "name": "minecraft:bubble_coral_wall_fan", + "id": -136 + }, + { + "name": "minecraft:bucket", + "id": 385 + }, + { + "name": "minecraft:budding_amethyst", + "id": -328 + }, + { + "name": "minecraft:bundle", + "id": 260 + }, + { + "name": "minecraft:burn_pottery_sherd", + "id": 697 + }, + { + "name": "minecraft:cactus", + "id": 81 + }, + { + "name": "minecraft:cake", + "id": 443 + }, + { + "name": "minecraft:calcite", + "id": -326 + }, + { + "name": "minecraft:calibrated_sculk_sensor", + "id": -580 + }, + { + "name": "minecraft:camel_spawn_egg", + "id": 691 + }, + { + "name": "minecraft:camera", + "id": 629 + }, + { + "name": "minecraft:campfire", + "id": 624 + }, + { + "name": "minecraft:candle", + "id": -412 + }, + { + "name": "minecraft:candle_cake", + "id": -429 + }, + { + "name": "minecraft:carpet", + "id": 744 + }, + { + "name": "minecraft:carrot", + "id": 301 + }, + { + "name": "minecraft:carrot_on_a_stick", + "id": 550 + }, + { + "name": "minecraft:carrots", + "id": 141 + }, + { + "name": "minecraft:cartography_table", + "id": -200 + }, + { + "name": "minecraft:carved_pumpkin", + "id": -155 + }, + { + "name": "minecraft:cat_spawn_egg", + "id": 516 + }, + { + "name": "minecraft:cauldron", + "id": 459 + }, + { + "name": "minecraft:cave_spider_spawn_egg", + "id": 484 + }, + { + "name": "minecraft:cave_vines", + "id": -322 + }, + { + "name": "minecraft:cave_vines_body_with_berries", + "id": -375 + }, + { + "name": "minecraft:cave_vines_head_with_berries", + "id": -376 + }, + { + "name": "minecraft:chain", + "id": 655 + }, + { + "name": "minecraft:chain_command_block", + "id": 189 + }, + { + "name": "minecraft:chainmail_boots", + "id": 367 + }, + { + "name": "minecraft:chainmail_chestplate", + "id": 365 + }, + { + "name": "minecraft:chainmail_helmet", + "id": 364 + }, + { + "name": "minecraft:chainmail_leggings", + "id": 366 + }, + { + "name": "minecraft:charcoal", + "id": 327 + }, + { + "name": "minecraft:chemical_heat", + "id": 192 + }, + { + "name": "minecraft:chemistry_table", + "id": 779 + }, + { + "name": "minecraft:cherry_boat", + "id": 685 + }, + { + "name": "minecraft:cherry_button", + "id": -530 + }, + { + "name": "minecraft:cherry_chest_boat", + "id": 686 + }, + { + "name": "minecraft:cherry_door", + "id": -531 + }, + { + "name": "minecraft:cherry_double_slab", + "id": -540 + }, + { + "name": "minecraft:cherry_fence", + "id": -532 + }, + { + "name": "minecraft:cherry_fence_gate", + "id": -533 + }, + { + "name": "minecraft:cherry_hanging_sign", + "id": -534 + }, + { + "name": "minecraft:cherry_leaves", + "id": -548 + }, + { + "name": "minecraft:cherry_log", + "id": -536 + }, + { + "name": "minecraft:cherry_planks", + "id": -537 + }, + { + "name": "minecraft:cherry_pressure_plate", + "id": -538 + }, + { + "name": "minecraft:cherry_sapling", + "id": -547 + }, + { + "name": "minecraft:cherry_sign", + "id": 687 + }, + { + "name": "minecraft:cherry_slab", + "id": -539 + }, + { + "name": "minecraft:cherry_stairs", + "id": -541 + }, + { + "name": "minecraft:cherry_standing_sign", + "id": -542 + }, + { + "name": "minecraft:cherry_trapdoor", + "id": -543 + }, + { + "name": "minecraft:cherry_wall_sign", + "id": -544 + }, + { + "name": "minecraft:cherry_wood", + "id": -546 + }, + { + "name": "minecraft:chest", + "id": 54 + }, + { + "name": "minecraft:chest_boat", + "id": 681 + }, + { + "name": "minecraft:chest_minecart", + "id": 415 + }, + { + "name": "minecraft:chicken", + "id": 297 + }, + { + "name": "minecraft:chicken_spawn_egg", + "id": 462 + }, + { + "name": "minecraft:chipped_anvil", + "id": -959 + }, + { + "name": "minecraft:chiseled_bookshelf", + "id": -526 + }, + { + "name": "minecraft:chiseled_copper", + "id": -760 + }, + { + "name": "minecraft:chiseled_deepslate", + "id": -395 + }, + { + "name": "minecraft:chiseled_nether_bricks", + "id": -302 + }, + { + "name": "minecraft:chiseled_polished_blackstone", + "id": -279 + }, + { + "name": "minecraft:chiseled_quartz_block", + "id": -953 + }, + { + "name": "minecraft:chiseled_red_sandstone", + "id": -956 + }, + { + "name": "minecraft:chiseled_sandstone", + "id": -944 + }, + { + "name": "minecraft:chiseled_stone_bricks", + "id": -870 + }, + { + "name": "minecraft:chiseled_tuff", + "id": -753 + }, + { + "name": "minecraft:chiseled_tuff_bricks", + "id": -759 + }, + { + "name": "minecraft:chorus_flower", + "id": 200 + }, + { + "name": "minecraft:chorus_fruit", + "id": 591 + }, + { + "name": "minecraft:chorus_plant", + "id": 240 + }, + { + "name": "minecraft:clay", + "id": 82 + }, + { + "name": "minecraft:clay_ball", + "id": 410 + }, + { + "name": "minecraft:client_request_placeholder_block", + "id": -465 + }, + { + "name": "minecraft:clock", + "id": 419 + }, + { + "name": "minecraft:coal", + "id": 326 + }, + { + "name": "minecraft:coal_block", + "id": 173 + }, + { + "name": "minecraft:coal_ore", + "id": 16 + }, + { + "name": "minecraft:coarse_dirt", + "id": -962 + }, + { + "name": "minecraft:coast_armor_trim_smithing_template", + "id": 719 + }, + { + "name": "minecraft:cobbled_deepslate", + "id": -379 + }, + { + "name": "minecraft:cobbled_deepslate_double_slab", + "id": -396 + }, + { + "name": "minecraft:cobbled_deepslate_slab", + "id": -380 + }, + { + "name": "minecraft:cobbled_deepslate_stairs", + "id": -381 + }, + { + "name": "minecraft:cobbled_deepslate_wall", + "id": -382 + }, + { + "name": "minecraft:cobblestone", + "id": 4 + }, + { + "name": "minecraft:cobblestone_double_slab", + "id": -879 + }, + { + "name": "minecraft:cobblestone_slab", + "id": -873 + }, + { + "name": "minecraft:cobblestone_wall", + "id": 139 + }, + { + "name": "minecraft:cocoa", + "id": 127 + }, + { + "name": "minecraft:cocoa_beans", + "id": 438 + }, + { + "name": "minecraft:cod", + "id": 286 + }, + { + "name": "minecraft:cod_bucket", + "id": 389 + }, + { + "name": "minecraft:cod_spawn_egg", + "id": 508 + }, + { + "name": "minecraft:colored_torch_blue", + "id": 204 + }, + { + "name": "minecraft:colored_torch_bp", + "id": 783 + }, + { + "name": "minecraft:colored_torch_green", + "id": -963 + }, + { + "name": "minecraft:colored_torch_purple", + "id": -964 + }, + { + "name": "minecraft:colored_torch_red", + "id": 202 + }, + { + "name": "minecraft:colored_torch_rg", + "id": 782 + }, + { + "name": "minecraft:command_block", + "id": 137 + }, + { + "name": "minecraft:command_block_minecart", + "id": 596 + }, + { + "name": "minecraft:comparator", + "id": 555 + }, + { + "name": "minecraft:compass", + "id": 417 + }, + { + "name": "minecraft:composter", + "id": -213 + }, + { + "name": "minecraft:compound", + "id": 630 + }, + { + "name": "minecraft:compound_creator", + "id": 238 + }, + { + "name": "minecraft:concrete", + "id": 770 + }, + { + "name": "minecraft:concrete_powder", + "id": 771 + }, + { + "name": "minecraft:conduit", + "id": -157 + }, + { + "name": "minecraft:cooked_beef", + "id": 296 + }, + { + "name": "minecraft:cooked_chicken", + "id": 298 + }, + { + "name": "minecraft:cooked_cod", + "id": 290 + }, + { + "name": "minecraft:cooked_mutton", + "id": 584 + }, + { + "name": "minecraft:cooked_porkchop", + "id": 285 + }, + { + "name": "minecraft:cooked_rabbit", + "id": 311 + }, + { + "name": "minecraft:cooked_salmon", + "id": 291 + }, + { + "name": "minecraft:cookie", + "id": 293 + }, + { + "name": "minecraft:copper_block", + "id": -340 + }, + { + "name": "minecraft:copper_bulb", + "id": -776 + }, + { + "name": "minecraft:copper_door", + "id": -784 + }, + { + "name": "minecraft:copper_grate", + "id": -768 + }, + { + "name": "minecraft:copper_ingot", + "id": 538 + }, + { + "name": "minecraft:copper_ore", + "id": -311 + }, + { + "name": "minecraft:copper_trapdoor", + "id": -792 + }, + { + "name": "minecraft:coral", + "id": 766 + }, + { + "name": "minecraft:coral_block", + "id": 748 + }, + { + "name": "minecraft:coral_fan", + "id": 757 + }, + { + "name": "minecraft:coral_fan_dead", + "id": 758 + }, + { + "name": "minecraft:cornflower", + "id": -838 + }, + { + "name": "minecraft:cow_spawn_egg", + "id": 463 + }, + { + "name": "minecraft:cracked_deepslate_bricks", + "id": -410 + }, + { + "name": "minecraft:cracked_deepslate_tiles", + "id": -409 + }, + { + "name": "minecraft:cracked_nether_bricks", + "id": -303 + }, + { + "name": "minecraft:cracked_polished_blackstone_bricks", + "id": -280 + }, + { + "name": "minecraft:cracked_stone_bricks", + "id": -869 + }, + { + "name": "minecraft:crafter", + "id": -313 + }, + { + "name": "minecraft:crafting_table", + "id": 58 + }, + { + "name": "minecraft:creeper_banner_pattern", + "id": 615 + }, + { + "name": "minecraft:creeper_head", + "id": -968 + }, + { + "name": "minecraft:creeper_spawn_egg", + "id": 468 + }, + { + "name": "minecraft:crimson_button", + "id": -260 + }, + { + "name": "minecraft:crimson_door", + "id": 652 + }, + { + "name": "minecraft:crimson_double_slab", + "id": -266 + }, + { + "name": "minecraft:crimson_fence", + "id": -256 + }, + { + "name": "minecraft:crimson_fence_gate", + "id": -258 + }, + { + "name": "minecraft:crimson_fungus", + "id": -228 + }, + { + "name": "minecraft:crimson_hanging_sign", + "id": -506 + }, + { + "name": "minecraft:crimson_hyphae", + "id": -299 + }, + { + "name": "minecraft:crimson_nylium", + "id": -232 + }, + { + "name": "minecraft:crimson_planks", + "id": -242 + }, + { + "name": "minecraft:crimson_pressure_plate", + "id": -262 + }, + { + "name": "minecraft:crimson_roots", + "id": -223 + }, + { + "name": "minecraft:crimson_sign", + "id": 650 + }, + { + "name": "minecraft:crimson_slab", + "id": -264 + }, + { + "name": "minecraft:crimson_stairs", + "id": -254 + }, + { + "name": "minecraft:crimson_standing_sign", + "id": -250 + }, + { + "name": "minecraft:crimson_stem", + "id": -225 + }, + { + "name": "minecraft:crimson_trapdoor", + "id": -246 + }, + { + "name": "minecraft:crimson_wall_sign", + "id": -252 + }, + { + "name": "minecraft:crossbow", + "id": 608 + }, + { + "name": "minecraft:crying_obsidian", + "id": -289 + }, + { + "name": "minecraft:cut_copper", + "id": -347 + }, + { + "name": "minecraft:cut_copper_slab", + "id": -361 + }, + { + "name": "minecraft:cut_copper_stairs", + "id": -354 + }, + { + "name": "minecraft:cut_red_sandstone", + "id": -957 + }, + { + "name": "minecraft:cut_red_sandstone_double_slab", + "id": -928 + }, + { + "name": "minecraft:cut_red_sandstone_slab", + "id": -901 + }, + { + "name": "minecraft:cut_sandstone", + "id": -945 + }, + { + "name": "minecraft:cut_sandstone_double_slab", + "id": -927 + }, + { + "name": "minecraft:cut_sandstone_slab", + "id": -900 + }, + { + "name": "minecraft:cyan_bundle", + "id": 261 + }, + { + "name": "minecraft:cyan_candle", + "id": -422 + }, + { + "name": "minecraft:cyan_candle_cake", + "id": -439 + }, + { + "name": "minecraft:cyan_carpet", + "id": -605 + }, + { + "name": "minecraft:cyan_concrete", + "id": -636 + }, + { + "name": "minecraft:cyan_concrete_powder", + "id": -717 + }, + { + "name": "minecraft:cyan_dye", + "id": 427 + }, + { + "name": "minecraft:cyan_glazed_terracotta", + "id": 229 + }, + { + "name": "minecraft:cyan_shulker_box", + "id": -621 + }, + { + "name": "minecraft:cyan_stained_glass", + "id": -681 + }, + { + "name": "minecraft:cyan_stained_glass_pane", + "id": -651 + }, + { + "name": "minecraft:cyan_terracotta", + "id": -732 + }, + { + "name": "minecraft:cyan_wool", + "id": -561 + }, + { + "name": "minecraft:damaged_anvil", + "id": -960 + }, + { + "name": "minecraft:dandelion", + "id": 37 + }, + { + "name": "minecraft:danger_pottery_sherd", + "id": 698 + }, + { + "name": "minecraft:dark_oak_boat", + "id": 406 + }, + { + "name": "minecraft:dark_oak_button", + "id": -142 + }, + { + "name": "minecraft:dark_oak_chest_boat", + "id": 679 + }, + { + "name": "minecraft:dark_oak_door", + "id": 590 + }, + { + "name": "minecraft:dark_oak_double_slab", + "id": -813 + }, + { + "name": "minecraft:dark_oak_fence", + "id": -577 + }, + { + "name": "minecraft:dark_oak_fence_gate", + "id": 186 + }, + { + "name": "minecraft:dark_oak_hanging_sign", + "id": -505 + }, + { + "name": "minecraft:dark_oak_leaves", + "id": -803 + }, + { + "name": "minecraft:dark_oak_log", + "id": -572 + }, + { + "name": "minecraft:dark_oak_planks", + "id": -743 + }, + { + "name": "minecraft:dark_oak_pressure_plate", + "id": -152 + }, + { + "name": "minecraft:dark_oak_sapling", + "id": -829 + }, + { + "name": "minecraft:dark_oak_sign", + "id": 613 + }, + { + "name": "minecraft:dark_oak_slab", + "id": -808 + }, + { + "name": "minecraft:dark_oak_stairs", + "id": 164 + }, + { + "name": "minecraft:dark_oak_trapdoor", + "id": -147 + }, + { + "name": "minecraft:dark_oak_wood", + "id": -818 + }, + { + "name": "minecraft:dark_prismarine", + "id": -947 + }, + { + "name": "minecraft:dark_prismarine_double_slab", + "id": -913 + }, + { + "name": "minecraft:dark_prismarine_slab", + "id": -886 + }, + { + "name": "minecraft:dark_prismarine_stairs", + "id": -3 + }, + { + "name": "minecraft:darkoak_standing_sign", + "id": -192 + }, + { + "name": "minecraft:darkoak_wall_sign", + "id": -193 + }, + { + "name": "minecraft:daylight_detector", + "id": 151 + }, + { + "name": "minecraft:daylight_detector_inverted", + "id": 178 + }, + { + "name": "minecraft:dead_brain_coral", + "id": -586 + }, + { + "name": "minecraft:dead_brain_coral_block", + "id": -854 + }, + { + "name": "minecraft:dead_brain_coral_fan", + "id": -844 + }, + { + "name": "minecraft:dead_brain_coral_wall_fan", + "id": -906 + }, + { + "name": "minecraft:dead_bubble_coral", + "id": -587 + }, + { + "name": "minecraft:dead_bubble_coral_block", + "id": -855 + }, + { + "name": "minecraft:dead_bubble_coral_fan", + "id": -845 + }, + { + "name": "minecraft:dead_bubble_coral_wall_fan", + "id": -908 + }, + { + "name": "minecraft:dead_fire_coral", + "id": -588 + }, + { + "name": "minecraft:dead_fire_coral_block", + "id": -856 + }, + { + "name": "minecraft:dead_fire_coral_fan", + "id": -846 + }, + { + "name": "minecraft:dead_fire_coral_wall_fan", + "id": -909 + }, + { + "name": "minecraft:dead_horn_coral", + "id": -589 + }, + { + "name": "minecraft:dead_horn_coral_block", + "id": -857 + }, + { + "name": "minecraft:dead_horn_coral_fan", + "id": -847 + }, + { + "name": "minecraft:dead_horn_coral_wall_fan", + "id": -910 + }, + { + "name": "minecraft:dead_tube_coral", + "id": -585 + }, + { + "name": "minecraft:dead_tube_coral_block", + "id": -853 + }, + { + "name": "minecraft:dead_tube_coral_fan", + "id": -134 + }, + { + "name": "minecraft:dead_tube_coral_wall_fan", + "id": -905 + }, + { + "name": "minecraft:deadbush", + "id": 32 + }, + { + "name": "minecraft:decorated_pot", + "id": -551 + }, + { + "name": "minecraft:deepslate", + "id": -378 + }, + { + "name": "minecraft:deepslate_brick_double_slab", + "id": -399 + }, + { + "name": "minecraft:deepslate_brick_slab", + "id": -392 + }, + { + "name": "minecraft:deepslate_brick_stairs", + "id": -393 + }, + { + "name": "minecraft:deepslate_brick_wall", + "id": -394 + }, + { + "name": "minecraft:deepslate_bricks", + "id": -391 + }, + { + "name": "minecraft:deepslate_coal_ore", + "id": -406 + }, + { + "name": "minecraft:deepslate_copper_ore", + "id": -408 + }, + { + "name": "minecraft:deepslate_diamond_ore", + "id": -405 + }, + { + "name": "minecraft:deepslate_emerald_ore", + "id": -407 + }, + { + "name": "minecraft:deepslate_gold_ore", + "id": -402 + }, + { + "name": "minecraft:deepslate_iron_ore", + "id": -401 + }, + { + "name": "minecraft:deepslate_lapis_ore", + "id": -400 + }, + { + "name": "minecraft:deepslate_redstone_ore", + "id": -403 + }, + { + "name": "minecraft:deepslate_tile_double_slab", + "id": -398 + }, + { + "name": "minecraft:deepslate_tile_slab", + "id": -388 + }, + { + "name": "minecraft:deepslate_tile_stairs", + "id": -389 + }, + { + "name": "minecraft:deepslate_tile_wall", + "id": -390 + }, + { + "name": "minecraft:deepslate_tiles", + "id": -387 + }, + { + "name": "minecraft:deny", + "id": 211 + }, + { + "name": "minecraft:deprecated_anvil", + "id": -961 + }, + { + "name": "minecraft:deprecated_purpur_block_1", + "id": -950 + }, + { + "name": "minecraft:deprecated_purpur_block_2", + "id": -952 + }, + { + "name": "minecraft:detector_rail", + "id": 28 + }, + { + "name": "minecraft:diamond", + "id": 328 + }, + { + "name": "minecraft:diamond_axe", + "id": 343 + }, + { + "name": "minecraft:diamond_block", + "id": 57 + }, + { + "name": "minecraft:diamond_boots", + "id": 375 + }, + { + "name": "minecraft:diamond_chestplate", + "id": 373 + }, + { + "name": "minecraft:diamond_helmet", + "id": 372 + }, + { + "name": "minecraft:diamond_hoe", + "id": 357 + }, + { + "name": "minecraft:diamond_horse_armor", + "id": 566 + }, + { + "name": "minecraft:diamond_leggings", + "id": 374 + }, + { + "name": "minecraft:diamond_ore", + "id": 56 + }, + { + "name": "minecraft:diamond_pickaxe", + "id": 342 + }, + { + "name": "minecraft:diamond_shovel", + "id": 341 + }, + { + "name": "minecraft:diamond_sword", + "id": 340 + }, + { + "name": "minecraft:diorite", + "id": -592 + }, + { + "name": "minecraft:diorite_double_slab", + "id": -921 + }, + { + "name": "minecraft:diorite_slab", + "id": -894 + }, + { + "name": "minecraft:diorite_stairs", + "id": -170 + }, + { + "name": "minecraft:diorite_wall", + "id": -973 + }, + { + "name": "minecraft:dirt", + "id": 3 + }, + { + "name": "minecraft:dirt_with_roots", + "id": -318 + }, + { + "name": "minecraft:disc_fragment_5", + "id": 673 + }, + { + "name": "minecraft:dispenser", + "id": 23 + }, + { + "name": "minecraft:dolphin_spawn_egg", + "id": 512 + }, + { + "name": "minecraft:donkey_spawn_egg", + "id": 493 + }, + { + "name": "minecraft:double_cut_copper_slab", + "id": -368 + }, + { + "name": "minecraft:double_plant", + "id": 764 + }, + { + "name": "minecraft:double_stone_block_slab", + "id": 753 + }, + { + "name": "minecraft:double_stone_block_slab2", + "id": 754 + }, + { + "name": "minecraft:double_stone_block_slab3", + "id": 755 + }, + { + "name": "minecraft:double_stone_block_slab4", + "id": 756 + }, + { + "name": "minecraft:dragon_breath", + "id": 593 + }, + { + "name": "minecraft:dragon_egg", + "id": 122 + }, + { + "name": "minecraft:dragon_head", + "id": -969 + }, + { + "name": "minecraft:dried_kelp", + "id": 292 + }, + { + "name": "minecraft:dried_kelp_block", + "id": -139 + }, + { + "name": "minecraft:dripstone_block", + "id": -317 + }, + { + "name": "minecraft:dropper", + "id": 125 + }, + { + "name": "minecraft:drowned_spawn_egg", + "id": 511 + }, + { + "name": "minecraft:dune_armor_trim_smithing_template", + "id": 718 + }, + { + "name": "minecraft:dye", + "id": 786 + }, + { + "name": "minecraft:echo_shard", + "id": 683 + }, + { + "name": "minecraft:egg", + "id": 416 + }, + { + "name": "minecraft:elder_guardian_spawn_egg", + "id": 499 + }, + { + "name": "minecraft:element_0", + "id": 36 + }, + { + "name": "minecraft:element_1", + "id": -12 + }, + { + "name": "minecraft:element_10", + "id": -21 + }, + { + "name": "minecraft:element_100", + "id": -111 + }, + { + "name": "minecraft:element_101", + "id": -112 + }, + { + "name": "minecraft:element_102", + "id": -113 + }, + { + "name": "minecraft:element_103", + "id": -114 + }, + { + "name": "minecraft:element_104", + "id": -115 + }, + { + "name": "minecraft:element_105", + "id": -116 + }, + { + "name": "minecraft:element_106", + "id": -117 + }, + { + "name": "minecraft:element_107", + "id": -118 + }, + { + "name": "minecraft:element_108", + "id": -119 + }, + { + "name": "minecraft:element_109", + "id": -120 + }, + { + "name": "minecraft:element_11", + "id": -22 + }, + { + "name": "minecraft:element_110", + "id": -121 + }, + { + "name": "minecraft:element_111", + "id": -122 + }, + { + "name": "minecraft:element_112", + "id": -123 + }, + { + "name": "minecraft:element_113", + "id": -124 + }, + { + "name": "minecraft:element_114", + "id": -125 + }, + { + "name": "minecraft:element_115", + "id": -126 + }, + { + "name": "minecraft:element_116", + "id": -127 + }, + { + "name": "minecraft:element_117", + "id": -128 + }, + { + "name": "minecraft:element_118", + "id": -129 + }, + { + "name": "minecraft:element_12", + "id": -23 + }, + { + "name": "minecraft:element_13", + "id": -24 + }, + { + "name": "minecraft:element_14", + "id": -25 + }, + { + "name": "minecraft:element_15", + "id": -26 + }, + { + "name": "minecraft:element_16", + "id": -27 + }, + { + "name": "minecraft:element_17", + "id": -28 + }, + { + "name": "minecraft:element_18", + "id": -29 + }, + { + "name": "minecraft:element_19", + "id": -30 + }, + { + "name": "minecraft:element_2", + "id": -13 + }, + { + "name": "minecraft:element_20", + "id": -31 + }, + { + "name": "minecraft:element_21", + "id": -32 + }, + { + "name": "minecraft:element_22", + "id": -33 + }, + { + "name": "minecraft:element_23", + "id": -34 + }, + { + "name": "minecraft:element_24", + "id": -35 + }, + { + "name": "minecraft:element_25", + "id": -36 + }, + { + "name": "minecraft:element_26", + "id": -37 + }, + { + "name": "minecraft:element_27", + "id": -38 + }, + { + "name": "minecraft:element_28", + "id": -39 + }, + { + "name": "minecraft:element_29", + "id": -40 + }, + { + "name": "minecraft:element_3", + "id": -14 + }, + { + "name": "minecraft:element_30", + "id": -41 + }, + { + "name": "minecraft:element_31", + "id": -42 + }, + { + "name": "minecraft:element_32", + "id": -43 + }, + { + "name": "minecraft:element_33", + "id": -44 + }, + { + "name": "minecraft:element_34", + "id": -45 + }, + { + "name": "minecraft:element_35", + "id": -46 + }, + { + "name": "minecraft:element_36", + "id": -47 + }, + { + "name": "minecraft:element_37", + "id": -48 + }, + { + "name": "minecraft:element_38", + "id": -49 + }, + { + "name": "minecraft:element_39", + "id": -50 + }, + { + "name": "minecraft:element_4", + "id": -15 + }, + { + "name": "minecraft:element_40", + "id": -51 + }, + { + "name": "minecraft:element_41", + "id": -52 + }, + { + "name": "minecraft:element_42", + "id": -53 + }, + { + "name": "minecraft:element_43", + "id": -54 + }, + { + "name": "minecraft:element_44", + "id": -55 + }, + { + "name": "minecraft:element_45", + "id": -56 + }, + { + "name": "minecraft:element_46", + "id": -57 + }, + { + "name": "minecraft:element_47", + "id": -58 + }, + { + "name": "minecraft:element_48", + "id": -59 + }, + { + "name": "minecraft:element_49", + "id": -60 + }, + { + "name": "minecraft:element_5", + "id": -16 + }, + { + "name": "minecraft:element_50", + "id": -61 + }, + { + "name": "minecraft:element_51", + "id": -62 + }, + { + "name": "minecraft:element_52", + "id": -63 + }, + { + "name": "minecraft:element_53", + "id": -64 + }, + { + "name": "minecraft:element_54", + "id": -65 + }, + { + "name": "minecraft:element_55", + "id": -66 + }, + { + "name": "minecraft:element_56", + "id": -67 + }, + { + "name": "minecraft:element_57", + "id": -68 + }, + { + "name": "minecraft:element_58", + "id": -69 + }, + { + "name": "minecraft:element_59", + "id": -70 + }, + { + "name": "minecraft:element_6", + "id": -17 + }, + { + "name": "minecraft:element_60", + "id": -71 + }, + { + "name": "minecraft:element_61", + "id": -72 + }, + { + "name": "minecraft:element_62", + "id": -73 + }, + { + "name": "minecraft:element_63", + "id": -74 + }, + { + "name": "minecraft:element_64", + "id": -75 + }, + { + "name": "minecraft:element_65", + "id": -76 + }, + { + "name": "minecraft:element_66", + "id": -77 + }, + { + "name": "minecraft:element_67", + "id": -78 + }, + { + "name": "minecraft:element_68", + "id": -79 + }, + { + "name": "minecraft:element_69", + "id": -80 + }, + { + "name": "minecraft:element_7", + "id": -18 + }, + { + "name": "minecraft:element_70", + "id": -81 + }, + { + "name": "minecraft:element_71", + "id": -82 + }, + { + "name": "minecraft:element_72", + "id": -83 + }, + { + "name": "minecraft:element_73", + "id": -84 + }, + { + "name": "minecraft:element_74", + "id": -85 + }, + { + "name": "minecraft:element_75", + "id": -86 + }, + { + "name": "minecraft:element_76", + "id": -87 + }, + { + "name": "minecraft:element_77", + "id": -88 + }, + { + "name": "minecraft:element_78", + "id": -89 + }, + { + "name": "minecraft:element_79", + "id": -90 + }, + { + "name": "minecraft:element_8", + "id": -19 + }, + { + "name": "minecraft:element_80", + "id": -91 + }, + { + "name": "minecraft:element_81", + "id": -92 + }, + { + "name": "minecraft:element_82", + "id": -93 + }, + { + "name": "minecraft:element_83", + "id": -94 + }, + { + "name": "minecraft:element_84", + "id": -95 + }, + { + "name": "minecraft:element_85", + "id": -96 + }, + { + "name": "minecraft:element_86", + "id": -97 + }, + { + "name": "minecraft:element_87", + "id": -98 + }, + { + "name": "minecraft:element_88", + "id": -99 + }, + { + "name": "minecraft:element_89", + "id": -100 + }, + { + "name": "minecraft:element_9", + "id": -20 + }, + { + "name": "minecraft:element_90", + "id": -101 + }, + { + "name": "minecraft:element_91", + "id": -102 + }, + { + "name": "minecraft:element_92", + "id": -103 + }, + { + "name": "minecraft:element_93", + "id": -104 + }, + { + "name": "minecraft:element_94", + "id": -105 + }, + { + "name": "minecraft:element_95", + "id": -106 + }, + { + "name": "minecraft:element_96", + "id": -107 + }, + { + "name": "minecraft:element_97", + "id": -108 + }, + { + "name": "minecraft:element_98", + "id": -109 + }, + { + "name": "minecraft:element_99", + "id": -110 + }, + { + "name": "minecraft:element_constructor", + "id": -987 + }, + { + "name": "minecraft:elytra", + "id": 597 + }, + { + "name": "minecraft:emerald", + "id": 546 + }, + { + "name": "minecraft:emerald_block", + "id": 133 + }, + { + "name": "minecraft:emerald_ore", + "id": 129 + }, + { + "name": "minecraft:empty_map", + "id": 549 + }, + { + "name": "minecraft:enchanted_book", + "id": 554 + }, + { + "name": "minecraft:enchanted_golden_apple", + "id": 281 + }, + { + "name": "minecraft:enchanting_table", + "id": 116 + }, + { + "name": "minecraft:end_brick_stairs", + "id": -178 + }, + { + "name": "minecraft:end_bricks", + "id": 206 + }, + { + "name": "minecraft:end_crystal", + "id": 789 + }, + { + "name": "minecraft:end_gateway", + "id": 209 + }, + { + "name": "minecraft:end_portal", + "id": 119 + }, + { + "name": "minecraft:end_portal_frame", + "id": 120 + }, + { + "name": "minecraft:end_rod", + "id": 208 + }, + { + "name": "minecraft:end_stone", + "id": 121 + }, + { + "name": "minecraft:end_stone_brick_double_slab", + "id": -167 + }, + { + "name": "minecraft:end_stone_brick_slab", + "id": -162 + }, + { + "name": "minecraft:end_stone_brick_wall", + "id": -980 + }, + { + "name": "minecraft:ender_chest", + "id": 130 + }, + { + "name": "minecraft:ender_dragon_spawn_egg", + "id": 535 + }, + { + "name": "minecraft:ender_eye", + "id": 460 + }, + { + "name": "minecraft:ender_pearl", + "id": 448 + }, + { + "name": "minecraft:enderman_spawn_egg", + "id": 469 + }, + { + "name": "minecraft:endermite_spawn_egg", + "id": 487 + }, + { + "name": "minecraft:evoker_spawn_egg", + "id": 503 + }, + { + "name": "minecraft:experience_bottle", + "id": 542 + }, + { + "name": "minecraft:explorer_pottery_sherd", + "id": 699 + }, + { + "name": "minecraft:exposed_chiseled_copper", + "id": -761 + }, + { + "name": "minecraft:exposed_copper", + "id": -341 + }, + { + "name": "minecraft:exposed_copper_bulb", + "id": -777 + }, + { + "name": "minecraft:exposed_copper_door", + "id": -785 + }, + { + "name": "minecraft:exposed_copper_grate", + "id": -769 + }, + { + "name": "minecraft:exposed_copper_trapdoor", + "id": -793 + }, + { + "name": "minecraft:exposed_cut_copper", + "id": -348 + }, + { + "name": "minecraft:exposed_cut_copper_slab", + "id": -362 + }, + { + "name": "minecraft:exposed_cut_copper_stairs", + "id": -355 + }, + { + "name": "minecraft:exposed_double_cut_copper_slab", + "id": -369 + }, + { + "name": "minecraft:eye_armor_trim_smithing_template", + "id": 722 + }, + { + "name": "minecraft:farmland", + "id": 60 + }, + { + "name": "minecraft:feather", + "id": 352 + }, + { + "name": "minecraft:fence", + "id": 746 + }, + { + "name": "minecraft:fence_gate", + "id": 107 + }, + { + "name": "minecraft:fermented_spider_eye", + "id": 455 + }, + { + "name": "minecraft:fern", + "id": -848 + }, + { + "name": "minecraft:field_masoned_banner_pattern", + "id": 618 + }, + { + "name": "minecraft:filled_map", + "id": 446 + }, + { + "name": "minecraft:fire", + "id": 51 + }, + { + "name": "minecraft:fire_charge", + "id": 543 + }, + { + "name": "minecraft:fire_coral", + "id": -583 + }, + { + "name": "minecraft:fire_coral_block", + "id": -851 + }, + { + "name": "minecraft:fire_coral_fan", + "id": -842 + }, + { + "name": "minecraft:fire_coral_wall_fan", + "id": -907 + }, + { + "name": "minecraft:firework_rocket", + "id": 552 + }, + { + "name": "minecraft:firework_star", + "id": 553 + }, + { + "name": "minecraft:fishing_rod", + "id": 418 + }, + { + "name": "minecraft:fletching_table", + "id": -201 + }, + { + "name": "minecraft:flint", + "id": 381 + }, + { + "name": "minecraft:flint_and_steel", + "id": 323 + }, + { + "name": "minecraft:flow_armor_trim_smithing_template", + "id": 733 + }, + { + "name": "minecraft:flow_banner_pattern", + "id": 622 + }, + { + "name": "minecraft:flow_pottery_sherd", + "id": 700 + }, + { + "name": "minecraft:flower_banner_pattern", + "id": 614 + }, + { + "name": "minecraft:flower_pot", + "id": 548 + }, + { + "name": "minecraft:flowering_azalea", + "id": -338 + }, + { + "name": "minecraft:flowing_lava", + "id": 10 + }, + { + "name": "minecraft:flowing_water", + "id": 8 + }, + { + "name": "minecraft:fox_spawn_egg", + "id": 518 + }, + { + "name": "minecraft:frame", + "id": 547 + }, + { + "name": "minecraft:friend_pottery_sherd", + "id": 701 + }, + { + "name": "minecraft:frog_spawn", + "id": -468 + }, + { + "name": "minecraft:frog_spawn_egg", + "id": 664 + }, + { + "name": "minecraft:frosted_ice", + "id": 207 + }, + { + "name": "minecraft:furnace", + "id": 61 + }, + { + "name": "minecraft:ghast_spawn_egg", + "id": 481 + }, + { + "name": "minecraft:ghast_tear", + "id": 451 + }, + { + "name": "minecraft:gilded_blackstone", + "id": -281 + }, + { + "name": "minecraft:glass", + "id": 20 + }, + { + "name": "minecraft:glass_bottle", + "id": 454 + }, + { + "name": "minecraft:glass_pane", + "id": 102 + }, + { + "name": "minecraft:glistering_melon_slice", + "id": 461 + }, + { + "name": "minecraft:globe_banner_pattern", + "id": 621 + }, + { + "name": "minecraft:glow_berries", + "id": 790 + }, + { + "name": "minecraft:glow_frame", + "id": 659 + }, + { + "name": "minecraft:glow_ink_sac", + "id": 537 + }, + { + "name": "minecraft:glow_lichen", + "id": -411 + }, + { + "name": "minecraft:glow_squid_spawn_egg", + "id": 532 + }, + { + "name": "minecraft:glow_stick", + "id": 637 + }, + { + "name": "minecraft:glowingobsidian", + "id": 246 + }, + { + "name": "minecraft:glowstone", + "id": 89 + }, + { + "name": "minecraft:glowstone_dust", + "id": 420 + }, + { + "name": "minecraft:goat_horn", + "id": 663 + }, + { + "name": "minecraft:goat_spawn_egg", + "id": 531 + }, + { + "name": "minecraft:gold_block", + "id": 41 + }, + { + "name": "minecraft:gold_ingot", + "id": 330 + }, + { + "name": "minecraft:gold_nugget", + "id": 452 + }, + { + "name": "minecraft:gold_ore", + "id": 14 + }, + { + "name": "minecraft:golden_apple", + "id": 280 + }, + { + "name": "minecraft:golden_axe", + "id": 350 + }, + { + "name": "minecraft:golden_boots", + "id": 379 + }, + { + "name": "minecraft:golden_carrot", + "id": 305 + }, + { + "name": "minecraft:golden_chestplate", + "id": 377 + }, + { + "name": "minecraft:golden_helmet", + "id": 376 + }, + { + "name": "minecraft:golden_hoe", + "id": 358 + }, + { + "name": "minecraft:golden_horse_armor", + "id": 565 + }, + { + "name": "minecraft:golden_leggings", + "id": 378 + }, + { + "name": "minecraft:golden_pickaxe", + "id": 349 + }, + { + "name": "minecraft:golden_rail", + "id": 27 + }, + { + "name": "minecraft:golden_shovel", + "id": 348 + }, + { + "name": "minecraft:golden_sword", + "id": 347 + }, + { + "name": "minecraft:granite", + "id": -590 + }, + { + "name": "minecraft:granite_double_slab", + "id": -923 + }, + { + "name": "minecraft:granite_slab", + "id": -896 + }, + { + "name": "minecraft:granite_stairs", + "id": -169 + }, + { + "name": "minecraft:granite_wall", + "id": -972 + }, + { + "name": "minecraft:grass_block", + "id": 2 + }, + { + "name": "minecraft:grass_path", + "id": 198 + }, + { + "name": "minecraft:gravel", + "id": 13 + }, + { + "name": "minecraft:gray_bundle", + "id": 262 + }, + { + "name": "minecraft:gray_candle", + "id": -420 + }, + { + "name": "minecraft:gray_candle_cake", + "id": -437 + }, + { + "name": "minecraft:gray_carpet", + "id": -603 + }, + { + "name": "minecraft:gray_concrete", + "id": -634 + }, + { + "name": "minecraft:gray_concrete_powder", + "id": -715 + }, + { + "name": "minecraft:gray_dye", + "id": 429 + }, + { + "name": "minecraft:gray_glazed_terracotta", + "id": 227 + }, + { + "name": "minecraft:gray_shulker_box", + "id": -619 + }, + { + "name": "minecraft:gray_stained_glass", + "id": -679 + }, + { + "name": "minecraft:gray_stained_glass_pane", + "id": -649 + }, + { + "name": "minecraft:gray_terracotta", + "id": -730 + }, + { + "name": "minecraft:gray_wool", + "id": -553 + }, + { + "name": "minecraft:green_bundle", + "id": 263 + }, + { + "name": "minecraft:green_candle", + "id": -426 + }, + { + "name": "minecraft:green_candle_cake", + "id": -443 + }, + { + "name": "minecraft:green_carpet", + "id": -609 + }, + { + "name": "minecraft:green_concrete", + "id": -640 + }, + { + "name": "minecraft:green_concrete_powder", + "id": -721 + }, + { + "name": "minecraft:green_dye", + "id": 423 + }, + { + "name": "minecraft:green_glazed_terracotta", + "id": 233 + }, + { + "name": "minecraft:green_shulker_box", + "id": -625 + }, + { + "name": "minecraft:green_stained_glass", + "id": -685 + }, + { + "name": "minecraft:green_stained_glass_pane", + "id": -655 + }, + { + "name": "minecraft:green_terracotta", + "id": -736 + }, + { + "name": "minecraft:green_wool", + "id": -560 + }, + { + "name": "minecraft:grindstone", + "id": -195 + }, + { + "name": "minecraft:guardian_spawn_egg", + "id": 488 + }, + { + "name": "minecraft:gunpowder", + "id": 353 + }, + { + "name": "minecraft:guster_banner_pattern", + "id": 623 + }, + { + "name": "minecraft:guster_pottery_sherd", + "id": 702 + }, + { + "name": "minecraft:hanging_roots", + "id": -319 + }, + { + "name": "minecraft:hard_black_stained_glass", + "id": -702 + }, + { + "name": "minecraft:hard_black_stained_glass_pane", + "id": -672 + }, + { + "name": "minecraft:hard_blue_stained_glass", + "id": -698 + }, + { + "name": "minecraft:hard_blue_stained_glass_pane", + "id": -668 + }, + { + "name": "minecraft:hard_brown_stained_glass", + "id": -699 + }, + { + "name": "minecraft:hard_brown_stained_glass_pane", + "id": -669 + }, + { + "name": "minecraft:hard_cyan_stained_glass", + "id": -696 + }, + { + "name": "minecraft:hard_cyan_stained_glass_pane", + "id": -666 + }, + { + "name": "minecraft:hard_glass", + "id": 253 + }, + { + "name": "minecraft:hard_glass_pane", + "id": 190 + }, + { + "name": "minecraft:hard_gray_stained_glass", + "id": -694 + }, + { + "name": "minecraft:hard_gray_stained_glass_pane", + "id": -664 + }, + { + "name": "minecraft:hard_green_stained_glass", + "id": -700 + }, + { + "name": "minecraft:hard_green_stained_glass_pane", + "id": -670 + }, + { + "name": "minecraft:hard_light_blue_stained_glass", + "id": -690 + }, + { + "name": "minecraft:hard_light_blue_stained_glass_pane", + "id": -660 + }, + { + "name": "minecraft:hard_light_gray_stained_glass", + "id": -695 + }, + { + "name": "minecraft:hard_light_gray_stained_glass_pane", + "id": -665 + }, + { + "name": "minecraft:hard_lime_stained_glass", + "id": -692 + }, + { + "name": "minecraft:hard_lime_stained_glass_pane", + "id": -662 + }, + { + "name": "minecraft:hard_magenta_stained_glass", + "id": -689 + }, + { + "name": "minecraft:hard_magenta_stained_glass_pane", + "id": -659 + }, + { + "name": "minecraft:hard_orange_stained_glass", + "id": -688 + }, + { + "name": "minecraft:hard_orange_stained_glass_pane", + "id": -658 + }, + { + "name": "minecraft:hard_pink_stained_glass", + "id": -693 + }, + { + "name": "minecraft:hard_pink_stained_glass_pane", + "id": -663 + }, + { + "name": "minecraft:hard_purple_stained_glass", + "id": -697 + }, + { + "name": "minecraft:hard_purple_stained_glass_pane", + "id": -667 + }, + { + "name": "minecraft:hard_red_stained_glass", + "id": -701 + }, + { + "name": "minecraft:hard_red_stained_glass_pane", + "id": -671 + }, + { + "name": "minecraft:hard_stained_glass", + "id": 780 + }, + { + "name": "minecraft:hard_stained_glass_pane", + "id": 781 + }, + { + "name": "minecraft:hard_white_stained_glass", + "id": 254 + }, + { + "name": "minecraft:hard_white_stained_glass_pane", + "id": 191 + }, + { + "name": "minecraft:hard_yellow_stained_glass", + "id": -691 + }, + { + "name": "minecraft:hard_yellow_stained_glass_pane", + "id": -661 + }, + { + "name": "minecraft:hardened_clay", + "id": 172 + }, + { + "name": "minecraft:hay_block", + "id": 170 + }, + { + "name": "minecraft:heart_of_the_sea", + "id": 604 + }, + { + "name": "minecraft:heart_pottery_sherd", + "id": 703 + }, + { + "name": "minecraft:heartbreak_pottery_sherd", + "id": 704 + }, + { + "name": "minecraft:heavy_core", + "id": -316 + }, + { + "name": "minecraft:heavy_weighted_pressure_plate", + "id": 148 + }, + { + "name": "minecraft:hoglin_spawn_egg", + "id": 524 + }, + { + "name": "minecraft:honey_block", + "id": -220 + }, + { + "name": "minecraft:honey_bottle", + "id": 627 + }, + { + "name": "minecraft:honeycomb", + "id": 626 + }, + { + "name": "minecraft:honeycomb_block", + "id": -221 + }, + { + "name": "minecraft:hopper", + "id": 560 + }, + { + "name": "minecraft:hopper_minecart", + "id": 559 + }, + { + "name": "minecraft:horn_coral", + "id": -584 + }, + { + "name": "minecraft:horn_coral_block", + "id": -852 + }, + { + "name": "minecraft:horn_coral_fan", + "id": -843 + }, + { + "name": "minecraft:horn_coral_wall_fan", + "id": -137 + }, + { + "name": "minecraft:horse_spawn_egg", + "id": 485 + }, + { + "name": "minecraft:host_armor_trim_smithing_template", + "id": 732 + }, + { + "name": "minecraft:howl_pottery_sherd", + "id": 705 + }, + { + "name": "minecraft:husk_spawn_egg", + "id": 491 + }, + { + "name": "minecraft:ice", + "id": 79 + }, + { + "name": "minecraft:ice_bomb", + "id": 631 + }, + { + "name": "minecraft:infested_chiseled_stone_bricks", + "id": -862 + }, + { + "name": "minecraft:infested_cobblestone", + "id": -858 + }, + { + "name": "minecraft:infested_cracked_stone_bricks", + "id": -861 + }, + { + "name": "minecraft:infested_deepslate", + "id": -454 + }, + { + "name": "minecraft:infested_mossy_stone_bricks", + "id": -860 + }, + { + "name": "minecraft:infested_stone", + "id": 97 + }, + { + "name": "minecraft:infested_stone_bricks", + "id": -859 + }, + { + "name": "minecraft:info_update", + "id": 248 + }, + { + "name": "minecraft:info_update2", + "id": 249 + }, + { + "name": "minecraft:ink_sac", + "id": 439 + }, + { + "name": "minecraft:invisible_bedrock", + "id": 95 + }, + { + "name": "minecraft:iron_axe", + "id": 322 + }, + { + "name": "minecraft:iron_bars", + "id": 101 + }, + { + "name": "minecraft:iron_block", + "id": 42 + }, + { + "name": "minecraft:iron_boots", + "id": 371 + }, + { + "name": "minecraft:iron_chestplate", + "id": 369 + }, + { + "name": "minecraft:iron_door", + "id": 397 + }, + { + "name": "minecraft:iron_golem_spawn_egg", + "id": 533 + }, + { + "name": "minecraft:iron_helmet", + "id": 368 + }, + { + "name": "minecraft:iron_hoe", + "id": 356 + }, + { + "name": "minecraft:iron_horse_armor", + "id": 564 + }, + { + "name": "minecraft:iron_ingot", + "id": 329 + }, + { + "name": "minecraft:iron_leggings", + "id": 370 + }, + { + "name": "minecraft:iron_nugget", + "id": 602 + }, + { + "name": "minecraft:iron_ore", + "id": 15 + }, + { + "name": "minecraft:iron_pickaxe", + "id": 321 + }, + { + "name": "minecraft:iron_shovel", + "id": 320 + }, + { + "name": "minecraft:iron_sword", + "id": 331 + }, + { + "name": "minecraft:iron_trapdoor", + "id": 167 + }, + { + "name": "minecraft:item.acacia_door", + "id": 196 + }, + { + "name": "minecraft:item.bed", + "id": 26 + }, + { + "name": "minecraft:item.beetroot", + "id": 244 + }, + { + "name": "minecraft:item.birch_door", + "id": 194 + }, + { + "name": "minecraft:item.brewing_stand", + "id": 117 + }, + { + "name": "minecraft:item.cake", + "id": 92 + }, + { + "name": "minecraft:item.camera", + "id": 242 + }, + { + "name": "minecraft:item.campfire", + "id": -209 + }, + { + "name": "minecraft:item.cauldron", + "id": 118 + }, + { + "name": "minecraft:item.chain", + "id": -286 + }, + { + "name": "minecraft:item.crimson_door", + "id": -244 + }, + { + "name": "minecraft:item.dark_oak_door", + "id": 197 + }, + { + "name": "minecraft:item.flower_pot", + "id": 140 + }, + { + "name": "minecraft:item.frame", + "id": 199 + }, + { + "name": "minecraft:item.glow_frame", + "id": -339 + }, + { + "name": "minecraft:item.hopper", + "id": 154 + }, + { + "name": "minecraft:item.iron_door", + "id": 71 + }, + { + "name": "minecraft:item.jungle_door", + "id": 195 + }, + { + "name": "minecraft:item.kelp", + "id": -138 + }, + { + "name": "minecraft:item.mangrove_door", + "id": -493 + }, + { + "name": "minecraft:item.nether_sprouts", + "id": -238 + }, + { + "name": "minecraft:item.nether_wart", + "id": 115 + }, + { + "name": "minecraft:item.reeds", + "id": 83 + }, + { + "name": "minecraft:item.soul_campfire", + "id": -290 + }, + { + "name": "minecraft:item.spruce_door", + "id": 193 + }, + { + "name": "minecraft:item.warped_door", + "id": -245 + }, + { + "name": "minecraft:item.wheat", + "id": 59 + }, + { + "name": "minecraft:item.wooden_door", + "id": 64 + }, + { + "name": "minecraft:jigsaw", + "id": -211 + }, + { + "name": "minecraft:jukebox", + "id": 84 + }, + { + "name": "minecraft:jungle_boat", + "id": 403 + }, + { + "name": "minecraft:jungle_button", + "id": -143 + }, + { + "name": "minecraft:jungle_chest_boat", + "id": 676 + }, + { + "name": "minecraft:jungle_door", + "id": 588 + }, + { + "name": "minecraft:jungle_double_slab", + "id": -811 + }, + { + "name": "minecraft:jungle_fence", + "id": -578 + }, + { + "name": "minecraft:jungle_fence_gate", + "id": 185 + }, + { + "name": "minecraft:jungle_hanging_sign", + "id": -503 + }, + { + "name": "minecraft:jungle_leaves", + "id": -802 + }, + { + "name": "minecraft:jungle_log", + "id": -571 + }, + { + "name": "minecraft:jungle_planks", + "id": -741 + }, + { + "name": "minecraft:jungle_pressure_plate", + "id": -153 + }, + { + "name": "minecraft:jungle_sapling", + "id": -827 + }, + { + "name": "minecraft:jungle_sign", + "id": 611 + }, + { + "name": "minecraft:jungle_slab", + "id": -806 + }, + { + "name": "minecraft:jungle_stairs", + "id": 136 + }, + { + "name": "minecraft:jungle_standing_sign", + "id": -188 + }, + { + "name": "minecraft:jungle_trapdoor", + "id": -148 + }, + { + "name": "minecraft:jungle_wall_sign", + "id": -189 + }, + { + "name": "minecraft:jungle_wood", + "id": -816 + }, + { + "name": "minecraft:kelp", + "id": 408 + }, + { + "name": "minecraft:lab_table", + "id": -988 + }, + { + "name": "minecraft:ladder", + "id": 65 + }, + { + "name": "minecraft:lantern", + "id": -208 + }, + { + "name": "minecraft:lapis_block", + "id": 22 + }, + { + "name": "minecraft:lapis_lazuli", + "id": 440 + }, + { + "name": "minecraft:lapis_ore", + "id": 21 + }, + { + "name": "minecraft:large_amethyst_bud", + "id": -330 + }, + { + "name": "minecraft:large_fern", + "id": -865 + }, + { + "name": "minecraft:lava", + "id": 11 + }, + { + "name": "minecraft:lava_bucket", + "id": 388 + }, + { + "name": "minecraft:lead", + "id": 580 + }, + { + "name": "minecraft:leather", + "id": 407 + }, + { + "name": "minecraft:leather_boots", + "id": 363 + }, + { + "name": "minecraft:leather_chestplate", + "id": 361 + }, + { + "name": "minecraft:leather_helmet", + "id": 360 + }, + { + "name": "minecraft:leather_horse_armor", + "id": 563 + }, + { + "name": "minecraft:leather_leggings", + "id": 362 + }, + { + "name": "minecraft:leaves", + "id": 760 + }, + { + "name": "minecraft:leaves2", + "id": 761 + }, + { + "name": "minecraft:lectern", + "id": -194 + }, + { + "name": "minecraft:lever", + "id": 69 + }, + { + "name": "minecraft:light_block", + "id": 784 + }, + { + "name": "minecraft:light_block_0", + "id": -215 + }, + { + "name": "minecraft:light_block_1", + "id": -929 + }, + { + "name": "minecraft:light_block_10", + "id": -938 + }, + { + "name": "minecraft:light_block_11", + "id": -939 + }, + { + "name": "minecraft:light_block_12", + "id": -940 + }, + { + "name": "minecraft:light_block_13", + "id": -941 + }, + { + "name": "minecraft:light_block_14", + "id": -942 + }, + { + "name": "minecraft:light_block_15", + "id": -943 + }, + { + "name": "minecraft:light_block_2", + "id": -930 + }, + { + "name": "minecraft:light_block_3", + "id": -931 + }, + { + "name": "minecraft:light_block_4", + "id": -932 + }, + { + "name": "minecraft:light_block_5", + "id": -933 + }, + { + "name": "minecraft:light_block_6", + "id": -934 + }, + { + "name": "minecraft:light_block_7", + "id": -935 + }, + { + "name": "minecraft:light_block_8", + "id": -936 + }, + { + "name": "minecraft:light_block_9", + "id": -937 + }, + { + "name": "minecraft:light_blue_bundle", + "id": 264 + }, + { + "name": "minecraft:light_blue_candle", + "id": -416 + }, + { + "name": "minecraft:light_blue_candle_cake", + "id": -433 + }, + { + "name": "minecraft:light_blue_carpet", + "id": -599 + }, + { + "name": "minecraft:light_blue_concrete", + "id": -630 + }, + { + "name": "minecraft:light_blue_concrete_powder", + "id": -711 + }, + { + "name": "minecraft:light_blue_dye", + "id": 433 + }, + { + "name": "minecraft:light_blue_glazed_terracotta", + "id": 223 + }, + { + "name": "minecraft:light_blue_shulker_box", + "id": -615 + }, + { + "name": "minecraft:light_blue_stained_glass", + "id": -675 + }, + { + "name": "minecraft:light_blue_stained_glass_pane", + "id": -645 + }, + { + "name": "minecraft:light_blue_terracotta", + "id": -726 + }, + { + "name": "minecraft:light_blue_wool", + "id": -562 + }, + { + "name": "minecraft:light_gray_bundle", + "id": 265 + }, + { + "name": "minecraft:light_gray_candle", + "id": -421 + }, + { + "name": "minecraft:light_gray_candle_cake", + "id": -438 + }, + { + "name": "minecraft:light_gray_carpet", + "id": -604 + }, + { + "name": "minecraft:light_gray_concrete", + "id": -635 + }, + { + "name": "minecraft:light_gray_concrete_powder", + "id": -716 + }, + { + "name": "minecraft:light_gray_dye", + "id": 428 + }, + { + "name": "minecraft:light_gray_shulker_box", + "id": -620 + }, + { + "name": "minecraft:light_gray_stained_glass", + "id": -680 + }, + { + "name": "minecraft:light_gray_stained_glass_pane", + "id": -650 + }, + { + "name": "minecraft:light_gray_terracotta", + "id": -731 + }, + { + "name": "minecraft:light_gray_wool", + "id": -552 + }, + { + "name": "minecraft:light_weighted_pressure_plate", + "id": 147 + }, + { + "name": "minecraft:lightning_rod", + "id": -312 + }, + { + "name": "minecraft:lilac", + "id": -863 + }, + { + "name": "minecraft:lily_of_the_valley", + "id": -839 + }, + { + "name": "minecraft:lime_bundle", + "id": 266 + }, + { + "name": "minecraft:lime_candle", + "id": -418 + }, + { + "name": "minecraft:lime_candle_cake", + "id": -435 + }, + { + "name": "minecraft:lime_carpet", + "id": -601 + }, + { + "name": "minecraft:lime_concrete", + "id": -632 + }, + { + "name": "minecraft:lime_concrete_powder", + "id": -713 + }, + { + "name": "minecraft:lime_dye", + "id": 431 + }, + { + "name": "minecraft:lime_glazed_terracotta", + "id": 225 + }, + { + "name": "minecraft:lime_shulker_box", + "id": -617 + }, + { + "name": "minecraft:lime_stained_glass", + "id": -677 + }, + { + "name": "minecraft:lime_stained_glass_pane", + "id": -647 + }, + { + "name": "minecraft:lime_terracotta", + "id": -728 + }, + { + "name": "minecraft:lime_wool", + "id": -559 + }, + { + "name": "minecraft:lingering_potion", + "id": 595 + }, + { + "name": "minecraft:lit_blast_furnace", + "id": -214 + }, + { + "name": "minecraft:lit_deepslate_redstone_ore", + "id": -404 + }, + { + "name": "minecraft:lit_furnace", + "id": 62 + }, + { + "name": "minecraft:lit_pumpkin", + "id": 91 + }, + { + "name": "minecraft:lit_redstone_lamp", + "id": 124 + }, + { + "name": "minecraft:lit_redstone_ore", + "id": 74 + }, + { + "name": "minecraft:lit_smoker", + "id": -199 + }, + { + "name": "minecraft:llama_spawn_egg", + "id": 501 + }, + { + "name": "minecraft:lodestone", + "id": -222 + }, + { + "name": "minecraft:lodestone_compass", + "id": 638 + }, + { + "name": "minecraft:log", + "id": 745 + }, + { + "name": "minecraft:log2", + "id": 768 + }, + { + "name": "minecraft:loom", + "id": -204 + }, + { + "name": "minecraft:mace", + "id": 344 + }, + { + "name": "minecraft:magenta_bundle", + "id": 267 + }, + { + "name": "minecraft:magenta_candle", + "id": -415 + }, + { + "name": "minecraft:magenta_candle_cake", + "id": -432 + }, + { + "name": "minecraft:magenta_carpet", + "id": -598 + }, + { + "name": "minecraft:magenta_concrete", + "id": -629 + }, + { + "name": "minecraft:magenta_concrete_powder", + "id": -710 + }, + { + "name": "minecraft:magenta_dye", + "id": 434 + }, + { + "name": "minecraft:magenta_glazed_terracotta", + "id": 222 + }, + { + "name": "minecraft:magenta_shulker_box", + "id": -614 + }, + { + "name": "minecraft:magenta_stained_glass", + "id": -674 + }, + { + "name": "minecraft:magenta_stained_glass_pane", + "id": -644 + }, + { + "name": "minecraft:magenta_terracotta", + "id": -725 + }, + { + "name": "minecraft:magenta_wool", + "id": -565 + }, + { + "name": "minecraft:magma", + "id": 213 + }, + { + "name": "minecraft:magma_cream", + "id": 457 + }, + { + "name": "minecraft:magma_cube_spawn_egg", + "id": 482 + }, + { + "name": "minecraft:mangrove_boat", + "id": 671 + }, + { + "name": "minecraft:mangrove_button", + "id": -487 + }, + { + "name": "minecraft:mangrove_chest_boat", + "id": 680 + }, + { + "name": "minecraft:mangrove_door", + "id": 669 + }, + { + "name": "minecraft:mangrove_double_slab", + "id": -499 + }, + { + "name": "minecraft:mangrove_fence", + "id": -491 + }, + { + "name": "minecraft:mangrove_fence_gate", + "id": -492 + }, + { + "name": "minecraft:mangrove_hanging_sign", + "id": -508 + }, + { + "name": "minecraft:mangrove_leaves", + "id": -472 + }, + { + "name": "minecraft:mangrove_log", + "id": -484 + }, + { + "name": "minecraft:mangrove_planks", + "id": -486 + }, + { + "name": "minecraft:mangrove_pressure_plate", + "id": -490 + }, + { + "name": "minecraft:mangrove_propagule", + "id": -474 + }, + { + "name": "minecraft:mangrove_roots", + "id": -482 + }, + { + "name": "minecraft:mangrove_sign", + "id": 670 + }, + { + "name": "minecraft:mangrove_slab", + "id": -489 + }, + { + "name": "minecraft:mangrove_stairs", + "id": -488 + }, + { + "name": "minecraft:mangrove_standing_sign", + "id": -494 + }, + { + "name": "minecraft:mangrove_trapdoor", + "id": -496 + }, + { + "name": "minecraft:mangrove_wall_sign", + "id": -495 + }, + { + "name": "minecraft:mangrove_wood", + "id": -497 + }, + { + "name": "minecraft:material_reducer", + "id": -986 + }, + { + "name": "minecraft:medicine", + "id": 635 + }, + { + "name": "minecraft:medium_amethyst_bud", + "id": -331 + }, + { + "name": "minecraft:melon_block", + "id": 103 + }, + { + "name": "minecraft:melon_seeds", + "id": 315 + }, + { + "name": "minecraft:melon_slice", + "id": 294 + }, + { + "name": "minecraft:melon_stem", + "id": 105 + }, + { + "name": "minecraft:milk_bucket", + "id": 386 + }, + { + "name": "minecraft:minecart", + "id": 395 + }, + { + "name": "minecraft:miner_pottery_sherd", + "id": 706 + }, + { + "name": "minecraft:mob_spawner", + "id": 52 + }, + { + "name": "minecraft:mojang_banner_pattern", + "id": 617 + }, + { + "name": "minecraft:monster_egg", + "id": 769 + }, + { + "name": "minecraft:mooshroom_spawn_egg", + "id": 467 + }, + { + "name": "minecraft:moss_block", + "id": -320 + }, + { + "name": "minecraft:moss_carpet", + "id": -335 + }, + { + "name": "minecraft:mossy_cobblestone", + "id": 48 + }, + { + "name": "minecraft:mossy_cobblestone_double_slab", + "id": -915 + }, + { + "name": "minecraft:mossy_cobblestone_slab", + "id": -888 + }, + { + "name": "minecraft:mossy_cobblestone_stairs", + "id": -179 + }, + { + "name": "minecraft:mossy_cobblestone_wall", + "id": -971 + }, + { + "name": "minecraft:mossy_stone_brick_double_slab", + "id": -168 + }, + { + "name": "minecraft:mossy_stone_brick_slab", + "id": -166 + }, + { + "name": "minecraft:mossy_stone_brick_stairs", + "id": -175 + }, + { + "name": "minecraft:mossy_stone_brick_wall", + "id": -978 + }, + { + "name": "minecraft:mossy_stone_bricks", + "id": -868 + }, + { + "name": "minecraft:mourner_pottery_sherd", + "id": 707 + }, + { + "name": "minecraft:moving_block", + "id": 250 + }, + { + "name": "minecraft:mud", + "id": -473 + }, + { + "name": "minecraft:mud_brick_double_slab", + "id": -479 + }, + { + "name": "minecraft:mud_brick_slab", + "id": -478 + }, + { + "name": "minecraft:mud_brick_stairs", + "id": -480 + }, + { + "name": "minecraft:mud_brick_wall", + "id": -481 + }, + { + "name": "minecraft:mud_bricks", + "id": -475 + }, + { + "name": "minecraft:muddy_mangrove_roots", + "id": -483 + }, + { + "name": "minecraft:mule_spawn_egg", + "id": 494 + }, + { + "name": "minecraft:mushroom_stem", + "id": -1008 + }, + { + "name": "minecraft:mushroom_stew", + "id": 282 + }, + { + "name": "minecraft:music_disc_11", + "id": 577 + }, + { + "name": "minecraft:music_disc_13", + "id": 567 + }, + { + "name": "minecraft:music_disc_5", + "id": 672 + }, + { + "name": "minecraft:music_disc_blocks", + "id": 569 + }, + { + "name": "minecraft:music_disc_cat", + "id": 568 + }, + { + "name": "minecraft:music_disc_chirp", + "id": 570 + }, + { + "name": "minecraft:music_disc_creator", + "id": 776 + }, + { + "name": "minecraft:music_disc_creator_music_box", + "id": 777 + }, + { + "name": "minecraft:music_disc_far", + "id": 571 + }, + { + "name": "minecraft:music_disc_mall", + "id": 572 + }, + { + "name": "minecraft:music_disc_mellohi", + "id": 573 + }, + { + "name": "minecraft:music_disc_otherside", + "id": 662 + }, + { + "name": "minecraft:music_disc_pigstep", + "id": 656 + }, + { + "name": "minecraft:music_disc_precipice", + "id": 778 + }, + { + "name": "minecraft:music_disc_relic", + "id": 735 + }, + { + "name": "minecraft:music_disc_stal", + "id": 574 + }, + { + "name": "minecraft:music_disc_strad", + "id": 575 + }, + { + "name": "minecraft:music_disc_wait", + "id": 578 + }, + { + "name": "minecraft:music_disc_ward", + "id": 576 + }, + { + "name": "minecraft:mutton", + "id": 583 + }, + { + "name": "minecraft:mycelium", + "id": 110 + }, + { + "name": "minecraft:name_tag", + "id": 581 + }, + { + "name": "minecraft:nautilus_shell", + "id": 603 + }, + { + "name": "minecraft:nether_brick", + "id": 112 + }, + { + "name": "minecraft:nether_brick_double_slab", + "id": -883 + }, + { + "name": "minecraft:nether_brick_fence", + "id": 113 + }, + { + "name": "minecraft:nether_brick_slab", + "id": -877 + }, + { + "name": "minecraft:nether_brick_stairs", + "id": 114 + }, + { + "name": "minecraft:nether_brick_wall", + "id": -979 + }, + { + "name": "minecraft:nether_gold_ore", + "id": -288 + }, + { + "name": "minecraft:nether_sprouts", + "id": 657 + }, + { + "name": "minecraft:nether_star", + "id": 551 + }, + { + "name": "minecraft:nether_wart", + "id": 316 + }, + { + "name": "minecraft:nether_wart_block", + "id": 214 + }, + { + "name": "minecraft:netherbrick", + "id": 556 + }, + { + "name": "minecraft:netherite_axe", + "id": 642 + }, + { + "name": "minecraft:netherite_block", + "id": -270 + }, + { + "name": "minecraft:netherite_boots", + "id": 648 + }, + { + "name": "minecraft:netherite_chestplate", + "id": 646 + }, + { + "name": "minecraft:netherite_helmet", + "id": 645 + }, + { + "name": "minecraft:netherite_hoe", + "id": 643 + }, + { + "name": "minecraft:netherite_ingot", + "id": 644 + }, + { + "name": "minecraft:netherite_leggings", + "id": 647 + }, + { + "name": "minecraft:netherite_pickaxe", + "id": 641 + }, + { + "name": "minecraft:netherite_scrap", + "id": 649 + }, + { + "name": "minecraft:netherite_shovel", + "id": 640 + }, + { + "name": "minecraft:netherite_sword", + "id": 639 + }, + { + "name": "minecraft:netherite_upgrade_smithing_template", + "id": 716 + }, + { + "name": "minecraft:netherrack", + "id": 87 + }, + { + "name": "minecraft:netherreactor", + "id": 247 + }, + { + "name": "minecraft:normal_stone_double_slab", + "id": -926 + }, + { + "name": "minecraft:normal_stone_slab", + "id": -899 + }, + { + "name": "minecraft:normal_stone_stairs", + "id": -180 + }, + { + "name": "minecraft:noteblock", + "id": 25 + }, + { + "name": "minecraft:npc_spawn_egg", + "id": 498 + }, + { + "name": "minecraft:oak_boat", + "id": 401 + }, + { + "name": "minecraft:oak_chest_boat", + "id": 674 + }, + { + "name": "minecraft:oak_double_slab", + "id": 157 + }, + { + "name": "minecraft:oak_fence", + "id": 85 + }, + { + "name": "minecraft:oak_hanging_sign", + "id": -500 + }, + { + "name": "minecraft:oak_leaves", + "id": 18 + }, + { + "name": "minecraft:oak_log", + "id": 17 + }, + { + "name": "minecraft:oak_planks", + "id": 5 + }, + { + "name": "minecraft:oak_sapling", + "id": 6 + }, + { + "name": "minecraft:oak_sign", + "id": 383 + }, + { + "name": "minecraft:oak_slab", + "id": 158 + }, + { + "name": "minecraft:oak_stairs", + "id": 53 + }, + { + "name": "minecraft:oak_wood", + "id": -212 + }, + { + "name": "minecraft:observer", + "id": 251 + }, + { + "name": "minecraft:obsidian", + "id": 49 + }, + { + "name": "minecraft:ocelot_spawn_egg", + "id": 478 + }, + { + "name": "minecraft:ochre_froglight", + "id": -471 + }, + { + "name": "minecraft:ominous_bottle", + "id": 628 + }, + { + "name": "minecraft:ominous_trial_key", + "id": 275 + }, + { + "name": "minecraft:orange_bundle", + "id": 268 + }, + { + "name": "minecraft:orange_candle", + "id": -414 + }, + { + "name": "minecraft:orange_candle_cake", + "id": -431 + }, + { + "name": "minecraft:orange_carpet", + "id": -597 + }, + { + "name": "minecraft:orange_concrete", + "id": -628 + }, + { + "name": "minecraft:orange_concrete_powder", + "id": -709 + }, + { + "name": "minecraft:orange_dye", + "id": 435 + }, + { + "name": "minecraft:orange_glazed_terracotta", + "id": 221 + }, + { + "name": "minecraft:orange_shulker_box", + "id": -613 + }, + { + "name": "minecraft:orange_stained_glass", + "id": -673 + }, + { + "name": "minecraft:orange_stained_glass_pane", + "id": -643 + }, + { + "name": "minecraft:orange_terracotta", + "id": -724 + }, + { + "name": "minecraft:orange_tulip", + "id": -834 + }, + { + "name": "minecraft:orange_wool", + "id": -557 + }, + { + "name": "minecraft:oxeye_daisy", + "id": -837 + }, + { + "name": "minecraft:oxidized_chiseled_copper", + "id": -763 + }, + { + "name": "minecraft:oxidized_copper", + "id": -343 + }, + { + "name": "minecraft:oxidized_copper_bulb", + "id": -779 + }, + { + "name": "minecraft:oxidized_copper_door", + "id": -787 + }, + { + "name": "minecraft:oxidized_copper_grate", + "id": -771 + }, + { + "name": "minecraft:oxidized_copper_trapdoor", + "id": -795 + }, + { + "name": "minecraft:oxidized_cut_copper", + "id": -350 + }, + { + "name": "minecraft:oxidized_cut_copper_slab", + "id": -364 + }, + { + "name": "minecraft:oxidized_cut_copper_stairs", + "id": -357 + }, + { + "name": "minecraft:oxidized_double_cut_copper_slab", + "id": -371 + }, + { + "name": "minecraft:packed_ice", + "id": 174 + }, + { + "name": "minecraft:packed_mud", + "id": -477 + }, + { + "name": "minecraft:painting", + "id": 382 + }, + { + "name": "minecraft:panda_spawn_egg", + "id": 517 + }, + { + "name": "minecraft:paper", + "id": 412 + }, + { + "name": "minecraft:parrot_spawn_egg", + "id": 506 + }, + { + "name": "minecraft:pearlescent_froglight", + "id": -469 + }, + { + "name": "minecraft:peony", + "id": -867 + }, + { + "name": "minecraft:petrified_oak_double_slab", + "id": -903 + }, + { + "name": "minecraft:petrified_oak_slab", + "id": -902 + }, + { + "name": "minecraft:phantom_membrane", + "id": 607 + }, + { + "name": "minecraft:phantom_spawn_egg", + "id": 514 + }, + { + "name": "minecraft:pig_spawn_egg", + "id": 464 + }, + { + "name": "minecraft:piglin_banner_pattern", + "id": 620 + }, + { + "name": "minecraft:piglin_brute_spawn_egg", + "id": 527 + }, + { + "name": "minecraft:piglin_head", + "id": -970 + }, + { + "name": "minecraft:piglin_spawn_egg", + "id": 525 + }, + { + "name": "minecraft:pillager_spawn_egg", + "id": 519 + }, + { + "name": "minecraft:pink_bundle", + "id": 269 + }, + { + "name": "minecraft:pink_candle", + "id": -419 + }, + { + "name": "minecraft:pink_candle_cake", + "id": -436 + }, + { + "name": "minecraft:pink_carpet", + "id": -602 + }, + { + "name": "minecraft:pink_concrete", + "id": -633 + }, + { + "name": "minecraft:pink_concrete_powder", + "id": -714 + }, + { + "name": "minecraft:pink_dye", + "id": 430 + }, + { + "name": "minecraft:pink_glazed_terracotta", + "id": 226 + }, + { + "name": "minecraft:pink_petals", + "id": -549 + }, + { + "name": "minecraft:pink_shulker_box", + "id": -618 + }, + { + "name": "minecraft:pink_stained_glass", + "id": -678 + }, + { + "name": "minecraft:pink_stained_glass_pane", + "id": -648 + }, + { + "name": "minecraft:pink_terracotta", + "id": -729 + }, + { + "name": "minecraft:pink_tulip", + "id": -836 + }, + { + "name": "minecraft:pink_wool", + "id": -566 + }, + { + "name": "minecraft:piston", + "id": 33 + }, + { + "name": "minecraft:piston_arm_collision", + "id": 34 + }, + { + "name": "minecraft:pitcher_crop", + "id": -574 + }, + { + "name": "minecraft:pitcher_plant", + "id": -612 + }, + { + "name": "minecraft:pitcher_pod", + "id": 319 + }, + { + "name": "minecraft:planks", + "id": 765 + }, + { + "name": "minecraft:player_head", + "id": -967 + }, + { + "name": "minecraft:plenty_pottery_sherd", + "id": 708 + }, + { + "name": "minecraft:podzol", + "id": 243 + }, + { + "name": "minecraft:pointed_dripstone", + "id": -308 + }, + { + "name": "minecraft:poisonous_potato", + "id": 304 + }, + { + "name": "minecraft:polar_bear_spawn_egg", + "id": 500 + }, + { + "name": "minecraft:polished_andesite", + "id": -595 + }, + { + "name": "minecraft:polished_andesite_double_slab", + "id": -919 + }, + { + "name": "minecraft:polished_andesite_slab", + "id": -892 + }, + { + "name": "minecraft:polished_andesite_stairs", + "id": -174 + }, + { + "name": "minecraft:polished_basalt", + "id": -235 + }, + { + "name": "minecraft:polished_blackstone", + "id": -291 + }, + { + "name": "minecraft:polished_blackstone_brick_double_slab", + "id": -285 + }, + { + "name": "minecraft:polished_blackstone_brick_slab", + "id": -284 + }, + { + "name": "minecraft:polished_blackstone_brick_stairs", + "id": -275 + }, + { + "name": "minecraft:polished_blackstone_brick_wall", + "id": -278 + }, + { + "name": "minecraft:polished_blackstone_bricks", + "id": -274 + }, + { + "name": "minecraft:polished_blackstone_button", + "id": -296 + }, + { + "name": "minecraft:polished_blackstone_double_slab", + "id": -294 + }, + { + "name": "minecraft:polished_blackstone_pressure_plate", + "id": -295 + }, + { + "name": "minecraft:polished_blackstone_slab", + "id": -293 + }, + { + "name": "minecraft:polished_blackstone_stairs", + "id": -292 + }, + { + "name": "minecraft:polished_blackstone_wall", + "id": -297 + }, + { + "name": "minecraft:polished_deepslate", + "id": -383 + }, + { + "name": "minecraft:polished_deepslate_double_slab", + "id": -397 + }, + { + "name": "minecraft:polished_deepslate_slab", + "id": -384 + }, + { + "name": "minecraft:polished_deepslate_stairs", + "id": -385 + }, + { + "name": "minecraft:polished_deepslate_wall", + "id": -386 + }, + { + "name": "minecraft:polished_diorite", + "id": -593 + }, + { + "name": "minecraft:polished_diorite_double_slab", + "id": -922 + }, + { + "name": "minecraft:polished_diorite_slab", + "id": -895 + }, + { + "name": "minecraft:polished_diorite_stairs", + "id": -173 + }, + { + "name": "minecraft:polished_granite", + "id": -591 + }, + { + "name": "minecraft:polished_granite_double_slab", + "id": -924 + }, + { + "name": "minecraft:polished_granite_slab", + "id": -897 + }, + { + "name": "minecraft:polished_granite_stairs", + "id": -172 + }, + { + "name": "minecraft:polished_tuff", + "id": -748 + }, + { + "name": "minecraft:polished_tuff_double_slab", + "id": -750 + }, + { + "name": "minecraft:polished_tuff_slab", + "id": -749 + }, + { + "name": "minecraft:polished_tuff_stairs", + "id": -751 + }, + { + "name": "minecraft:polished_tuff_wall", + "id": -752 + }, + { + "name": "minecraft:popped_chorus_fruit", + "id": 592 + }, + { + "name": "minecraft:poppy", + "id": 38 + }, + { + "name": "minecraft:porkchop", + "id": 284 + }, + { + "name": "minecraft:portal", + "id": 90 + }, + { + "name": "minecraft:potato", + "id": 302 + }, + { + "name": "minecraft:potatoes", + "id": 142 + }, + { + "name": "minecraft:potion", + "id": 453 + }, + { + "name": "minecraft:powder_snow", + "id": -306 + }, + { + "name": "minecraft:powder_snow_bucket", + "id": 393 + }, + { + "name": "minecraft:powered_comparator", + "id": 150 + }, + { + "name": "minecraft:powered_repeater", + "id": 94 + }, + { + "name": "minecraft:prismarine", + "id": 168 + }, + { + "name": "minecraft:prismarine_brick_double_slab", + "id": -914 + }, + { + "name": "minecraft:prismarine_brick_slab", + "id": -887 + }, + { + "name": "minecraft:prismarine_bricks", + "id": -948 + }, + { + "name": "minecraft:prismarine_bricks_stairs", + "id": -4 + }, + { + "name": "minecraft:prismarine_crystals", + "id": 582 + }, + { + "name": "minecraft:prismarine_double_slab", + "id": -912 + }, + { + "name": "minecraft:prismarine_shard", + "id": 598 + }, + { + "name": "minecraft:prismarine_slab", + "id": -885 + }, + { + "name": "minecraft:prismarine_stairs", + "id": -2 + }, + { + "name": "minecraft:prismarine_wall", + "id": -981 + }, + { + "name": "minecraft:prize_pottery_sherd", + "id": 709 + }, + { + "name": "minecraft:pufferfish", + "id": 289 + }, + { + "name": "minecraft:pufferfish_bucket", + "id": 392 + }, + { + "name": "minecraft:pufferfish_spawn_egg", + "id": 509 + }, + { + "name": "minecraft:pumpkin", + "id": 86 + }, + { + "name": "minecraft:pumpkin_pie", + "id": 306 + }, + { + "name": "minecraft:pumpkin_seeds", + "id": 314 + }, + { + "name": "minecraft:pumpkin_stem", + "id": 104 + }, + { + "name": "minecraft:purple_bundle", + "id": 270 + }, + { + "name": "minecraft:purple_candle", + "id": -423 + }, + { + "name": "minecraft:purple_candle_cake", + "id": -440 + }, + { + "name": "minecraft:purple_carpet", + "id": -606 + }, + { + "name": "minecraft:purple_concrete", + "id": -637 + }, + { + "name": "minecraft:purple_concrete_powder", + "id": -718 + }, + { + "name": "minecraft:purple_dye", + "id": 426 + }, + { + "name": "minecraft:purple_glazed_terracotta", + "id": 219 + }, + { + "name": "minecraft:purple_shulker_box", + "id": -622 + }, + { + "name": "minecraft:purple_stained_glass", + "id": -682 + }, + { + "name": "minecraft:purple_stained_glass_pane", + "id": -652 + }, + { + "name": "minecraft:purple_terracotta", + "id": -733 + }, + { + "name": "minecraft:purple_wool", + "id": -564 + }, + { + "name": "minecraft:purpur_block", + "id": 201 + }, + { + "name": "minecraft:purpur_double_slab", + "id": -911 + }, + { + "name": "minecraft:purpur_pillar", + "id": -951 + }, + { + "name": "minecraft:purpur_slab", + "id": -884 + }, + { + "name": "minecraft:purpur_stairs", + "id": 203 + }, + { + "name": "minecraft:quartz", + "id": 557 + }, + { + "name": "minecraft:quartz_block", + "id": 155 + }, + { + "name": "minecraft:quartz_bricks", + "id": -304 + }, + { + "name": "minecraft:quartz_double_slab", + "id": -882 + }, + { + "name": "minecraft:quartz_ore", + "id": 153 + }, + { + "name": "minecraft:quartz_pillar", + "id": -954 + }, + { + "name": "minecraft:quartz_slab", + "id": -876 + }, + { + "name": "minecraft:quartz_stairs", + "id": 156 + }, + { + "name": "minecraft:rabbit", + "id": 310 + }, + { + "name": "minecraft:rabbit_foot", + "id": 561 + }, + { + "name": "minecraft:rabbit_hide", + "id": 562 + }, + { + "name": "minecraft:rabbit_spawn_egg", + "id": 486 + }, + { + "name": "minecraft:rabbit_stew", + "id": 312 + }, + { + "name": "minecraft:rail", + "id": 66 + }, + { + "name": "minecraft:raiser_armor_trim_smithing_template", + "id": 730 + }, + { + "name": "minecraft:rapid_fertilizer", + "id": 633 + }, + { + "name": "minecraft:ravager_spawn_egg", + "id": 521 + }, + { + "name": "minecraft:raw_copper", + "id": 541 + }, + { + "name": "minecraft:raw_copper_block", + "id": -452 + }, + { + "name": "minecraft:raw_gold", + "id": 540 + }, + { + "name": "minecraft:raw_gold_block", + "id": -453 + }, + { + "name": "minecraft:raw_iron", + "id": 539 + }, + { + "name": "minecraft:raw_iron_block", + "id": -451 + }, + { + "name": "minecraft:recovery_compass", + "id": 682 + }, + { + "name": "minecraft:red_bundle", + "id": 271 + }, + { + "name": "minecraft:red_candle", + "id": -427 + }, + { + "name": "minecraft:red_candle_cake", + "id": -444 + }, + { + "name": "minecraft:red_carpet", + "id": -610 + }, + { + "name": "minecraft:red_concrete", + "id": -641 + }, + { + "name": "minecraft:red_concrete_powder", + "id": -722 + }, + { + "name": "minecraft:red_dye", + "id": 422 + }, + { + "name": "minecraft:red_flower", + "id": 763 + }, + { + "name": "minecraft:red_glazed_terracotta", + "id": 234 + }, + { + "name": "minecraft:red_mushroom", + "id": 40 + }, + { + "name": "minecraft:red_mushroom_block", + "id": 100 + }, + { + "name": "minecraft:red_nether_brick", + "id": 215 + }, + { + "name": "minecraft:red_nether_brick_double_slab", + "id": -917 + }, + { + "name": "minecraft:red_nether_brick_slab", + "id": -890 + }, + { + "name": "minecraft:red_nether_brick_stairs", + "id": -184 + }, + { + "name": "minecraft:red_nether_brick_wall", + "id": -983 + }, + { + "name": "minecraft:red_sand", + "id": -949 + }, + { + "name": "minecraft:red_sandstone", + "id": 179 + }, + { + "name": "minecraft:red_sandstone_double_slab", + "id": 181 + }, + { + "name": "minecraft:red_sandstone_slab", + "id": 182 + }, + { + "name": "minecraft:red_sandstone_stairs", + "id": 180 + }, + { + "name": "minecraft:red_sandstone_wall", + "id": -982 + }, + { + "name": "minecraft:red_shulker_box", + "id": -626 + }, + { + "name": "minecraft:red_stained_glass", + "id": -686 + }, + { + "name": "minecraft:red_stained_glass_pane", + "id": -656 + }, + { + "name": "minecraft:red_terracotta", + "id": -737 + }, + { + "name": "minecraft:red_tulip", + "id": -833 + }, + { + "name": "minecraft:red_wool", + "id": -556 + }, + { + "name": "minecraft:redstone", + "id": 398 + }, + { + "name": "minecraft:redstone_block", + "id": 152 + }, + { + "name": "minecraft:redstone_lamp", + "id": 123 + }, + { + "name": "minecraft:redstone_ore", + "id": 73 + }, + { + "name": "minecraft:redstone_torch", + "id": 76 + }, + { + "name": "minecraft:redstone_wire", + "id": 55 + }, + { + "name": "minecraft:reinforced_deepslate", + "id": -466 + }, + { + "name": "minecraft:repeater", + "id": 445 + }, + { + "name": "minecraft:repeating_command_block", + "id": 188 + }, + { + "name": "minecraft:reserved6", + "id": 255 + }, + { + "name": "minecraft:respawn_anchor", + "id": -272 + }, + { + "name": "minecraft:rib_armor_trim_smithing_template", + "id": 726 + }, + { + "name": "minecraft:rose_bush", + "id": -866 + }, + { + "name": "minecraft:rotten_flesh", + "id": 299 + }, + { + "name": "minecraft:saddle", + "id": 396 + }, + { + "name": "minecraft:salmon", + "id": 287 + }, + { + "name": "minecraft:salmon_bucket", + "id": 390 + }, + { + "name": "minecraft:salmon_spawn_egg", + "id": 510 + }, + { + "name": "minecraft:sand", + "id": 12 + }, + { + "name": "minecraft:sandstone", + "id": 24 + }, + { + "name": "minecraft:sandstone_double_slab", + "id": -878 + }, + { + "name": "minecraft:sandstone_slab", + "id": -872 + }, + { + "name": "minecraft:sandstone_stairs", + "id": 128 + }, + { + "name": "minecraft:sandstone_wall", + "id": -975 + }, + { + "name": "minecraft:sapling", + "id": 759 + }, + { + "name": "minecraft:scaffolding", + "id": -165 + }, + { + "name": "minecraft:scrape_pottery_sherd", + "id": 710 + }, + { + "name": "minecraft:sculk", + "id": -458 + }, + { + "name": "minecraft:sculk_catalyst", + "id": -460 + }, + { + "name": "minecraft:sculk_sensor", + "id": -307 + }, + { + "name": "minecraft:sculk_shrieker", + "id": -461 + }, + { + "name": "minecraft:sculk_vein", + "id": -459 + }, + { + "name": "minecraft:sea_lantern", + "id": 169 + }, + { + "name": "minecraft:sea_pickle", + "id": -156 + }, + { + "name": "minecraft:seagrass", + "id": -130 + }, + { + "name": "minecraft:sentry_armor_trim_smithing_template", + "id": 717 + }, + { + "name": "minecraft:shaper_armor_trim_smithing_template", + "id": 731 + }, + { + "name": "minecraft:sheaf_pottery_sherd", + "id": 711 + }, + { + "name": "minecraft:shears", + "id": 447 + }, + { + "name": "minecraft:sheep_spawn_egg", + "id": 465 + }, + { + "name": "minecraft:shelter_pottery_sherd", + "id": 712 + }, + { + "name": "minecraft:shield", + "id": 380 + }, + { + "name": "minecraft:short_grass", + "id": 31 + }, + { + "name": "minecraft:shroomlight", + "id": -230 + }, + { + "name": "minecraft:shulker_box", + "id": 774 + }, + { + "name": "minecraft:shulker_shell", + "id": 599 + }, + { + "name": "minecraft:shulker_spawn_egg", + "id": 497 + }, + { + "name": "minecraft:silence_armor_trim_smithing_template", + "id": 728 + }, + { + "name": "minecraft:silver_glazed_terracotta", + "id": 228 + }, + { + "name": "minecraft:silverfish_spawn_egg", + "id": 470 + }, + { + "name": "minecraft:skeleton_horse_spawn_egg", + "id": 495 + }, + { + "name": "minecraft:skeleton_skull", + "id": 144 + }, + { + "name": "minecraft:skeleton_spawn_egg", + "id": 471 + }, + { + "name": "minecraft:skull", + "id": 736 + }, + { + "name": "minecraft:skull_banner_pattern", + "id": 616 + }, + { + "name": "minecraft:skull_pottery_sherd", + "id": 713 + }, + { + "name": "minecraft:slime", + "id": 165 + }, + { + "name": "minecraft:slime_ball", + "id": 414 + }, + { + "name": "minecraft:slime_spawn_egg", + "id": 472 + }, + { + "name": "minecraft:small_amethyst_bud", + "id": -332 + }, + { + "name": "minecraft:small_dripleaf_block", + "id": -336 + }, + { + "name": "minecraft:smithing_table", + "id": -202 + }, + { + "name": "minecraft:smoker", + "id": -198 + }, + { + "name": "minecraft:smooth_basalt", + "id": -377 + }, + { + "name": "minecraft:smooth_quartz", + "id": -955 + }, + { + "name": "minecraft:smooth_quartz_double_slab", + "id": -925 + }, + { + "name": "minecraft:smooth_quartz_slab", + "id": -898 + }, + { + "name": "minecraft:smooth_quartz_stairs", + "id": -185 + }, + { + "name": "minecraft:smooth_red_sandstone", + "id": -958 + }, + { + "name": "minecraft:smooth_red_sandstone_double_slab", + "id": -918 + }, + { + "name": "minecraft:smooth_red_sandstone_slab", + "id": -891 + }, + { + "name": "minecraft:smooth_red_sandstone_stairs", + "id": -176 + }, + { + "name": "minecraft:smooth_sandstone", + "id": -946 + }, + { + "name": "minecraft:smooth_sandstone_double_slab", + "id": -916 + }, + { + "name": "minecraft:smooth_sandstone_slab", + "id": -889 + }, + { + "name": "minecraft:smooth_sandstone_stairs", + "id": -177 + }, + { + "name": "minecraft:smooth_stone", + "id": -183 + }, + { + "name": "minecraft:smooth_stone_double_slab", + "id": 43 + }, + { + "name": "minecraft:smooth_stone_slab", + "id": 44 + }, + { + "name": "minecraft:sniffer_egg", + "id": -596 + }, + { + "name": "minecraft:sniffer_spawn_egg", + "id": 528 + }, + { + "name": "minecraft:snort_pottery_sherd", + "id": 714 + }, + { + "name": "minecraft:snout_armor_trim_smithing_template", + "id": 725 + }, + { + "name": "minecraft:snow", + "id": 80 + }, + { + "name": "minecraft:snow_golem_spawn_egg", + "id": 534 + }, + { + "name": "minecraft:snow_layer", + "id": 78 + }, + { + "name": "minecraft:snowball", + "id": 399 + }, + { + "name": "minecraft:soul_campfire", + "id": 658 + }, + { + "name": "minecraft:soul_fire", + "id": -237 + }, + { + "name": "minecraft:soul_lantern", + "id": -269 + }, + { + "name": "minecraft:soul_sand", + "id": 88 + }, + { + "name": "minecraft:soul_soil", + "id": -236 + }, + { + "name": "minecraft:soul_torch", + "id": -268 + }, + { + "name": "minecraft:sparkler", + "id": 636 + }, + { + "name": "minecraft:spawn_egg", + "id": 788 + }, + { + "name": "minecraft:spider_eye", + "id": 300 + }, + { + "name": "minecraft:spider_spawn_egg", + "id": 473 + }, + { + "name": "minecraft:spire_armor_trim_smithing_template", + "id": 727 + }, + { + "name": "minecraft:splash_potion", + "id": 594 + }, + { + "name": "minecraft:sponge", + "id": 19 + }, + { + "name": "minecraft:spore_blossom", + "id": -321 + }, + { + "name": "minecraft:spruce_boat", + "id": 404 + }, + { + "name": "minecraft:spruce_button", + "id": -144 + }, + { + "name": "minecraft:spruce_chest_boat", + "id": 677 + }, + { + "name": "minecraft:spruce_door", + "id": 586 + }, + { + "name": "minecraft:spruce_double_slab", + "id": -809 + }, + { + "name": "minecraft:spruce_fence", + "id": -579 + }, + { + "name": "minecraft:spruce_fence_gate", + "id": 183 + }, + { + "name": "minecraft:spruce_hanging_sign", + "id": -501 + }, + { + "name": "minecraft:spruce_leaves", + "id": -800 + }, + { + "name": "minecraft:spruce_log", + "id": -569 + }, + { + "name": "minecraft:spruce_planks", + "id": -739 + }, + { + "name": "minecraft:spruce_pressure_plate", + "id": -154 + }, + { + "name": "minecraft:spruce_sapling", + "id": -825 + }, + { + "name": "minecraft:spruce_sign", + "id": 609 + }, + { + "name": "minecraft:spruce_slab", + "id": -804 + }, + { + "name": "minecraft:spruce_stairs", + "id": 134 + }, + { + "name": "minecraft:spruce_standing_sign", + "id": -181 + }, + { + "name": "minecraft:spruce_trapdoor", + "id": -149 + }, + { + "name": "minecraft:spruce_wall_sign", + "id": -182 + }, + { + "name": "minecraft:spruce_wood", + "id": -814 + }, + { + "name": "minecraft:spyglass", + "id": 661 + }, + { + "name": "minecraft:squid_spawn_egg", + "id": 477 + }, + { + "name": "minecraft:stained_glass", + "id": 772 + }, + { + "name": "minecraft:stained_glass_pane", + "id": 773 + }, + { + "name": "minecraft:stained_hardened_clay", + "id": 737 + }, + { + "name": "minecraft:standing_banner", + "id": 176 + }, + { + "name": "minecraft:standing_sign", + "id": 63 + }, + { + "name": "minecraft:stick", + "id": 345 + }, + { + "name": "minecraft:sticky_piston", + "id": 29 + }, + { + "name": "minecraft:sticky_piston_arm_collision", + "id": -217 + }, + { + "name": "minecraft:stone", + "id": 1 + }, + { + "name": "minecraft:stone_axe", + "id": 339 + }, + { + "name": "minecraft:stone_block_slab", + "id": 749 + }, + { + "name": "minecraft:stone_block_slab2", + "id": 750 + }, + { + "name": "minecraft:stone_block_slab3", + "id": 751 + }, + { + "name": "minecraft:stone_block_slab4", + "id": 752 + }, + { + "name": "minecraft:stone_brick_double_slab", + "id": -881 + }, + { + "name": "minecraft:stone_brick_slab", + "id": -875 + }, + { + "name": "minecraft:stone_brick_stairs", + "id": 109 + }, + { + "name": "minecraft:stone_brick_wall", + "id": -977 + }, + { + "name": "minecraft:stone_bricks", + "id": 98 + }, + { + "name": "minecraft:stone_button", + "id": 77 + }, + { + "name": "minecraft:stone_hoe", + "id": 355 + }, + { + "name": "minecraft:stone_pickaxe", + "id": 338 + }, + { + "name": "minecraft:stone_pressure_plate", + "id": 70 + }, + { + "name": "minecraft:stone_shovel", + "id": 337 + }, + { + "name": "minecraft:stone_stairs", + "id": 67 + }, + { + "name": "minecraft:stone_sword", + "id": 336 + }, + { + "name": "minecraft:stonebrick", + "id": 747 + }, + { + "name": "minecraft:stonecutter", + "id": 245 + }, + { + "name": "minecraft:stonecutter_block", + "id": -197 + }, + { + "name": "minecraft:stray_spawn_egg", + "id": 489 + }, + { + "name": "minecraft:strider_spawn_egg", + "id": 523 + }, + { + "name": "minecraft:string", + "id": 351 + }, + { + "name": "minecraft:stripped_acacia_log", + "id": -8 + }, + { + "name": "minecraft:stripped_acacia_wood", + "id": -823 + }, + { + "name": "minecraft:stripped_bamboo_block", + "id": -528 + }, + { + "name": "minecraft:stripped_birch_log", + "id": -6 + }, + { + "name": "minecraft:stripped_birch_wood", + "id": -821 + }, + { + "name": "minecraft:stripped_cherry_log", + "id": -535 + }, + { + "name": "minecraft:stripped_cherry_wood", + "id": -545 + }, + { + "name": "minecraft:stripped_crimson_hyphae", + "id": -300 + }, + { + "name": "minecraft:stripped_crimson_stem", + "id": -240 + }, + { + "name": "minecraft:stripped_dark_oak_log", + "id": -9 + }, + { + "name": "minecraft:stripped_dark_oak_wood", + "id": -824 + }, + { + "name": "minecraft:stripped_jungle_log", + "id": -7 + }, + { + "name": "minecraft:stripped_jungle_wood", + "id": -822 + }, + { + "name": "minecraft:stripped_mangrove_log", + "id": -485 + }, + { + "name": "minecraft:stripped_mangrove_wood", + "id": -498 + }, + { + "name": "minecraft:stripped_oak_log", + "id": -10 + }, + { + "name": "minecraft:stripped_oak_wood", + "id": -819 + }, + { + "name": "minecraft:stripped_spruce_log", + "id": -5 + }, + { + "name": "minecraft:stripped_spruce_wood", + "id": -820 + }, + { + "name": "minecraft:stripped_warped_hyphae", + "id": -301 + }, + { + "name": "minecraft:stripped_warped_stem", + "id": -241 + }, + { + "name": "minecraft:structure_block", + "id": 252 + }, + { + "name": "minecraft:structure_void", + "id": 217 + }, + { + "name": "minecraft:sugar", + "id": 442 + }, + { + "name": "minecraft:sugar_cane", + "id": 411 + }, + { + "name": "minecraft:sunflower", + "id": 175 + }, + { + "name": "minecraft:suspicious_gravel", + "id": -573 + }, + { + "name": "minecraft:suspicious_sand", + "id": -529 + }, + { + "name": "minecraft:suspicious_stew", + "id": 625 + }, + { + "name": "minecraft:sweet_berries", + "id": 309 + }, + { + "name": "minecraft:sweet_berry_bush", + "id": -207 + }, + { + "name": "minecraft:tadpole_bucket", + "id": 666 + }, + { + "name": "minecraft:tadpole_spawn_egg", + "id": 665 + }, + { + "name": "minecraft:tall_grass", + "id": -864 + }, + { + "name": "minecraft:tallgrass", + "id": 767 + }, + { + "name": "minecraft:target", + "id": -239 + }, + { + "name": "minecraft:tide_armor_trim_smithing_template", + "id": 724 + }, + { + "name": "minecraft:tinted_glass", + "id": -334 + }, + { + "name": "minecraft:tnt", + "id": 46 + }, + { + "name": "minecraft:tnt_minecart", + "id": 558 + }, + { + "name": "minecraft:torch", + "id": 50 + }, + { + "name": "minecraft:torchflower", + "id": -568 + }, + { + "name": "minecraft:torchflower_crop", + "id": -567 + }, + { + "name": "minecraft:torchflower_seeds", + "id": 318 + }, + { + "name": "minecraft:totem_of_undying", + "id": 601 + }, + { + "name": "minecraft:trader_llama_spawn_egg", + "id": 684 + }, + { + "name": "minecraft:trapdoor", + "id": 96 + }, + { + "name": "minecraft:trapped_chest", + "id": 146 + }, + { + "name": "minecraft:trial_key", + "id": 276 + }, + { + "name": "minecraft:trial_spawner", + "id": -315 + }, + { + "name": "minecraft:trident", + "id": 579 + }, + { + "name": "minecraft:trip_wire", + "id": 132 + }, + { + "name": "minecraft:tripwire_hook", + "id": 131 + }, + { + "name": "minecraft:tropical_fish", + "id": 288 + }, + { + "name": "minecraft:tropical_fish_bucket", + "id": 391 + }, + { + "name": "minecraft:tropical_fish_spawn_egg", + "id": 507 + }, + { + "name": "minecraft:tube_coral", + "id": -131 + }, + { + "name": "minecraft:tube_coral_block", + "id": -132 + }, + { + "name": "minecraft:tube_coral_fan", + "id": -133 + }, + { + "name": "minecraft:tube_coral_wall_fan", + "id": -135 + }, + { + "name": "minecraft:tuff", + "id": -333 + }, + { + "name": "minecraft:tuff_brick_double_slab", + "id": -756 + }, + { + "name": "minecraft:tuff_brick_slab", + "id": -755 + }, + { + "name": "minecraft:tuff_brick_stairs", + "id": -757 + }, + { + "name": "minecraft:tuff_brick_wall", + "id": -758 + }, + { + "name": "minecraft:tuff_bricks", + "id": -754 + }, + { + "name": "minecraft:tuff_double_slab", + "id": -745 + }, + { + "name": "minecraft:tuff_slab", + "id": -744 + }, + { + "name": "minecraft:tuff_stairs", + "id": -746 + }, + { + "name": "minecraft:tuff_wall", + "id": -747 + }, + { + "name": "minecraft:turtle_egg", + "id": -159 + }, + { + "name": "minecraft:turtle_helmet", + "id": 606 + }, + { + "name": "minecraft:turtle_scute", + "id": 605 + }, + { + "name": "minecraft:turtle_spawn_egg", + "id": 513 + }, + { + "name": "minecraft:twisting_vines", + "id": -287 + }, + { + "name": "minecraft:underwater_tnt", + "id": -985 + }, + { + "name": "minecraft:underwater_torch", + "id": 239 + }, + { + "name": "minecraft:undyed_shulker_box", + "id": 205 + }, + { + "name": "minecraft:unknown", + "id": -305 + }, + { + "name": "minecraft:unlit_redstone_torch", + "id": 75 + }, + { + "name": "minecraft:unpowered_comparator", + "id": 149 + }, + { + "name": "minecraft:unpowered_repeater", + "id": 93 + }, + { + "name": "minecraft:vault", + "id": -314 + }, + { + "name": "minecraft:verdant_froglight", + "id": -470 + }, + { + "name": "minecraft:vex_armor_trim_smithing_template", + "id": 723 + }, + { + "name": "minecraft:vex_spawn_egg", + "id": 504 + }, + { + "name": "minecraft:villager_spawn_egg", + "id": 476 + }, + { + "name": "minecraft:vindicator_spawn_egg", + "id": 502 + }, + { + "name": "minecraft:vine", + "id": 106 + }, + { + "name": "minecraft:wall_banner", + "id": 177 + }, + { + "name": "minecraft:wall_sign", + "id": 68 + }, + { + "name": "minecraft:wandering_trader_spawn_egg", + "id": 520 + }, + { + "name": "minecraft:ward_armor_trim_smithing_template", + "id": 721 + }, + { + "name": "minecraft:warden_spawn_egg", + "id": 668 + }, + { + "name": "minecraft:warped_button", + "id": -261 + }, + { + "name": "minecraft:warped_door", + "id": 653 + }, + { + "name": "minecraft:warped_double_slab", + "id": -267 + }, + { + "name": "minecraft:warped_fence", + "id": -257 + }, + { + "name": "minecraft:warped_fence_gate", + "id": -259 + }, + { + "name": "minecraft:warped_fungus", + "id": -229 + }, + { + "name": "minecraft:warped_fungus_on_a_stick", + "id": 654 + }, + { + "name": "minecraft:warped_hanging_sign", + "id": -507 + }, + { + "name": "minecraft:warped_hyphae", + "id": -298 + }, + { + "name": "minecraft:warped_nylium", + "id": -233 + }, + { + "name": "minecraft:warped_planks", + "id": -243 + }, + { + "name": "minecraft:warped_pressure_plate", + "id": -263 + }, + { + "name": "minecraft:warped_roots", + "id": -224 + }, + { + "name": "minecraft:warped_sign", + "id": 651 + }, + { + "name": "minecraft:warped_slab", + "id": -265 + }, + { + "name": "minecraft:warped_stairs", + "id": -255 + }, + { + "name": "minecraft:warped_standing_sign", + "id": -251 + }, + { + "name": "minecraft:warped_stem", + "id": -226 + }, + { + "name": "minecraft:warped_trapdoor", + "id": -247 + }, + { + "name": "minecraft:warped_wall_sign", + "id": -253 + }, + { + "name": "minecraft:warped_wart_block", + "id": -227 + }, + { + "name": "minecraft:water", + "id": 9 + }, + { + "name": "minecraft:water_bucket", + "id": 387 + }, + { + "name": "minecraft:waterlily", + "id": 111 + }, + { + "name": "minecraft:waxed_chiseled_copper", + "id": -764 + }, + { + "name": "minecraft:waxed_copper", + "id": -344 + }, + { + "name": "minecraft:waxed_copper_bulb", + "id": -780 + }, + { + "name": "minecraft:waxed_copper_door", + "id": -788 + }, + { + "name": "minecraft:waxed_copper_grate", + "id": -772 + }, + { + "name": "minecraft:waxed_copper_trapdoor", + "id": -796 + }, + { + "name": "minecraft:waxed_cut_copper", + "id": -351 + }, + { + "name": "minecraft:waxed_cut_copper_slab", + "id": -365 + }, + { + "name": "minecraft:waxed_cut_copper_stairs", + "id": -358 + }, + { + "name": "minecraft:waxed_double_cut_copper_slab", + "id": -372 + }, + { + "name": "minecraft:waxed_exposed_chiseled_copper", + "id": -765 + }, + { + "name": "minecraft:waxed_exposed_copper", + "id": -345 + }, + { + "name": "minecraft:waxed_exposed_copper_bulb", + "id": -781 + }, + { + "name": "minecraft:waxed_exposed_copper_door", + "id": -789 + }, + { + "name": "minecraft:waxed_exposed_copper_grate", + "id": -773 + }, + { + "name": "minecraft:waxed_exposed_copper_trapdoor", + "id": -797 + }, + { + "name": "minecraft:waxed_exposed_cut_copper", + "id": -352 + }, + { + "name": "minecraft:waxed_exposed_cut_copper_slab", + "id": -366 + }, + { + "name": "minecraft:waxed_exposed_cut_copper_stairs", + "id": -359 + }, + { + "name": "minecraft:waxed_exposed_double_cut_copper_slab", + "id": -373 + }, + { + "name": "minecraft:waxed_oxidized_chiseled_copper", + "id": -766 + }, + { + "name": "minecraft:waxed_oxidized_copper", + "id": -446 + }, + { + "name": "minecraft:waxed_oxidized_copper_bulb", + "id": -783 + }, + { + "name": "minecraft:waxed_oxidized_copper_door", + "id": -791 + }, + { + "name": "minecraft:waxed_oxidized_copper_grate", + "id": -775 + }, + { + "name": "minecraft:waxed_oxidized_copper_trapdoor", + "id": -799 + }, + { + "name": "minecraft:waxed_oxidized_cut_copper", + "id": -447 + }, + { + "name": "minecraft:waxed_oxidized_cut_copper_slab", + "id": -449 + }, + { + "name": "minecraft:waxed_oxidized_cut_copper_stairs", + "id": -448 + }, + { + "name": "minecraft:waxed_oxidized_double_cut_copper_slab", + "id": -450 + }, + { + "name": "minecraft:waxed_weathered_chiseled_copper", + "id": -767 + }, + { + "name": "minecraft:waxed_weathered_copper", + "id": -346 + }, + { + "name": "minecraft:waxed_weathered_copper_bulb", + "id": -782 + }, + { + "name": "minecraft:waxed_weathered_copper_door", + "id": -790 + }, + { + "name": "minecraft:waxed_weathered_copper_grate", + "id": -774 + }, + { + "name": "minecraft:waxed_weathered_copper_trapdoor", + "id": -798 + }, + { + "name": "minecraft:waxed_weathered_cut_copper", + "id": -353 + }, + { + "name": "minecraft:waxed_weathered_cut_copper_slab", + "id": -367 + }, + { + "name": "minecraft:waxed_weathered_cut_copper_stairs", + "id": -360 + }, + { + "name": "minecraft:waxed_weathered_double_cut_copper_slab", + "id": -374 + }, + { + "name": "minecraft:wayfinder_armor_trim_smithing_template", + "id": 729 + }, + { + "name": "minecraft:weathered_chiseled_copper", + "id": -762 + }, + { + "name": "minecraft:weathered_copper", + "id": -342 + }, + { + "name": "minecraft:weathered_copper_bulb", + "id": -778 + }, + { + "name": "minecraft:weathered_copper_door", + "id": -786 + }, + { + "name": "minecraft:weathered_copper_grate", + "id": -770 + }, + { + "name": "minecraft:weathered_copper_trapdoor", + "id": -794 + }, + { + "name": "minecraft:weathered_cut_copper", + "id": -349 + }, + { + "name": "minecraft:weathered_cut_copper_slab", + "id": -363 + }, + { + "name": "minecraft:weathered_cut_copper_stairs", + "id": -356 + }, + { + "name": "minecraft:weathered_double_cut_copper_slab", + "id": -370 + }, + { + "name": "minecraft:web", + "id": 30 + }, + { + "name": "minecraft:weeping_vines", + "id": -231 + }, + { + "name": "minecraft:wet_sponge", + "id": -984 + }, + { + "name": "minecraft:wheat", + "id": 359 + }, + { + "name": "minecraft:wheat_seeds", + "id": 313 + }, + { + "name": "minecraft:white_bundle", + "id": 272 + }, + { + "name": "minecraft:white_candle", + "id": -413 + }, + { + "name": "minecraft:white_candle_cake", + "id": -430 + }, + { + "name": "minecraft:white_carpet", + "id": 171 + }, + { + "name": "minecraft:white_concrete", + "id": 236 + }, + { + "name": "minecraft:white_concrete_powder", + "id": 237 + }, + { + "name": "minecraft:white_dye", + "id": 436 + }, + { + "name": "minecraft:white_glazed_terracotta", + "id": 220 + }, + { + "name": "minecraft:white_shulker_box", + "id": 218 + }, + { + "name": "minecraft:white_stained_glass", + "id": 241 + }, + { + "name": "minecraft:white_stained_glass_pane", + "id": 160 + }, + { + "name": "minecraft:white_terracotta", + "id": 159 + }, + { + "name": "minecraft:white_tulip", + "id": -835 + }, + { + "name": "minecraft:white_wool", + "id": 35 + }, + { + "name": "minecraft:wild_armor_trim_smithing_template", + "id": 720 + }, + { + "name": "minecraft:wind_charge", + "id": 277 + }, + { + "name": "minecraft:witch_spawn_egg", + "id": 479 + }, + { + "name": "minecraft:wither_rose", + "id": -216 + }, + { + "name": "minecraft:wither_skeleton_skull", + "id": -965 + }, + { + "name": "minecraft:wither_skeleton_spawn_egg", + "id": 492 + }, + { + "name": "minecraft:wither_spawn_egg", + "id": 536 + }, + { + "name": "minecraft:wolf_armor", + "id": 740 + }, + { + "name": "minecraft:wolf_spawn_egg", + "id": 466 + }, + { + "name": "minecraft:wood", + "id": 775 + }, + { + "name": "minecraft:wooden_axe", + "id": 335 + }, + { + "name": "minecraft:wooden_button", + "id": 143 + }, + { + "name": "minecraft:wooden_door", + "id": 384 + }, + { + "name": "minecraft:wooden_hoe", + "id": 354 + }, + { + "name": "minecraft:wooden_pickaxe", + "id": 334 + }, + { + "name": "minecraft:wooden_pressure_plate", + "id": 72 + }, + { + "name": "minecraft:wooden_shovel", + "id": 333 + }, + { + "name": "minecraft:wooden_slab", + "id": 762 + }, + { + "name": "minecraft:wooden_sword", + "id": 332 + }, + { + "name": "minecraft:wool", + "id": 743 + }, + { + "name": "minecraft:writable_book", + "id": 544 + }, + { + "name": "minecraft:written_book", + "id": 545 + }, + { + "name": "minecraft:yellow_bundle", + "id": 273 + }, + { + "name": "minecraft:yellow_candle", + "id": -417 + }, + { + "name": "minecraft:yellow_candle_cake", + "id": -434 + }, + { + "name": "minecraft:yellow_carpet", + "id": -600 + }, + { + "name": "minecraft:yellow_concrete", + "id": -631 + }, + { + "name": "minecraft:yellow_concrete_powder", + "id": -712 + }, + { + "name": "minecraft:yellow_dye", + "id": 432 + }, + { + "name": "minecraft:yellow_glazed_terracotta", + "id": 224 + }, + { + "name": "minecraft:yellow_shulker_box", + "id": -616 + }, + { + "name": "minecraft:yellow_stained_glass", + "id": -676 + }, + { + "name": "minecraft:yellow_stained_glass_pane", + "id": -646 + }, + { + "name": "minecraft:yellow_terracotta", + "id": -727 + }, + { + "name": "minecraft:yellow_wool", + "id": -558 + }, + { + "name": "minecraft:zoglin_spawn_egg", + "id": 526 + }, + { + "name": "minecraft:zombie_head", + "id": -966 + }, + { + "name": "minecraft:zombie_horse_spawn_egg", + "id": 496 + }, + { + "name": "minecraft:zombie_pigman_spawn_egg", + "id": 475 + }, + { + "name": "minecraft:zombie_spawn_egg", + "id": 474 + }, + { + "name": "minecraft:zombie_villager_spawn_egg", + "id": 505 + } +] \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3a3831044..dc9329b91 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,9 +10,9 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol-connection = "3.0.0.Beta5-20240916.181041-6" -protocol-common = "3.0.0.Beta5-20240916.181041-6" -protocol-codec = "3.0.0.Beta5-20240916.181041-6" +protocol-connection = "3.0.0.Beta5-20241021.154858-12" +protocol-common = "3.0.0.Beta5-20241021.154858-12" +protocol-codec = "3.0.0.Beta5-20241021.154858-12" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" mcprotocollib = "1.21-20241010.155958-24" From 264a914d41f34c48d9a79aaf94d8a2940d51e583 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:41:55 -0400 Subject: [PATCH 397/897] Clean up inventory packet sending --- README.md | 2 +- .../updater/AnvilInventoryUpdater.java | 10 ------- .../updater/ChestInventoryUpdater.java | 8 +----- .../updater/ContainerInventoryUpdater.java | 6 ----- .../updater/CrafterInventoryUpdater.java | 8 ------ .../updater/HorseInventoryUpdater.java | 6 ----- .../inventory/updater/InventoryUpdater.java | 6 ----- .../inventory/updater/UIInventoryUpdater.java | 7 ----- .../inventory/OldSmithingTableTranslator.java | 9 ++++--- .../inventory/PlayerInventoryTranslator.java | 26 ++++++++----------- .../ChestedHorseInventoryTranslator.java | 5 ---- .../entity/JavaEntityEventTranslator.java | 5 ---- .../JavaContainerSetSlotTranslator.java | 12 +++------ .../geysermc/geyser/util/InventoryUtils.java | 10 +++---- gradle/libs.versions.toml | 6 ++--- 15 files changed, 29 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index dec1e9dd1..418bfcdeb 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.30 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.40 and Minecraft Java 1.21/1.21.1. 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/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java index cc98d0ae5..dc532cc62 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 @@ -31,8 +31,6 @@ import net.kyori.adventure.text.Component; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; -import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.GeyserImpl; @@ -80,8 +78,6 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(bedrockSlot); slotPacket.setItem(inventory.getItem(i).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } } @@ -102,8 +98,6 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } else if (lastTargetSlot != javaSlot) { // Update the previous target slot to remove repair cost changes @@ -111,8 +105,6 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(lastTargetSlot)); slotPacket.setItem(inventory.getItem(lastTargetSlot).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } @@ -176,8 +168,6 @@ public class AnvilInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(slot)); slotPacket.setItem(itemData); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java index b28bd23d1..a67f594ab 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java @@ -25,12 +25,10 @@ package org.geysermc.geyser.inventory.updater; -import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; +import lombok.AllArgsConstructor; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; -import lombok.AllArgsConstructor; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -63,8 +61,6 @@ public class ChestInventoryUpdater extends InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(bedrockItems); - contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); } @@ -77,8 +73,6 @@ public class ChestInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(inventory.getBedrockId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java index 224b7d4c9..c9f313f2a 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.inventory.updater; -import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -51,8 +49,6 @@ public class ContainerInventoryUpdater extends InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); - contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); } @@ -65,8 +61,6 @@ public class ContainerInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(inventory.getBedrockId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java index d3135c97e..4474d420c 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/CrafterInventoryUpdater.java @@ -26,8 +26,6 @@ package org.geysermc.geyser.inventory.updater; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; -import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -58,8 +56,6 @@ public class CrafterInventoryUpdater extends InventoryUpdater { contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); - contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); // inventory and hotbar @@ -71,8 +67,6 @@ public class CrafterInventoryUpdater extends InventoryUpdater { contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); - contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); // Crafter result - it doesn't come after the grid, as explained elsewhere. @@ -94,8 +88,6 @@ public class CrafterInventoryUpdater extends InventoryUpdater { packet.setContainerId(containerId); packet.setSlot(translator.javaSlotToBedrock(javaSlot)); packet.setItem(inventory.getItem(javaSlot).getItemData(session)); - packet.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - packet.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(packet); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java index 657c91604..7441e66d0 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.inventory.updater; -import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -51,8 +49,6 @@ public class HorseInventoryUpdater extends InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); - contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); } @@ -65,8 +61,6 @@ public class HorseInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(4); // Horse GUI? slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java index c57f59bfd..68ee334ba 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java @@ -26,8 +26,6 @@ package org.geysermc.geyser.inventory.updater; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; -import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -47,8 +45,6 @@ public class InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); - contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); } @@ -58,8 +54,6 @@ public class InventoryUpdater { slotPacket.setContainerId(ContainerId.INVENTORY); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java index 23cfc79f5..a23385b53 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java @@ -26,9 +26,6 @@ package org.geysermc.geyser.inventory.updater; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; -import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; -import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.session.GeyserSession; @@ -49,8 +46,6 @@ public class UIInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(bedrockSlot); slotPacket.setItem(inventory.getItem(i).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } } @@ -64,8 +59,6 @@ public class UIInventoryUpdater extends InventoryUpdater { slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java index 125614e77..38bb6ddcd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java @@ -28,11 +28,14 @@ package org.geysermc.geyser.translator.inventory; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; 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.DropAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.PlaceAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.SwapAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.TakeAction; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.inventory.BedrockContainerSlot; @@ -140,8 +143,6 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator slotPacket.setContainerId(ContainerId.UI); slotPacket.setSlot(53); slotPacket.setItem(UPGRADE_TEMPLATE.apply(session.getUpstream().getProtocolVersion())); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 65fd87c83..8fd365d7f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -30,17 +30,25 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; 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.CraftCreativeAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.DestroyAction; +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.packet.ContainerClosePacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; -import org.geysermc.geyser.inventory.*; +import org.geysermc.geyser.inventory.BedrockContainerSlot; +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.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.FakeHeadProvider; @@ -84,8 +92,6 @@ public class PlayerInventoryTranslator extends InventoryTranslator { contents[i - 36] = inventory.getItem(i).getItemData(session); } inventoryContentPacket.setContents(Arrays.asList(contents)); - inventoryContentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - inventoryContentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(inventoryContentPacket); // Armor @@ -102,16 +108,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } } armorContentPacket.setContents(Arrays.asList(contents)); - armorContentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - armorContentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(armorContentPacket); // Offhand InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); offhandPacket.setContents(Collections.singletonList(inventory.getItem(45).getItemData(session))); - offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - offhandPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(offhandPacket); } @@ -133,8 +135,6 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setItem(inventory.getItem(i).getItemData(session)); } - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } } @@ -171,15 +171,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setSlot(slot + 27); } slotPacket.setItem(bedrockItem); - slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - slotPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(slotPacket); } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); offhandPacket.setContents(Collections.singletonList(bedrockItem)); - offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - offhandPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(offhandPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java index 363761e47..f1a5723c8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.inventory.horse; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; @@ -95,8 +94,6 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); contentPacket.setContents(Arrays.asList(bedrockItems)); - contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - contentPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(contentPacket); ItemData[] horseItems = new ItemData[chestSize + 1]; @@ -110,8 +107,6 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven InventoryContentPacket horseContentsPacket = new InventoryContentPacket(); horseContentsPacket.setContainerId(inventory.getBedrockId()); horseContentsPacket.setContents(Arrays.asList(horseItems)); - horseContentsPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null)); - horseContentsPacket.setStorageItem(ItemData.AIR); session.sendUpstreamPacket(horseContentsPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index a37ba88b3..6c2e02cd3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -30,9 +30,6 @@ import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; -import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; -import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; -import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; @@ -170,8 +167,6 @@ public class JavaEntityEventTranslator extends PacketTranslator Date: Wed, 23 Oct 2024 03:49:04 +0800 Subject: [PATCH 398/897] API: Expose a GeyserConnection's protocol version (#5083) * Add protocolVersion() to GeyserConnection * specify which protocol --- .../org/geysermc/geyser/api/connection/GeyserConnection.java | 5 +++++ .../main/java/org/geysermc/geyser/session/GeyserSession.java | 5 +++++ gradle.properties | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java index 0a580f975..ede4c1bc4 100644 --- a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java +++ b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java @@ -70,6 +70,11 @@ public interface GeyserConnection extends Connection, CommandSource { */ void closeForm(); + /** + * Gets the Bedrock protocol version of the player. + */ + int protocolVersion(); + /** * @param javaId the Java entity ID to look up. * @return a {@link GeyserEntity} if present in this connection's entity tracker. 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 9c20e9909..b8a991013 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -2229,6 +2229,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return (int) Math.floor(rakSessionCodec.getPing()); } + @Override + public int protocolVersion() { + return upstream.getProtocolVersion(); + } + @Override public void closeForm() { if (!GameProtocol.isPre1_21_2(this)) { diff --git a/gradle.properties b/gradle.properties index 1ee0e12cc..86cf4e922 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,5 +8,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.4.3-SNAPSHOT +version=2.4.4-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From e7ecb55f33abd6e951aeac9ce0b462205cbd3339 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:10:27 -0400 Subject: [PATCH 399/897] Indicate support for Bedrock 1.21.41 --- README.md | 2 +- .../java/org/geysermc/geyser/network/GameProtocol.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 418bfcdeb..3e99a96a7 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.40 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.41 and Minecraft Java 1.21/1.21.1. 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/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index c76958777..c39629917 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -52,7 +52,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() - .minecraftVersion("1.21.40") + .minecraftVersion("1.21.41") .build()); /** @@ -80,10 +80,10 @@ public final class GameProtocol { .minecraftVersion("1.21.20 - 1.21.23") .build())); SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v729.CODEC.toBuilder() - .minecraftVersion("1.21.30/1.21.31") - .build())); + .minecraftVersion("1.21.30/1.21.31") + .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.40") + .minecraftVersion("1.21.40/1.21.41") .build()); } From e78b24830de8a72ce6e66867050d073e66503bd1 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 22 Oct 2024 22:31:37 +0000 Subject: [PATCH 400/897] Improve tag loading and load non-vanilla tags as well (#4849) * Work on new tag system, still largely unfinished * Continue work on new tag system, closer to testing now * Add holderset class for geyser * My IDE did some stuff it shouldn't have done * Add is method for HolderSets to TagCache * Add some documentation * Fix build and slightly adjust documentation * Fix some issues, still broken * Fix more issues with registering vanilla tags, works better now * Fix all issues with vanilla and non-vanilla tags, fix documentation a bit. * Small cleanup * Use IllegalArgumentException instead of asserting and make TagRegistry#getVanillaTags return original map * Generics - still untested * Remove different lookups for vanilla- and non-vanilla tags * Add toNetworkId and fromNetworkId methods to JavaRegistryKey, simplify TagCache * More cleanup, add documentation * Fix registry loading * Rename HolderSet to GeyserHolderSet and address reviews by camotoy * Make holder set reader method not throw an exception, clean up * Make holder set reader warn when failing to read * Add comment to make clearer why a cast is make --------- Co-authored-by: chris --- .../type/living/animal/AnimalEntity.java | 7 +- .../type/living/animal/ArmadilloEntity.java | 4 +- .../type/living/animal/AxolotlEntity.java | 4 +- .../entity/type/living/animal/BeeEntity.java | 4 +- .../type/living/animal/ChickenEntity.java | 4 +- .../entity/type/living/animal/CowEntity.java | 4 +- .../entity/type/living/animal/FoxEntity.java | 4 +- .../entity/type/living/animal/FrogEntity.java | 4 +- .../entity/type/living/animal/GoatEntity.java | 4 +- .../type/living/animal/HoglinEntity.java | 4 +- .../type/living/animal/OcelotEntity.java | 4 +- .../type/living/animal/PandaEntity.java | 4 +- .../entity/type/living/animal/PigEntity.java | 4 +- .../type/living/animal/PolarBearEntity.java | 5 +- .../type/living/animal/RabbitEntity.java | 4 +- .../type/living/animal/SheepEntity.java | 6 +- .../type/living/animal/SnifferEntity.java | 4 +- .../type/living/animal/StriderEntity.java | 4 +- .../type/living/animal/TurtleEntity.java | 4 +- .../animal/horse/AbstractHorseEntity.java | 4 +- .../type/living/animal/horse/CamelEntity.java | 4 +- .../type/living/animal/horse/LlamaEntity.java | 4 +- .../living/animal/tameable/CatEntity.java | 4 +- .../living/animal/tameable/ParrotEntity.java | 3 +- .../living/animal/tameable/WolfEntity.java | 4 +- .../updater/AnvilInventoryUpdater.java | 14 +- .../geyser/item/enchantment/Enchantment.java | 37 +- .../geyser/session/GeyserSession.java | 2 +- .../geyser/session/cache/RegistryCache.java | 48 +-- .../geyser/session/cache/TagCache.java | 140 +++--- .../cache/registry/JavaRegistries.java | 112 +++++ .../cache/registry/JavaRegistryKey.java | 86 ++++ .../geyser/session/cache/tags/BlockTag.java | 399 +++++++++--------- .../session/cache/tags/EnchantmentTag.java | 102 ++--- .../session/cache/tags/GeyserHolderSet.java | 118 ++++++ .../geyser/session/cache/tags/ItemTag.java | 324 +++++++------- .../geyser/session/cache/tags/Tag.java | 35 ++ 37 files changed, 927 insertions(+), 595 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistries.java create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistryKey.java create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/tags/Tag.java 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 b83a85bfb..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; } 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/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/enchantment/Enchantment.java b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java index 301f69a5f..9088d9626 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,23 +25,20 @@ 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. @@ -49,23 +46,23 @@ import java.util.function.ToIntFunction; */ 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()); @@ -86,24 +83,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/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index bf396a3c3..fb64cfc41 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -679,7 +679,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { 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); 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..fcbc7c64c 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 @@ -46,7 +46,9 @@ 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; @@ -74,35 +76,34 @@ import java.util.function.ToIntFunction; @Accessors(fluent = true) @Getter public final class RegistryCache { - private static final Map> DEFAULTS; - private static final Map>> REGISTRIES = new HashMap<>(); + private static final Map, Map> DEFAULTS; + private static final Map, BiConsumer>> REGISTRIES = new HashMap<>(); 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("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); - register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); - register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); - register("banner_pattern", cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); - register("wolf_variant", cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); + register(JavaRegistries.CHAT_TYPE, cache -> cache.chatTypes, ChatDecoration::readChatType); + register(JavaRegistries.DIMENSION_TYPE, cache -> cache.dimensions, JavaDimension::read); + register(JavaRegistries.ENCHANTMENT, cache -> cache.enchantments, Enchantment::read); + register(JavaRegistries.JUKEBOX_SONG, cache -> cache.jukeboxSongs, JukeboxSong::read); + register(JavaRegistries.PAINTING_VARIANT, cache -> cache.paintings, context -> PaintingType.getByName(context.id())); + register(JavaRegistries.TRIM_MATERIAL, cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); + register(JavaRegistries.TRIM_PATTERN, cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); + register(JavaRegistries.BIOME, (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); + register(JavaRegistries.BANNER_PATTERN, cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); + register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); - Map> defaults = new HashMap<>(); + Map, 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); + REGISTRIES.forEach((registry, $) -> { + List rawValues = tag.getCompound(registry.registryKey().asString()).getList("value", NbtType.COMPOUND); Map values = new HashMap<>(); for (NbtMap value : rawValues) { Key name = MinecraftKey.key(value.getString("name")); values.put(name, value.getCompound("element")); } // Can make these maps immutable and as efficient as possible after initialization - defaults.put(key, Map.copyOf(values)); + defaults.put(registry, Map.copyOf(values)); }); DEFAULTS = Map.copyOf(defaults); @@ -137,7 +138,7 @@ public final class RegistryCache { * Loads a registry in, if we are tracking it. */ public void load(ClientboundRegistryDataPacket packet) { - var reader = REGISTRIES.get(packet.getRegistry()); + var reader = REGISTRIES.get(JavaRegistries.fromKey(packet.getRegistry())); if (reader != null) { reader.accept(this, packet.getEntries()); } else { @@ -151,9 +152,8 @@ public final class RegistryCache { * @param reader converts the RegistryEntry NBT into a class file * @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) -> { + private static void register(JavaRegistryKey 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 +172,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())); } @@ -189,8 +189,8 @@ public final class RegistryCache { /** * @param localCacheFunction the int array to set the final values to. */ - private static void register(String registry, BiConsumer localCacheFunction, ToIntFunction reader) { - REGISTRIES.put(MinecraftKey.key(registry), (registryCache, entries) -> { + private static void register(JavaRegistryKey registry, BiConsumer localCacheFunction, ToIntFunction reader) { + REGISTRIES.put(registry, (registryCache, entries) -> { Int2IntMap temp = new Int2IntOpenHashMap(); int greatestId = 0; for (int i = 0; i < entries.size(); i++) { 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..f01ef64c5 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,114 @@ 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); + } } - /** - * @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) { + for (Map.Entry tag : packetTags.entrySet()) { + this.tags.put(new Tag<>(registry, tag.getKey()), tag.getValue()); + } + } + + 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/registry/JavaRegistries.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistries.java new file mode 100644 index 000000000..cb51f488e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistries.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.registry; + +import net.kyori.adventure.key.Key; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; +import org.cloudburstmc.protocol.bedrock.data.TrimPattern; +import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; +import org.geysermc.geyser.inventory.item.BannerPattern; +import org.geysermc.geyser.item.enchantment.Enchantment; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.level.JavaDimension; +import org.geysermc.geyser.level.JukeboxSong; +import org.geysermc.geyser.level.PaintingType; +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 org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType; + +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 CHAT_TYPE = create("chat_type", RegistryCache::chatTypes); + public static final JavaRegistryKey DIMENSION_TYPE = create("dimension_type", RegistryCache::dimensions); + public static final JavaRegistryKey ENCHANTMENT = create("enchantment", RegistryCache::enchantments); + public static final JavaRegistryKey JUKEBOX_SONG = create("jukebox_song", RegistryCache::jukeboxSongs); + public static final JavaRegistryKey PAINTING_VARIANT = create("painting_variant", RegistryCache::paintings); + public static final JavaRegistryKey TRIM_MATERIAL = create("trim_material", RegistryCache::trimMaterials); + public static final JavaRegistryKey TRIM_PATTERN = create("trim_pattern", RegistryCache::trimPatterns); + /** + * This registry should not be used in holder sets, tags, etc. It's simply used as a mapping from Java biomes to Bedrock ones. + */ + public static final JavaRegistryKey BIOME = create("worldgen/biome"); + public static final JavaRegistryKey BANNER_PATTERN = create("banner_pattern", RegistryCache::bannerPatterns); + public static final JavaRegistryKey WOLF_VARIANT = create("wolf_variant", RegistryCache::wolfVariants); + + 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)); + } + + private static JavaRegistryKey create(String key) { + // Cast for ambiguous call + return create(key, (JavaRegistryKey.NetworkSerializer) null, null); + } + + @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) { +} From e00ef21af454722ddf0e13aecf4dfd37ccdb50e9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 22 Oct 2024 23:22:47 -0400 Subject: [PATCH 401/897] Work on recipes --- .../geyser/inventory/recipe/GeyserRecipe.java | 2 +- .../inventory/recipe/GeyserShapedRecipe.java | 7 +- .../recipe/GeyserShapelessRecipe.java | 9 +- .../geysermc/geyser/registry/Registries.java | 21 +- .../registry/loader/RecipeRegistryLoader.java | 76 +++-- .../geyser/session/GeyserSession.java | 7 +- .../java/JavaRecipeBookAddTranslator.java | 273 +++++++++++++++--- .../java/JavaRecipeBookRemoveTranslator.java | 65 +++++ .../JavaContainerSetSlotTranslator.java | 3 + 9 files changed, 365 insertions(+), 98 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookRemoveTranslator.java 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..3037b725e 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 @@ -29,7 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; /** - * 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.Recipe}. */ public interface GeyserRecipe { /** 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..413041ba7 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 @@ -28,13 +28,12 @@ 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; public record GeyserShapedRecipe(int width, int height, Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe { - public GeyserShapedRecipe(ShapedRecipeData data) { - this(data.getWidth(), data.getHeight(), data.getIngredients(), data.getResult()); - } +// public GeyserShapedRecipe(ShapedRecipeData data) { +// this(data.getWidth(), data.getHeight(), data.getIngredients(), data.getResult()); +// } @Override public boolean isShaped() { 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..6b9e36956 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,16 +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.ShapelessRecipeData; -import org.checkerframework.checker.nullness.qual.Nullable; public record GeyserShapelessRecipe(Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe { - public GeyserShapelessRecipe(ShapelessRecipeData data) { - this(data.getIngredients(), data.getResult()); - } +// public GeyserShapelessRecipe(ShapelessRecipeData data) { +// this(data.getIngredients(), data.getResult()); +// } @Override public boolean isShaped() { 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 30d3c0763..3f9ad6815 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -37,10 +37,17 @@ import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.loader.*; +import org.geysermc.geyser.registry.loader.BiomeIdentifierRegistryLoader; +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.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.loader.RecipeRegistryLoader; import org.geysermc.geyser.registry.provider.ProviderSupplier; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ParticleMapping; @@ -54,9 +61,13 @@ 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.*; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; /** * Holds all the common registries in Geyser. @@ -140,7 +151,7 @@ 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 SimpleMappedRegistry> RECIPES = SimpleMappedRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new); + //public static final SimpleMappedRegistry> RECIPES = SimpleMappedRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new); /** * A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys. 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 1af6a8661..f061ed070 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,29 +27,19 @@ 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.Collections; import java.util.List; import java.util.Map; @@ -57,41 +47,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) { - if (true) { - return Collections.emptyMap(); - } - 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()); 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 fb64cfc41..211486963 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -441,10 +441,9 @@ 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; @Setter private Int2ObjectMap craftingRecipes; @@ -694,7 +693,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.playerInventory = new PlayerInventory(); this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); - this.javaToBedrockRecipeIds = new Object2ObjectOpenHashMap<>(); + this.javaToBedrockRecipeIds = new Int2ObjectOpenHashMap<>(); this.lastRecipeNetId = new AtomicInteger(1); this.spawned = false; 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 index 74fb11814..49c62989c 100644 --- 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 @@ -25,57 +25,258 @@ package org.geysermc.geyser.translator.protocol.java; +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.descriptor.DefaultDescriptor; +import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; +import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; import org.cloudburstmc.protocol.bedrock.packet.UnlockedRecipesPacket; +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.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.packet.ingame.clientbound.ClientboundRecipeBookAddPacket; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + @Translator(packet = ClientboundRecipeBookAddPacket.class) public class JavaRecipeBookAddTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundRecipeBookAddPacket packet) { + System.out.println(packet); + int netId = session.getLastRecipeNetId().get(); + Int2ObjectMap> javaToBedrockRecipeIds = session.getJavaToBedrockRecipeIds(); + CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); + // Check if we should set cleanRecipes here or not. + + UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket(); recipesPacket.setAction(packet.isReplace() ? UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED : UnlockedRecipesPacket.ActionType.NEWLY_UNLOCKED); -// List recipes = getBedrockRecipes(session, packet.getEntries()); -// if (recipes.isEmpty() && !packet.isReplace()) { -// // Sending an empty list here packet will crash the client as of 1.20.60 -// return; -// } -// switch (packet.getAction()) { -// case INIT -> { -// recipesPacket.setAction(UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED); -// recipesPacket.getUnlockedRecipes().addAll(getBedrockRecipes(session, packet.getAlreadyKnownRecipes())); -// } -// case ADD -> { -// -// 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); -// } -// } -// session.sendUpstreamPacket(recipesPacket); + + for (ClientboundRecipeBookAddPacket.Entry entry : packet.getEntries()) { + RecipeDisplayEntry contents = entry.contents(); + RecipeDisplay display = contents.display(); + + switch (display.getType()) { + case CRAFTING_SHAPED -> { + ShapedCraftingRecipeDisplay shapedRecipe = (ShapedCraftingRecipeDisplay) display; + Pair pair = translateToOutput(session, shapedRecipe.result()); + if (pair == null || !pair.right().isValid()) { + // Likely modded item Bedrock will complain about + continue; + } + + 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<>(shapedRecipe.ingredients().size()); + for (SlotDisplay input : shapedRecipe.ingredients()) { + ItemDescriptorWithCount[] translated = translateToInput(session, input); + if (translated == null) { + continue; + } + inputs.add(translated); + if (translated.length != 1 || translated[0] != ItemDescriptorWithCount.EMPTY) { + empty = false; + } + complexInputs |= translated.length > 1; + } + if (empty) { + // Crashes Bedrock 1.19.70 otherwise + // Fixes https://github.com/GeyserMC/Geyser/issues/3549 + continue; + } + + if (complexInputs) { + + } else { + String recipeId = Integer.toString(contents.id()); + craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, + shapedRecipe.width(), shapedRecipe.height(), inputs.stream().map(descriptors -> descriptors[0]).toList(), + Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, false, RecipeUnlockingRequirement.INVALID)); + recipesPacket.getUnlockedRecipes().add(recipeId); + javaToBedrockRecipeIds.put(contents.id(), Collections.singletonList(recipeId)); + } + } + case CRAFTING_SHAPELESS -> { + ShapelessCraftingRecipeDisplay shapelessRecipe = (ShapelessCraftingRecipeDisplay) display; + Pair pair = translateToOutput(session, shapelessRecipe.result()); + if (pair == null || !pair.right().isValid()) { + // Likely modded item Bedrock will complain about + continue; + } + + 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(); + } + } + } + } + + System.out.println(craftingDataPacket); + session.sendUpstreamPacket(craftingDataPacket); + session.sendUpstreamPacket(recipesPacket); + session.getLastRecipeNetId().set(netId); + + // Multi-version can mean different Bedrock item IDs + TAG_TO_ITEM_DESCRIPTOR_CACHE.remove(); } -// private List getBedrockRecipes(GeyserSession session, List entry) { -// List recipes = new ArrayList<>(); -// for (String javaIdentifier : javaRecipeIdentifiers) { -// 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. -// if (bedrockRecipes != null) { -// recipes.addAll(bedrockRecipes); -// } + private static final ThreadLocal> TAG_TO_ITEM_DESCRIPTOR_CACHE = ThreadLocal.withInitial(Object2ObjectOpenHashMap::new); + + private ItemDescriptorWithCount[] translateToInput(GeyserSession session, SlotDisplay slotDisplay) { + if (slotDisplay instanceof EmptySlotDisplay) { + return new ItemDescriptorWithCount[] {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(Arrays::stream) + .toArray(ItemDescriptorWithCount[]::new); + } + if (slotDisplay instanceof ItemSlotDisplay itemSlot) { + return new ItemDescriptorWithCount[] {fromItem(session, itemSlot.item())}; + } + if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlot) { + ItemData item = ItemTranslator.translateToBedrock(session, itemStackSlot.itemStack()); + return new ItemDescriptorWithCount[] {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 new ItemDescriptorWithCount[] {ItemDescriptorWithCount.EMPTY}; + } else if (items.length == 1) { + return new ItemDescriptorWithCount[] {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 -> { +// String molang = "q.is_item_name_any('', " +// + Arrays.stream(items).mapToObj(item -> { +// ItemMapping mapping = session.getItemMappings().getMapping(item); +// return "'" + mapping.getBedrockIdentifier() + "'"; +// }).collect(Collectors.joining(", ")) +// + ")"; +// String molang = Arrays.stream(items).mapToObj(item -> { +// ItemMapping mapping = session.getItemMappings().getMapping(item); +// return "q.identifier == '" + mapping.getBedrockIdentifier() + "'"; +// }).collect(Collectors.joining(" || ")); +// if ("minecraft:planks".equals(tag.toString())) { +// String molang = "q.any_tag('minecraft:planks')"; +// return new ItemDescriptorWithCount[] {new ItemDescriptorWithCount(new MolangDescriptor(molang, 10), 1)}; +// } + return null; +// Set itemDescriptors = new HashSet<>(); +// for (int item : key) { +// itemDescriptors.add(fromItem(session, item)); +// } +// return itemDescriptors.toArray(ItemDescriptorWithCount[]::new); + }); + } + } + 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 static ItemDescriptorWithCount[][] combinations(ItemDescriptorWithCount[] itemDescriptors) { +// 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; +// } +// } +// 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 recipes; // } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookRemoveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookRemoveTranslator.java new file mode 100644 index 000000000..27faecef7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookRemoveTranslator.java @@ -0,0 +1,65 @@ +/* + * 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; + +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 = ClientboundRecipeBookRemovePacket.class) +public class JavaRecipeBookRemoveTranslator extends PacketTranslator { + + @Override + 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, int[] javaRecipeIds) { + List recipes = new ArrayList<>(); + 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. + if (bedrockRecipes != null) { + recipes.addAll(bedrockRecipes); + } + } + return recipes; + } +} 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 f5dab4cd0..2ea116de5 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 @@ -109,6 +109,9 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator Date: Wed, 23 Oct 2024 20:40:46 -0400 Subject: [PATCH 402/897] Re-implement stonecutter recipes --- .../geyser/session/GeyserSession.java | 2 +- .../java/JavaUpdateRecipesTranslator.java | 87 ++++++++++++++++++- 2 files changed, 87 insertions(+), 2 deletions(-) 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 211486963..df5c3d7a8 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -451,7 +451,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * 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; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index e6e875791..729ff965b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -25,15 +25,35 @@ package org.geysermc.geyser.translator.protocol.java; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; 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.MultiRecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData; +import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor; +import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; +import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; +import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; +import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +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.MinecraftKey; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemStackSlotDisplay; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket.SelectableRecipe; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.UUID; @@ -84,7 +104,72 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator> 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; + } + 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); + } + + 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()))); + + // 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; + } + 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)); + session.getGeyser().getLogger().info(mapping.getJavaItem().javaIdentifier() + " " + buttonId + " " + recipeNetId); + + // 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. + } + } + + session.sendUpstreamPacket(craftingDataPacket); + session.setStonecutterRecipes(stonecutterRecipeMap); + session.getLastRecipeNetId().set(netId); } // boolean sendTrimRecipes = false; // Map> recipeIDs = session.getJavaToBedrockRecipeIds(); From 29fe033257d78e92cf7f3c957b809599d3f83b06 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 25 Oct 2024 00:55:19 +0800 Subject: [PATCH 403/897] Don't attempt to clear registry that hasn't been loaded yet (#5101) --- core/src/main/java/org/geysermc/geyser/GeyserImpl.java | 4 +++- .../org/geysermc/geyser/registry/DeferredRegistry.java | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 9df1d2189..4672aef5b 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -723,7 +723,9 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { runIfNonNull(newsHandler, NewsHandler::shutdown); runIfNonNull(erosionUnixListener, UnixSocketClientListener::close); - Registries.RESOURCE_PACKS.get().clear(); + if (Registries.RESOURCE_PACKS.loaded()) { + Registries.RESOURCE_PACKS.get().clear(); + } this.setEnabled(false); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java index 6a2f2ae37..ce77261ae 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java @@ -112,6 +112,13 @@ public final class DeferredRegistry implements IRegistry { this.loaded = true; } + /** + * Whether this registry was loaded. + */ + public boolean loaded() { + return this.loaded; + } + /** * Creates a new deferred registry. * From e17ad64d8ca4e5e9b4eff351baee0ebcd0388043 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 24 Oct 2024 13:47:03 -0400 Subject: [PATCH 404/897] Migrate to SERVER-AUTHORITATIVE MOVEMENT dun dun dunnnn --- .../level/physics/CollisionManager.java | 14 +- .../geyser/level/physics/CollisionResult.java | 3 +- .../geyser/network/CodecProcessor.java | 3 +- .../geyser/network/UpstreamPacketHandler.java | 2 +- .../geyser/session/GeyserSession.java | 24 +- .../geyser/session/cache/InputCache.java | 80 +++++++ ...BedrockInventoryTransactionTranslator.java | 73 ++----- ...anslator.java => BedrockBlockActions.java} | 181 ++-------------- .../player/BedrockMovePlayerTranslator.java | 51 +++-- .../player/BedrockPlayerActionTranslator.java | 108 +++++++++ .../BedrockPlayerAuthInputTranslator.java | 205 ++++++++++++++++++ .../java/JavaRecipeBookAddTranslator.java | 150 +++++++------ .../java/JavaUpdateRecipesTranslator.java | 3 +- 13 files changed, 557 insertions(+), 340 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java rename core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/{BedrockActionTranslator.java => BedrockBlockActions.java} (58%) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerActionTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java 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..5c87993df 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,9 +198,9 @@ public class CollisionManager { position = playerBoundingBox.getBottomCenter(); - boolean newOnGround = adjustedMovement.getY() != movement.getY() && movement.getY() < 0 || onGround; + boolean newOnGround = adjustedMovement.getY() != movement.getY() && movement.getY() < 0; // 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 (/*onGround != newOnGround || */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()) { @@ -208,12 +208,12 @@ public class CollisionManager { } } - if (!onGround) { + if (!newOnGround) { // Trim the position to prevent rounding errors that make Java think we are clipping into a block position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ()); } - return position; + return new CollisionResult(position, TriState.byBoolean(newOnGround)); } // TODO: This makes the player look upwards for some reason, rotation values must be wrong diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java index 8ba5f895b..3c8271cd9 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java @@ -25,10 +25,11 @@ package org.geysermc.geyser.level.physics; +import net.kyori.adventure.util.TriState; import org.cloudburstmc.math.vector.Vector3d; /** * Holds the result of a collision check. */ -public record CollisionResult(Vector3d correctedMovement, boolean horizontalCollision) { +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..d5a4dd246 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -71,7 +71,6 @@ 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.PlayerSkinPacket; import org.cloudburstmc.protocol.bedrock.packet.PurchaseReceiptPacket; @@ -318,7 +317,7 @@ 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(PlayerAuthInputPacket.class, ILLEGAL_SERIALIZER) TODO keeping until we determine which packets should replace .updateSerializer(ClientCacheBlobStatusPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(SubClientLoginPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(SubChunkRequestPacket.class, ILLEGAL_SERIALIZER) 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..19e56c8a8 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -290,7 +290,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } @Override - public PacketSignal handle(MovePlayerPacket packet) { + public PacketSignal handle(MovePlayerPacket packet) { // TODO if (session.isLoggingIn()) { SetTitlePacket titlePacket = new SetTitlePacket(); titlePacket.setType(SetTitlePacket.Type.ACTIONBAR); 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 df5c3d7a8..9b9e86bb2 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -161,6 +161,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; @@ -210,7 +211,6 @@ import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.Serverbound 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.player.ServerboundPlayerAbilitiesPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; @@ -276,6 +276,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; @@ -523,12 +524,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 */ @@ -672,6 +667,7 @@ 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); @@ -1266,18 +1262,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(), false, //FIXME - position.getX(), position.getY(), position.getZ()); - sendDownstreamGamePacket(packet); - } - lastMovementTimestamp = System.currentTimeMillis(); - } if (worldBorder.isResizing()) { worldBorder.resize(); @@ -1668,7 +1652,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); 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..b59df0c16 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java @@ -0,0 +1,80 @@ +/* + * 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 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; + + 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; + // TODO when is UP_LEFT, etc. used? + this.inputPacket = this.inputPacket + .withForward(bedrockInput.contains(PlayerAuthInputData.UP)) + .withBackward(bedrockInput.contains(PlayerAuthInputData.DOWN)) + .withLeft(bedrockInput.contains(PlayerAuthInputData.LEFT)) + .withRight(bedrockInput.contains(PlayerAuthInputData.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 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/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 7ed4ac72c..421e082b1 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,7 +41,6 @@ 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.UpdateBlockPacket; import org.geysermc.geyser.entity.EntityDefinitions; @@ -187,7 +185,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator false; }; if (isGodBridging) { - restoreCorrectBlock(session, blockPos, packet); + restoreCorrectBlock(session, blockPos); return; } } @@ -207,7 +205,7 @@ 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: @@ -550,7 +501,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { +import java.util.List; - @Override - public void translate(GeyserSession session, PlayerActionPacket packet) { +final class BedrockBlockActions { + + static void translate(GeyserSession session, List playerActions) { SessionPlayerEntity entity = session.getPlayerEntity(); // Send book update before any player action - if (packet.getAction() != PlayerActionType.RESPAWN) { - session.getBookEditCache().checkForSend(); + session.getBookEditCache().checkForSend(); + + for (PlayerBlockActionData blockActionData : playerActions) { + handle(session, entity, blockActionData); } + } - Vector3i vector = packet.getBlockPosition(); + private static void handle(GeyserSession session, SessionPlayerEntity entity, PlayerBlockActionData blockActionData) { + PlayerActionType action = blockActionData.getAction(); + Vector3i vector = blockActionData.getBlockPosition(); + int blockFace = blockActionData.getFace(); - 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); - } + switch (action) { case DROP_ITEM -> { ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, - vector, Direction.VALUES[packet.getFace()], 0); + vector, Direction.VALUES[blockFace], 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) { @@ -191,9 +114,9 @@ public class BedrockActionTranslator extends PacketTranslator { // 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, - 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) { + 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); @@ -380,9 +244,4 @@ public class BedrockActionTranslator extends PacketTranslator { - @Override - public void translate(GeyserSession session, MovePlayerPacket packet) { +public final class BedrockMovePlayerTranslator { + + 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(); + boolean actualPositionChanged = !entity.getPosition().equals(packet.getPosition()); // Ignore movement packets until Bedrock's position matches the teleported position - if (session.getUnconfirmedTeleport() != null) { + if (session.getUnconfirmedTeleport() != null && actualPositionChanged) { session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityDefinitions.PLAYER.offset(), 0)); return; } @@ -70,7 +69,8 @@ public class BedrockMovePlayerTranslator 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); + } + } + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java new file mode 100644 index 000000000..5465de51c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -0,0 +1,205 @@ +/* + * 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.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.PlayerAuthInputData; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.ItemUseTransaction; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; +import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; +import org.geysermc.geyser.entity.EntityDefinitions; +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.type.Block; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransactionTranslator; +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.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 java.util.Set; + +@Translator(packet = PlayerAuthInputPacket.class) +public class BedrockPlayerAuthInputTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, PlayerAuthInputPacket packet) { + SessionPlayerEntity entity = session.getPlayerEntity(); + session.getInputCache().processInputs(packet); + + BedrockMovePlayerTranslator.translate(session, packet); + + Set inputData = packet.getInputData(); + if (!inputData.isEmpty()) { + 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_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); + } + } + } + } + + 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!"); + } + } +} 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 index 49c62989c..9cb238c71 100644 --- 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 @@ -25,6 +25,7 @@ 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; @@ -32,6 +33,7 @@ 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.SmithingTransformRecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; @@ -52,6 +54,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.RecipeDispla 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; @@ -61,11 +64,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.TagSlot import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipeBookAddPacket; import java.util.ArrayList; -import java.util.Arrays; 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) @@ -104,17 +108,17 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator inputs = new ArrayList<>(shapedRecipe.ingredients().size()); + List> inputs = new ArrayList<>(shapedRecipe.ingredients().size()); for (SlotDisplay input : shapedRecipe.ingredients()) { - ItemDescriptorWithCount[] translated = translateToInput(session, input); + List translated = translateToInput(session, input); if (translated == null) { continue; } inputs.add(translated); - if (translated.length != 1 || translated[0] != ItemDescriptorWithCount.EMPTY) { + if (translated.size() != 1 || translated.get(0) != ItemDescriptorWithCount.EMPTY) { empty = false; } - complexInputs |= translated.length > 1; + complexInputs |= translated.size() > 1; } if (empty) { // Crashes Bedrock 1.19.70 otherwise @@ -123,15 +127,31 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator descriptors[0]).toList(), - Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, false, RecipeUnlockingRequirement.INVALID)); - recipesPacket.getUnlockedRecipes().add(recipeId); - javaToBedrockRecipeIds.put(contents.id(), Collections.singletonList(recipeId)); + System.out.println(inputs); + if (true) continue; + List> processedInputs = Lists.cartesianProduct(inputs); + System.out.println(processedInputs.size()); + if (processedInputs.size() <= 500) { // Do not let us process giant lists. + List bedrockRecipeIds = new ArrayList<>(); + for (int i = 0; i < processedInputs.size(); i++) { + List possibleInput = processedInputs.get(i); + String recipeId = contents.id() + "_" + i; + craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, + shapedRecipe.width(), shapedRecipe.height(), possibleInput, + Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, false, RecipeUnlockingRequirement.INVALID)); + recipesPacket.getUnlockedRecipes().add(recipeId); + bedrockRecipeIds.add(recipeId); + } + javaToBedrockRecipeIds.put(contents.id(), bedrockRecipeIds); + continue; + } } + String recipeId = Integer.toString(contents.id()); + craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, + shapedRecipe.width(), shapedRecipe.height(), inputs.stream().map(descriptors -> descriptors.get(0)).toList(), + Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, false, RecipeUnlockingRequirement.INVALID)); + recipesPacket.getUnlockedRecipes().add(recipeId); + javaToBedrockRecipeIds.put(contents.id(), Collections.singletonList(recipeId)); } case CRAFTING_SHAPELESS -> { ShapelessCraftingRecipeDisplay shapelessRecipe = (ShapelessCraftingRecipeDisplay) display; @@ -147,6 +167,42 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator { + if (true) { + System.out.println(display); + 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); + } } } @@ -159,11 +215,11 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator> TAG_TO_ITEM_DESCRIPTOR_CACHE = ThreadLocal.withInitial(Object2ObjectOpenHashMap::new); + private static final ThreadLocal>> TAG_TO_ITEM_DESCRIPTOR_CACHE = ThreadLocal.withInitial(Object2ObjectOpenHashMap::new); - private ItemDescriptorWithCount[] translateToInput(GeyserSession session, SlotDisplay slotDisplay) { + private List translateToInput(GeyserSession session, SlotDisplay slotDisplay) { if (slotDisplay instanceof EmptySlotDisplay) { - return new ItemDescriptorWithCount[] {ItemDescriptorWithCount.EMPTY}; + return Collections.singletonList(ItemDescriptorWithCount.EMPTY); } if (slotDisplay instanceof CompositeSlotDisplay composite) { if (composite.contents().size() == 1) { @@ -172,23 +228,23 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator translateToInput(session, subDisplay)) .filter(Objects::nonNull) - .flatMap(Arrays::stream) - .toArray(ItemDescriptorWithCount[]::new); + .flatMap(List::stream) + .toList(); } if (slotDisplay instanceof ItemSlotDisplay itemSlot) { - return new ItemDescriptorWithCount[] {fromItem(session, itemSlot.item())}; + return Collections.singletonList(fromItem(session, itemSlot.item())); } if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlot) { ItemData item = ItemTranslator.translateToBedrock(session, itemStackSlot.itemStack()); - return new ItemDescriptorWithCount[] {ItemDescriptorWithCount.fromItem(item)}; + 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 new ItemDescriptorWithCount[] {ItemDescriptorWithCount.EMPTY}; + return Collections.singletonList(ItemDescriptorWithCount.EMPTY); } else if (items.length == 1) { - return new ItemDescriptorWithCount[] {fromItem(session, items[0])}; + 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) @@ -205,14 +261,14 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator itemDescriptors = new HashSet<>(); -// for (int item : key) { -// itemDescriptors.add(fromItem(session, item)); -// } -// return itemDescriptors.toArray(ItemDescriptorWithCount[]::new); + + Set itemDescriptors = new HashSet<>(); + for (int item : key) { + itemDescriptors.add(fromItem(session, item)); + } + return new ArrayList<>(itemDescriptors); // This, or a list from the start with contains -> add? }); } } @@ -243,40 +299,4 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator 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; -// } -// } -// 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(); -// } -// } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 729ff965b..de62fb922 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -154,10 +154,9 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Date: Fri, 25 Oct 2024 02:15:51 +0800 Subject: [PATCH 405/897] Initial 1.21.3 changes for mod platforms --- .../platform/fabric/GeyserFabricBootstrap.java | 4 ++-- .../mod/fabric/src/main/resources/fabric.mod.json | 4 ++-- .../platform/neoforge/GeyserNeoForgeBootstrap.java | 8 +++++--- .../platform/mod/GeyserModCompressionDisabler.java | 4 ++-- .../platform/mod/GeyserModUpdateListener.java | 4 ++-- .../platform/mod/world/GeyserModWorldManager.java | 4 ++-- ...geyser.modrinth-uploading-conventions.gradle.kts | 2 +- core/build.gradle.kts | 4 ++++ core/src/main/resources/mappings | 2 +- gradle.properties | 5 ++++- gradle/libs.versions.toml | 13 +++++++------ 11 files changed, 32 insertions(+), 22 deletions(-) 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/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..ec41a0d79 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 @@ -84,7 +84,7 @@ public class GeyserModWorldManager extends GeyserWorldManager { } Level level = player.level(); - if (y < level.getMinBuildHeight()) { + if (y < level.getMinY()) { return 0; } @@ -93,7 +93,7 @@ public class GeyserModWorldManager extends GeyserWorldManager { 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/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..3c0d102f7 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 @@ -12,7 +12,7 @@ modrinth { 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/build.gradle.kts b/core/build.gradle.kts index b0ea5fdf6..ff1de4dc0 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -6,6 +6,10 @@ plugins { id("io.freefair.lombok") } +tasks.test { + enabled = false +} + dependencies { constraints { implementation(libs.raknet) // Ensure protocol does not override the RakNet version diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 93f207e7e..4594e8f88 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 93f207e7e9d73f58a7c8902f7deda9dcb0524c8e +Subproject commit 4594e8f88738d2e623d0854a8831b9033e60154a diff --git a/gradle.properties b/gradle.properties index 1ee0e12cc..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.3-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 e5582e5c1..a88862965 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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 @@ -105,7 +105,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" } @@ -120,7 +120,8 @@ guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } minecraftauth = { group = "net.raphimc", name = "MinecraftAuth", version.ref = "minecraftauth" } -mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" } +#mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" } +mcprotocollib = { group = "com.github.geysermc", name = "mcprotocollib", version = "feature~1.21.2-SNAPSHOT"} raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } From 787dc244c86531bc8ad19f6b888129be143500e0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 24 Oct 2024 19:27:12 -0400 Subject: [PATCH 406/897] onGround works --- .../level/physics/CollisionManager.java | 78 +++++++++---------- .../player/BedrockMovePlayerTranslator.java | 17 ++-- .../org/geysermc/geyser/util/BlockUtils.java | 4 - 3 files changed, 46 insertions(+), 53 deletions(-) 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 5c87993df..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 @@ -198,22 +198,22 @@ public class CollisionManager { position = playerBoundingBox.getBottomCenter(); - boolean newOnGround = adjustedMovement.getY() != movement.getY() && movement.getY() < 0; + 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); } } - if (!newOnGround) { + if (!onGround) { // Trim the position to prevent rounding errors that make Java think we are clipping into a block position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ()); } - return new CollisionResult(position, TriState.byBoolean(newOnGround)); + 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/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java index 22732ad01..a22c44089 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/BedrockMovePlayerTranslator.java @@ -48,14 +48,17 @@ public final class BedrockMovePlayerTranslator { SessionPlayerEntity entity = session.getPlayerEntity(); if (!session.isSpawned()) return; - // Send book update before the player moves - session.getBookEditCache().checkForSend(); - boolean actualPositionChanged = !entity.getPosition().equals(packet.getPosition()); - // Ignore movement packets until Bedrock's position matches the teleported position - if (session.getUnconfirmedTeleport() != null && actualPositionChanged) { - session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityDefinitions.PLAYER.offset(), 0)); - return; + + if (actualPositionChanged) { + // 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; + } } if (entity.getBedPosition() != null) { 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() { } } From 67dbd869e4774ce89edbd9166883373268e4578d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 24 Oct 2024 19:39:45 -0400 Subject: [PATCH 407/897] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 418bfcdeb..9e53b1d85 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.40 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.40 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. From 6331cb6d586d1a19bf9d0daabb535d82c9a58e29 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 24 Oct 2024 19:52:18 -0400 Subject: [PATCH 408/897] Fix pulling skulls/heads from creative inventory --- .../populator/ItemRegistryPopulator.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 12b5ebb0e..0b61c7999 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -33,7 +33,13 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import it.unimi.dsi.fastutil.objects.*; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -66,10 +72,22 @@ import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.*; +import org.geysermc.geyser.registry.type.BlockMappings; +import org.geysermc.geyser.registry.type.GeyserBedrockBlock; +import org.geysermc.geyser.registry.type.GeyserMappingItem; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.registry.type.NonVanillaItemRegistration; +import org.geysermc.geyser.registry.type.PaletteItem; import java.io.InputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; /** @@ -96,7 +114,13 @@ public class ItemRegistryPopulator { 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())); - paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), Collections.emptyMap(), (item, mapping) -> { + String identifier = item.javaIdentifier(); + if (identifier.endsWith("_head") || identifier.endsWith("_skull")) { + return mapping.withBedrockIdentifier(item.javaIdentifier()); + } + return mapping; + })); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); From 2025a2dc3ac9c13853642cb12f078588ede1845e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:41:35 -0400 Subject: [PATCH 409/897] Fix teleport packets; implement new inventory packets --- .../geysermc/geyser/entity/type/Entity.java | 14 +++-- .../geyser/inventory/GeyserItemStack.java | 3 + .../entity/player/BedrockBlockActions.java | 1 - .../JavaEntityPositionSyncTranslator.java | 2 +- .../player/JavaPlayerPositionTranslator.java | 12 ++-- .../JavaContainerSetSlotTranslator.java | 11 +--- .../JavaSetCursorItemTranslator.java | 44 +++++++++++++ .../JavaSetPlayerInventoryTranslator.java | 61 +++++++++++++++++++ .../geysermc/geyser/util/InventoryUtils.java | 56 +++++++++-------- 9 files changed, 158 insertions(+), 46 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaSetCursorItemTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaSetPlayerInventoryTranslator.java 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..7f1eca8d6 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; 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..b843b3d4d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -164,6 +164,9 @@ public class GeyserItemStack { } 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/translator/protocol/bedrock/entity/player/BedrockBlockActions.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java index 0d4da1cb1..8a56915fb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java @@ -209,7 +209,6 @@ final class BedrockBlockActions { 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. diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityPositionSyncTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityPositionSyncTranslator.java index ecc153ce0..fd7fa09ca 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityPositionSyncTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityPositionSyncTranslator.java @@ -47,6 +47,6 @@ public class JavaEntityPositionSyncTranslator 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/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index 947f7ed9a..3b99d5e47 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -49,7 +49,6 @@ 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.text.ChatColor; @@ -305,14 +304,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 +364,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 +382,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); } /** From 774d3670c5a193f1807b4e5a376703baccfd55e4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 26 Oct 2024 01:27:55 -0400 Subject: [PATCH 410/897] Horses are still weird, but boats are mostly working --- .../geysermc/geyser/entity/type/Entity.java | 5 - .../entity/vehicle/VehicleComponent.java | 1 - .../geyser/session/GeyserSession.java | 6 - .../geyser/session/cache/InputCache.java | 10 ++ .../geyser/session/cache/TeleportCache.java | 2 +- .../BedrockMoveEntityAbsoluteTranslator.java | 8 +- .../bedrock/BedrockPlayerInputTranslator.java | 41 ------- .../player/BedrockMovePlayerTranslator.java | 27 ++--- .../BedrockPlayerAuthInputTranslator.java | 103 +++++++++++++++++- .../org/geysermc/geyser/util/MathUtils.java | 11 ++ 10 files changed, 138 insertions(+), 76 deletions(-) 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 7f1eca8d6..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 @@ -701,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/vehicle/VehicleComponent.java b/core/src/main/java/org/geysermc/geyser/entity/vehicle/VehicleComponent.java index 4f4a46dc9..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 @@ -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/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 9b9e86bb2..dd8fdd59b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -524,12 +524,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private boolean placedBucket; - /** - * 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. 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 index b59df0c16..c666ded64 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.session.cache; +import lombok.Getter; +import lombok.Setter; import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData; import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; import org.geysermc.geyser.session.GeyserSession; @@ -37,6 +39,10 @@ public final class InputCache { 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; public InputCache(GeyserSession session) { this.session = session; @@ -61,6 +67,10 @@ public final class InputCache { } } + public boolean wasJumping() { + return this.inputPacket.isJump(); + } + public void markPositionPacketSent() { this.ticksSinceLastMovePacket = 0; } 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/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java index f2d69d51c..81b06c87d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java @@ -42,17 +42,15 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator= 100) { - Vector3f vehiclePosition = vehicle.getPosition(); - - if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) { - // Remove some Y position to prevents boats flying up - vehiclePosition = vehiclePosition.down(vehicle.getDefinition().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/BedrockMovePlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java index a22c44089..1940258e4 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/BedrockMovePlayerTranslator.java @@ -31,7 +31,6 @@ 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; @@ -48,17 +47,17 @@ public final class BedrockMovePlayerTranslator { SessionPlayerEntity entity = session.getPlayerEntity(); if (!session.isSpawned()) return; + // 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(); - - // 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; - } } if (entity.getBedPosition() != null) { @@ -72,9 +71,11 @@ public final class BedrockMovePlayerTranslator { float pitch = packet.getRotation().getX(); float headYaw = packet.getRotation().getY(); - // shouldSendPositionReminder also increments a tick counter, so make sure it's always called. - boolean positionChanged = session.getInputCache().shouldSendPositionReminder() || actualPositionChanged; - boolean rotationChanged = entity.getYaw() != yaw || entity.getPitch() != pitch || entity.getHeadYaw() != headYaw; + boolean hasVehicle = entity.getVehicle() != null; + + // shouldSendPositionReminder also increments a tick counter, so make sure it's always called unless the player is on a vehicle. + boolean positionChanged = !hasVehicle && session.getInputCache().shouldSendPositionReminder() || actualPositionChanged; + boolean rotationChanged = hasVehicle || (entity.getYaw() != yaw || entity.getPitch() != pitch || entity.getHeadYaw() != headYaw); if (session.getLookBackScheduledFuture() != null) { // Resend the rotation if it was changed by Geyser @@ -99,12 +100,6 @@ public final class BedrockMovePlayerTranslator { session.sendDownstreamGamePacket(playerRotationPacket); } else if (positionChanged) { - // World border collision will be handled by client vehicle - if (!(entity.getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) - && session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) { - return; - } - if (isValidMove(session, entity.getPosition(), packet.getPosition())) { CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT)); if (result != null) { // A null return value cancels the packet diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java index 5465de51c..0889579c2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; +import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; @@ -36,19 +37,25 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; 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.ItemFrameEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; +import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransactionTranslator; +import org.geysermc.geyser.util.MathUtils; 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.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.level.ServerboundMoveVehiclePacket; 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; @@ -57,13 +64,17 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.Serv import java.util.Set; @Translator(packet = PlayerAuthInputPacket.class) -public class BedrockPlayerAuthInputTranslator extends PacketTranslator { +public final class BedrockPlayerAuthInputTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, PlayerAuthInputPacket packet) { SessionPlayerEntity entity = session.getPlayerEntity(); + + boolean wasJumping = session.getInputCache().wasJumping(); session.getInputCache().processInputs(packet); + processVehicleInput(session, packet, wasJumping); + BedrockMovePlayerTranslator.translate(session, packet); Set inputData = packet.getInputData(); @@ -202,4 +213,94 @@ public class BedrockPlayerAuthInputTranslator extends PacketTranslator truncated ? truncated + 1 : truncated; } + /** + * Round the given float to the previous whole number + * + * @param floatNumber Float to round + * @return Rounded number + */ + public static int floor(float floatNumber) { + int truncated = (int) floatNumber; + return floatNumber < truncated ? truncated - 1 : truncated; + } + /** * If number is greater than the max, set it to max, and if number is lower than low, set it to low. * From 9d2d12b87bb84528968f01546388b7f56113e803 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 26 Oct 2024 01:41:23 -0400 Subject: [PATCH 411/897] Re-implement steering indicators --- .../geyser/entity/type/BoatEntity.java | 7 + .../bedrock/BedrockAnimateTranslator.java | 70 ++++---- .../BedrockPlayerAuthInputTranslator.java | 149 +++++++++--------- 3 files changed, 111 insertions(+), 115 deletions(-) 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 9312d83f5..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 @@ -39,6 +39,7 @@ 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.player.Hand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket; import java.util.UUID; @@ -182,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; 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..487c3ef75 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,32 @@ 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); - } + System.out.println("wewewewewewewewewewewe"); + 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/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java index 0889579c2..a0c874743 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -78,83 +78,86 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator inputData = packet.getInputData(); - if (!inputData.isEmpty()) { - 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); + 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_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); + 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_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); } } + 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) { From c9eeed905bb87168308d9d618008b330465b1dbd Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 26 Oct 2024 13:24:15 -0400 Subject: [PATCH 412/897] Fix horse movement --- .../player/BedrockPlayerAuthInputTranslator.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java index a0c874743..9f9d061e1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -153,11 +153,13 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator sendPlayerGlideToggle(session, entity); } } - 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)); + 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) { @@ -228,7 +230,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator Date: Sat, 26 Oct 2024 23:48:31 -0400 Subject: [PATCH 413/897] Implement shapeless/complex recipes; fix crawling --- .../geysermc/geyser/entity/type/Entity.java | 1 + .../geyser/network/UpstreamPacketHandler.java | 7 + .../geyser/session/GeyserSession.java | 18 ++- .../bedrock/BedrockAnimateTranslator.java | 1 - .../entity/player/BedrockBlockActions.java | 40 +---- .../player/BedrockPlayerActionTranslator.java | 13 ++ .../BedrockPlayerAuthInputTranslator.java | 15 +- .../java/JavaRecipeBookAddTranslator.java | 148 ++++++++++-------- 8 files changed, 134 insertions(+), 109 deletions(-) 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 0d3214709..2ad89dd2f 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 @@ -45,6 +45,7 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.GeyserDirtyMetadata; import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager; +import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; 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 19e56c8a8..b797eb811 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -41,6 +41,7 @@ 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; @@ -64,6 +65,7 @@ import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.PendingMicrosoftAuthentication; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.LoginEncryptionUtils; import org.geysermc.geyser.util.MathUtils; @@ -94,6 +96,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } private PacketSignal translateAndDefault(BedrockPacket packet) { + if (packet instanceof PlayerAuthInputPacket) { + //System.out.println(packet); + } else { + System.out.println(ChatColor.toANSI(ChatColor.GREEN) + packet + ChatColor.ANSI_RESET); + } Registries.BEDROCK_PACKET_TRANSLATORS.translate(packet.getClass(), packet, session); return PacketSignal.HANDLED; // PacketSignal.UNHANDLED will log a WARN publicly } 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 dd8fdd59b..1ca127657 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1371,14 +1371,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(); } 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 487c3ef75..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 @@ -44,7 +44,6 @@ public class BedrockAnimateTranslator extends PacketTranslator { return; } - System.out.println("wewewewewewewewewewewe"); if (packet.getAction() == AnimatePacket.Action.SWING_ARM) { session.armSwingPending(); // Delay so entity damage can be processed first diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java index 8a56915fb..f1b91a0a5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java @@ -31,14 +31,10 @@ 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.AnimatePacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; -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.type.Block; @@ -49,7 +45,6 @@ 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.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; @@ -57,24 +52,21 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractActio 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 org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import java.util.List; final class BedrockBlockActions { static void translate(GeyserSession session, List playerActions) { - SessionPlayerEntity entity = session.getPlayerEntity(); - // Send book update before any player action session.getBookEditCache().checkForSend(); for (PlayerBlockActionData blockActionData : playerActions) { - handle(session, entity, blockActionData); + handle(session, blockActionData); } } - private static void handle(GeyserSession session, SessionPlayerEntity entity, PlayerBlockActionData blockActionData) { + private static void handle(GeyserSession session, PlayerBlockActionData blockActionData) { PlayerActionType action = blockActionData.getAction(); Vector3i vector = blockActionData.getBlockPosition(); int blockFace = blockActionData.getFace(); @@ -198,34 +190,6 @@ final class BedrockBlockActions { // 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 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); - } - } } } 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 index 39f773418..797505e99 100644 --- 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 @@ -28,6 +28,7 @@ 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; @@ -103,6 +104,18 @@ public class BedrockPlayerActionTranslator extends PacketTranslator { + 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/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java index 9f9d061e1..93e4cb92a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -49,6 +49,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransactionTranslator; +import org.geysermc.geyser.util.CooldownUtils; import org.geysermc.geyser.util.MathUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; @@ -65,18 +66,23 @@ import java.util.Set; @Translator(packet = PlayerAuthInputPacket.class) public final class BedrockPlayerAuthInputTranslator extends PacketTranslator { + private Set data = Set.of(); @Override public void translate(GeyserSession session, PlayerAuthInputPacket packet) { + if (!data.equals(packet.getInputData())) { + System.out.println(data); + this.data = packet.getInputData(); + } SessionPlayerEntity entity = session.getPlayerEntity(); boolean wasJumping = session.getInputCache().wasJumping(); session.getInputCache().processInputs(packet); - processVehicleInput(session, packet, wasJumping); - BedrockMovePlayerTranslator.translate(session, packet); + processVehicleInput(session, packet, wasJumping); + Set inputData = packet.getInputData(); for (PlayerAuthInputData input : inputData) { switch (input) { @@ -110,6 +116,8 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator 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) { @@ -151,6 +159,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator sendPlayerGlideToggle(session, entity); + case MISSED_SWING -> CooldownUtils.sendCooldown(session); // Java edition sends a cooldown when hitting air. } } if (entity.getVehicle() instanceof BoatEntity) { @@ -249,7 +258,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator> javaToBedrockRecipeIds = session.getJavaToBedrockRecipeIds(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); - // Check if we should set cleanRecipes here or not. - UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket(); recipesPacket.setAction(packet.isReplace() ? UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED : UnlockedRecipesPacket.ActionType.NEWLY_UNLOCKED); @@ -94,78 +93,42 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator { ShapedCraftingRecipeDisplay shapedRecipe = (ShapedCraftingRecipeDisplay) display; - Pair pair = translateToOutput(session, shapedRecipe.result()); - if (pair == null || !pair.right().isValid()) { - // Likely modded item Bedrock will complain about + var bedrockRecipes = combinations(session, display, shapedRecipe.ingredients()); + if (bedrockRecipes == null) { continue; } - - 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(); + List bedrockRecipeIds = new ArrayList<>(); + ItemData output = bedrockRecipes.right(); + List> left = bedrockRecipes.left(); + for (int i = 0; i < left.size(); i++) { + List inputs = left.get(i); + String recipeId = contents.id() + "_" + i; + craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, + shapedRecipe.width(), shapedRecipe.height(), inputs, + Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, false, RecipeUnlockingRequirement.INVALID)); + recipesPacket.getUnlockedRecipes().add(recipeId); + bedrockRecipeIds.add(recipeId); } - - boolean empty = true; - boolean complexInputs = false; - List> inputs = new ArrayList<>(shapedRecipe.ingredients().size()); - for (SlotDisplay input : shapedRecipe.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 - continue; - } - - if (complexInputs) { - System.out.println(inputs); - if (true) continue; - List> processedInputs = Lists.cartesianProduct(inputs); - System.out.println(processedInputs.size()); - if (processedInputs.size() <= 500) { // Do not let us process giant lists. - List bedrockRecipeIds = new ArrayList<>(); - for (int i = 0; i < processedInputs.size(); i++) { - List possibleInput = processedInputs.get(i); - String recipeId = contents.id() + "_" + i; - craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, - shapedRecipe.width(), shapedRecipe.height(), possibleInput, - Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, false, RecipeUnlockingRequirement.INVALID)); - recipesPacket.getUnlockedRecipes().add(recipeId); - bedrockRecipeIds.add(recipeId); - } - javaToBedrockRecipeIds.put(contents.id(), bedrockRecipeIds); - continue; - } - } - String recipeId = Integer.toString(contents.id()); - craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, - shapedRecipe.width(), shapedRecipe.height(), inputs.stream().map(descriptors -> descriptors.get(0)).toList(), - Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, false, RecipeUnlockingRequirement.INVALID)); - recipesPacket.getUnlockedRecipes().add(recipeId); - javaToBedrockRecipeIds.put(contents.id(), Collections.singletonList(recipeId)); + javaToBedrockRecipeIds.put(contents.id(), List.copyOf(bedrockRecipeIds)); } case CRAFTING_SHAPELESS -> { ShapelessCraftingRecipeDisplay shapelessRecipe = (ShapelessCraftingRecipeDisplay) display; - Pair pair = translateToOutput(session, shapelessRecipe.result()); - if (pair == null || !pair.right().isValid()) { - // Likely modded item Bedrock will complain about + var bedrockRecipes = combinations(session, display, shapelessRecipe.ingredients()); + if (bedrockRecipes == null) { continue; } - - 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(); + List bedrockRecipeIds = new ArrayList<>(); + ItemData output = bedrockRecipes.right(); + List> left = bedrockRecipes.left(); + for (int i = 0; i < left.size(); i++) { + List inputs = left.get(i); + String recipeId = contents.id() + "_" + i; + craftingDataPacket.getCraftingData().add(ShapelessRecipeData.shapeless(recipeId, + inputs, Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, netId++, RecipeUnlockingRequirement.INVALID)); + recipesPacket.getUnlockedRecipes().add(recipeId); + bedrockRecipeIds.add(recipeId); } + javaToBedrockRecipeIds.put(contents.id(), List.copyOf(bedrockRecipeIds)); } case SMITHING -> { if (true) { @@ -299,4 +262,59 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator>, 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 + 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) { + System.out.println(inputs); + 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 + ); + } } From d6d19b02b204ef21f74b203cf26badb36f42ec46 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 27 Oct 2024 22:53:56 +0100 Subject: [PATCH 414/897] Fix #5089 and don't auto-load Registries (#5093) * Fix #5089 and made Registries instance based * Instead of using instance based Registries, manually initialize them * Address review * Commit this too pls --- .../geyser/entity/EntityDefinition.java | 8 +- .../geyser/entity/EntityDefinitions.java | 6 +- .../geyser/entity/GeyserDirtyMetadata.java | 10 +- .../entity/type/living/ArmorStandEntity.java | 8 + .../entity/type/player/PlayerEntity.java | 21 +- .../geysermc/geyser/registry/Registries.java | 41 ++- .../geysermc/geyser/registry/Registry.java | 20 +- .../loader/PotionMixRegistryLoader.java | 2 +- .../registry/loader/RegistryLoaderHolder.java | 33 ++ .../org/geysermc/geyser/scoreboard/Team.java | 11 + .../geyser/session/cache/EntityCache.java | 11 +- .../JavaPlayerInfoUpdateTranslator.java | 4 +- .../entity/spawn/JavaAddEntityTranslator.java | 28 +- .../JavaSetDisplayObjectiveTranslator.java | 2 +- .../org/geysermc/geyser/util/EntityUtils.java | 2 +- .../geyser/util/EnvironmentUtils.java | 2 +- .../network/NameVisibilityScoreboardTest.java | 42 +-- .../network/ScoreboardIssueTests.java | 170 +++++++++- .../BasicBelownameScoreboardTests.java | 36 +- .../BasicPlayerlistScoreboardTests.java | 31 +- .../server/CubecraftScoreboardTest.java | 313 +++++++----------- .../sidebar/BasicSidebarScoreboardTests.java | 35 +- .../OrderAndLimitSidebarScoreboardTests.java | 112 +++---- .../VanillaSidebarScoreboardTests.java | 52 +-- .../scoreboard/network/util/AssertUtils.java | 13 +- .../network/util/GeyserMockContext.java | 19 +- .../util/GeyserMockContextScoreboard.java | 18 +- 27 files changed, 626 insertions(+), 424 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java index ea3950bd4..5b4dc0969 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java @@ -37,7 +37,6 @@ import org.geysermc.geyser.entity.properties.GeyserEntityProperties; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.entity.EntityMetadataTranslator; -import org.geysermc.geyser.util.EnvironmentUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; @@ -146,13 +145,8 @@ public record EntityDefinition(EntityFactory factory, Entit return this; } - /** - * Build the given entity. If a testing environment has been discovered the entity is not registered, - * otherwise it is. This is to prevent all the registries from loading, which will fail (and should - * not be loaded) while testing - */ public EntityDefinition build() { - return build(!EnvironmentUtils.isUnitTesting); + return build(true); } /** 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 39357eb60..391130146 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -145,7 +145,6 @@ import org.geysermc.geyser.entity.type.living.monster.raid.VindicatorEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.EnvironmentUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; @@ -1122,10 +1121,7 @@ public final class EntityDefinitions { .identifier("minecraft:armor_stand") // Emulated .build(false); // Never sent over the network - // causes the registries to load - if (!EnvironmentUtils.isUnitTesting) { - 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 - } + 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 } public static void init() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java b/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java index bc567ab91..1ee84f4b5 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java +++ b/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java @@ -32,7 +32,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType; import java.util.Map; /** - * A write-only wrapper for temporarily storing entity metadata that will be sent to Bedrock. + * A wrapper for temporarily storing entity metadata that will be sent to Bedrock. */ public final class GeyserDirtyMetadata { private final Map, Object> metadata = new Object2ObjectLinkedOpenHashMap<>(); @@ -53,6 +53,14 @@ public final class GeyserDirtyMetadata { return !metadata.isEmpty(); } + /** + * Intended for testing purposes only + */ + public T get(EntityDataType entityData) { + //noinspection unchecked + return (T) metadata.get(entityData); + } + @Override public String toString() { return metadata.toString(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index d057f09c7..e1c82345f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type.living; import lombok.Getter; import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -36,6 +37,7 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.MathUtils; @@ -123,6 +125,12 @@ public class ArmorStandEntity extends LivingEntity { this.position = position; } + @Override + public void updateNametag(@Nullable Team team) { + // unlike all other LivingEntities, armor stands are not affected by team nametag visibility + super.updateNametag(team, true); + } + @Override public void setDisplayName(EntityMetadata, ?> entityMetadata) { super.setDisplayName(entityMetadata); 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 4e0de44ea..2abc34d2b 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 @@ -43,7 +43,6 @@ import org.cloudburstmc.protocol.bedrock.data.AbilityLayer; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.PlayerPermission; import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataMap; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; @@ -112,20 +111,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { this.texturesProperty = texturesProperty; } - /** - * Do not use! For testing purposes only - */ - public PlayerEntity(GeyserSession session, long geyserId, UUID uuid, String username) { - super(session, -1, geyserId, uuid, EntityDefinitions.PLAYER, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0); - this.username = username; - this.nametag = username; - this.texturesProperty = null; - - // clear initial metadata - dirtyMetadata.apply(new EntityDataMap()); - setFlagsDirty(false); - } - @Override protected void initializeMetadata() { super.initializeMetadata(); @@ -193,11 +178,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { if (session.getEntityCache().getPlayerEntity(uuid) == null) return; - if (session.getEntityCache().getEntityByGeyserId(geyserId) == null) { - session.getEntityCache().spawnEntity(this); - } else { - spawnEntity(); - } + session.getEntityCache().spawnEntity(this); } @Override 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 30d3c0763..e9ff837ab 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -62,6 +62,8 @@ import java.util.*; * Holds all the common registries in Geyser. */ public final class Registries { + private static boolean initialized = false; + /** * A registry holding all the providers. * This has to be initialized first to allow extensions to access providers during other registry events. @@ -69,7 +71,7 @@ public final class Registries { public static final SimpleMappedRegistry, ProviderSupplier> PROVIDERS = SimpleMappedRegistry.create(new IdentityHashMap<>(), ProviderRegistryLoader::new); /** - * A registry holding a CompoundTag of the known entity identifiers. + * A registry holding a NbtMap of the known entity identifiers. */ public static final SimpleRegistry BEDROCK_ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); @@ -79,7 +81,7 @@ public final class Registries { public static final PacketTranslatorRegistry BEDROCK_PACKET_TRANSLATORS = PacketTranslatorRegistry.create(); /** - * A registry holding a CompoundTag of all the known biomes. + * A registry holding a NbtMap of all the known biomes. */ public static final SimpleRegistry BIOMES_NBT = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); @@ -118,6 +120,9 @@ public final class Registries { */ public static final ListRegistry JAVA_ITEMS = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); + /** + * A registry containing item identifiers. + */ public static final SimpleMappedRegistry JAVA_ITEM_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); /** @@ -135,7 +140,7 @@ public final class Registries { /** * A registry holding all the potion mixes. */ - public static final VersionedRegistry> POTION_MIXES; + public static final VersionedRegistry> POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); /** * A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value. @@ -163,15 +168,35 @@ public final class Registries { public static final SimpleMappedRegistry> SOUND_TRANSLATORS = SimpleMappedRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); public static void init() { - // no-op - } + if (initialized) return; + initialized = true; + + PROVIDERS.load(); + BEDROCK_ENTITY_IDENTIFIERS.load(); + BEDROCK_PACKET_TRANSLATORS.load(); + BIOMES_NBT.load(); + BIOME_IDENTIFIERS.load(); + BLOCK_ENTITIES.load(); + ENTITY_DEFINITIONS.load(); + BEDROCK_ENTITY_PROPERTIES.load(); + JAVA_ENTITY_IDENTIFIERS.load(); + JAVA_PACKET_TRANSLATORS.load(); + JAVA_ITEMS.load(); + JAVA_ITEM_IDENTIFIERS.load(); + ITEMS.load(); + PARTICLES.load(); + // load potion mixes later + RECIPES.load(); + RESOURCE_PACKS.load(); + SOUNDS.load(); + SOUND_LEVEL_EVENTS.load(); + SOUND_TRANSLATORS.load(); - static { PacketRegistryPopulator.populate(); ItemRegistryPopulator.populate(); - // Create registries that require other registries to load first - POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); + // potion mixes depend on other registries + POTION_MIXES.load(); // Remove unneeded client generation data from NbtMapBuilder NbtMapBuilder biomesNbt = NbtMap.builder(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registry.java b/core/src/main/java/org/geysermc/geyser/registry/Registry.java index 8836502b3..4e83a3c2e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registry.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.registry; -import org.geysermc.geyser.registry.loader.RegistryLoader; - import java.util.function.Consumer; +import org.geysermc.geyser.registry.loader.RegistryLoader; +import org.geysermc.geyser.registry.loader.RegistryLoaderHolder; /** * A wrapper around a value which is loaded based on the output from the provided @@ -63,7 +63,9 @@ import java.util.function.Consumer; * * @param the value being held by the registry */ +@SuppressWarnings("rawtypes") public abstract class Registry implements IRegistry { + protected RegistryLoaderHolder loaderHolder; protected M mappings; /** @@ -76,7 +78,17 @@ public abstract class Registry implements IRegistry { * @param the input type */ protected Registry(I input, RegistryLoader registryLoader) { - this.mappings = registryLoader.load(input); + this.loaderHolder = new RegistryLoaderHolder<>(input, registryLoader); + } + + public void load() { + // don't load twice + if (this.mappings != null) return; + + var holder = this.loaderHolder; + this.loaderHolder = null; + //noinspection unchecked + this.mappings = (M) holder.registryLoader().load(holder.input()); } /** @@ -111,4 +123,4 @@ public abstract class Registry implements IRegistry { public void register(Consumer consumer) { consumer.accept(this.mappings); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java index eae4e2bea..613df61aa 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java @@ -125,4 +125,4 @@ public class PotionMixRegistryLoader implements RegistryLoader(I input, RegistryLoader registryLoader) { +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java index d7c06ac4f..507523539 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java @@ -90,6 +90,8 @@ public final class Team { // Remove old team from this map, and from the set of players of the old team. // Java 1.19.3 Mojmap: Scoreboard#addPlayerToTeam calls #removePlayerFromTeam oldTeam.entities.remove(player); + // also remove the managed entity if there is one + removeManagedEntity(player); } return this; }); @@ -282,6 +284,15 @@ public final class Team { } } + /** + * Used internally to remove a managed entity without causing an update. + * This is fine because its only used when the entity is added to another team, + * which will fire the correct nametag updates etc. + */ + private void removeManagedEntity(String name) { + managedEntities.removeIf(entity -> name.equals(entity.teamIdentifier())); + } + private void refreshAllEntities() { for (Entity entity : session().getEntityCache().getEntities().values()) { entity.updateNametag(scoreboard.getTeamFor(entity.teamIdentifier())); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java index a80ed3e3a..78d21e63b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java @@ -69,12 +69,13 @@ public class EntityCache { public void spawnEntity(Entity entity) { if (cacheEntity(entity)) { - entity.spawnEntity(); - - // start tracking newly spawned entities. - // This is however not called for players, that's done in addPlayerEntity + // start tracking newly spawned entities. Doing this before the actual entity spawn can result in combining + // the otherwise sent metadata packet (in the case of team visibility, which sets the NAME metadata to + // empty) with the entity spawn packet (which also includes metadata). Resulting in 1 less packet sent. session.getWorldCache().getScoreboard().entityRegistered(entity); + entity.spawnEntity(); + if (entity instanceof Tickable) { // Start ticking it tickableEntities.add((Tickable) entity); @@ -144,8 +145,6 @@ public class EntityCache { // notify scoreboard for new entity var scoreboard = session.getWorldCache().getScoreboard(); scoreboard.playerRegistered(entity); - // spawnPlayer's entityRegistered is not called for players - scoreboard.entityRegistered(entity); } public PlayerEntity getPlayerEntity(UUID uuid) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java index 19f34db74..d950d9d0e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import org.geysermc.mcprotocollib.auth.GameProfile; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; @@ -35,6 +34,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntryAction; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; @@ -95,8 +95,6 @@ public class JavaPlayerInfoUpdateTranslator extends PacketTranslator GeyserImpl.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data for " + session.getClientData().getUsername())); - } else { - playerEntity.setValid(true); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java index 572d233d0..ed1951243 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java @@ -25,17 +25,14 @@ package org.geysermc.geyser.translator.protocol.java.entity.spawn; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.FallingBlockData; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ProjectileData; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.WardenData; -import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.entity.type.*; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.entity.type.FallingBlockEntity; +import org.geysermc.geyser.entity.type.FishingHookEntity; +import org.geysermc.geyser.entity.type.ItemFrameEntity; +import org.geysermc.geyser.entity.type.PaintingEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; @@ -43,6 +40,14 @@ import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.EnvironmentUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.FallingBlockData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ProjectileData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.WardenData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; @Translator(packet = ClientboundAddEntityPacket.class) public class JavaAddEntityTranslator extends PacketTranslator { @@ -83,10 +88,13 @@ public class JavaAddEntityTranslator extends PacketTranslator { 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 8e5a57fae..f8b20fbc4 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -297,7 +297,7 @@ public final class EntityUtils { private static String translatedEntityName(@NonNull String namespace, @NonNull String name, @NonNull GeyserSession session) { // MinecraftLocale would otherwise invoke getBootstrap (which doesn't exist) and create some folders, // so use the default fallback value as used in Minecraft Java - if (EnvironmentUtils.isUnitTesting) { + if (EnvironmentUtils.IS_UNIT_TESTING) { return "entity." + namespace + "." + name; } return MinecraftLocale.getLocaleString("entity." + namespace + "." + name, session.locale()); diff --git a/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java b/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java index 909398bf4..35a1a1e8f 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.util; public final class EnvironmentUtils { - public static final boolean isUnitTesting = isUnitTesting(); + public static final boolean IS_UNIT_TESTING = isUnitTesting(); private EnvironmentUtils() {} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java index 523e4dca2..29882ca2e 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java @@ -27,7 +27,7 @@ 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.assertNoNextPacket; -import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.spawnPlayerSilently; import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; import net.kyori.adventure.text.Component; @@ -47,7 +47,7 @@ public class NameVisibilityScoreboardTest { mockContextScoreboard(context -> { var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setPlayerTeamTranslator, @@ -64,12 +64,12 @@ public class NameVisibilityScoreboardTest { new String[]{"player1"} ) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, ""); return packet; - }, context); + }); }); } @@ -78,7 +78,7 @@ public class NameVisibilityScoreboardTest { mockContextScoreboard(context -> { var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setPlayerTeamTranslator, @@ -96,12 +96,12 @@ public class NameVisibilityScoreboardTest { ) ); // only hidden if session player (Tim203) is in a team as well - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); assertNoNextPacket(context); // create another team and add Tim203 to it @@ -121,12 +121,12 @@ public class NameVisibilityScoreboardTest { ) ); // Tim203 is now in another team, so it should be hidden - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, ""); return packet; - }, context); + }); assertNoNextPacket(context); // add Tim203 to same team as player1, score should be visible again @@ -134,12 +134,12 @@ public class NameVisibilityScoreboardTest { setPlayerTeamTranslator, new ClientboundSetPlayerTeamPacket("team1", TeamAction.ADD_PLAYER, new String[]{"Tim203"}) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); }); } @@ -148,7 +148,7 @@ public class NameVisibilityScoreboardTest { mockContextScoreboard(context -> { var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setPlayerTeamTranslator, @@ -166,12 +166,12 @@ public class NameVisibilityScoreboardTest { ) ); // Tim203 is not in a team (let alone the same team), so should be visible - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); assertNoNextPacket(context); // Tim203 is now in the same team as player1, so should be hidden @@ -179,12 +179,12 @@ public class NameVisibilityScoreboardTest { setPlayerTeamTranslator, new ClientboundSetPlayerTeamPacket("team1", TeamAction.ADD_PLAYER, new String[]{"Tim203"}) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, ""); return packet; - }, context); + }); assertNoNextPacket(context); // create another team and add Tim203 to there, score should be visible again @@ -203,12 +203,12 @@ public class NameVisibilityScoreboardTest { new String[]{"Tim203"} ) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); }); } @@ -217,7 +217,7 @@ public class NameVisibilityScoreboardTest { mockContextScoreboard(context -> { var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setPlayerTeamTranslator, @@ -234,12 +234,12 @@ public class NameVisibilityScoreboardTest { new String[]{"player1"} ) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); // adding self to another team shouldn't make a difference context.translate( 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 1ec245007..17ad7f3d3 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,23 +25,58 @@ 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; +import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; +import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; +import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.geysermc.geyser.entity.type.living.monster.EnderDragonPartEntity; import org.geysermc.geyser.session.cache.EntityCache; import org.geysermc.geyser.translator.protocol.java.entity.JavaRemoveEntitiesTranslator; +import org.geysermc.geyser.translator.protocol.java.entity.JavaSetEntityDataTranslator; +import org.geysermc.geyser.translator.protocol.java.entity.player.JavaPlayerInfoUpdateTranslator; +import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddEntityTranslator; import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddExperienceOrbTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetPlayerTeamTranslator; +import org.geysermc.mcprotocollib.auth.GameProfile; +import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry; +import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntryAction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.CollisionRule; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRemoveEntitiesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityDataPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; import org.junit.jupiter.api.Test; +import java.util.EnumSet; +import java.util.Optional; +import java.util.UUID; + /** - * Tests that don't fit in a larger system (e.g. sidebar objective) that were reported on GitHub + * Tests for issues reported on GitHub. */ public class ScoreboardIssueTests { /** @@ -90,4 +125,137 @@ public class ScoreboardIssueTests { }); }); } + + /** + * Test for
    #5089. + * It follows the reproduction steps with all the packets it sends along its way. + * Tested with the 2.0.0-SNAPSHOT version. + * Note that this exact issue is actually 2 issues: + *
      + *
    • + * An issue caused by remainders of code that was part of the initial PR that added support for players. + * The code is now more streamlined. + *
    • + *
    • Armor stands are excluded from team visibility checks (the only living entity)
    • + *
    + */ + @Test + void nameNotUpdating() { + mockContextScoreboard(context -> { + var playerInfoUpdateTranslator = new JavaPlayerInfoUpdateTranslator(); + var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); + var addEntityTranslator = new JavaAddEntityTranslator(); + var setEntityDataTranslator = new JavaSetEntityDataTranslator(); + + + // first command, create NPC + + + var npcUuid = UUID.fromString("b0eb01d7-52c9-4730-9fd3-2c03fcb00d6e"); + context.translate( + playerInfoUpdateTranslator, + 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) + })); + + //todo we don't have to remove an entry that was never in the playerlist in the first place + assertNextPacket(context, () -> { + var packet = new PlayerListPacket(); + packet.getEntries().add(new PlayerListPacket.Entry(npcUuid)); + packet.setAction(PlayerListPacket.Action.REMOVE); + return packet; + }); + assertNoNextPacket(context); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "npc_team_1297", + Component.empty(), + Component.empty(), + Component.empty(), + false, + false, + NameTagVisibility.NEVER, + CollisionRule.NEVER, + TeamColor.WHITE, + new String[0] + ) + ); + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket("npc_team_1297", TeamAction.ADD_PLAYER, new String[]{ "1297" })); + + context.translate(addEntityTranslator, new ClientboundAddEntityPacket(1297, npcUuid, EntityType.PLAYER, 1, 2, 3, 4, 5, 6)); + // then it updates the displayed skin parts, which isn't relevant for us + + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(3, packet.getRuntimeEntityId()); + assertEquals(npcUuid, packet.getUuid()); + assertEquals("1297", packet.getUsername()); + assertEquals((byte) 1, packet.getMetadata().get(EntityDataTypes.NAMETAG_ALWAYS_SHOW)); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); + assertNoNextPacket(context); + + + // second command, create hologram + + + var hologramUuid = UUID.fromString("b1586291-5f68-44dc-847d-6c123c5b8cbf"); + context.translate( + addEntityTranslator, + new ClientboundAddEntityPacket(1298, hologramUuid, EntityType.ARMOR_STAND, 6, 5, 4, 3, 2, 1)); + + assertNextPacketMatch(context, AddEntityPacket.class, packet -> { + assertEquals(4, packet.getRuntimeEntityId()); + assertEquals("minecraft:armor_stand", packet.getIdentifier()); + }); + + // metadata set: invisible, custom name, custom name visible + context.translate(setEntityDataTranslator, new ClientboundSetEntityDataPacket(1298, new EntityMetadata[]{ + new ByteEntityMetadata(0, MetadataType.BYTE, (byte) 0x20), + new ObjectEntityMetadata<>(2, MetadataType.OPTIONAL_CHAT, Optional.of(Component.text("tesss"))), + new BooleanEntityMetadata(3, MetadataType.BOOLEAN, true) + })); + + assertNextPacketMatch(context, SetEntityDataPacket.class, packet -> { + assertEquals(4, packet.getRuntimeEntityId()); + var metadata = packet.getMetadata(); + assertEquals(0.0f, metadata.get(EntityDataTypes.SCALE)); + assertEquals("tesss", metadata.get(EntityDataTypes.NAME)); + assertEquals((byte) 1, metadata.get(EntityDataTypes.NAMETAG_ALWAYS_SHOW)); + }); + // because the armor stand turned invisible and has a nametag (nametag is hidden when invisible) + assertNextPacketType(context, MoveEntityAbsolutePacket.class); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "npc_team_1298", + Component.empty(), + Component.empty(), + Component.empty(), + false, + false, + NameTagVisibility.NEVER, + CollisionRule.NEVER, + TeamColor.WHITE, + new String[0] + ) + ); + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket("npc_team_1298", TeamAction.ADD_PLAYER, new String[]{ hologramUuid.toString() })); + + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.getMetadata().put(EntityDataTypes.NAME, "§f§r§ftesss§r§f"); + packet.setRuntimeEntityId(4); + return packet; + }); + }); + } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java index 5d8d8309f..dfe85a0ee 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.scoreboard.network.belowname; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; -import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.spawnPlayerSilently; import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; import net.kyori.adventure.text.Component; @@ -80,7 +80,7 @@ public class BasicBelownameScoreboardTests { var setObjectiveTranslator = new JavaSetObjectiveTranslator(); var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setObjectiveTranslator, @@ -98,12 +98,12 @@ public class BasicBelownameScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, "0 §r§9objective"); return packet; - }, context); + }); }); } @@ -113,7 +113,7 @@ public class BasicBelownameScoreboardTests { var setObjectiveTranslator = new JavaSetObjectiveTranslator(); var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setObjectiveTranslator, @@ -131,24 +131,24 @@ public class BasicBelownameScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective"); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, ""); return packet; - }, context); + }); }); } @@ -158,7 +158,7 @@ public class BasicBelownameScoreboardTests { var setObjectiveTranslator = new JavaSetObjectiveTranslator(); var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setObjectiveTranslator, @@ -186,42 +186,42 @@ public class BasicBelownameScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective2") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective2"); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective1") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, ""); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective1"); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, ""); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java index a3d4ad671..4ac5ee098 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java @@ -32,7 +32,6 @@ import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScore import java.util.List; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; @@ -75,7 +74,7 @@ public class BasicPlayerlistScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -83,7 +82,7 @@ public class BasicPlayerlistScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -98,7 +97,7 @@ public class BasicPlayerlistScoreboardTests { new ClientboundSetObjectivePacket( "objective", ObjectiveAction.ADD, - Component.text("objective", Style.style(NamedTextColor.AQUA, TextDecoration.BOLD)), + Component.text("objective", NamedTextColor.AQUA, TextDecoration.BOLD), ScoreType.INTEGER, null ) @@ -109,7 +108,7 @@ public class BasicPlayerlistScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("§b§lobjective"); @@ -117,7 +116,7 @@ public class BasicPlayerlistScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -156,7 +155,7 @@ public class BasicPlayerlistScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective2") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective2"); @@ -164,26 +163,26 @@ public class BasicPlayerlistScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); // session player name is Tim203 packet.setInfos(List.of(new ScoreInfo(1, "0", 2, ScoreInfo.ScorerType.PLAYER, 1))); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective1") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new RemoveObjectivePacket(); packet.setObjectiveId("0"); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("2"); packet.setDisplayName("objective1"); @@ -191,14 +190,14 @@ public class BasicPlayerlistScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); // session player name is Tim203 packet.setInfos(List.of(new ScoreInfo(3, "2", 1, ScoreInfo.ScorerType.PLAYER, 1))); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java index dd693022c..80f562fc3 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java @@ -26,21 +26,22 @@ package org.geysermc.geyser.scoreboard.network.server; 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.assertNoNextPacket; -import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.spawnPlayer; import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; -import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; @@ -88,7 +89,7 @@ public class CubecraftScoreboardTest { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "sidebar") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("sidebar"); @@ -96,7 +97,7 @@ public class CubecraftScoreboardTest { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); + }); // Now they're going to create a bunch of teams and add players to those teams in a very inefficient way. @@ -191,27 +192,23 @@ public class CubecraftScoreboardTest { ObjectiveAction.UPDATE, Component.empty() .append(Component.text( - "CubeCraft", Style.style(NamedTextColor.WHITE, TextDecoration.BOLD))), + "CubeCraft", NamedTextColor.WHITE, TextDecoration.BOLD)), ScoreType.INTEGER, null)); - assertNextPacket( - () -> { - var packet = new RemoveObjectivePacket(); - packet.setObjectiveId("0"); - return packet; - }, - context); - assertNextPacket( - () -> { - var packet = new SetDisplayObjectivePacket(); - packet.setObjectiveId("0"); - packet.setDisplayName("§f§lCubeCraft"); - packet.setCriteria("dummy"); - packet.setDisplaySlot("sidebar"); - packet.setSortOrder(1); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new RemoveObjectivePacket(); + packet.setObjectiveId("0"); + return packet; + }); + assertNextPacket(context, () -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("§f§lCubeCraft"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }); context.translate( setTeamTranslator, @@ -234,7 +231,7 @@ public class CubecraftScoreboardTest { new ClientboundSetPlayerTeamPacket( "SB_l-0", Component.text("SB_l-0"), - Component.empty().append(Component.text("", Style.style(NamedTextColor.BLACK))), + Component.empty().append(Component.text("", NamedTextColor.BLACK)), Component.empty(), true, true, @@ -244,14 +241,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§0", "sidebar", 10)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(1, "0", 10, "§r§0§0§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 10, "§r§0§0§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -287,14 +282,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§1", "sidebar", 9)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(2, "0", 9, "§bUser: §r§fTim203§r§0§1§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(2, "0", 9, "§bUser: §r§fTim203§r§0§1§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -330,14 +323,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§2", "sidebar", 8)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(3, "0", 8, "§bRank: §r§f\uE1AB §r§0§2§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(3, "0", 8, "§bRank: §r§f\uE1AB §r§0§2§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -370,14 +361,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§3", "sidebar", 7)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(4, "0", 7, "§r§0§3§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(4, "0", 7, "§r§0§3§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -410,14 +399,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§4", "sidebar", 6)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(5, "0", 6, "§r§0§4§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(5, "0", 6, "§r§0§4§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -450,14 +437,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§5", "sidebar", 5)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(6, "0", 5, "§r§0§5§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(6, "0", 5, "§r§0§5§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -493,14 +478,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§6", "sidebar", 4)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(7, "0", 4, "§bLobby: §r§fEU #10§r§0§6§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(7, "0", 4, "§bLobby: §r§fEU #10§r§0§6§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -536,14 +519,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§7", "sidebar", 3)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(8, "0", 3, "§bPlayers: §r§f783§r§0§7§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(8, "0", 3, "§bPlayers: §r§f783§r§0§7§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -576,14 +557,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§8", "sidebar", 2)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(9, "0", 2, "§r§0§8§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(9, "0", 2, "§r§0§8§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -616,14 +595,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§9", "sidebar", 1)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(10, "0", 1, "§824/09/24 (g2208)§r§0§9§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(10, "0", 1, "§824/09/24 (g2208)§r§0§9§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -656,14 +633,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§a", "sidebar", 0)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(11, "0", 0, "§6play.cubecraft.net§r§0§a§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(11, "0", 0, "§6play.cubecraft.net§r§0§a§r"))); + return packet; + }); // after this we get a ClientboundPlayerInfoUpdatePacket with the action UPDATE_DISPLAY_NAME, // but that one is only shown in the tablist so we don't have to handle that. @@ -672,85 +647,53 @@ public class CubecraftScoreboardTest { // CubeCraft seems to use two armor stands per player: 1 for the rank badge and 1 for the player name. // So the only thing we have to verify is that the nametag is hidden - mockAndAddPlayerEntity(context, "A_Player", 2); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(2); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "A_Player", 2); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(2, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "B_Player", 3); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(3); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "B_Player", 3); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(3, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "E_Player", 4); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(4); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "E_Player", 4); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(4, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "H_Player", 5); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(5); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "H_Player", 5); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(5, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "J_Player", 6); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(6); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "J_Player", 6); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(6, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "K_Player", 7); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(7); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "K_Player", 7); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(7, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "L_Player", 8); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(8); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "L_Player", 8); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(8, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "O_Player", 9); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(9); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "O_Player", 9); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(9, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java index b3999303e..bd0d64c80 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java @@ -32,7 +32,6 @@ import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScore import java.util.List; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; @@ -75,7 +74,7 @@ public class BasicSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -83,17 +82,17 @@ public class BasicSidebarScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); + }); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new RemoveObjectivePacket(); packet.setObjectiveId("0"); return packet; - }, context); + }); }); } @@ -108,7 +107,7 @@ public class BasicSidebarScoreboardTests { new ClientboundSetObjectivePacket( "objective", ObjectiveAction.ADD, - Component.text("objective", Style.style(NamedTextColor.AQUA, TextDecoration.BOLD)), + Component.text("objective", NamedTextColor.AQUA, TextDecoration.BOLD), ScoreType.INTEGER, null ) @@ -119,7 +118,7 @@ public class BasicSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("§b§lobjective"); @@ -127,7 +126,7 @@ public class BasicSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -170,7 +169,7 @@ public class BasicSidebarScoreboardTests { new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective2") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective2"); @@ -178,13 +177,13 @@ public class BasicSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "Tim203"))); return packet; - }, context); + }); assertNoNextPacket(context); @@ -193,12 +192,12 @@ public class BasicSidebarScoreboardTests { new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective1") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new RemoveObjectivePacket(); packet.setObjectiveId("0"); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("2"); packet.setDisplayName("objective1"); @@ -206,13 +205,13 @@ public class BasicSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(3, "2", 1, "Tim203"))); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java index 3e0be1c02..aab837456 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java @@ -98,7 +98,7 @@ public class OrderAndLimitSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -106,8 +106,8 @@ public class OrderAndLimitSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -128,7 +128,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(15, "0", 3, "c") )); return packet; - }, context); + }); assertNoNextPacket(context); // remove a score @@ -136,43 +136,43 @@ public class OrderAndLimitSidebarScoreboardTests { resetScoreTranslator, new ClientboundResetScorePacket("m", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(5, "0", 13, "m"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); return packet; - }, context); + }); // add a score context.translate( setScoreTranslator, new ClientboundSetScorePacket("aa", "objective", 13) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(17, "0", 13, "aa"))); return packet; - }, context); + }); // add score with same score value (after) context.translate( setScoreTranslator, new ClientboundSetScorePacket("ga", "objective", 9) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -180,8 +180,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(9, "0", 9, "§0§rg") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -189,14 +189,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 9, "§1§rga") )); return packet; - }, context); + }); // add another score with same score value (before all) context.translate( setScoreTranslator, new ClientboundSetScorePacket("ag", "objective", 9) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -205,8 +205,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 9, "§2§rga") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -215,14 +215,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 9, "§2§rga") )); return packet; - }, context); + }); // remove score with same value context.translate( resetScoreTranslator, new ClientboundResetScorePacket("g", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -230,8 +230,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 9, "§1§rga") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -239,14 +239,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(20, "0", 4, "e") )); return packet; - }, context); + }); // remove the other score with the same value context.translate( resetScoreTranslator, new ClientboundResetScorePacket("ga", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -254,8 +254,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(19, "0", 9, "ag") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -263,7 +263,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(21, "0", 3, "c") )); return packet; - }, context); + }); }); } @@ -327,7 +327,7 @@ public class OrderAndLimitSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -335,8 +335,8 @@ public class OrderAndLimitSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -357,7 +357,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(15, "0", 3, "c") )); return packet; - }, context); + }); assertNoNextPacket(context); // remove a score @@ -365,36 +365,36 @@ public class OrderAndLimitSidebarScoreboardTests { resetScoreTranslator, new ClientboundResetScorePacket("m", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(5, "0", 13, "m"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); return packet; - }, context); + }); // add a score context.translate( setScoreTranslator, new ClientboundSetScorePacket("aa", "objective", 13) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(17, "0", 13, "aa"))); return packet; - }, context); + }); // add some teams for the upcoming score adds context.translate( @@ -435,7 +435,7 @@ public class OrderAndLimitSidebarScoreboardTests { setScoreTranslator, new ClientboundSetScorePacket("oa", "objective", 11) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -443,8 +443,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(7, "0", 11, "§0§r§4prefix§r§4o§r§4suffix") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -452,7 +452,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 11, "§1§r§3prefix§r§3oa§r§3suffix") )); return packet; - }, context); + }); // add a score that on Java should be before 'o', but would be after on Bedrock without manual order // due to the team color @@ -460,7 +460,7 @@ public class OrderAndLimitSidebarScoreboardTests { setScoreTranslator, new ClientboundSetScorePacket("ao", "objective", 11) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -469,8 +469,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 11, "§2§r§3prefix§r§3oa§r§3suffix") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -479,14 +479,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 11, "§2§r§3prefix§r§3oa§r§3suffix") )); return packet; - }, context); + }); // remove original 'o' score context.translate( resetScoreTranslator, new ClientboundResetScorePacket("o", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -494,8 +494,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 11, "§1§r§3prefix§r§3oa§r§3suffix") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -503,14 +503,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(20, "0", 4, "e") )); return packet; - }, context); + }); // remove the other score with the same value as 'o' context.translate( resetScoreTranslator, new ClientboundResetScorePacket("oa", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -518,8 +518,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(19, "0", 11, "§5prefix§r§5ao§r§5suffix") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -527,7 +527,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(21, "0", 3, "c") )); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java index 0a02a58d9..f511f59c7 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java @@ -69,7 +69,7 @@ public class VanillaSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -77,16 +77,16 @@ public class VanillaSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); + }); assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 1)); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); return packet; - }, context); + }); }); } @@ -114,7 +114,7 @@ public class VanillaSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -122,22 +122,22 @@ public class VanillaSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); return packet; - }, context); + }); assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 2)); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "owner"))); return packet; - }, context); + }); }); } @@ -166,7 +166,7 @@ public class VanillaSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -174,31 +174,31 @@ public class VanillaSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 1).withDisplay(Component.text("hi")) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "hi"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "hi"))); return packet; - }, context); + }); }); } @@ -227,7 +227,7 @@ public class VanillaSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -235,31 +235,31 @@ public class VanillaSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 2).withDisplay(Component.text("hi")) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "hi"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "hi"))); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java index b15994533..9177f205a 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.scoreboard.network.util; import java.util.Collections; +import java.util.function.Consumer; import java.util.function.Supplier; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.junit.jupiter.api.Assertions; @@ -38,7 +39,7 @@ public class AssertUtils { Assertions.assertEquals(expected.get(), actual); } - public static void assertNextPacket(Supplier expected, GeyserMockContext context) { + public static void assertNextPacket(GeyserMockContext context, Supplier expected) { assertContextEquals(expected, context.nextPacket()); } @@ -50,6 +51,16 @@ public class AssertUtils { Assertions.assertEquals(type, actual.getClass()); } + public static void assertNextPacketMatch(GeyserMockContext context, Class type, Consumer matcher) { + var actual = context.nextPacket(); + if (actual == null) { + Assertions.fail("Expected another packet!"); + } + Assertions.assertEquals(type, actual.getClass(), "Expected packet to be an instance of " + type); + //noinspection unchecked verified in the line above me + matcher.accept((T) actual); + } + public static void assertNoNextPacket(GeyserMockContext context) { Assertions.assertEquals( Collections.emptyList(), diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java index 72515d714..1d262d8b8 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java @@ -35,16 +35,15 @@ import java.util.function.Consumer; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.configuration.GeyserConfiguration; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.mockito.MockedStatic; import org.mockito.Mockito; public class GeyserMockContext { private final List mocksAndSpies = new ArrayList<>(); private final List storedObjects = new ArrayList<>(); private final List packets = Collections.synchronizedList(new ArrayList<>()); - private MockedStatic geyserImplMock; public static void mockContext(Consumer geyserContext) { var context = new GeyserMockContext(); @@ -59,9 +58,15 @@ public class GeyserMockContext { var logger = context.storeObject(new EmptyGeyserLogger()); when(geyserImpl.getLogger()).thenReturn(logger); - try (var mocked = mockStatic(GeyserImpl.class)) { - mocked.when(GeyserImpl::getInstance).thenReturn(geyserImpl); - context.geyserImplMock = mocked; + try (var geyserImplMock = mockStatic(GeyserImpl.class)) { + geyserImplMock.when(GeyserImpl::getInstance).thenReturn(geyserImpl); + + // Since Geyser isn't actually loaded, the Registries#init will not be called. + // This means that we manually load the registries we want to use + Registries.ENTITY_DEFINITIONS.load(); + Registries.JAVA_ENTITY_IDENTIFIERS.load(); + Registries.BEDROCK_ENTITY_PROPERTIES.load(); + geyserContext.accept(context); } } @@ -136,8 +141,4 @@ public class GeyserMockContext { public void translate(PacketTranslator translator, T packet) { translator.translate(session(), packet); } - - public MockedStatic geyserImplMock() { - return geyserImplMock; - } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java index bc76a1b70..e0d9918e5 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.scoreboard.network.util; +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.GeyserMockContext.mockContext; import static org.mockito.ArgumentMatchers.any; @@ -34,6 +35,8 @@ import static org.mockito.Mockito.when; import java.util.UUID; import java.util.function.Consumer; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.player.PlayerEntity; @@ -82,15 +85,20 @@ public class GeyserMockContextScoreboard { when(worldCache.increaseAndGetScoreboardPacketsPerSecond()).thenReturn(0); } - public static PlayerEntity mockAndAddPlayerEntity(GeyserMockContext context, String username, long geyserId) { - var playerEntity = spy(new PlayerEntity(context.session(), geyserId, UUID.randomUUID(), username)); - // fake the player being spawned - when(playerEntity.isValid()).thenReturn(true); + public static PlayerEntity spawnPlayerSilently(GeyserMockContext context, String username, long geyserId) { + var player = spawnPlayer(context, username, geyserId); + assertNextPacketType(context, AddPlayerPacket.class); + return player; + } + + public static PlayerEntity spawnPlayer(GeyserMockContext context, String username, long geyserId) { + var playerEntity = spy(new PlayerEntity(context.session(), (int) geyserId, geyserId, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, username, null)); var entityCache = context.mockOrSpy(EntityCache.class); entityCache.addPlayerEntity(playerEntity); // called when the player spawns - entityCache.cacheEntity(playerEntity); + entityCache.spawnEntity(playerEntity); + return playerEntity; } } From 8f7a0d0778aa9106ea32527e535fe5d1cc7d7d0d Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 28 Oct 2024 00:56:39 +0100 Subject: [PATCH 415/897] Correct the loading of the block registries and the common registries --- .../java/org/geysermc/geyser/GeyserImpl.java | 12 ++++++-- .../geyser/registry/BlockRegistries.java | 30 ++++++++++++++----- .../geysermc/geyser/registry/Registries.java | 10 ++++--- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 4672aef5b..f679b412c 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -231,9 +231,15 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { } logger.info("******************************************"); - /* Initialize registries */ - Registries.init(); - BlockRegistries.init(); + /* + First load the registries and then populate them. + Both the block registries and the common registries depend on each other, + so maintaining this order is crucial for Geyser to load. + */ + BlockRegistries.load(); + Registries.load(); + BlockRegistries.populate(); + Registries.populate(); RegistryCache.init(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 2f15094ef..8cf11979f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -69,7 +69,7 @@ public class BlockRegistries { /** * A mapped registry containing which holds block IDs to its {@link BlockCollision}. */ - public static final ListRegistry COLLISIONS; + public static final ListRegistry COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); /** * A registry which stores Java IDs to {@link Block}, containing miscellaneous information about @@ -130,22 +130,36 @@ public class BlockRegistries { */ public static final SimpleMappedRegistry CUSTOM_SKULLS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); - static { + public static void load() { + BLOCKS.load(); + BLOCK_STATES.load(); + // collisions are loaded later, because they are initialized later + JAVA_BLOCKS.load(); + JAVA_IDENTIFIER_TO_ID.load(); + WATERLOGGED.load(); + INTERACTIVE.load(); + INTERACTIVE_MAY_BUILD.load(); + CUSTOM_BLOCKS.load(); + CUSTOM_BLOCK_STATE_OVERRIDES.load(); + NON_VANILLA_BLOCK_STATE_OVERRIDES.load(); + CUSTOM_BLOCK_ITEM_OVERRIDES.load(); + EXTENDED_COLLISION_BOXES.load(); + CUSTOM_SKULLS.load(); + + COLLISIONS.load(); + } + + public static void populate() { Blocks.VAULT.javaId(); // FIXME CustomSkullRegistryPopulator.populate(); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.PRE_INIT); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA); - COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.POST_INIT); } - public static void init() { - // no-op - } - -} \ No newline at end of file +} 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 e9ff837ab..b86ea3bbf 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -62,7 +62,7 @@ import java.util.*; * Holds all the common registries in Geyser. */ public final class Registries { - private static boolean initialized = false; + private static boolean loaded = false; /** * A registry holding all the providers. @@ -167,9 +167,9 @@ public final class Registries { */ public static final SimpleMappedRegistry> SOUND_TRANSLATORS = SimpleMappedRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); - public static void init() { - if (initialized) return; - initialized = true; + public static void load() { + if (loaded) return; + loaded = true; PROVIDERS.load(); BEDROCK_ENTITY_IDENTIFIERS.load(); @@ -191,7 +191,9 @@ public final class Registries { SOUNDS.load(); SOUND_LEVEL_EVENTS.load(); SOUND_TRANSLATORS.load(); + } + public static void populate() { PacketRegistryPopulator.populate(); ItemRegistryPopulator.populate(); From 0f1a32e1c11231a0faaf623e0a7ebe979de4c9d6 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:29:03 -0400 Subject: [PATCH 416/897] Clear recipes during the configuration phase --- .../geyser/session/GeyserSession.java | 10 ++----- ...vaFinishConfigurationPacketTranslator.java | 30 +++++++++++++++++++ .../java/JavaUpdateRecipesTranslator.java | 13 -------- 3 files changed, 32 insertions(+), 21 deletions(-) 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 1ca127657..fa06a53ba 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -83,7 +83,6 @@ 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; @@ -179,6 +178,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; @@ -684,7 +684,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); this.javaToBedrockRecipeIds = new Int2ObjectOpenHashMap<>(); - this.lastRecipeNetId = new AtomicInteger(1); + this.lastRecipeNetId = new AtomicInteger(InventoryUtils.LAST_RECIPE_NET_ID); this.spawned = false; this.loggedIn = false; @@ -756,12 +756,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); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java index 8ade4a1f0..1a32c1a97 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java @@ -25,15 +25,33 @@ package org.geysermc.geyser.translator.protocol.java; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.MultiRecipeData; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData; +import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.registry.Registries; 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.configuration.clientbound.ClientboundFinishConfigurationPacket; +import java.util.List; +import java.util.UUID; + +import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; + @Translator(packet = ClientboundFinishConfigurationPacket.class) public class JavaFinishConfigurationPacketTranslator 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) { @@ -45,5 +63,17 @@ public class JavaFinishConfigurationPacketTranslator extends PacketTranslator @@ -67,15 +63,6 @@ import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; */ @Translator(packet = ClientboundUpdateRecipesPacket.class) public class JavaUpdateRecipesTranslator 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", From 6c0d3419fc5439e534755f2d453a5679fe2a36cf Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:31:08 -0400 Subject: [PATCH 417/897] Prevent recipe ID conflict --- .../main/java/org/geysermc/geyser/session/GeyserSession.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fa06a53ba..25bfe19e7 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -684,7 +684,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); this.javaToBedrockRecipeIds = new Int2ObjectOpenHashMap<>(); - this.lastRecipeNetId = new AtomicInteger(InventoryUtils.LAST_RECIPE_NET_ID); + this.lastRecipeNetId = new AtomicInteger(InventoryUtils.LAST_RECIPE_NET_ID + 1); this.spawned = false; this.loggedIn = false; From 3f60db1483b8b48d00bc94b77afad0b79ad84dd9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:38:45 -0400 Subject: [PATCH 418/897] Fix collision registry loading --- .../java/org/geysermc/geyser/registry/BlockRegistries.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 8cf11979f..b7c5e2d07 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -145,8 +145,6 @@ public class BlockRegistries { CUSTOM_BLOCK_ITEM_OVERRIDES.load(); EXTENDED_COLLISION_BOXES.load(); CUSTOM_SKULLS.load(); - - COLLISIONS.load(); } public static void populate() { @@ -156,6 +154,7 @@ public class BlockRegistries { CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA); + COLLISIONS.load(); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); From 344d40dd1f0dc6a39f840e6ab6c4127298359a04 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:58:37 -0400 Subject: [PATCH 419/897] Smithing recipes mostly work --- .../geyser/session/cache/InputCache.java | 26 +++++- .../BedrockPlayerAuthInputTranslator.java | 6 +- .../java/JavaRecipeBookAddTranslator.java | 26 ++---- .../java/JavaUpdateRecipesTranslator.java | 84 +++++++++++++------ .../player/JavaPlayerPositionTranslator.java | 1 + .../inventory/JavaOpenScreenTranslator.java | 5 +- .../org/geysermc/geyser/util/MathUtils.java | 11 --- 7 files changed, 95 insertions(+), 64 deletions(-) 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 index c666ded64..79c37a5a8 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java @@ -27,6 +27,8 @@ package org.geysermc.geyser.session.cache; import lombok.Getter; import lombok.Setter; +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; @@ -52,12 +54,28 @@ public final class InputCache { // Input is sent to the server before packet positions, as of 1.21.2 Set bedrockInput = packet.getInputData(); var oldInputPacket = this.inputPacket; + + boolean up, down, left, right; + if (packet.getInputMode() == 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(bedrockInput.contains(PlayerAuthInputData.UP)) - .withBackward(bedrockInput.contains(PlayerAuthInputData.DOWN)) - .withLeft(bedrockInput.contains(PlayerAuthInputData.LEFT)) - .withRight(bedrockInput.contains(PlayerAuthInputData.RIGHT)) + .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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java index 93e4cb92a..a366a5b69 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; +import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; @@ -50,7 +51,6 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransactionTranslator; import org.geysermc.geyser.util.CooldownUtils; -import org.geysermc.geyser.util.MathUtils; 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.InteractAction; @@ -71,7 +71,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator> javaToBedrockRecipeIds = session.getJavaToBedrockRecipeIds(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); @@ -131,8 +132,8 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator { - if (true) { - System.out.println(display); + if (display.result() instanceof SmithingTrimDemoSlotDisplay) { + // Skip these - Bedrock already knows about them from the TrimDataPacket continue; } SmithingRecipeDisplay smithingRecipe = (SmithingRecipeDisplay) display; @@ -169,7 +170,7 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator { -// String molang = "q.is_item_name_any('', " -// + Arrays.stream(items).mapToObj(item -> { -// ItemMapping mapping = session.getItemMappings().getMapping(item); -// return "'" + mapping.getBedrockIdentifier() + "'"; -// }).collect(Collectors.joining(", ")) -// + ")"; -// String molang = Arrays.stream(items).mapToObj(item -> { -// ItemMapping mapping = session.getItemMappings().getMapping(item); -// return "q.identifier == '" + mapping.getBedrockIdentifier() + "'"; -// }).collect(Collectors.joining(" || ")); -// if ("minecraft:planks".equals(tag.toString())) { -// String molang = "q.any_tag('minecraft:planks')"; -// return Collections.singletonList(new ItemDescriptorWithCount(new MolangDescriptor(molang, 10), 1)); -// } - Set itemDescriptors = new HashSet<>(); for (int item : key) { itemDescriptors.add(fromItem(session, item)); } - return new ArrayList<>(itemDescriptors); // This, or a list from the start with contains -> add? + return List.copyOf(itemDescriptors); // This, or a list from the start with contains -> add? }); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 693b451ba..9f53a9af4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -28,13 +28,20 @@ package org.geysermc.geyser.translator.protocol.java; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.kyori.adventure.key.Key; +import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; 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.RecipeData; 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.crafting.recipe.SmithingTrimRecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; +import org.cloudburstmc.protocol.bedrock.packet.TrimDataPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; +import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; @@ -50,11 +57,14 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.Clientbound import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket.SelectableRecipe; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; /** * Used to send all valid recipes from Java to Bedrock. @@ -94,6 +104,34 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Registries.JAVA_ITEMS.get(i).javaIdentifier()).collect(Collectors.joining(" "))); + System.out.println(Arrays.stream(smithingAddition).mapToObj(i -> Registries.JAVA_ITEMS.get(i).javaIdentifier()).collect(Collectors.joining(" "))); + oldSmithingTable = false; + // BDS sends armor trim templates and materials before the CraftingDataPacket + TrimDataPacket trimDataPacket = new TrimDataPacket(); + trimDataPacket.getPatterns().addAll(session.getRegistryCache().trimPatterns().values()); + trimDataPacket.getMaterials().addAll(session.getRegistryCache().trimMaterials().values()); + session.sendUpstreamPacket(trimDataPacket); + + // Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the + // approach of using many default-descriptors (which we do for smithing_transform) + craftingDataPacket.getCraftingData().add(SmithingTrimRecipeData.of(TrimRecipe.ID, + TrimRecipe.BASE, TrimRecipe.ADDITION, TrimRecipe.TEMPLATE, "smithing_table", netId++)); + } + session.getGeyser().getLogger().debug("Using old smithing table workaround? " + oldSmithingTable); + session.setOldSmithingTable(oldSmithingTable); + Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); List stonecutterRecipes = packet.getStonecutterRecipes(); @@ -433,30 +471,28 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator getSmithingTransformRecipes(GeyserSession session) { -// List recipes = new ArrayList<>(); -// 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", -// getDescriptorFromId(session, template.getBedrockIdentifier()), -// getDescriptorFromId(session, identifier.replace("netherite", "diamond")), -// getDescriptorFromId(session, "minecraft:netherite_ingot"), -// ItemData.builder().definition(Objects.requireNonNull(session.getItemMappings().getDefinition(identifier))).count(1).build(), -// "smithing_table", -// session.getLastRecipeNetId().getAndIncrement())); -// } -// return recipes; -// } -// -// private ItemDescriptorWithCount getDescriptorFromId(GeyserSession session, String bedrockId) { -// ItemDefinition bedrockDefinition = session.getItemMappings().getDefinition(bedrockId); -// if (bedrockDefinition != null) { -// return ItemDescriptorWithCount.fromItem(ItemData.builder().definition(bedrockDefinition).count(1).build()); -// } -// GeyserImpl.getInstance().getLogger().debug("Unable to find item with identifier " + bedrockId); -// return ItemDescriptorWithCount.EMPTY; -// } + private void addSmithingTransformRecipes(GeyserSession session, List recipes) { + ItemMapping template = session.getItemMappings().getStoredItems().upgradeTemplate(); + + for (String identifier : NETHERITE_UPGRADES) { + recipes.add(SmithingTransformRecipeData.of(identifier + "_smithing", + getDescriptorFromId(session, template.getBedrockIdentifier()), + getDescriptorFromId(session, identifier.replace("netherite", "diamond")), + getDescriptorFromId(session, "minecraft:netherite_ingot"), + ItemData.builder().definition(Objects.requireNonNull(session.getItemMappings().getDefinition(identifier))).count(1).build(), + "smithing_table", + session.getLastRecipeNetId().getAndIncrement())); + } + } + + private ItemDescriptorWithCount getDescriptorFromId(GeyserSession session, String bedrockId) { + ItemDefinition bedrockDefinition = session.getItemMappings().getDefinition(bedrockId); + if (bedrockDefinition != null) { + return ItemDescriptorWithCount.fromItem(ItemData.builder().definition(bedrockDefinition).count(1).build()); + } + GeyserImpl.getInstance().getLogger().debug("Unable to find item with identifier " + bedrockId); + return ItemDescriptorWithCount.EMPTY; + } // // @EqualsAndHashCode // @AllArgsConstructor diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java index ca1b95997..89e8eff82 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java @@ -47,6 +47,7 @@ public class JavaPlayerPositionTranslator extends PacketTranslator truncated ? truncated + 1 : truncated; } - /** - * Round the given float to the previous whole number - * - * @param floatNumber Float to round - * @return Rounded number - */ - public static int floor(float floatNumber) { - int truncated = (int) floatNumber; - return floatNumber < truncated ? truncated - 1 : truncated; - } - /** * If number is greater than the max, set it to max, and if number is lower than low, set it to low. * From 05f153c9416302564317fe79589ae4310a102a2e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:53:16 -0400 Subject: [PATCH 420/897] Re-implement on-the-fly recipe sending --- .../geyser/inventory/GeyserItemStack.java | 19 +++ .../geyser/inventory/recipe/GeyserRecipe.java | 4 +- .../inventory/recipe/GeyserShapedRecipe.java | 14 ++- .../recipe/GeyserShapelessRecipe.java | 14 ++- .../registry/loader/RecipeRegistryLoader.java | 6 +- .../geyser/session/GeyserSession.java | 3 +- .../inventory/InventoryTranslator.java | 52 +++++--- ...=> JavaFinishConfigurationTranslator.java} | 5 +- .../java/JavaRecipeBookAddTranslator.java | 16 ++- .../JavaContainerSetSlotTranslator.java | 17 ++- .../geysermc/geyser/util/InventoryUtils.java | 118 ++++++++++-------- 11 files changed, 170 insertions(+), 98 deletions(-) rename core/src/main/java/org/geysermc/geyser/translator/protocol/java/{JavaFinishConfigurationPacketTranslator.java => JavaFinishConfigurationTranslator.java} (93%) 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 b843b3d4d..b4809edf2 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; } 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 3037b725e..d9cae943f 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 @@ -26,7 +26,7 @@ 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}. @@ -38,5 +38,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 413041ba7..70b71cf4d 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 @@ -26,14 +26,16 @@ 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.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, @Nullable SlotDisplay result) implements GeyserRecipe { + + public GeyserShapedRecipe(ShapedCraftingRecipeDisplay data) { + this(data.width(), data.height(), data.ingredients(), data.result()); + } @Override public boolean isShaped() { 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 6b9e36956..90eeb01c9 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 @@ -26,14 +26,16 @@ 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.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, @Nullable SlotDisplay result) implements GeyserRecipe { + + public GeyserShapelessRecipe(ShapelessCraftingRecipeDisplay data) { + this(data.ingredients(), data.result()); + } @Override public boolean isShaped() { 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 f061ed070..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 @@ -31,8 +31,6 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; -import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; -import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; 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; @@ -92,7 +90,7 @@ public abstract class RecipeRegistryLoader implements RegistryLoader> javaToBedrockRecipeIds; - @Setter - private Int2ObjectMap craftingRecipes; + private final Int2ObjectMap craftingRecipes; private final AtomicInteger lastRecipeNetId; /** 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 f051885d4..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,11 +752,11 @@ public abstract class InventoryTranslator { craftState = CraftState.INGREDIENTS; if (ingRemaining == 0) { - while (++ingredientIndex < ingredients.length) { -// if (ingredients[ingredientIndex].getOptions().length != 0) { -// ingRemaining = timesCrafted; -// break; -// } + 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/protocol/java/JavaFinishConfigurationPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java similarity index 93% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java index 1a32c1a97..6cbefde0d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java @@ -42,7 +42,7 @@ import java.util.UUID; import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; @Translator(packet = ClientboundFinishConfigurationPacket.class) -public class JavaFinishConfigurationPacketTranslator extends PacketTranslator { +public class JavaFinishConfigurationTranslator extends PacketTranslator { /** * Required to use the specified cartography table recipes */ @@ -72,6 +72,9 @@ public class JavaFinishConfigurationPacketTranslator extends PacketTranslator> javaToBedrockRecipeIds = session.getJavaToBedrockRecipeIds(); + Int2ObjectMap geyserRecipes = session.getCraftingRecipes(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket(); @@ -101,14 +105,17 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator 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, netId++, false, RecipeUnlockingRequirement.INVALID)); + 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)); } @@ -121,13 +128,16 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator 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, netId++, RecipeUnlockingRequirement.INVALID)); + 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)); } 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 743c07a31..c98ab1ff6 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 @@ -44,12 +44,15 @@ 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.item.component.HolderSet; -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.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; @@ -104,9 +107,6 @@ 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); - int[] items = new int[] {geyserItemStack.isEmpty() ? 0 : geyserItemStack.getJavaId()}; - javaIngredients[index] = new Ingredient(new HolderSet(items)); + javaIngredients.add(geyserItemStack.isEmpty() ? new EmptySlotDisplay() : new ItemStackSlotDisplay(geyserItemStack.getItemStack())); InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.UI); @@ -185,7 +184,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator acceptsAsInput(session, aSlotDisplay, 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 * @@ -462,91 +499,70 @@ 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)]; + mirroredIngredients.add(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 (int item : ingredient.getValues().getHolders()) { // FIXME - 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 = item == 0; - if (inventoryHasItem) { - break crafting; - } - } else if (item == geyserItemStack.getJavaId()) { - 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; } } } + System.out.println("Found existing match for item: " + recipe); return recipe; } return null; } @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++]; - int[] items = ingredient.getValues().getHolders(); // FIXME - if (items.length == 0) { - if (!geyserItemStack.isEmpty()) { - return false; - } - } else { - boolean inventoryHasItem = false; - for (int item : items) { - if (geyserItemStack.getJavaId() == item) { - inventoryHasItem = true; - break; - } - } - if (!inventoryHasItem) { - return false; - } + SlotDisplay slotDisplay = ingredients.get(ingredientIndex++); + if (!acceptsAsInput(session, slotDisplay, geyserItemStack)) { + return false; } } } From 52679f9f8139a512eebdcf0ef177e29072833f7e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 29 Oct 2024 01:33:57 -0400 Subject: [PATCH 421/897] On-the-fly smithing transform recipes --- .../geyser/inventory/GeyserItemStack.java | 7 ++ .../recipe/GeyserSmithingRecipe.java | 43 +++++++++ .../geyser/session/GeyserSession.java | 8 +- .../SmithingInventoryTranslator.java | 29 +++--- .../java/JavaRecipeBookAddTranslator.java | 3 + .../JavaContainerSetSlotTranslator.java | 89 +++++++++++++++++-- 6 files changed, 160 insertions(+), 19 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserSmithingRecipe.java 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 b4809edf2..a2797e6dd 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -182,6 +182,13 @@ public class GeyserItemStack { return session.getItemMappings().getMapping(this.javaId); } + public SlotDisplay asSlotDisplay() { + if (isEmpty()) { + return new EmptySlotDisplay(); + } + return new ItemStackSlotDisplay(this.getItemStack()); + } + public Item asItem() { if (isEmpty()) { return Items.AIR; 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/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 7e55261f4..ef8ad17ef 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,6 +78,7 @@ 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; @@ -141,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; @@ -311,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 @@ -447,6 +450,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final Int2ObjectMap> javaToBedrockRecipeIds; private final Int2ObjectMap craftingRecipes; + @Setter + private Pair lastCreatedRecipe = null; // TODO try to prevent sending duplicate recipes private final AtomicInteger lastRecipeNetId; /** @@ -455,6 +460,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { */ @Setter private Int2ObjectMap stonecutterRecipes; + private final List smithingRecipes = new ArrayList<>(); /** * Whether to work around 1.13's different behavior in villager trading menus. 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/protocol/java/JavaRecipeBookAddTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookAddTranslator.java index da8fd01d3..f23ebebcb 100644 --- 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 @@ -42,6 +42,7 @@ 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; @@ -176,6 +177,8 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator { + session.setContainerOutputFuture(session.scheduleInEventLoop(() -> { int offset = gridSize == 4 ? 28 : 32; int gridDimensions = gridSize == 4 ? 2 : 3; int firstRow = -1, height = -1; @@ -172,7 +179,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(); + + ItemData bedrockAddition = ItemTranslator.translateToBedrock(session, material.getItemStack()); + + 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(bedrockAddition), + 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)); + } } From 8ba70f0fc83c9732f4c84cb52808e9a49e4aed41 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 29 Oct 2024 23:16:24 -0400 Subject: [PATCH 422/897] Implement remainder slot display recipes --- .../java/org/geysermc/geyser/entity/EntityDefinitions.java | 1 + .../protocol/java/JavaFinishConfigurationTranslator.java | 1 + .../protocol/java/JavaRecipeBookAddTranslator.java | 5 +++++ .../protocol/java/JavaSelectKnownPacksTranslator.java | 3 ++- .../java/inventory/JavaContainerSetSlotTranslator.java | 4 +--- .../sound/block/ComparatorSoundInteractionTranslator.java | 5 ++--- .../sound/block/GrassPathInteractionTranslator.java | 4 +--- .../translator/sound/block/HoeInteractionTranslator.java | 4 +--- .../sound/block/LeverSoundInteractionTranslator.java | 5 ++--- .../sound/block/OpenableSoundInteractionTranslator.java | 5 ++--- .../main/java/org/geysermc/geyser/util/InventoryUtils.java | 4 ++++ 11 files changed, 22 insertions(+), 19 deletions(-) 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 1443a9443..62283f4df 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -858,6 +858,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) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java index 6cbefde0d..d73c2e2ed 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java @@ -74,6 +74,7 @@ public class JavaFinishConfigurationTranslator 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 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(); } From 74b25ea3a5f5e1e4ad45805140553b4c539837ee Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 30 Oct 2024 10:41:00 +0100 Subject: [PATCH 423/897] Use deferred where needed instead of a load method on all registries (#5112) * Use deferred where needed instead of a load method on all registries * We don't have to load the registries, they're now safe to use for tests * Renamed the deferred registries --- .../java/org/geysermc/geyser/GeyserImpl.java | 1 - .../AbstractMappedDeferredRegistry.java | 103 +++++++++++ .../geyser/registry/BlockRegistries.java | 20 +- .../geyser/registry/DeferredRegistry.java | 72 ++----- .../geyser/registry/ListDeferredRegistry.java | 175 ++++++++++++++++++ .../geyser/registry/ListRegistry.java | 12 ++ .../geysermc/geyser/registry/Registries.java | 55 +++--- .../geysermc/geyser/registry/Registry.java | 15 +- .../registry/SimpleDeferredRegistry.java | 119 ++++++++++++ .../SimpleMappedDeferredRegistry.java | 120 ++++++++++++ .../registry/VersionedDeferredRegistry.java | 114 ++++++++++++ .../registry/loader/RegistryLoaderHolder.java | 33 ---- .../network/util/GeyserMockContext.java | 6 - 13 files changed, 689 insertions(+), 156 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/AbstractMappedDeferredRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/ListDeferredRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/SimpleDeferredRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/SimpleMappedDeferredRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/VersionedDeferredRegistry.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index f679b412c..0a8222f8d 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -236,7 +236,6 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { Both the block registries and the common registries depend on each other, so maintaining this order is crucial for Geyser to load. */ - BlockRegistries.load(); Registries.load(); BlockRegistries.populate(); Registries.populate(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedDeferredRegistry.java new file mode 100644 index 000000000..2506bb873 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedDeferredRegistry.java @@ -0,0 +1,103 @@ +/* + * 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; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +public abstract class AbstractMappedDeferredRegistry, R extends AbstractMappedRegistry> extends DeferredRegistry { + protected AbstractMappedDeferredRegistry(Function, R> registryLoader, RegistryLoader deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected AbstractMappedDeferredRegistry(Function, R> registryLoader, Supplier> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected AbstractMappedDeferredRegistry(I input, RegistryInitializer registryInitializer, RegistryLoader deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected AbstractMappedDeferredRegistry(I input, RegistryInitializer registryInitializer, Supplier> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + /** + * Returns the value registered by the given key. + * + * @param key the key + * @return the value registered by the given key. + */ + public @Nullable V get(K key) { + return get().get(key); + } + + /** + * Returns and maps the value by the given key if present. + * + * @param key the key + * @param mapper the mapper + * @param the type + * @return the mapped value from the given key if present + */ + public Optional map(K key, Function mapper) { + V value = this.get(key); + if (value == null) { + return Optional.empty(); + } else { + return Optional.ofNullable(mapper.apply(value)); + } + } + + /** + * Returns the value registered by the given key or the default value + * specified if null. + * + * @param key the key + * @param defaultValue the default value + * @return the value registered by the given key or the default value + * specified if null. + */ + public V getOrDefault(K key, V defaultValue) { + return get().getOrDefault(key, defaultValue); + } + + /** + * Registers a new value into this registry with the given key. + * + * @param key the key + * @param value the value + * @return a new value into this registry with the given key. + */ + public V register(K key, V value) { + return get().put(key, value); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index b7c5e2d07..521d67542 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -69,7 +69,7 @@ public class BlockRegistries { /** * A mapped registry containing which holds block IDs to its {@link BlockCollision}. */ - public static final ListRegistry COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); + public static final ListDeferredRegistry COLLISIONS = ListDeferredRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); /** * A registry which stores Java IDs to {@link Block}, containing miscellaneous information about @@ -130,23 +130,6 @@ public class BlockRegistries { */ public static final SimpleMappedRegistry CUSTOM_SKULLS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); - public static void load() { - BLOCKS.load(); - BLOCK_STATES.load(); - // collisions are loaded later, because they are initialized later - JAVA_BLOCKS.load(); - JAVA_IDENTIFIER_TO_ID.load(); - WATERLOGGED.load(); - INTERACTIVE.load(); - INTERACTIVE_MAY_BUILD.load(); - CUSTOM_BLOCKS.load(); - CUSTOM_BLOCK_STATE_OVERRIDES.load(); - NON_VANILLA_BLOCK_STATE_OVERRIDES.load(); - CUSTOM_BLOCK_ITEM_OVERRIDES.load(); - EXTENDED_COLLISION_BOXES.load(); - CUSTOM_SKULLS.load(); - } - public static void populate() { Blocks.VAULT.javaId(); // FIXME CustomSkullRegistryPopulator.populate(); @@ -160,5 +143,4 @@ public class BlockRegistries { BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.POST_INIT); } - } diff --git a/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java index ce77261ae..f4273edea 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java @@ -43,32 +43,36 @@ import java.util.function.Supplier; * * @param the value being held by the registry */ -public final class DeferredRegistry implements IRegistry { - private final Registry backingRegistry; +class DeferredRegistry> implements IRegistry { + private final R backingRegistry; private final Supplier loader; private boolean loaded; - private DeferredRegistry(Function, Registry> registryLoader, RegistryLoader deferredLoader) { + protected DeferredRegistry(Function, R> registryLoader, RegistryLoader deferredLoader) { this.backingRegistry = registryLoader.apply(RegistryLoaders.uninitialized()); this.loader = () -> deferredLoader.load(null); } - private DeferredRegistry(Function, Registry> registryLoader, Supplier> deferredLoader) { + protected DeferredRegistry(Function, R> registryLoader, Supplier> deferredLoader) { this.backingRegistry = registryLoader.apply(RegistryLoaders.uninitialized()); this.loader = () -> deferredLoader.get().load(null); } - private DeferredRegistry(I input, RegistryInitializer registryInitializer, RegistryLoader deferredLoader) { + protected DeferredRegistry(I input, RegistryInitializer registryInitializer, RegistryLoader deferredLoader) { this.backingRegistry = registryInitializer.initialize(input, RegistryLoaders.uninitialized()); this.loader = () -> deferredLoader.load(input); } - private DeferredRegistry(I input, RegistryInitializer registryInitializer, Supplier> deferredLoader) { + protected DeferredRegistry(I input, RegistryInitializer registryInitializer, Supplier> deferredLoader) { this.backingRegistry = registryInitializer.initialize(input, RegistryLoaders.uninitialized()); this.loader = () -> deferredLoader.get().load(input); } + protected R backingRegistry() { + return this.backingRegistry; + } + /** * Gets the underlying value held by this registry. * @@ -119,64 +123,12 @@ public final class DeferredRegistry implements IRegistry { return this.loaded; } - /** - * Creates a new deferred registry. - * - * @param registryLoader the registry loader - * @param deferredLoader the deferred loader - * @param the input type - * @param the registry type - * @return the new deferred registry - */ - public static DeferredRegistry create(Function, Registry> registryLoader, RegistryLoader deferredLoader) { - return new DeferredRegistry<>(registryLoader, deferredLoader); - } - - /** - * Creates a new deferred registry. - * - * @param registryLoader the registry loader - * @param deferredLoader the deferred loader - * @param the input type - * @param the registry type - * @return the new deferred registry - */ - public static DeferredRegistry create(Function, Registry> registryLoader, Supplier> deferredLoader) { - return new DeferredRegistry<>(registryLoader, deferredLoader); - } - - /** - * Creates a new deferred registry. - * - * @param registryInitializer the registry initializer - * @param deferredLoader the deferred loader - * @param the input type - * @param the registry type - * @return the new deferred registry - */ - public static DeferredRegistry create(I input, RegistryInitializer registryInitializer, RegistryLoader deferredLoader) { - return new DeferredRegistry<>(input, registryInitializer, deferredLoader); - } - - /** - * Creates a new deferred registry. - * - * @param registryInitializer the registry initializer - * @param deferredLoader the deferred loader - * @param the input type - * @param the registry type - * @return the new deferred registry - */ - public static DeferredRegistry create(I input, RegistryInitializer registryInitializer, Supplier> deferredLoader) { - return new DeferredRegistry<>(input, registryInitializer, deferredLoader); - } - /** * A registry initializer. * * @param the registry type */ - interface RegistryInitializer { + public interface RegistryInitializer> { /** * Initializes the registry. @@ -186,6 +138,6 @@ public final class DeferredRegistry implements IRegistry { * @param the input type * @return the initialized registry */ - Registry initialize(I input, RegistryLoader registryLoader); + R initialize(I input, RegistryLoader registryLoader); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListDeferredRegistry.java new file mode 100644 index 000000000..91dc74eb7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/ListDeferredRegistry.java @@ -0,0 +1,175 @@ +/* + * 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; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +public class ListDeferredRegistry extends DeferredRegistry, ListRegistry> { + protected ListDeferredRegistry(Function>, ListRegistry> registryLoader, RegistryLoader> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected ListDeferredRegistry(Function>, ListRegistry> registryLoader, Supplier>> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected ListDeferredRegistry(I input, RegistryInitializer, ListRegistry> registryInitializer, RegistryLoader> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected ListDeferredRegistry(I input, RegistryInitializer, ListRegistry> registryInitializer, Supplier>> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + /** + * Returns the value registered by the given index. + * + * @param index the index + * @return the value registered by the given index. + */ + @Nullable + public V get(int index) { + return backingRegistry().get(index); + } + + /** + * Returns the value registered by the given index or the default value + * specified if null. + * + * @param index the index + * @param defaultValue the default value + * @return the value registered by the given key or the default value + * specified if null. + */ + public V getOrDefault(int index, V defaultValue) { + return backingRegistry().getOrDefault(index, defaultValue); + } + + /** + * Registers a new value into this registry with the given index. + * + * @param index the index + * @param value the value + * @return a new value into this registry with the given index. + */ + public V register(int index, V value) { + return backingRegistry().register(index, value); + } + + /** + * Registers a new value into this registry with the given index, even if this value would normally be outside + * the range of a list. + * + * @param index the index + * @param value the value + * @param defaultValue the default value to fill empty spaces in the registry with. + * @return a new value into this registry with the given index. + */ + public V registerWithAnyIndex(int index, V value, V defaultValue) { + return backingRegistry().registerWithAnyIndex(index, value, defaultValue); + } + + /** + * Mark this registry as unsuitable for new additions. The backing list will then be optimized for storage. + */ + public void freeze() { + backingRegistry().freeze(); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(Function>, ListRegistry> registryLoader, RegistryLoader> deferredLoader) { + return new ListDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(Function>, ListRegistry> registryLoader, Supplier>> deferredLoader) { + return new ListDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(I input, RegistryInitializer, ListRegistry> registryInitializer, RegistryLoader> deferredLoader) { + return new ListDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(I input, RegistryInitializer, ListRegistry> registryInitializer, Supplier>> deferredLoader) { + return new ListDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(I input, RegistryLoader> deferredLoader) { + return create(input, ListRegistry::create, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(I input, Supplier>> deferredLoader) { + return create(input, ListRegistry::create, deferredLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java index 2070d67ae..d1d3d7af0 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java @@ -140,6 +140,18 @@ public class ListRegistry extends Registry> { return new ListRegistry<>(null, registryLoader); } + /** + * Creates a new integer mapped registry with the given {@link RegistryLoader} and input. + * + * @param registryLoader the registry loader + * @param the input + * @param the type value + * @return a new registry with the given RegistryLoader + */ + public static ListRegistry create(I input, RegistryLoader> registryLoader) { + return new ListRegistry<>(input, registryLoader); + } + /** * Creates a new integer mapped registry with the given {@link RegistryLoader} and input. * 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 b86ea3bbf..0d286d5c3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -37,10 +37,18 @@ import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.loader.*; +import org.geysermc.geyser.registry.loader.BiomeIdentifierRegistryLoader; +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.loader.RecipeRegistryLoader; import org.geysermc.geyser.registry.provider.ProviderSupplier; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ParticleMapping; @@ -56,7 +64,13 @@ 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.*; +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; /** * Holds all the common registries in Geyser. @@ -73,7 +87,7 @@ public final class Registries { /** * A registry holding a NbtMap of the known entity identifiers. */ - public static final SimpleRegistry BEDROCK_ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); + public static final SimpleDeferredRegistry BEDROCK_ENTITY_IDENTIFIERS = SimpleDeferredRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); /** * A registry containing all the Bedrock packet translators. @@ -83,17 +97,17 @@ public final class Registries { /** * A registry holding a NbtMap of all the known biomes. */ - public static final SimpleRegistry BIOMES_NBT = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); + public static final SimpleDeferredRegistry BIOMES_NBT = SimpleDeferredRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); /** * A mapped registry which stores Java biome identifiers and their Bedrock biome identifier. */ - public static final SimpleRegistry> BIOME_IDENTIFIERS = SimpleRegistry.create("mappings/biomes.json", BiomeIdentifierRegistryLoader::new); + public static final SimpleDeferredRegistry> BIOME_IDENTIFIERS = SimpleDeferredRegistry.create("mappings/biomes.json", BiomeIdentifierRegistryLoader::new); /** * A mapped registry which stores a block entity identifier to its {@link BlockEntityTranslator}. */ - public static final SimpleMappedRegistry BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new); + public static final SimpleMappedDeferredRegistry BLOCK_ENTITIES = SimpleMappedDeferredRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new); /** * A map containing all entity types and their respective Geyser definitions @@ -135,55 +149,50 @@ public final class Registries { * A mapped registry holding the {@link ParticleType} to a corresponding {@link ParticleMapping}, containing various pieces of * data primarily for how Bedrock should handle the particle. */ - public static final SimpleMappedRegistry PARTICLES = SimpleMappedRegistry.create("mappings/particles.json", ParticleTypesRegistryLoader::new); + public static final SimpleMappedDeferredRegistry PARTICLES = SimpleMappedDeferredRegistry.create("mappings/particles.json", ParticleTypesRegistryLoader::new); /** * A registry holding all the potion mixes. */ - public static final VersionedRegistry> POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); + public static final VersionedDeferredRegistry> POTION_MIXES = VersionedDeferredRegistry.create(VersionedRegistry::create, PotionMixRegistryLoader::new); /** * A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value. */ - public static final SimpleMappedRegistry> RECIPES = SimpleMappedRegistry.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 DeferredRegistry> RESOURCE_PACKS = DeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), SimpleMappedRegistry::create, RegistryLoaders.RESOURCE_PACKS); + public static final SimpleMappedDeferredRegistry RESOURCE_PACKS = SimpleMappedDeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), RegistryLoaders.RESOURCE_PACKS); /** * A mapped registry holding sound identifiers to their corresponding {@link SoundMapping}. */ - public static final SimpleMappedRegistry SOUNDS = SimpleMappedRegistry.create("mappings/sounds.json", SoundRegistryLoader::new); + public static final SimpleMappedDeferredRegistry SOUNDS = SimpleMappedDeferredRegistry.create("mappings/sounds.json", SoundRegistryLoader::new); /** * A mapped registry holding {@link LevelEvent}s to their corresponding {@link LevelEventTranslator}. */ - public static final SimpleMappedRegistry SOUND_LEVEL_EVENTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); + public static final SimpleMappedDeferredRegistry SOUND_LEVEL_EVENTS = SimpleMappedDeferredRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); /** * A mapped registry holding {@link SoundTranslator}s to their corresponding {@link SoundInteractionTranslator}. */ - public static final SimpleMappedRegistry> SOUND_TRANSLATORS = SimpleMappedRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); + public static final SimpleMappedDeferredRegistry> SOUND_TRANSLATORS = SimpleMappedDeferredRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); public static void load() { if (loaded) return; loaded = true; - PROVIDERS.load(); + // the following registries are registries that are more complicated than initializing as an empty collection. + // They generally have in common that they either depend on loading a resource file directly or indirectly + // (by using the Items or Blocks class, which loads all the blocks) + BEDROCK_ENTITY_IDENTIFIERS.load(); - BEDROCK_PACKET_TRANSLATORS.load(); BIOMES_NBT.load(); BIOME_IDENTIFIERS.load(); BLOCK_ENTITIES.load(); - ENTITY_DEFINITIONS.load(); - BEDROCK_ENTITY_PROPERTIES.load(); - JAVA_ENTITY_IDENTIFIERS.load(); - JAVA_PACKET_TRANSLATORS.load(); - JAVA_ITEMS.load(); - JAVA_ITEM_IDENTIFIERS.load(); - ITEMS.load(); PARTICLES.load(); // load potion mixes later RECIPES.load(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registry.java b/core/src/main/java/org/geysermc/geyser/registry/Registry.java index 4e83a3c2e..8a82af053 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registry.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.registry; import java.util.function.Consumer; import org.geysermc.geyser.registry.loader.RegistryLoader; -import org.geysermc.geyser.registry.loader.RegistryLoaderHolder; /** * A wrapper around a value which is loaded based on the output from the provided @@ -63,9 +62,7 @@ import org.geysermc.geyser.registry.loader.RegistryLoaderHolder; * * @param the value being held by the registry */ -@SuppressWarnings("rawtypes") public abstract class Registry implements IRegistry { - protected RegistryLoaderHolder loaderHolder; protected M mappings; /** @@ -78,17 +75,7 @@ public abstract class Registry implements IRegistry { * @param the input type */ protected Registry(I input, RegistryLoader registryLoader) { - this.loaderHolder = new RegistryLoaderHolder<>(input, registryLoader); - } - - public void load() { - // don't load twice - if (this.mappings != null) return; - - var holder = this.loaderHolder; - this.loaderHolder = null; - //noinspection unchecked - this.mappings = (M) holder.registryLoader().load(holder.input()); + this.mappings = registryLoader.load(input); } /** diff --git a/core/src/main/java/org/geysermc/geyser/registry/SimpleDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/SimpleDeferredRegistry.java new file mode 100644 index 000000000..cdbd985be --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/SimpleDeferredRegistry.java @@ -0,0 +1,119 @@ +/* + * 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; + +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.function.Function; +import java.util.function.Supplier; + +public class SimpleDeferredRegistry extends DeferredRegistry> { + protected SimpleDeferredRegistry(Function, SimpleRegistry> registryLoader, RegistryLoader deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected SimpleDeferredRegistry(Function, SimpleRegistry> registryLoader, Supplier> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected SimpleDeferredRegistry(I input, RegistryInitializer> registryInitializer, RegistryLoader deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected SimpleDeferredRegistry(I input, RegistryInitializer> registryInitializer, Supplier> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(Function, SimpleRegistry> registryLoader, RegistryLoader deferredLoader) { + return new SimpleDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(Function, SimpleRegistry> registryLoader, Supplier> deferredLoader) { + return new SimpleDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(I input, RegistryInitializer> registryInitializer, RegistryLoader deferredLoader) { + return new SimpleDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(I input, RegistryInitializer> registryInitializer, Supplier> deferredLoader) { + return new SimpleDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(I input, RegistryLoader deferredLoader) { + return create(input, SimpleRegistry::create, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(I input, Supplier> deferredLoader) { + return create(input, SimpleRegistry::create, deferredLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedDeferredRegistry.java new file mode 100644 index 000000000..6a837c9e0 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedDeferredRegistry.java @@ -0,0 +1,120 @@ +/* + * 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; + +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.Map; +import java.util.function.Function; +import java.util.function.Supplier; + +public class SimpleMappedDeferredRegistry extends AbstractMappedDeferredRegistry, SimpleMappedRegistry> { + protected SimpleMappedDeferredRegistry(Function>, SimpleMappedRegistry> registryLoader, RegistryLoader> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected SimpleMappedDeferredRegistry(Function>, SimpleMappedRegistry> registryLoader, Supplier>> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected SimpleMappedDeferredRegistry(I input, RegistryInitializer, SimpleMappedRegistry> registryInitializer, RegistryLoader> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected SimpleMappedDeferredRegistry(I input, RegistryInitializer, SimpleMappedRegistry> registryInitializer, Supplier>> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(Function>, SimpleMappedRegistry> registryLoader, RegistryLoader> deferredLoader) { + return new SimpleMappedDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(Function>, SimpleMappedRegistry> registryLoader, Supplier>> deferredLoader) { + return new SimpleMappedDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(I input, DeferredRegistry.RegistryInitializer, SimpleMappedRegistry> registryInitializer, RegistryLoader> deferredLoader) { + return new SimpleMappedDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(I input, DeferredRegistry.RegistryInitializer, SimpleMappedRegistry> registryInitializer, Supplier>> deferredLoader) { + return new SimpleMappedDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(I input, RegistryLoader> deferredLoader) { + return create(input, SimpleMappedRegistry::create, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(I input, Supplier>> deferredLoader) { + return create(input, SimpleMappedRegistry::create, deferredLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/VersionedDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/VersionedDeferredRegistry.java new file mode 100644 index 000000000..6b2f9906b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/VersionedDeferredRegistry.java @@ -0,0 +1,114 @@ +/* + * 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; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.function.Function; +import java.util.function.Supplier; + +public class VersionedDeferredRegistry extends AbstractMappedDeferredRegistry, VersionedRegistry> { + protected VersionedDeferredRegistry(Function>, VersionedRegistry> registryLoader, RegistryLoader> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected VersionedDeferredRegistry(Function>, VersionedRegistry> registryLoader, Supplier>> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected VersionedDeferredRegistry(I input, RegistryInitializer, VersionedRegistry> registryInitializer, RegistryLoader> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected VersionedDeferredRegistry(I input, RegistryInitializer, VersionedRegistry> registryInitializer, Supplier>> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + /** + * Gets the closest value for the specified version. Only + * returns versions higher up than the specified if one + * does not exist for the given one. Useful in the event + * that you want to get a resource which is guaranteed for + * older versions, but not on newer ones. + * + * @param version the version + * @return the closest value for the specified version + * @throws IllegalArgumentException if no values exist at or above the given version + */ + @NonNull + public V forVersion(int version) { + return backingRegistry().forVersion(version); + } + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static VersionedDeferredRegistry create(Function>, VersionedRegistry> registryLoader, RegistryLoader> deferredLoader) { + return new VersionedDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static VersionedDeferredRegistry create(Function>, VersionedRegistry> registryLoader, Supplier>> deferredLoader) { + return new VersionedDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static VersionedDeferredRegistry create(I input, RegistryInitializer, VersionedRegistry> registryInitializer, RegistryLoader> deferredLoader) { + return new VersionedDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static VersionedDeferredRegistry create(I input, RegistryInitializer, VersionedRegistry> registryInitializer, Supplier>> deferredLoader) { + return new VersionedDeferredRegistry<>(input, registryInitializer, deferredLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java b/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java deleted file mode 100644 index 751cb4ed4..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.loader; - -/** - * A holder of the constructor parameters to prevent them from automatically loading, - * and instead load them when the load method is called. - */ -public record RegistryLoaderHolder(I input, RegistryLoader registryLoader) { -} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java index 1d262d8b8..2b89867fb 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java @@ -61,12 +61,6 @@ public class GeyserMockContext { try (var geyserImplMock = mockStatic(GeyserImpl.class)) { geyserImplMock.when(GeyserImpl::getInstance).thenReturn(geyserImpl); - // Since Geyser isn't actually loaded, the Registries#init will not be called. - // This means that we manually load the registries we want to use - Registries.ENTITY_DEFINITIONS.load(); - Registries.JAVA_ENTITY_IDENTIFIERS.load(); - Registries.BEDROCK_ENTITY_PROPERTIES.load(); - geyserContext.accept(context); } } From 448c75e8f2ec330893f8669e5ab4b8d5fb7c3121 Mon Sep 17 00:00:00 2001 From: Tjorven Liebe <32434395+Tjorven-Liebe@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:53:43 +0100 Subject: [PATCH 424/897] Fix pulling and placing skulls/heads from creative inventory (#5114) * fix: pulling and placing skulls/heads from creative inventory * fix: getting values of map * fix: correct submodule permalink --- .../registry/populator/Conversion685_671.java | 21 ++++---- .../registry/populator/Conversion712_685.java | 51 +++++++++---------- .../registry/populator/Conversion729_712.java | 1 + .../registry/populator/Conversion748_729.java | 48 +++++++++++++++++ .../populator/ItemRegistryPopulator.java | 10 +--- core/src/main/resources/mappings | 2 +- 6 files changed, 87 insertions(+), 46 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java index 0c7f540bf..c72ea64b2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java @@ -46,8 +46,7 @@ public class Conversion685_671 { static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { mapping = Conversion712_685.remapItem(item, mapping); - - String identifer = mapping.getBedrockIdentifier(); + String identifier = mapping.getBedrockIdentifier(); if (NEW_MUSIC_DISCS.contains(item)) { return mapping.withBedrockIdentifier("minecraft:music_disc_otherside"); @@ -59,12 +58,12 @@ public class Conversion685_671 { return mapping.withBedrockIdentifier("minecraft:glass_bottle"); } - if (!NEW_BLOCKS.contains(identifer)) { + if (!NEW_BLOCKS.contains(identifier)) { return mapping; } - if (NEW_CORAL_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_CORAL_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(0); } case "minecraft:brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(1); } case "minecraft:bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(2); } @@ -78,8 +77,8 @@ public class Conversion685_671 { } } - if (NEW_DOUBLE_PLANTS.contains(identifer)) { - switch (identifer) { + if (NEW_DOUBLE_PLANTS.contains(identifier)) { + switch (identifier) { case "minecraft:sunflower" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(0); } case "minecraft:lilac" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(1); } case "minecraft:tall_grass" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(2); } @@ -89,8 +88,8 @@ public class Conversion685_671 { } } - if (NEW_STONE_BLOCK_SLABS.contains(identifer)) { - switch (identifer) { + if (NEW_STONE_BLOCK_SLABS.contains(identifier)) { + switch (identifier) { case "minecraft:smooth_stone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(0); } case "minecraft:sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(1); } case "minecraft:petrified_oak_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(2); } @@ -102,8 +101,8 @@ public class Conversion685_671 { } } - if (NEW_TALLGRASSES.contains(identifer)) { - switch (identifer) { + if (NEW_TALLGRASSES.contains(identifier)) { + switch (identifier) { case "minecraft:short_grass" -> { return mapping.withBedrockIdentifier("minecraft:tallgrass").withBedrockData(1); } case "minecraft:fern" -> { return mapping.withBedrockIdentifier("minecraft:tallgrass").withBedrockData(2); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java index db715e015..45963cb90 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java @@ -33,35 +33,34 @@ public class Conversion712_685 { static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { mapping = Conversion729_712.remapItem(item, mapping); + String identifier = mapping.getBedrockIdentifier(); - String identifer = mapping.getBedrockIdentifier(); - - if (!NEW_BLOCKS.contains(identifer)) { + if (!NEW_BLOCKS.contains(identifier)) { return mapping; } - if (identifer.equals("minecraft:coarse_dirt")) { + if (identifier.equals("minecraft:coarse_dirt")) { return mapping.withBedrockIdentifier("minecraft:dirt").withBedrockData(1); } - if (identifer.equals("minecraft:dandelion")) { + if (identifier.equals("minecraft:dandelion")) { return mapping.withBedrockIdentifier("minecraft:yellow_flower").withBedrockData(0); } - if (identifer.equals("minecraft:red_sand")) { + if (identifier.equals("minecraft:red_sand")) { return mapping.withBedrockIdentifier("minecraft:sand").withBedrockData(1); } - if (NEW_PRISMARINE_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_PRISMARINE_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:prismarine" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(0); } case "minecraft:dark_prismarine" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(1); } case "minecraft:prismarine_bricks" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(2); } } } - if (NEW_SANDSTONE_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_SANDSTONE_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(0); } case "minecraft:chiseled_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(1); } case "minecraft:cut_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(2); } @@ -69,8 +68,8 @@ public class Conversion712_685 { } } - if (NEW_RED_SANDSTONE_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_RED_SANDSTONE_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(0); } case "minecraft:chiseled_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(1); } case "minecraft:cut_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(2); } @@ -78,8 +77,8 @@ public class Conversion712_685 { } } - if (NEW_QUARTZ_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_QUARTZ_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:quartz_block" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(0); } case "minecraft:chiseled_quartz_block" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(1); } case "minecraft:quartz_pillar" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(2); } @@ -87,8 +86,8 @@ public class Conversion712_685 { } } - if (NEW_STONE_BLOCK_SLABS_2.contains(identifer)) { - switch (identifer) { + if (NEW_STONE_BLOCK_SLABS_2.contains(identifier)) { + switch (identifier) { case "minecraft:red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(0); } case "minecraft:purpur_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(1); } case "minecraft:prismarine_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(2); } @@ -100,8 +99,8 @@ public class Conversion712_685 { } } - if (NEW_STONE_BLOCK_SLABS_3.contains(identifer)) { - switch (identifer) { + if (NEW_STONE_BLOCK_SLABS_3.contains(identifier)) { + switch (identifier) { case "minecraft:end_stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(0); } case "minecraft:smooth_red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(1); } case "minecraft:polished_andesite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(2); } @@ -113,8 +112,8 @@ public class Conversion712_685 { } } - if (NEW_STONE_BLOCK_SLABS_4.contains(identifer)) { - switch (identifer) { + if (NEW_STONE_BLOCK_SLABS_4.contains(identifier)) { + switch (identifier) { case "minecraft:mossy_stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(0); } case "minecraft:smooth_quartz_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(1); } case "minecraft:normal_stone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(2); } @@ -123,8 +122,8 @@ public class Conversion712_685 { } } - if (NEW_MONSTER_EGGS.contains(identifer)) { - switch (identifer) { + if (NEW_MONSTER_EGGS.contains(identifier)) { + switch (identifier) { case "minecraft:infested_stone" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(0); } case "minecraft:infested_cobblestone" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(1); } case "minecraft:infested_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(2); } @@ -134,8 +133,8 @@ public class Conversion712_685 { } } - if (NEW_STONEBRICK_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_STONEBRICK_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(0); } case "minecraft:mossy_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(1); } case "minecraft:cracked_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(2); } @@ -143,8 +142,8 @@ public class Conversion712_685 { } } - if (NEW_ANVILS.contains(identifer)) { - switch (identifer) { + if (NEW_ANVILS.contains(identifier)) { + switch (identifier) { case "minecraft:anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(0); } case "minecraft:chipped_anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(4); } case "minecraft:damaged_anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(8); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java index 5d4ebdc47..fbc2233bc 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java @@ -16,6 +16,7 @@ public class Conversion729_712 { private static final List NEW_BLOCKS = Stream.of(NEW_PURPUR_BLOCKS, NEW_WALL_BLOCKS, NEW_SPONGE_BLOCKS, NEW_TNT_BLOCKS, STRUCTURE_VOID).flatMap(List::stream).toList(); static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { + mapping = Conversion748_729.remapItem(item, mapping); String identifier = mapping.getBedrockIdentifier(); if (!NEW_BLOCKS.contains(identifier)) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java new file mode 100644 index 000000000..7a2d1a0cb --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java @@ -0,0 +1,48 @@ +/* + * 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 org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.type.GeyserMappingItem; + +import java.util.Map; + +public class Conversion748_729 { + + private static final Map NEW_PLAYER_HEADS = Map.of("minecraft:skeleton_skull", 0, "minecraft:wither_skeleton_skull", 1, "minecraft:zombie_head", 2, "minecraft:player_head", 3, "minecraft:creeper_head", 4, "minecraft:dragon_head", 5, "minecraft:piglin_head", 6); + + static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { + String identifier = mapping.getBedrockIdentifier(); + + if (NEW_PLAYER_HEADS.containsKey(identifier)) { + return mapping.withBedrockIdentifier("minecraft:skull") + .withBedrockData(NEW_PLAYER_HEADS.get(identifier)); + } + + return mapping; + } + +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 0b61c7999..65a35aa50 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -113,14 +113,8 @@ public class ItemRegistryPopulator { 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())); - paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), Collections.emptyMap(), (item, mapping) -> { - String identifier = item.javaIdentifier(); - if (identifier.endsWith("_head") || identifier.endsWith("_skull")) { - return mapping.withBedrockIdentifier(item.javaIdentifier()); - } - return mapping; - })); + paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion748_729::remapItem)); + paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 93f207e7e..a6d04157d 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 93f207e7e9d73f58a7c8902f7deda9dcb0524c8e +Subproject commit a6d04157d1866e55e35f2ce3ebde3cf4e007aabf From c34b4b311f960b49c8f606cc80534ed7392ef69d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:37:10 -0400 Subject: [PATCH 425/897] Clean out debug logging statements --- .../org/geysermc/geyser/network/UpstreamPacketHandler.java | 7 ------- .../entity/player/BedrockPlayerAuthInputTranslator.java | 5 ----- .../protocol/java/JavaRecipeBookAddTranslator.java | 4 ---- .../protocol/java/JavaUpdateRecipesTranslator.java | 5 ----- .../java/entity/player/JavaPlayerPositionTranslator.java | 1 - .../main/java/org/geysermc/geyser/util/InventoryUtils.java | 3 +-- 6 files changed, 1 insertion(+), 24 deletions(-) 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 b797eb811..19e56c8a8 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -41,7 +41,6 @@ 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; @@ -65,7 +64,6 @@ import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.PendingMicrosoftAuthentication; -import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.LoginEncryptionUtils; import org.geysermc.geyser.util.MathUtils; @@ -96,11 +94,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } private PacketSignal translateAndDefault(BedrockPacket packet) { - if (packet instanceof PlayerAuthInputPacket) { - //System.out.println(packet); - } else { - System.out.println(ChatColor.toANSI(ChatColor.GREEN) + packet + ChatColor.ANSI_RESET); - } Registries.BEDROCK_PACKET_TRANSLATORS.translate(packet.getClass(), packet, session); return PacketSignal.HANDLED; // PacketSignal.UNHANDLED will log a WARN publicly } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java index a366a5b69..a07ebe04a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -66,14 +66,9 @@ import java.util.Set; @Translator(packet = PlayerAuthInputPacket.class) public final class BedrockPlayerAuthInputTranslator extends PacketTranslator { - private Set data = Set.of(); @Override public void translate(GeyserSession session, PlayerAuthInputPacket packet) { - if (!data.equals(packet.getInputData())) { - System.out.println(packet.getInputData()); - this.data = packet.getInputData(); - } SessionPlayerEntity entity = session.getPlayerEntity(); boolean wasJumping = session.getInputCache().wasJumping(); 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 index 182a1b7d5..5cc2e3063 100644 --- 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 @@ -84,7 +84,6 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator> javaToBedrockRecipeIds = session.getJavaToBedrockRecipeIds(); Int2ObjectMap geyserRecipes = session.getCraftingRecipes(); @@ -179,12 +178,10 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator list : inputs) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 9f53a9af4..ad67da81e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -57,14 +57,12 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.Clientbound import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket.SelectableRecipe; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.UUID; -import java.util.stream.Collectors; /** * Used to send all valid recipes from Java to Bedrock. @@ -103,7 +101,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Registries.JAVA_ITEMS.get(i).javaIdentifier()).collect(Collectors.joining(" "))); - System.out.println(Arrays.stream(smithingAddition).mapToObj(i -> Registries.JAVA_ITEMS.get(i).javaIdentifier()).collect(Collectors.joining(" "))); oldSmithingTable = false; // BDS sends armor trim templates and materials before the CraftingDataPacket TrimDataPacket trimDataPacket = new TrimDataPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java index 89e8eff82..ca1b95997 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java @@ -47,7 +47,6 @@ public class JavaPlayerPositionTranslator extends PacketTranslator Date: Wed, 30 Oct 2024 20:11:34 -0400 Subject: [PATCH 426/897] Indicate support for Bedrock 1.21.43 --- README.md | 2 +- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3e99a96a7..fedb5bb96 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.41 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.43 and Minecraft Java 1.21/1.21.1. 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/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index c39629917..464edd487 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -52,7 +52,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() - .minecraftVersion("1.21.41") + .minecraftVersion("1.21.43") .build()); /** @@ -83,7 +83,7 @@ public final class GameProtocol { .minecraftVersion("1.21.30/1.21.31") .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.40/1.21.41") + .minecraftVersion("1.21.40/1.21.41/1.21.43") .build()); } From 37b9e6591ee15471f27d025b75f43e5e435f1032 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:25:57 -0400 Subject: [PATCH 427/897] Re-enable testing --- core/build.gradle.kts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index ff1de4dc0..b0ea5fdf6 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -6,10 +6,6 @@ plugins { id("io.freefair.lombok") } -tasks.test { - enabled = false -} - dependencies { constraints { implementation(libs.raknet) // Ensure protocol does not override the RakNet version From 4588f341ec2cc484a3bb3c1e0b1acfd90aa2ef8a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:40:34 -0400 Subject: [PATCH 428/897] Fix test --- .../scoreboard/network/ScoreboardIssueTests.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) 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 From faf663d3cd235d129dadf86bdab2e18ec2acedb2 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Thu, 31 Oct 2024 09:30:01 +0100 Subject: [PATCH 429/897] Check if objective is null and made scoreboard errors player-specific --- .../org/geysermc/geyser/scoreboard/Scoreboard.java | 2 +- .../java/scoreboard/JavaResetScorePacket.java | 14 ++++++++++++++ .../java/scoreboard/JavaSetScoreTranslator.java | 11 ++++------- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java index 6e0867ddc..3d3bfb48d 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java @@ -178,7 +178,7 @@ public final class Scoreboard { Team team = teams.get(teamName); if (team != null) { if (SHOW_SCOREBOARD_LOGS) { - logger.info(GeyserLocale.getLocaleStringLog("geyser.network.translator.team.failed_overrides", teamName)); + logger.info("Ignoring team %s for %s. It overrides without removing old team.".formatted(teamName, session.javaUsername())); } return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java index cf688bbfd..72dcd4062 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaResetScorePacket.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.scoreboard.Objective; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; @@ -36,6 +38,10 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard. @Translator(packet = ClientboundResetScorePacket.class) public class JavaResetScorePacket extends PacketTranslator { + private static final boolean SHOW_SCOREBOARD_LOGS = Boolean.parseBoolean(System.getProperty("Geyser.ShowScoreboardLogs", "true")); + + private final GeyserLogger logger = GeyserImpl.getInstance().getLogger(); + @Override public void translate(GeyserSession session, ClientboundResetScorePacket packet) { WorldCache worldCache = session.getWorldCache(); @@ -47,6 +53,14 @@ public class JavaResetScorePacket extends PacketTranslator { private static final boolean SHOW_SCOREBOARD_LOGS = Boolean.parseBoolean(System.getProperty("Geyser.ShowScoreboardLogs", "true")); - private final GeyserLogger logger; - - public JavaSetScoreTranslator() { - logger = GeyserImpl.getInstance().getLogger(); - } + private final GeyserLogger logger = GeyserImpl.getInstance().getLogger(); @Override public void translate(GeyserSession session, ClientboundSetScorePacket packet) { @@ -56,7 +51,9 @@ public class JavaSetScoreTranslator extends PacketTranslator Date: Thu, 31 Oct 2024 22:52:26 +0000 Subject: [PATCH 430/897] Goat horns and item cooldowns for 1.21.2 (#5102) Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../inventory/item/GeyserInstrument.java | 166 ++++++++++++++++++ .../geyser/item/enchantment/Enchantment.java | 4 +- .../geysermc/geyser/item/type/ArrowItem.java | 5 +- .../geyser/item/type/CompassItem.java | 10 +- .../geyser/item/type/FilledMapItem.java | 5 +- .../geyser/item/type/GoatHornItem.java | 40 ++++- .../org/geysermc/geyser/item/type/Item.java | 4 +- .../geyser/item/type/OminousBottleItem.java | 9 +- .../geysermc/geyser/item/type/PotionItem.java | 11 +- .../geyser/item/type/TippedArrowItem.java | 5 +- .../geysermc/geyser/level/JukeboxSong.java | 12 +- .../geyser/session/cache/RegistryCache.java | 3 + .../geyser/session/cache/WorldCache.java | 28 ++- .../cache/registry/JavaRegistries.java | 2 + .../translator/item/ItemTranslator.java | 4 +- ...BedrockInventoryTransactionTranslator.java | 33 ++-- .../java/level/JavaCooldownTranslator.java | 9 +- .../translator/text/MessageTranslator.java | 21 +++ .../org/geysermc/geyser/util/SoundUtils.java | 15 ++ 19 files changed, 320 insertions(+), 66 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/inventory/item/GeyserInstrument.java 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/item/enchantment/Enchantment.java b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java index 9088d9626..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 @@ -41,7 +41,7 @@ import java.util.Map; import java.util.Set; /** - * @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, @@ -66,8 +66,6 @@ public record Enchantment(String identifier, 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, 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..fad13d1bb 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java +++ b/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java @@ -29,21 +29,13 @@ 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/session/cache/RegistryCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/RegistryCache.java index fcbc7c64c..2cc7bd5a6 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 @@ -42,6 +42,7 @@ import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.item.enchantment.Enchantment; +import org.geysermc.geyser.inventory.item.GeyserInstrument; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.JukeboxSong; import org.geysermc.geyser.level.PaintingType; @@ -90,6 +91,7 @@ public final class RegistryCache { register(JavaRegistries.BIOME, (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register(JavaRegistries.BANNER_PATTERN, cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); + register(JavaRegistries.INSTRUMENT, cache -> cache.instruments, GeyserInstrument::read); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); @@ -129,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; 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 5927963c0..2663fc511 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 index cb51f488e..f0cd3afde 100644 --- 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 @@ -33,6 +33,7 @@ import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.inventory.item.GeyserInstrument; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.JukeboxSong; import org.geysermc.geyser.level.PaintingType; @@ -62,6 +63,7 @@ public class JavaRegistries { public static final JavaRegistryKey PAINTING_VARIANT = create("painting_variant", RegistryCache::paintings); public static final JavaRegistryKey TRIM_MATERIAL = create("trim_material", RegistryCache::trimMaterials); public static final JavaRegistryKey TRIM_PATTERN = create("trim_pattern", RegistryCache::trimPatterns); + public static final JavaRegistryKey INSTRUMENT = create("instrument", RegistryCache::instruments); /** * This registry should not be used in holder sets, tags, etc. It's simply used as a mapping from Java biomes to Bedrock ones. */ 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/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 421e082b1..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 @@ -42,6 +42,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.LegacySetIte import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryTransactionPacket; 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; @@ -51,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; @@ -75,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; @@ -379,18 +382,28 @@ 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); + } } } } 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 168992dd4..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 Date: Thu, 31 Oct 2024 19:31:34 -0400 Subject: [PATCH 431/897] Cleanup and update Adapters --- .../geyser/inventory/recipe/GeyserRecipe.java | 2 +- .../geyser/session/cache/RegistryCache.java | 62 ++++++++++++------- .../cache/registry/JavaRegistries.java | 27 -------- gradle/libs.versions.toml | 2 +- 4 files changed, 43 insertions(+), 50 deletions(-) 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 d9cae943f..b0f5a1b44 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 @@ -29,7 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; 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 { /** 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 2cc7bd5a6..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,9 +40,9 @@ 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.inventory.item.GeyserInstrument; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.JukeboxSong; import org.geysermc.geyser.level.PaintingType; @@ -77,35 +77,35 @@ import java.util.function.ToIntFunction; @Accessors(fluent = true) @Getter public final class RegistryCache { - private static final Map, Map> DEFAULTS; - private static final Map, BiConsumer>> REGISTRIES = new HashMap<>(); + private static final Map> DEFAULTS; + private static final Map>> REGISTRIES = new HashMap<>(); static { - register(JavaRegistries.CHAT_TYPE, cache -> cache.chatTypes, ChatDecoration::readChatType); - register(JavaRegistries.DIMENSION_TYPE, cache -> cache.dimensions, JavaDimension::read); + register("chat_type", cache -> cache.chatTypes, ChatDecoration::readChatType); + register("dimension_type", cache -> cache.dimensions, JavaDimension::read); register(JavaRegistries.ENCHANTMENT, cache -> cache.enchantments, Enchantment::read); - register(JavaRegistries.JUKEBOX_SONG, cache -> cache.jukeboxSongs, JukeboxSong::read); - register(JavaRegistries.PAINTING_VARIANT, cache -> cache.paintings, context -> PaintingType.getByName(context.id())); - register(JavaRegistries.TRIM_MATERIAL, cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); - register(JavaRegistries.TRIM_PATTERN, cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); - register(JavaRegistries.BIOME, (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); - register(JavaRegistries.BANNER_PATTERN, cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); - register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); - register(JavaRegistries.INSTRUMENT, cache -> cache.instruments, GeyserInstrument::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); + register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); + register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); + register("banner_pattern", cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); + register("wolf_variant", cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); - Map, Map> defaults = new HashMap<>(); + 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((registry, $) -> { - List rawValues = tag.getCompound(registry.registryKey().asString()).getList("value", NbtType.COMPOUND); + REGISTRIES.forEach((key, $) -> { + 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")); values.put(name, value.getCompound("element")); } // Can make these maps immutable and as efficient as possible after initialization - defaults.put(registry, Map.copyOf(values)); + defaults.put(key, Map.copyOf(values)); }); DEFAULTS = Map.copyOf(defaults); @@ -141,7 +141,7 @@ public final class RegistryCache { * Loads a registry in, if we are tracking it. */ public void load(ClientboundRegistryDataPacket packet) { - var reader = REGISTRIES.get(JavaRegistries.fromKey(packet.getRegistry())); + var reader = REGISTRIES.get(packet.getRegistry()); if (reader != null) { reader.accept(this, packet.getEntries()); } else { @@ -155,7 +155,27 @@ public final class RegistryCache { * @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) { + private static void register(String registry, Function> localCacheFunction, Function reader) { + 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); @@ -192,8 +212,8 @@ public final class RegistryCache { /** * @param localCacheFunction the int array to set the final values to. */ - private static void register(JavaRegistryKey registry, BiConsumer localCacheFunction, ToIntFunction reader) { - REGISTRIES.put(registry, (registryCache, entries) -> { + private static void register(String registry, BiConsumer localCacheFunction, ToIntFunction reader) { + REGISTRIES.put(MinecraftKey.key(registry), (registryCache, entries) -> { Int2IntMap temp = new Int2IntOpenHashMap(); int greatestId = 0; for (int i = 0; i < entries.size(); i++) { 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 index f0cd3afde..646b647d0 100644 --- 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 @@ -27,23 +27,14 @@ package org.geysermc.geyser.session.cache.registry; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; -import org.cloudburstmc.protocol.bedrock.data.TrimPattern; -import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; -import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.inventory.item.GeyserInstrument; -import org.geysermc.geyser.level.JavaDimension; -import org.geysermc.geyser.level.JukeboxSong; -import org.geysermc.geyser.level.PaintingType; 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 org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType; import java.util.ArrayList; import java.util.List; @@ -56,20 +47,7 @@ public class JavaRegistries { 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 CHAT_TYPE = create("chat_type", RegistryCache::chatTypes); - public static final JavaRegistryKey DIMENSION_TYPE = create("dimension_type", RegistryCache::dimensions); public static final JavaRegistryKey ENCHANTMENT = create("enchantment", RegistryCache::enchantments); - public static final JavaRegistryKey JUKEBOX_SONG = create("jukebox_song", RegistryCache::jukeboxSongs); - public static final JavaRegistryKey PAINTING_VARIANT = create("painting_variant", RegistryCache::paintings); - public static final JavaRegistryKey TRIM_MATERIAL = create("trim_material", RegistryCache::trimMaterials); - public static final JavaRegistryKey TRIM_PATTERN = create("trim_pattern", RegistryCache::trimPatterns); - public static final JavaRegistryKey INSTRUMENT = create("instrument", RegistryCache::instruments); - /** - * This registry should not be used in holder sets, tags, etc. It's simply used as a mapping from Java biomes to Bedrock ones. - */ - public static final JavaRegistryKey BIOME = create("worldgen/biome"); - public static final JavaRegistryKey BANNER_PATTERN = create("banner_pattern", RegistryCache::bannerPatterns); - public static final JavaRegistryKey WOLF_VARIANT = create("wolf_variant", RegistryCache::wolfVariants); private static JavaRegistryKey create(String key, JavaRegistryKey.NetworkSerializer networkSerializer, JavaRegistryKey.NetworkDeserializer networkDeserializer) { JavaRegistryKey registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer); @@ -85,11 +63,6 @@ public class JavaRegistries { return create(key, (session, object) -> getter.get(session.getRegistryCache()).byValue(object), (session, id) -> getter.get(session.getRegistryCache()).byId(id)); } - private static JavaRegistryKey create(String key) { - // Cast for ambiguous call - return create(key, (JavaRegistryKey.NetworkSerializer) null, null); - } - @Nullable public static JavaRegistryKey fromKey(Key registryKey) { for (JavaRegistryKey registry : VALUES) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a88862965..9031799cf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" From edd62eb39e71cf23ee64141392766a86656bfd40 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 31 Oct 2024 19:48:22 -0400 Subject: [PATCH 432/897] Update CodecProcessor --- .../geysermc/geyser/level/JukeboxSong.java | 3 +- .../geyser/network/CodecProcessor.java | 25 ++++++- .../BedrockMoveEntityAbsoluteTranslator.java | 74 ------------------- .../bedrock/BedrockPlayerInputTranslator.java | 49 ------------ .../player/BedrockRiderJumpTranslator.java | 49 ------------ 5 files changed, 25 insertions(+), 175 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java 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 fad13d1bb..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,7 +26,6 @@ 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; @@ -35,7 +34,7 @@ public record JukeboxSong(String soundEvent, String description) { public static JukeboxSong read(RegistryEntryContext context) { NbtMap data = context.data(); - String soundEvent = SoundUtils.readSoundEvent(data, "jukebox song " + context.id());; + 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/network/CodecProcessor.java b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java index d5a4dd246..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,14 +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.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; @@ -189,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. */ @@ -317,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) TODO keeping until we determine which packets should replace .updateSerializer(ClientCacheBlobStatusPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(SubClientLoginPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(SubChunkRequestPacket.class, ILLEGAL_SERIALIZER) @@ -333,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/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java deleted file mode 100644 index 81b06c87d..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java +++ /dev/null @@ -1,74 +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.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; -import org.geysermc.geyser.entity.type.BoatEntity; -import org.geysermc.geyser.entity.type.Entity; -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.serverbound.level.ServerboundMoveVehiclePacket; - -/** - * Sent by the client when moving a horse or boat. - */ -@Translator(packet = MoveEntityAbsolutePacket.class) -public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, MoveEntityAbsolutePacket packet) { - 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 -= ridingEntity.getDefinition().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 46d6b9203..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java +++ /dev/null @@ -1,49 +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.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.packet.PlayerInputPacket; -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; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket; - -/** - * 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) { - - } -} 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/bedrock/entity/player/BedrockRiderJumpTranslator.java deleted file mode 100644 index 17668e000..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java +++ /dev/null @@ -1,49 +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.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.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; - -@Translator(packet = RiderJumpPacket.class) -public class BedrockRiderJumpTranslator extends PacketTranslator { - @Override - public void translate(GeyserSession session, RiderJumpPacket packet) { - session.getPlayerEntity().setVehicleJumpStrength(packet.getJumpStrength()); - - Entity vehicle = session.getPlayerEntity().getVehicle(); - if (vehicle instanceof AbstractHorseEntity) { - ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket(vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength()); - session.sendDownstreamGamePacket(playerCommandPacket); - } - } -} From df8bd9b58319ea38535906c991484b7593af4871 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 1 Nov 2024 00:39:24 -0400 Subject: [PATCH 433/897] Implement rich commands for Cloud on standalone --- .../geyser/command/CommandRegistry.java | 111 ++++++++++++++++++ .../protocol/java/JavaCommandsTranslator.java | 5 + 2 files changed, 116 insertions(+) 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..78e8a5cb1 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,26 @@ 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 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 +318,96 @@ public class CommandRegistry implements EventRegistrar { public void runCommand(@NonNull GeyserCommandSource source, @NonNull String command) { cloud.commandExecutor().executeCommand(source, command); } + + public void export(GeyserSession session, List bedrockCommands) { + cloud.commandTree().rootNode().children().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(); + + 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 = new ArrayList<>(); + createParamData(node, params); + 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 void createParamData(CommandNode node, List> bedrockData) { + 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 { + data.setType(CommandParam.STRING); + } + + // This, realistically, is not going to be used without extensions using internals and implementing complicated commands. + // It essentially does the same behavior as JavaCommandsTranslator#isCompatible. + // But, selfishly, I would like to use it, and in the future it's possible extensions can register commands + // using Cloud, and in that case this becomes relevant! + if (bedrockData.isEmpty()) { + List list = new ArrayList<>(); + list.add(data); + bedrockData.add(list); + } else { + int size = bedrockData.size(); // Preserve original list size in case new entries get added. + for (int i = 0; i < size; i++) { + List cpdList = bedrockData.get(i); + if (cpdList.size() <= 1) { // No commands or parent will be root. + cpdList.add(data); + } else { + String parentName = node.parent().component().name(); // Should never be null. + if (!cpdList.get(cpdList.size() - 1).getName().equals(parentName)) { // We need to copy the list as this is a new branch. + for (int j = cpdList.size() - 2; j >= 0; j--) { + if (cpdList.get(j).getName().equals(parentName)) { + List newList = new ArrayList<>(cpdList.subList(0, j + 1)); + newList.add(data); + bedrockData.add(newList); + break; + } + } + } else { + cpdList.add(data); + } + } + } + } + + for (var child : node.children()) { + createParamData(child, bedrockData); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index f189658cd..8eff3d16c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -41,6 +41,7 @@ import org.cloudburstmc.protocol.bedrock.data.command.*; import org.cloudburstmc.protocol.bedrock.packet.AvailableCommandsPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.java.ServerDefineCommandsEvent; +import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.registry.BlockRegistries; @@ -213,6 +214,10 @@ public class JavaCommandsTranslator extends PacketTranslator Date: Fri, 1 Nov 2024 13:13:20 -0400 Subject: [PATCH 434/897] Massively clean up Cloud -> Bedrock code --- .../geyser/command/CommandRegistry.java | 55 ++++++------------- 1 file changed, 18 insertions(+), 37 deletions(-) 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 78e8a5cb1..03569d49f 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java @@ -67,6 +67,7 @@ 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 java.util.ArrayList; import java.util.Collection; @@ -320,7 +321,7 @@ public class CommandRegistry implements EventRegistrar { } public void export(GeyserSession session, List bedrockCommands) { - cloud.commandTree().rootNode().children().forEach(commandTree -> { + 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())) { @@ -335,9 +336,8 @@ public class CommandRegistry implements EventRegistrar { List data = new ArrayList<>(); for (var node : commandTree.children()) { - List> params = new ArrayList<>(); - createParamData(node, params); - params.forEach(param -> data.add(new CommandOverloadData(false, param.toArray(CommandParamData[]::new)))); + List> params = createParamData(node); + params.forEach(param -> data.add(new CommandOverloadData(false, param.toArray(CommandParamData[]::new)))); } CommandData bedrockCommand = new CommandData(name, rootComponent.description().textDescription(), @@ -348,7 +348,7 @@ public class CommandRegistry implements EventRegistrar { }); } - private void createParamData(CommandNode node, List> bedrockData) { + private List> createParamData(CommandNode node) { CommandParamData data = new CommandParamData(); var component = node.component(); data.setName(component.name()); @@ -370,44 +370,25 @@ public class CommandRegistry implements EventRegistrar { } 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); } - // This, realistically, is not going to be used without extensions using internals and implementing complicated commands. - // It essentially does the same behavior as JavaCommandsTranslator#isCompatible. - // But, selfishly, I would like to use it, and in the future it's possible extensions can register commands - // using Cloud, and in that case this becomes relevant! - if (bedrockData.isEmpty()) { - List list = new ArrayList<>(); + var children = node.children(); + if (children.isEmpty()) { + List list = new ArrayList<>(); // Must be mutable; parents will be added to list. list.add(data); - bedrockData.add(list); - } else { - int size = bedrockData.size(); // Preserve original list size in case new entries get added. - for (int i = 0; i < size; i++) { - List cpdList = bedrockData.get(i); - if (cpdList.size() <= 1) { // No commands or parent will be root. - cpdList.add(data); - } else { - String parentName = node.parent().component().name(); // Should never be null. - if (!cpdList.get(cpdList.size() - 1).getName().equals(parentName)) { // We need to copy the list as this is a new branch. - for (int j = cpdList.size() - 2; j >= 0; j--) { - if (cpdList.get(j).getName().equals(parentName)) { - List newList = new ArrayList<>(cpdList.subList(0, j + 1)); - newList.add(data); - bedrockData.add(newList); - break; - } - } - } else { - cpdList.add(data); - } - } - } + return Collections.singletonList(list); // Safe to do; will be consumed in an addAll call. } - - for (var child : node.children()) { - createParamData(child, bedrockData); + 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(child)); } + collectiveData.forEach(list -> list.add(0, data)); + return collectiveData; } } From dd8a7a7edda4058748c5cd5d9c25adb73f26d524 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:42:21 -0400 Subject: [PATCH 435/897] Map experimental items to 'minecraft:unknown' Bedrock block --- .../geyser/command/CommandRegistry.java | 6 ++++- .../populator/BlockRegistryPopulator.java | 2 +- .../populator/ItemRegistryPopulator.java | 26 ++++++++++++------- .../protocol/java/JavaCommandsTranslator.java | 2 +- .../java/JavaRecipeBookAddTranslator.java | 7 +++++ core/src/main/resources/mappings | 2 +- 6 files changed, 31 insertions(+), 14 deletions(-) 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 03569d49f..9de7582a5 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java @@ -320,13 +320,17 @@ public class CommandRegistry implements EventRegistrar { cloud.commandExecutor().executeCommand(source, command); } - public void export(GeyserSession session, List bedrockCommands) { + 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()) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index a8c3ee89f..b95da4f8f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -283,7 +283,7 @@ public final class BlockRegistryPopulator { .build(); } - GeyserBedrockBlock vanillaBedrockDefinition = blockStateOrderedMap.getOrDefault(bedrockTag, airDefinition); // FIXME EEE + GeyserBedrockBlock vanillaBedrockDefinition = blockStateOrderedMap.get(bedrockTag); GeyserBedrockBlock bedrockDefinition; CustomBlockState blockStateOverride = BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get(javaRuntimeId); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index e8b894759..18a34f088 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -84,6 +84,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -95,7 +96,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class ItemRegistryPopulator { - record PaletteVersion(String version, int protocolVersion, Map 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()); @@ -260,8 +267,7 @@ public class ItemRegistryPopulator { String bedrockIdentifier = mappingItem.getBedrockIdentifier(); ItemDefinition definition = definitions.get(bedrockIdentifier); if (definition == null) { - definition = definitions.get("minecraft:air"); - //throw new RuntimeException("Missing Bedrock ItemDefinition in version " + palette.version() + " for mapping: " + mappingItem); + throw new RuntimeException("Missing Bedrock ItemDefinition in version " + palette.version() + " for mapping: " + mappingItem); } BlockDefinition bedrockBlock = null; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 8eff3d16c..5500deb80 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -215,7 +215,7 @@ public class JavaCommandsTranslator extends PacketTranslator inputs = left.get(i); String recipeId = contents.id() + "_" + i; + if (recipeId.equals("1318_0")) { + System.out.println(display); + } int recipeNetworkId = netId++; craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, shapedRecipe.width(), shapedRecipe.height(), inputs, @@ -268,8 +271,12 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator 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; } + if (pair.left() == Items.PALE_OAK_TRAPDOOR) { + System.out.println(pair.right()); + } ItemData output = pair.right(); if (!(pair.left() instanceof BedrockRequiresTagItem)) { diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 4200a8c57..e1eafe2c5 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 4200a8c57a79a87b5b9e7ea1aaf9d5522c4f5626 +Subproject commit e1eafe2c5304012d23acba80659459f7868fe2b1 From 293102e60dd98a6d54e667b58c150698874f3489 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:44:08 -0400 Subject: [PATCH 436/897] Remove debug code --- .../protocol/java/JavaRecipeBookAddTranslator.java | 6 ------ 1 file changed, 6 deletions(-) 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 index d59d608a2..039afc2e7 100644 --- 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 @@ -110,9 +110,6 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator inputs = left.get(i); String recipeId = contents.id() + "_" + i; - if (recipeId.equals("1318_0")) { - System.out.println(display); - } int recipeNetworkId = netId++; craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, shapedRecipe.width(), shapedRecipe.height(), inputs, @@ -274,9 +271,6 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator 0 and the air definition may not be ItemDefinition.AIR return null; } - if (pair.left() == Items.PALE_OAK_TRAPDOOR) { - System.out.println(pair.right()); - } ItemData output = pair.right(); if (!(pair.left() instanceof BedrockRequiresTagItem)) { From 67a1805fa65374b079e72da6ca8db83da6aabed4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:48:07 -0400 Subject: [PATCH 437/897] Indicate support for Bedrock 1.21.44 Bedrock are u ok --- README.md | 2 +- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fedb5bb96..329a9045e 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.43 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/1.21.1. 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/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 464edd487..873fa413a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -52,7 +52,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() - .minecraftVersion("1.21.43") + .minecraftVersion("1.21.44") .build()); /** @@ -83,7 +83,7 @@ public final class GameProtocol { .minecraftVersion("1.21.30/1.21.31") .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.40/1.21.41/1.21.43") + .minecraftVersion("1.21.40 - 1.21.44") .build()); } From 0eec65c1880396a0ba105a58eccea30fa7d08eec Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 31 Oct 2024 18:24:54 +0800 Subject: [PATCH 438/897] Fix: Geyser-NeoForge complaining about jackson --- bootstrap/mod/fabric/build.gradle.kts | 1 - bootstrap/mod/neoforge/build.gradle.kts | 14 ++++++++++++++ ...eyser.modrinth-uploading-conventions.gradle.kts | 1 + gradle/libs.versions.toml | 5 +++-- 4 files changed, 18 insertions(+), 3 deletions(-) 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/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/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts index 3c0d102f7..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,6 +7,7 @@ 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)) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9031799cf..60fe78448 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" } @@ -150,7 +151,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" ] From 734e429cef16049ae0b4b3f39dc168b2b0ce52b1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 2 Nov 2024 01:38:24 -0400 Subject: [PATCH 439/897] Map Java tags to Bedrock tags in recipes where possible Bedrock tags have been generated from Endstone's devtools. --- .../geysermc/geyser/registry/Registries.java | 8 + .../populator/TagRegistryPopulator.java | 133 +++ .../geyser/session/cache/TagCache.java | 11 +- .../java/JavaRecipeBookAddTranslator.java | 14 + .../resources/bedrock/item_tags.1_20_80.json | 784 +++++++++++++++++ .../resources/bedrock/item_tags.1_21_0.json | 802 +++++++++++++++++ .../resources/bedrock/item_tags.1_21_20.json | 806 ++++++++++++++++++ .../resources/bedrock/item_tags.1_21_30.json | 806 ++++++++++++++++++ .../resources/bedrock/item_tags.1_21_40.json | 806 ++++++++++++++++++ 9 files changed, 4167 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java create mode 100644 core/src/main/resources/bedrock/item_tags.1_20_80.json create mode 100644 core/src/main/resources/bedrock/item_tags.1_21_0.json create mode 100644 core/src/main/resources/bedrock/item_tags.1_21_20.json create mode 100644 core/src/main/resources/bedrock/item_tags.1_21_30.json create mode 100644 core/src/main/resources/bedrock/item_tags.1_21_40.json 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 20b3c9331..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; @@ -48,6 +49,7 @@ 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; @@ -163,6 +165,11 @@ public final class Registries { */ 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}. */ @@ -202,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/populator/TagRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java new file mode 100644 index 000000000..455145217 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java @@ -0,0 +1,133 @@ +/* + * 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.Object2ObjectMap; +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() { + 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); + } + + Object2ObjectMap javaItemsToBedrockTag = new Object2ObjectOpenCustomHashMap<>(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); + } + }); + + 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()); + } + + Registries.TAGS.register(palette.rightInt(), javaItemsToBedrockTag); + } + } +} 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 f01ef64c5..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 @@ -90,13 +90,18 @@ public final class TagCache { } } - loadTags(registryTags, registry); + loadTags(registryTags, registry, registry == JavaRegistries.ITEM); } } - private void loadTags(Map packetTags, JavaRegistryKey registry) { + private void loadTags(Map packetTags, JavaRegistryKey registry, boolean sort) { for (Map.Entry tag : packetTags.entrySet()) { - this.tags.put(new Tag<>(registry, tag.getKey()), tag.getValue()); + int[] value = tag.getValue(); + if (sort) { + // Used in RecipeBookAddTranslator + Arrays.sort(value); + } + this.tags.put(new Tag<>(registry, tag.getKey()), value); } } 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 index 039afc2e7..05be7db3d 100644 --- 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 @@ -37,6 +37,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.Shapeles 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; @@ -190,6 +191,7 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator>> TAG_TO_ITEM_DESCRIPTOR_CACHE = ThreadLocal.withInitial(Object2ObjectOpenHashMap::new); private List translateToInput(GeyserSession session, SlotDisplay slotDisplay) { @@ -228,6 +230,18 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator { + 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)); 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" + ] +} From e9cee51be2bbd3b6f9fc8c6dbc998627a6bdbb2e Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sat, 2 Nov 2024 17:06:55 +0800 Subject: [PATCH 440/897] Water creatures are now ageable --- .../geyser/entity/EntityDefinitions.java | 37 ++++++++++--------- .../entity/type/living/WaterEntity.java | 2 +- .../org/geysermc/geyser/util/Ordered.java | 33 ----------------- 3 files changed, 21 insertions(+), 51 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/util/Ordered.java 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 7a92a5fe3..a25861813 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -678,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) @@ -755,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) @@ -885,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(); @@ -1081,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) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java index ae9d0d659..b8fd864b6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java @@ -31,7 +31,7 @@ import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; -public class WaterEntity extends CreatureEntity { +public class WaterEntity extends AgeableEntity { public WaterEntity(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/util/Ordered.java b/core/src/main/java/org/geysermc/geyser/util/Ordered.java deleted file mode 100644 index 08ff5df72..000000000 --- a/core/src/main/java/org/geysermc/geyser/util/Ordered.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.util; - -/** - * Represents anything that could be tracked like a enum, without also creating a name and enum-wide array. - */ -public interface Ordered { - int ordinal(); -} From 47ac22aecf584706cdc781d1e451cd7c5cd4df62 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sat, 2 Nov 2024 17:38:41 +0800 Subject: [PATCH 441/897] Not all water entities are ageable; only some are; oops --- .../type/living/AgeableWaterEntity.java | 43 +++++++++++++++++++ .../entity/type/living/DolphinEntity.java | 2 +- .../entity/type/living/SquidEntity.java | 2 +- .../entity/type/living/WaterEntity.java | 2 +- 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableWaterEntity.java 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/WaterEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java index b8fd864b6..ae9d0d659 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java @@ -31,7 +31,7 @@ import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; -public class WaterEntity extends AgeableEntity { +public class WaterEntity extends CreatureEntity { public WaterEntity(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); From d61ad7baeffb1f3d35d05783a8e89ce9c6e35e30 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 2 Nov 2024 11:48:58 +0100 Subject: [PATCH 442/897] Reset the scoreboard in the configuration stage --- .../java/org/geysermc/geyser/session/cache/WorldCache.java | 2 +- .../java/JavaFinishConfigurationPacketTranslator.java | 6 ++++++ .../translator/protocol/java/JavaLoginTranslator.java | 2 -- 3 files changed, 7 insertions(+), 3 deletions(-) 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 5927963c0..f2198c7dc 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 @@ -81,7 +81,7 @@ public final class WorldCache { resetTitleTimes(false); } - public void removeScoreboard() { + public void resetScoreboard() { scoreboard.removeScoreboard(); scoreboard = new Scoreboard(session); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java index 8ade4a1f0..f6ed79fd5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationPacketTranslator.java @@ -45,5 +45,11 @@ public class JavaFinishConfigurationPacketTranslator extends PacketTranslator Date: Sun, 3 Nov 2024 00:01:39 +0800 Subject: [PATCH 443/897] Fix different ResourcePackPushPacket handling, cache current input mode --- .../java/org/geysermc/geyser/session/GeyserSession.java | 9 +++++++-- .../org/geysermc/geyser/session/cache/InputCache.java | 6 +++++- .../java/JavaClientboundResourcePackPushPacket.java | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) 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 d965f05bf..36ed3f02e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -255,7 +255,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final EventLoop eventLoop; @Setter private AuthData authData; - @Setter private BedrockClientData clientData; /** * Used for Floodgate skin uploading @@ -1411,6 +1410,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. */ @@ -2124,7 +2129,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 index 79c37a5a8..f12c4d3c8 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java @@ -27,6 +27,7 @@ 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; @@ -45,6 +46,8 @@ public final class InputCache { private int jumpingTicks; @Getter @Setter private float jumpScale; + @Getter @Setter + private @MonotonicNonNull InputMode inputMode; public InputCache(GeyserSession session) { this.session = session; @@ -54,9 +57,10 @@ public final class InputCache { // 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 (packet.getInputMode() == InputMode.MOUSE) { + if (this.inputMode == InputMode.MOUSE) { up = bedrockInput.contains(PlayerAuthInputData.UP); down = bedrockInput.contains(PlayerAuthInputData.DOWN); left = bedrockInput.contains(PlayerAuthInputData.LEFT); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePackPushPacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePackPushPacket.java index 9e7306ab1..4091405e4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePackPushPacket.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePackPushPacket.java @@ -40,6 +40,8 @@ public class JavaClientboundResourcePackPushPacket extends PacketTranslator Date: Sun, 3 Nov 2024 03:23:00 +0800 Subject: [PATCH 444/897] Small fixes; start on new rotation packet why is bedrock weird with player rotation --- .../type/player/SessionPlayerEntity.java | 14 ++++++- .../JavaFinishConfigurationTranslator.java | 4 +- .../player/JavaCookieRequestTranslator.java | 2 +- .../player/JavaPlayerPositionTranslator.java | 14 +++++-- .../player/JavaPlayerRotationTranslator.java | 42 +++++++++++++++++++ 5 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerRotationTranslator.java 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 a8b0765f3..5db47a34a 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 @@ -34,12 +34,13 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; 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; @@ -338,6 +339,17 @@ public class SessionPlayerEntity extends PlayerEntity { this.vehicleJumpStrength = MathUtils.constrain(vehicleJumpStrength, 0, 100); } + public void forceRotationUpdate() { + MoveEntityAbsolutePacket absolutePacket = new MoveEntityAbsolutePacket(); + absolutePacket.setPosition(this.getPosition()); + absolutePacket.setRotation(this.getBedrockRotation()); + absolutePacket.setRuntimeEntityId(this.getGeyserId()); + absolutePacket.setForceMove(true); + absolutePacket.setOnGround(this.isOnGround()); + + session.sendUpstreamPacket(absolutePacket); + } + private boolean isBelowVoidFloor() { return position.getY() < voidFloorPosition(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java index d73c2e2ed..0c5dcf31b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaFinishConfigurationTranslator.java @@ -70,7 +70,9 @@ public class JavaFinishConfigurationTranslator extends PacketTranslator { @@ -76,6 +76,12 @@ public class JavaPlayerPositionTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundPlayerRotationPacket packet) { + GeyserImpl.getInstance().getLogger().info(packet.toString()); + // TODO + } +} From 5b5ac3024fcbea1d56132eae160db6203c705bc9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 3 Nov 2024 01:04:56 -0500 Subject: [PATCH 445/897] Use non-Jitpack MCPL --- .../geyser/inventory/GeyserItemStack.java | 2 +- .../populator/TagRegistryPopulator.java | 26 ++++++++++--------- .../geyser/session/GeyserSession.java | 1 + gradle/libs.versions.toml | 5 ++-- 4 files changed, 18 insertions(+), 16 deletions(-) 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 a2797e6dd..256de7799 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -184,7 +184,7 @@ public class GeyserItemStack { public SlotDisplay asSlotDisplay() { if (isEmpty()) { - return new EmptySlotDisplay(); + return EmptySlotDisplay.INSTANCE; } return new ItemStackSlotDisplay(this.getItemStack()); } 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 index 455145217..4e249d483 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java @@ -56,6 +56,19 @@ 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()), @@ -77,18 +90,7 @@ public final class TagRegistryPopulator { throw new AssertionError("Unable to load Bedrock runtime item IDs", e); } - Object2ObjectMap javaItemsToBedrockTag = new Object2ObjectOpenCustomHashMap<>(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); - } - }); + Object2ObjectMap javaItemsToBedrockTag = new Object2ObjectOpenCustomHashMap<>(hashStrategy); for (var entry : bedrockTags.entrySet()) { List value = entry.getValue(); 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 36ed3f02e..2036f2941 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -214,6 +214,7 @@ import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.Serverbound 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.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; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 60fe78448..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.2-SNAPSHOT" +mcprotocollib = "1.21.2-20241103.011758-1" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" @@ -121,8 +121,7 @@ guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } minecraftauth = { group = "net.raphimc", name = "MinecraftAuth", version.ref = "minecraftauth" } -#mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" } -mcprotocollib = { group = "com.github.geysermc", name = "mcprotocollib", version = "feature~1.21.2-SNAPSHOT"} +mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" } raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } From 9a41f59a339e46e2e742a0304159765027da45b6 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 3 Nov 2024 23:54:45 +0800 Subject: [PATCH 446/897] Fix: Ignored rotation players to session player (self) --- .../geysermc/geyser/entity/type/Entity.java | 1 - .../entity/type/player/PlayerEntity.java | 17 ++++++-------- .../type/player/SessionPlayerEntity.java | 23 +++++++++++++++++++ .../player/JavaPlayerLookAtTranslator.java | 2 +- .../player/JavaPlayerPositionTranslator.java | 2 +- .../player/JavaPlayerRotationTranslator.java | 4 +--- 6 files changed, 33 insertions(+), 16 deletions(-) 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 2ad89dd2f..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 @@ -45,7 +45,6 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.GeyserDirtyMetadata; import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager; -import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; 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 5db47a34a..ee56e25a7 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 @@ -144,6 +144,29 @@ 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java index b1413542b..22786e918 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java @@ -49,7 +49,7 @@ public class JavaPlayerLookAtTranslator extends PacketTranslator Date: Sun, 3 Nov 2024 11:38:15 -0500 Subject: [PATCH 447/897] Clear old recipe code from UpdateRecipesTranslator --- .../java/JavaUpdateRecipesTranslator.java | 418 +----------------- 1 file changed, 1 insertion(+), 417 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index ad67da81e..7ea66e0a3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -60,7 +60,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.UUID; @@ -84,15 +83,6 @@ 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"); @@ -190,282 +180,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator> recipeIDs = session.getJavaToBedrockRecipeIds(); -// recipeIDs.clear(); -// Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(); -// Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); -// 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) { -// // BDS sends armor trim templates and materials before the CraftingDataPacket -// TrimDataPacket trimDataPacket = new TrimDataPacket(); -// trimDataPacket.getPatterns().addAll(session.getRegistryCache().trimPatterns().values()); -// trimDataPacket.getMaterials().addAll(session.getRegistryCache().trimMaterials().values()); -// session.sendUpstreamPacket(trimDataPacket); -// -// // Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the -// // approach of using many default-descriptors (which we do for smithing_transform) -// craftingDataPacket.getCraftingData().add(SmithingTrimRecipeData.of(TrimRecipe.ID, -// TrimRecipe.BASE, TrimRecipe.ADDITION, TrimRecipe.TEMPLATE, "smithing_table", session.getLastRecipeNetId().getAndIncrement())); -// } else { -// // manually add recipes for the upgrade template (workaround), since Java pre-1.20 doesn't -// craftingDataPacket.getCraftingData().addAll(getSmithingTransformRecipes(session)); -// } -// session.setOldSmithingTable(!sendTrimRecipes); -// session.sendUpstreamPacket(craftingDataPacket); -// session.setCraftingRecipes(recipeMap); -// session.setStonecutterRecipes(stonecutterRecipeMap); -// } -// -// //TODO: rewrite -// /** -// * The Java server sends an array of items for each ingredient you can use per slot in the crafting grid. -// * Bedrock recipes take only one ingredient per crafting grid slot. -// * -// * @return the Java ingredient list as an array that Bedrock can understand -// */ -// private static ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) { -// boolean empty = true; -// Map, 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); -// 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(); -// -// String recipeTag = RECIPE_TAGS.get(groupedItem.id.getIdentifier()); -// if (recipeTag != null && ingredients.length > 1) { -// optionSet.add(new ItemDescriptorWithCount(new ItemTagDescriptor(recipeTag), groupedItem.count)); -// continue; -// } -// -// 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); -// } -// } -// 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; -// } -// } -// 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; -// } -// + private void addSmithingTransformRecipes(GeyserSession session, List recipes) { ItemMapping template = session.getItemMappings().getStoredItems().upgradeTemplate(); @@ -488,135 +203,4 @@ 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++; -// } -// } } From ee4047b52919080aa9407a76fe838475f33bc0dd Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 3 Nov 2024 13:17:59 -0500 Subject: [PATCH 448/897] Send end tick packet --- .../java/org/geysermc/geyser/session/GeyserSession.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 2036f2941..ea0dc58de 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1312,6 +1312,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(); } From 1958c41e4dccb2fc79fe06fde444ba16269a2482 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 3 Nov 2024 13:23:28 -0500 Subject: [PATCH 449/897] Fixed dyed horse armor --- core/src/main/java/org/geysermc/geyser/item/Items.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ba4b37ff5..302fdf99c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -1237,7 +1237,7 @@ public final class Items { 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 Item("leather_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))); From 521b9f3dce39b6aaac47547dd81b47fb2bea8944 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 4 Nov 2024 00:42:01 -0500 Subject: [PATCH 450/897] Add tab completion to Geyser standalone --- .../standalone/GeyserStandaloneLogger.java | 14 ++++++++++++++ .../geysermc/geyser/command/CommandRegistry.java | 6 ++++++ 2 files changed, 20 insertions(+) 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/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java index 9de7582a5..5d44016c9 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java @@ -68,6 +68,8 @@ 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; @@ -320,6 +322,10 @@ public class CommandRegistry implements EventRegistrar { 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(); From cfaa219f192b017163ea0c44b683ca9edac215dd Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 4 Nov 2024 17:59:56 +0800 Subject: [PATCH 451/897] Remove unused method --- .../entity/type/player/SessionPlayerEntity.java | 12 ------------ 1 file changed, 12 deletions(-) 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 ee56e25a7..bfa30fed4 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 @@ -34,7 +34,6 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; @@ -362,17 +361,6 @@ public class SessionPlayerEntity extends PlayerEntity { this.vehicleJumpStrength = MathUtils.constrain(vehicleJumpStrength, 0, 100); } - public void forceRotationUpdate() { - MoveEntityAbsolutePacket absolutePacket = new MoveEntityAbsolutePacket(); - absolutePacket.setPosition(this.getPosition()); - absolutePacket.setRotation(this.getBedrockRotation()); - absolutePacket.setRuntimeEntityId(this.getGeyserId()); - absolutePacket.setForceMove(true); - absolutePacket.setOnGround(this.isOnGround()); - - session.sendUpstreamPacket(absolutePacket); - } - private boolean isBelowVoidFloor() { return position.getY() < voidFloorPosition(); } From 5162d4516d429025aeee539e8d97dd7807909a5b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 4 Nov 2024 17:56:24 -0500 Subject: [PATCH 452/897] Cleanup and fixes --- .../org/geysermc/geyser/command/CommandRegistry.java | 12 +++++++++--- .../geyser/inventory/recipe/GeyserRecipe.java | 2 -- .../geyser/inventory/recipe/GeyserShapedRecipe.java | 3 +-- .../inventory/recipe/GeyserShapelessRecipe.java | 3 +-- .../registry/populator/BlockRegistryPopulator.java | 5 ++--- .../player/BedrockPlayerAuthInputTranslator.java | 10 ++++++---- 6 files changed, 19 insertions(+), 16 deletions(-) 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 5d44016c9..838ab71b1 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java @@ -346,7 +346,7 @@ public class CommandRegistry implements EventRegistrar { List data = new ArrayList<>(); for (var node : commandTree.children()) { - List> params = createParamData(node); + List> params = createParamData(session, node); params.forEach(param -> data.add(new CommandOverloadData(false, param.toArray(CommandParamData[]::new)))); } @@ -358,7 +358,13 @@ public class CommandRegistry implements EventRegistrar { }); } - private List> createParamData(CommandNode node) { + 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()); @@ -396,7 +402,7 @@ public class CommandRegistry implements EventRegistrar { // 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(child)); + collectiveData.addAll(createParamData(session, child)); } collectiveData.forEach(list -> list.add(0, data)); return collectiveData; 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 b0f5a1b44..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,7 +25,6 @@ package org.geysermc.geyser.inventory.recipe; -import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; /** @@ -37,6 +36,5 @@ public interface GeyserRecipe { */ boolean isShaped(); - @Nullable 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 70b71cf4d..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,13 +25,12 @@ package org.geysermc.geyser.inventory.recipe; -import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapedCraftingRecipeDisplay; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; import java.util.List; -public record GeyserShapedRecipe(int width, int height, List ingredients, @Nullable SlotDisplay result) implements GeyserRecipe { +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()); 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 90eeb01c9..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,13 +25,12 @@ package org.geysermc.geyser.inventory.recipe; -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; import java.util.List; -public record GeyserShapelessRecipe(List ingredients, @Nullable SlotDisplay result) implements GeyserRecipe { +public record GeyserShapelessRecipe(List ingredients, SlotDisplay result) implements GeyserRecipe { public GeyserShapelessRecipe(ShapelessCraftingRecipeDisplay data) { this(data.ingredients(), data.result()); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index b95da4f8f..5b7213bee 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -196,11 +196,10 @@ public final class BlockRegistryPopulator { GeyserBedrockBlock[] bedrockRuntimeMap = new GeyserBedrockBlock[blockStates.size()]; for (int i = 0; i < blockStates.size(); i++) { NbtMap tag = blockStates.get(i); - if (blockStateOrderedMap.containsKey(tag)) { + GeyserBedrockBlock block = new GeyserBedrockBlock(i, tag); + if (blockStateOrderedMap.put(tag, block) != null) { throw new AssertionError("Duplicate block states in Bedrock palette: " + tag); } - GeyserBedrockBlock block = new GeyserBedrockBlock(i, tag); - blockStateOrderedMap.put(tag, block); bedrockRuntimeMap[i] = block; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java index a07ebe04a..3c9b41488 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java @@ -229,12 +229,12 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator Date: Mon, 4 Nov 2024 21:13:14 -0500 Subject: [PATCH 453/897] Some final touches --- .../entity/type/player/SessionPlayerEntity.java | 2 +- .../geyser/network/UpstreamPacketHandler.java | 8 +++++--- .../registry/populator/TagRegistryPopulator.java | 4 ++-- .../geysermc/geyser/session/GeyserSession.java | 5 +++++ .../player/{ => input}/BedrockBlockActions.java | 4 ++-- .../BedrockMovePlayer.java} | 10 ++++++---- .../BedrockPlayerAuthInputTranslator.java | 7 +++++-- .../java/JavaFinishConfigurationTranslator.java | 16 +++++++++------- .../org/geysermc/geyser/util/InventoryUtils.java | 6 +++++- 9 files changed, 40 insertions(+), 22 deletions(-) rename core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/{ => input}/BedrockBlockActions.java (99%) rename core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/{BedrockMovePlayerTranslator.java => input/BedrockMovePlayer.java} (98%) rename core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/{ => input}/BedrockPlayerAuthInputTranslator.java (98%) 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 bfa30fed4..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 @@ -168,7 +168,7 @@ public class SessionPlayerEntity extends PlayerEntity { /** * 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 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 19e56c8a8..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) { // TODO - 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/populator/TagRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java index 4e249d483..bee207a00 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java @@ -31,7 +31,6 @@ 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.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; import it.unimi.dsi.fastutil.objects.ObjectIntPair; import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; @@ -90,7 +89,7 @@ public final class TagRegistryPopulator { throw new AssertionError("Unable to load Bedrock runtime item IDs", e); } - Object2ObjectMap javaItemsToBedrockTag = new Object2ObjectOpenCustomHashMap<>(hashStrategy); + var javaItemsToBedrockTag = new Object2ObjectOpenCustomHashMap(hashStrategy); for (var entry : bedrockTags.entrySet()) { List value = entry.getValue(); @@ -129,6 +128,7 @@ public final class TagRegistryPopulator { 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 ea0dc58de..ef6261ead 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1077,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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java similarity index 99% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java index f1b91a0a5..061a04b77 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockBlockActions.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.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,7 +23,7 @@ * @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.Vector3f; import org.cloudburstmc.math.vector.Vector3i; 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 98% 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 1940258e4..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,7 +23,7 @@ * @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; @@ -40,8 +40,10 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.Serv import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerRotPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerStatusOnlyPacket; - -public final class BedrockMovePlayerTranslator { +/** + * Holds processing input coming in from the {@link PlayerAuthInputPacket} packet. + */ +final class BedrockMovePlayer { static void translate(GeyserSession session, PlayerAuthInputPacket packet) { SessionPlayerEntity entity = session.getPlayerEntity(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java similarity index 98% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java index 3c9b41488..02ea02232 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java @@ -23,7 +23,7 @@ * @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.GenericMath; import org.cloudburstmc.math.vector.Vector2f; @@ -74,7 +74,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator mirroredIngredients = new ArrayList<>(ingredients.size()); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { - mirroredIngredients.add(ingredients.get((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))); } } From 6e8a955ee0386595248c83bd1e81f78e5e277847 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 4 Nov 2024 21:26:17 -0500 Subject: [PATCH 454/897] Dust particle color verified working --- .../protocol/java/level/JavaLevelParticlesTranslator.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java index 3c73b1886..336fedc65 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java @@ -132,11 +132,7 @@ public class JavaLevelParticlesTranslator 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(); // TEST + int rgbData = data.getColor(); return (position) -> { LevelEventPacket packet = new LevelEventPacket(); packet.setType(ParticleType.FALLING_DUST); From 881b8e9b905e99145d6be28f9b0144fbc18aa82a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:37:31 -0500 Subject: [PATCH 455/897] Better multi-item recipe support for 1.21.1 --- .../java/JavaRecipeBookAddTranslator.java | 77 ++++++++++++++++--- 1 file changed, 66 insertions(+), 11 deletions(-) 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 index 05be7db3d..71fd4a200 100644 --- 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 @@ -30,6 +30,7 @@ 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.checkerframework.checker.nullness.qual.Nullable; 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; @@ -72,6 +73,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.WithRem import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipeBookAddPacket; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -202,11 +204,39 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator translateToInput(session, subDisplay)) - .filter(Objects::nonNull) - .flatMap(List::stream) - .toList(); + + // Try and see if the contents match a tag. + // ViaVersion maps pre-1.21.2 ingredient lists to CompositeSlotDisplays. + int[] items = new int[composite.contents().size()]; + List contents = composite.contents(); + for (int i = 0; i < contents.size(); i++) { + SlotDisplay subDisplay = contents.get(i); + int id; + if (subDisplay instanceof ItemSlotDisplay item) { + id = item.item(); + } else if (!(subDisplay instanceof ItemStackSlotDisplay itemStackSlotDisplay)) { + id = -1; + } else if (itemStackSlotDisplay.itemStack().getAmount() == 1 + && itemStackSlotDisplay.itemStack().getDataComponents() == null) { + id = itemStackSlotDisplay.itemStack().getId(); + } else { + id = -1; + } + if (id == -1) { + // We couldn't guarantee a "normal" item from this stack. + return fallbackCompositeMapping(session, composite); + } + items[i] = id; + } + // For searching in the tag map. + Arrays.sort(items); + + List tagDescriptor = lookupBedrockTag(session, items); + if (tagDescriptor != null) { + return tagDescriptor; + } + + return fallbackCompositeMapping(session, composite); } 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 @@ -230,12 +260,9 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator { - 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) - ); + List tagDescriptor = lookupBedrockTag(session, key); + if (tagDescriptor != null) { + return tagDescriptor; } // In the future, we can probably search through and use subsets of tags as well. @@ -278,6 +305,33 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator lookupBedrockTag(GeyserSession session, int[] items) { + var bedrockTags = Registries.TAGS.forVersion(session.getUpstream().getProtocolVersion()); + String bedrockTag = bedrockTags.get(items); + if (bedrockTag != null) { + return Collections.singletonList( + new ItemDescriptorWithCount(new ItemTagDescriptor(bedrockTag), 1) + ); + } else { + return null; + } + } + + /** + * Converts CompositeSlotDisplay contents to a list of basic ItemDescriptorWithCounts. + */ + private List fallbackCompositeMapping(GeyserSession session, CompositeSlotDisplay composite) { + return composite.contents().stream() + .map(subDisplay -> translateToInput(session, subDisplay)) + .filter(Objects::nonNull) + .flatMap(List::stream) + .toList(); + } + private Pair>, ItemData> combinations(GeyserSession session, RecipeDisplay display, List ingredients) { Pair pair = translateToOutput(session, display.result()); if (pair == null || !pair.right().isValid()) { @@ -327,6 +381,7 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator descriptors.get(0)).toList()), output From 2bc3773cb0e70dcae0c2537d0767e05914f81c17 Mon Sep 17 00:00:00 2001 From: Matthias Ahouansou Date: Thu, 7 Nov 2024 17:23:23 +0000 Subject: [PATCH 456/897] Set Minecraft & protocol version in Velocity ping (#5130) this fixes issues caused by plugins which use the version in the ping --- .../platform/velocity/GeyserVelocityPingPassthrough.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java index b2258d3a3..f20076597 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java @@ -31,8 +31,10 @@ import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.server.ServerPing; +import com.velocitypowered.api.proxy.server.ServerPing.Version; import lombok.AllArgsConstructor; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; @@ -51,7 +53,9 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough { try { event = server.getEventManager().fire(new ProxyPingEvent(new GeyserInboundConnection(inetSocketAddress), ServerPing.builder() .description(server.getConfiguration().getMotd()).onlinePlayers(server.getPlayerCount()) - .maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get(); + .maximumPlayers(server.getConfiguration().getShowMaxPlayers()) + .version(new Version(GameProtocol.getJavaProtocolVersion(), GameProtocol.getJavaMinecraftVersion())) + .build())).get(); } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } From aebf9d399b1fe60d7254d7d94e6746b5e37adb94 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:43:37 -0500 Subject: [PATCH 457/897] Fix TagRegistryPopulator on older Gson versions Fixes #5132 --- .../geyser/registry/populator/TagRegistryPopulator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index bee207a00..24cc270c9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java @@ -47,6 +47,7 @@ import org.geysermc.geyser.registry.type.ItemMappings; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -75,7 +76,7 @@ public final class TagRegistryPopulator { ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()), ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()) ); - TypeToken>> type = new TypeToken<>() {}; + Type type = new TypeToken>>() {}.getType(); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); From 1b4d257e3571ef321e0778e33e6d98727012d0ac Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:09:31 -0500 Subject: [PATCH 458/897] Better onGround check Thanks to @AJ-Ferguson for the suggestion. Includes hacks to still maintain pre-1.21.30, but that will likely lose support very soon, anyway. --- .../level/physics/CollisionManager.java | 13 ++++++----- .../geysermc/geyser/network/GameProtocol.java | 4 ++++ .../player/input/BedrockMovePlayer.java | 22 ++++++++++++++----- 3 files changed, 27 insertions(+), 12 deletions(-) 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 c5f986499..69f88e2a1 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 @@ -154,10 +154,11 @@ 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 CollisionResult adjustBedrockPosition(Vector3f bedrockPosition, boolean teleported) { + public @Nullable CollisionResult adjustBedrockPosition(Vector3f bedrockPosition, boolean onGround, 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()) { @@ -198,9 +199,9 @@ public class CollisionManager { position = playerBoundingBox.getBottomCenter(); - boolean onGround = (adjustedMovement.getY() != movement.getY() && movement.getY() < 0) || isOnGround(); + boolean newOnGround = adjustedMovement.getY() != movement.getY() && movement.getY() < 0 || onGround; // Send corrected position to Bedrock if they differ by too much to prevent de-syncs - if (movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) { + if (onGround != newOnGround || 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()) { @@ -208,7 +209,7 @@ public class CollisionManager { } } - if (!onGround) { + if (!newOnGround) { // Trim the position to prevent rounding errors that make Java think we are clipping into a block position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ()); } @@ -415,8 +416,8 @@ public class CollisionManager { return BlockUtils.getCollision(blockId); } - private boolean isOnGround() { - // Someone smarter than me at collisions plz check this. + public boolean isOnGround() { + // Temporary until pre-1.21.30 support is dropped. Vector3d bottomCenter = playerBoundingBox.getBottomCenter(); Vector3i groundPos = Vector3i.from(bottomCenter.getX(), bottomCenter.getY() - 1, bottomCenter.getZ()); BlockCollision collision = BlockUtils.getCollisionAt(session, groundPos); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 873fa413a..463cc54fd 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -111,6 +111,10 @@ public final class GameProtocol { return session.getUpstream().getProtocolVersion() < Bedrock_v686.CODEC.getProtocolVersion(); } + public static boolean isPre1_21_30(GeyserSession session) { + return session.getUpstream().getProtocolVersion() < Bedrock_v729.CODEC.getProtocolVersion(); + } + public static boolean isPre1_21_40(GeyserSession session) { return session.getUpstream().getProtocolVersion() < Bedrock_v748.CODEC.getProtocolVersion(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java index 6220b6623..6abb3899a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player.input; +import net.kyori.adventure.util.TriState; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData; @@ -32,6 +33,7 @@ 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.level.physics.CollisionResult; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.mcprotocollib.network.packet.Packet; @@ -86,6 +88,14 @@ final class BedrockMovePlayer { session.setLookBackScheduledFuture(null); } + TriState maybeOnGround; + if (GameProtocol.isPre1_21_30(session)) { + // VERTICAL_COLLISION input data does not exist. + maybeOnGround = TriState.NOT_SET; + } else { + // Client is telling us it wants to move down, but something is blocking it from doing so. + maybeOnGround = TriState.byBoolean(packet.getInputData().contains(PlayerAuthInputData.VERTICAL_COLLISION) && packet.getDelta().getY() < 0); + } // This takes into account no movement sent from the client, but the player is trying to move anyway. // (Press into a wall in a corner - you're trying to move but nothing actually happens) boolean horizontalCollision = packet.getInputData().contains(PlayerAuthInputData.HORIZONTAL_COLLISION); @@ -94,7 +104,7 @@ final class BedrockMovePlayer { // This isn't needed, but it makes the packets closer to vanilla // It also means you can't "lag back" while only looking, in theory if (!positionChanged && rotationChanged) { - ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(entity.isOnGround(), horizontalCollision, yaw, pitch); + ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(maybeOnGround.toBooleanOrElse(entity.isOnGround()), horizontalCollision, yaw, pitch); entity.setYaw(yaw); entity.setPitch(pitch); @@ -103,10 +113,10 @@ final class BedrockMovePlayer { session.sendDownstreamGamePacket(playerRotationPacket); } else if (positionChanged) { if (isValidMove(session, entity.getPosition(), packet.getPosition())) { - CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT)); + CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), maybeOnGround.toBooleanOrElse(false), packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT)); if (result != null) { // A null return value cancels the packet Vector3d position = result.correctedMovement(); - boolean onGround = result.onGround().toBooleanOrElse(entity.isOnGround()); + boolean onGround = maybeOnGround.toBooleanOrElseGet(() -> session.getCollisionManager().isOnGround()); boolean isBelowVoid = entity.isVoidPositionDesynched(); boolean teleportThroughVoidFloor, mustResyncPosition; @@ -155,7 +165,6 @@ final class BedrockMovePlayer { } entity.setPositionManual(packet.getPosition()); - entity.setOnGround(onGround); // Send final movement changes session.sendDownstreamGamePacket(movePacket); @@ -174,11 +183,12 @@ final class BedrockMovePlayer { session.getGeyser().getLogger().debug("Recalculating position..."); session.getCollisionManager().recalculatePosition(); } - } else if (horizontalCollision != session.getInputCache().lastHorizontalCollision()) { - session.sendDownstreamGamePacket(new ServerboundMovePlayerStatusOnlyPacket(entity.isOnGround(), horizontalCollision)); + } else if (horizontalCollision != session.getInputCache().lastHorizontalCollision() || maybeOnGround.toBooleanOrElse(entity.isOnGround()) != entity.isOnGround()) { + session.sendDownstreamGamePacket(new ServerboundMovePlayerStatusOnlyPacket(maybeOnGround.toBooleanOrElse(false), horizontalCollision)); } session.getInputCache().setLastHorizontalCollision(horizontalCollision); + entity.setOnGround(maybeOnGround.toBooleanOrElse(entity.isOnGround())); // Move parrots to match if applicable if (entity.getLeftParrot() != null) { From 4598ffec0515c5f992cf8daf1e66e56000ed2d1b Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 7 Nov 2024 20:35:41 -0500 Subject: [PATCH 459/897] Update MCPL and adapters (#5135) * Update MCPL * Update adapters --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b8908f518..f95574ee1 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.2-20241103.011758-1" +mcprotocollib = "1.21.2-20241107.110329-3" 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.14-SNAPSHOT" +adapters = "1.15-SNAPSHOT" cloud = "2.0.0-rc.2" cloud-minecraft = "2.0.0-beta.9" cloud-minecraft-modded = "2.0.0-beta.7" From e645935533e87f0318c9acc392dc817f84d44803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=92=9F=E8=92=BB?= <41978811+patyhank@users.noreply.github.com> Date: Tue, 12 Nov 2024 02:44:22 +0800 Subject: [PATCH 460/897] Fix #5070 light block placement (#5104) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 蒟蒻 --- .../java/org/geysermc/geyser/item/Items.java | 3 +- .../geysermc/geyser/item/type/LightItem.java | 79 +++++++++++++++++++ .../populator/ItemRegistryPopulator.java | 22 ++++++ .../geyser/registry/type/ItemMappings.java | 6 ++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/type/LightItem.java 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 302fdf99c..f123583f3 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -45,6 +45,7 @@ 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.LightItem; import org.geysermc.geyser.item.type.MaceItem; import org.geysermc.geyser.item.type.MapItem; import org.geysermc.geyser.item.type.PlayerHeadItem; @@ -526,7 +527,7 @@ public final class Items { 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(), Blocks.BARRIER)); - public static final Item LIGHT = register(new BlockItem(builder(), Blocks.LIGHT)); + public static final Item LIGHT = register(new LightItem(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)); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java b/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java new file mode 100644 index 000000000..fa10b08b1 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java @@ -0,0 +1,79 @@ +/* + * 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.item.type; + +import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.Block; +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.BlockStateProperties; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; + +public class LightItem extends BlockItem { + + public LightItem(Builder builder, Block block, Block... otherBlocks) { + super(builder, block, otherBlocks); + } + + @Override + public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + ItemMapping lightLevelMapping = getLightLevelMapping(components, mappings); + if (lightLevelMapping != null) { + return super.translateToBedrock(session, count, components, lightLevelMapping, mappings); + } + return super.translateToBedrock(session, count, components, mapping, mappings); + } + + @Override + public ItemMapping toBedrockDefinition(DataComponents components, ItemMappings mappings) { + ItemMapping lightLevelMapping = getLightLevelMapping(components, mappings); + if (lightLevelMapping != null) { + return lightLevelMapping; + } + return super.toBedrockDefinition(components, mappings); + } + + + private static ItemMapping getLightLevelMapping(DataComponents components, ItemMappings mappings) { + String lightLevel = "15"; + if (components != null) { + BlockStateProperties blockStateProperties = components.get(DataComponentType.BLOCK_STATE); + + if (blockStateProperties != null) { + lightLevel = blockStateProperties.getProperties().get(Properties.LEVEL.name()); + } + } + ItemDefinition definition = mappings.getDefinition("minecraft:light_block_" + lightLevel); + if (definition != null) { + return mappings.getLightBlocks().get(definition.getRuntimeId()); + } + return null; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 18a34f088..1da3b0e66 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -70,6 +70,7 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; @@ -508,6 +509,26 @@ public class ItemRegistryPopulator { javaItemToMapping.put(javaItem, mapping); } + // Add the light block level since it doesn't exist on java but we need it for item conversion + Int2ObjectMap lightBlocks = new Int2ObjectOpenHashMap<>(); + + for (int i = 0; i <= Properties.LEVEL.high(); i++) { + ItemDefinition lightBlock = definitions.get("minecraft:light_block_" + i); + if (lightBlock == null) { + break; + } + + ItemMapping lightBlockEntry = ItemMapping.builder() + .javaItem(Items.LIGHT) + .bedrockIdentifier("minecraft:light_block_" + i) + .bedrockDefinition(lightBlock) + .bedrockData(0) + .bedrockBlockDefinition(null) + .customItemOptions(Collections.emptyList()) + .build(); + lightBlocks.put(lightBlock.getRuntimeId(), lightBlockEntry); + } + ItemDefinition lodestoneCompass = definitions.get("minecraft:lodestone_compass"); if (lodestoneCompass == null) { throw new RuntimeException("Lodestone compass not found in item palette!"); @@ -641,6 +662,7 @@ public class ItemRegistryPopulator { .javaOnlyItems(javaOnlyItems) .buckets(buckets) .componentItemData(componentItemData) + .lightBlocks(lightBlocks) .lodestoneCompass(lodestoneEntry) .customIdMappings(customIdMappings) .customBlockItemDefinitions(customBlockItemDefinitions) diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index 189474238..8aae05fdc 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -59,6 +59,7 @@ public class ItemMappings implements DefinitionRegistry { * A unique exception as this is an item in Bedrock, but not in Java. */ ItemMapping lodestoneCompass; + Int2ObjectMap lightBlocks; ItemData[] creativeItems; Int2ObjectMap itemDefinitions; @@ -136,6 +137,11 @@ public class ItemMappings implements DefinitionRegistry { return lodestoneCompass; } + ItemMapping lightBlock = lightBlocks.get(definition.getRuntimeId()); + if (lightBlock != null) { + return lightBlock; + } + boolean isBlock = data.getBlockDefinition() != null; boolean hasDamage = data.getDamage() != 0; From fd58c729d839073c193d7c2af663a1968dad52ab Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 11 Nov 2024 20:11:03 -0500 Subject: [PATCH 461/897] Fix smithing recipes on 1.21.1 --- .../inventory/JavaContainerSetContentTranslator.java | 12 ++++++++++++ .../inventory/JavaContainerSetSlotTranslator.java | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java index 36d382d69..f2445856d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java @@ -31,6 +31,7 @@ import org.geysermc.geyser.inventory.Inventory; 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.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.InventoryUtils; @@ -74,6 +75,17 @@ public class JavaContainerSetContentTranslator extends PacketTranslator Date: Wed, 13 Nov 2024 15:47:39 +0000 Subject: [PATCH 462/897] Fix abstract arrow entity metadata (#5149) --- .../main/java/org/geysermc/geyser/entity/EntityDefinitions.java | 1 + 1 file changed, 1 insertion(+) 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 a25861813..47b97c934 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -492,6 +492,7 @@ public final class EntityDefinitions { EntityDefinition abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase) .addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags) .addTranslator(null) // "Piercing level" + .addTranslator(null) // If the arrow is in the ground .build(); ARROW = EntityDefinition.inherited(ArrowEntity::new, abstractArrowBase) .type(EntityType.ARROW) From abf68604beb3b8d3a1ee16e70f1f8ecfd86d5996 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 16 Nov 2024 13:31:17 -0500 Subject: [PATCH 463/897] Fix missing ominous potion levels Fixes #5153 --- core/src/main/java/org/geysermc/geyser/item/Items.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 f123583f3..7af5aadce 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -48,6 +48,7 @@ import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.LightItem; import org.geysermc.geyser.item.type.MaceItem; import org.geysermc.geyser.item.type.MapItem; +import org.geysermc.geyser.item.type.OminousBottleItem; import org.geysermc.geyser.item.type.PlayerHeadItem; import org.geysermc.geyser.item.type.PotionItem; import org.geysermc.geyser.item.type.ShieldItem; @@ -1443,7 +1444,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 Item("ominous_bottle", builder())); + public static final Item OMINOUS_BOTTLE = register(new OminousBottleItem("ominous_bottle", builder())); public static final int AIR_ID = AIR.javaId(); From 2ebce9c5c93e37847c690a5ee41e477e08485344 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Fri, 22 Nov 2024 07:33:32 -0500 Subject: [PATCH 464/897] Fix camel jump cooldown (#5161) --- .../entity/player/input/BedrockPlayerAuthInputTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java index 02ea02232..8e2781a98 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java @@ -250,7 +250,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator Date: Mon, 25 Nov 2024 10:18:10 -0500 Subject: [PATCH 465/897] Fix #5162 (#5163) --- .../protocol/java/JavaRecipeBookAddTranslator.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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 index 71fd4a200..96c5951d5 100644 --- 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 @@ -185,8 +185,13 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator Date: Wed, 27 Nov 2024 13:22:09 +0800 Subject: [PATCH 466/897] Fix: Fabric permissions api conflict --- bootstrap/mod/fabric/build.gradle.kts | 1 + gradle/libs.versions.toml | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index 2599a47b5..d48e184a2 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -38,6 +38,7 @@ dependencies { modImplementation(libs.cloud.fabric) include(libs.cloud.fabric) + include(libs.fabric.permissions.api) } tasks.withType { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f95574ee1..1e942df77 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,13 +28,14 @@ viaversion = "4.9.2" adapters = "1.15-SNAPSHOT" cloud = "2.0.0-rc.2" cloud-minecraft = "2.0.0-beta.9" -cloud-minecraft-modded = "2.0.0-beta.7" +cloud-minecraft-modded = "2.0.0-beta.9" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" viaproxy = "3.3.2-SNAPSHOT" fabric-loader = "0.16.7" fabric-api = "0.106.1+1.21.3" +fabric-permissions-api = "0.3.3" neoforge-minecraft = "21.3.0-beta" mixin = "0.8.5" mixinextras = "0.3.5" @@ -109,6 +110,7 @@ minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft # 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" } +fabric-permissions-api = { group = "me.lucko", name = "fabric-permissions-api", version.ref = "fabric-permissions-api" } neoforge-minecraft = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge-minecraft" } From c145c3f495b1e9f05e15b65da8c813b2e9a5f11f Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 27 Nov 2024 22:51:59 +0800 Subject: [PATCH 467/897] Fix: Don't include player offset when querying player position in the api (#5168) --- .../geyser/api/entity/type/player/GeyserPlayerEntity.java | 4 ++-- .../geysermc/geyser/entity/type/player/PlayerEntity.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java b/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java index bba4dbf3e..d31def996 100644 --- a/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java +++ b/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java @@ -31,9 +31,9 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity; public interface GeyserPlayerEntity extends GeyserEntity { /** - * Gets the position of the player. + * Gets the position of the player, as it is known to the Java server. * - * @return the position of the player. + * @return the player's position */ Vector3f position(); } 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 7e747e33d..7a443d6e8 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 @@ -97,11 +97,11 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { /** * Saves the parrot currently on the player's left shoulder; otherwise null */ - private ParrotEntity leftParrot; + private @Nullable ParrotEntity leftParrot; /** * Saves the parrot currently on the player's right shoulder; otherwise null */ - private ParrotEntity rightParrot; + private @Nullable ParrotEntity rightParrot; public PlayerEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, String username, @Nullable String texturesProperty) { @@ -450,6 +450,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { @Override public Vector3f position() { - return this.position.clone(); + return this.position.down(definition.offset()); } } From c240c1cfb540b79145a4bf758621dbcfe6f06551 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 29 Nov 2024 11:43:58 +0800 Subject: [PATCH 468/897] Fix: Virtual lecterns not displaying book contents (#5169) --- .../geyser/inventory/LecternContainer.java | 14 ++++++-------- .../holder/BlockInventoryHolder.java | 2 +- .../inventory/LecternInventoryTranslator.java | 19 +++++++++---------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java index 389611c67..ff21f561e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java @@ -34,17 +34,15 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.java.inventory.JavaOpenBookTranslator; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +@Getter public class LecternContainer extends Container { - @Getter @Setter + @Setter private int currentBedrockPage = 0; - @Getter @Setter + @Setter private NbtMap blockEntityTag; - @Getter @Setter + @Setter private Vector3i position; - // Sigh. When the lectern container is created, we don't know (yet) if it's fake or not. - // So... time for a manual check :/ - @Getter private boolean isFakeLectern = false; public LecternContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) { @@ -52,8 +50,8 @@ public class LecternContainer extends Container { } /** - * When we are using a fake lectern, the Java server expects us to still be in a player inventory. - * We can't use {@link #isUsingRealBlock()} as that may not be determined yet. + * When the Java server asks the client to open a book in their hotbar, we create a fake lectern to show it to the client. + * We can't use the {@link #isUsingRealBlock()} check as we may also be dealing with a real virtual lectern (with its own inventory). */ @Override public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index cdda4fe4c..385a1e2bd 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -157,7 +157,7 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { if (inventory instanceof Container container) { - if (container.isUsingRealBlock() && !(inventory instanceof LecternContainer)) { + if (container.isUsingRealBlock() && !(container instanceof LecternContainer)) { // No need to reset a block since we didn't change any blocks // But send a container close packet because we aren't destroying the original. ContainerClosePacket packet = new ContainerClosePacket(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 3b33f5909..007811999 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -30,8 +30,6 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.erosion.util.LecternUtils; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.LecternContainer; @@ -55,7 +53,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator * Hack: Java opens a lectern first, and then follows it up with a ClientboundContainerSetContentPacket * to actually send the book's contents. We delay opening the inventory until the book was sent. */ - private boolean initialized = false; + private boolean receivedBook = false; public LecternInventoryTranslator() { super(1, Blocks.LECTERN, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.LECTERN , ContainerInventoryUpdater.INSTANCE); @@ -64,11 +62,12 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator @Override public boolean prepareInventory(GeyserSession session, Inventory inventory) { super.prepareInventory(session, inventory); - if (((Container) inventory).isUsingRealBlock()) { - initialized = false; // We have to wait until we get the book to show to the client + if (((LecternContainer) inventory).isFakeLectern()) { + // See JavaOpenBookTranslator; this isn't a lectern but a book in the player inventory + updateBook(session, inventory, inventory.getItem(0)); + receivedBook = true; } else { - updateBook(session, inventory, inventory.getItem(0)); // See JavaOpenBookTranslator; placed here manually - initialized = true; + receivedBook = false; // We have to wait until we get the book } return true; } @@ -79,7 +78,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator // "initialized" indicates whether we've received the book from the Java server yet. // dropping lectern book is the fun workaround when we have to enter the gui to drop the book. // Since we leave it immediately... don't open it! - if (initialized && !session.isDroppingLecternBook()) { + if (receivedBook && !session.isDroppingLecternBook()) { super.openInventory(session, inventory); } } @@ -122,8 +121,8 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator boolean isDropping = session.isDroppingLecternBook(); updateBook(session, inventory, itemStack); - if (!initialized && !isDropping) { - initialized = true; + if (!receivedBook && !isDropping) { + receivedBook = true; openInventory(session, inventory); } } From d53a1a5cc44a3f838c35fed3a0df8e134858736a Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 28 Nov 2024 02:17:11 +0800 Subject: [PATCH 469/897] Start on 1.21.4 support --- .../entity/vehicle/VehicleComponent.java | 6 +++++- .../java/org/geysermc/geyser/item/Items.java | 5 +++++ .../org/geysermc/geyser/item/type/Item.java | 18 ++++++------------ .../translator/item/CustomItemTranslator.java | 13 +++++++++++-- .../BedrockPlayerAuthInputTranslator.java | 5 +++-- .../java/entity/JavaMoveVehicleTranslator.java | 7 +++---- .../geysermc/geyser/util/InventoryUtils.java | 11 ++++++----- .../network/ScoreboardIssueTests.java | 2 +- gradle.properties | 2 +- gradle/libs.versions.toml | 6 +++--- settings.gradle.kts | 4 ++-- 11 files changed, 46 insertions(+), 33 deletions(-) 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 91f54162b..61875ec90 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 @@ -105,6 +105,10 @@ public class VehicleComponent { boundingBox.setMiddleZ(z); } + public void moveAbsolute(Vector3d vec) { + moveAbsolute(vec.getX(), vec.getY(), vec.getZ()); + } + public void moveRelative(double x, double y, double z) { boundingBox.translate(x, y, z); } @@ -756,7 +760,7 @@ public class VehicleComponent { vehicle.getSession().sendUpstreamPacket(moveEntityDeltaPacket); } - ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(javaPos.getX(), javaPos.getY(), javaPos.getZ(), rotation.getX(), rotation.getY()); + ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(javaPos, rotation.getX(), rotation.getY(), vehicle.isOnGround()); vehicle.getSession().sendDownstreamPacket(moveVehiclePacket); } 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 7af5aadce..c7ab076b4 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -70,6 +70,11 @@ import static org.geysermc.geyser.item.type.Item.builder; */ @SuppressWarnings("unused") public final class Items { + + static { + // Load data components here + } + public static final Item AIR = register(new Item("air", builder())); public static final Item STONE = register(new BlockItem(builder(), Blocks.STONE)); public static final Item GRANITE = register(new BlockItem(builder(), Blocks.GRANITE)); 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 249936e5a..0155c4e35 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 @@ -62,12 +62,16 @@ public class Item { private static final Map BLOCK_TO_ITEM = new HashMap<>(); protected final Key javaIdentifier; private int javaId = -1; + + // TODO remove these private final int stackSize; private final int attackDamage; private final int maxDamage; private final Rarity rarity; private final boolean glint; + private DataComponents dataComponents; + public Item(String javaIdentifier, Builder builder) { this.javaIdentifier = MinecraftKey.key(javaIdentifier); this.stackSize = builder.stackSize; @@ -86,7 +90,7 @@ public class Item { } public int maxDamage() { - return maxDamage; + return dataComponents.getOrDefault(DataComponentType.MAX_DAMAGE, 0); } public int attackDamage() { @@ -94,7 +98,7 @@ public class Item { } public int maxStackSize() { - return stackSize; + return dataComponents.getOrDefault(DataComponentType.MAX_STACK_SIZE, 1); } public Rarity rarity() { @@ -317,16 +321,6 @@ public class Item { return this; } - public Builder rarity(Rarity rarity) { - this.rarity = rarity; - return this; - } - - public Builder glint(boolean glintOverride) { - this.glint = glintOverride; - return this; - } - private Builder() { } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java index 91eee3895..b65b06431 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.item; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.CustomModelData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import it.unimi.dsi.fastutil.Pair; @@ -52,7 +53,15 @@ public final class CustomItemTranslator { return null; } - int customModelData = components.getOrDefault(DataComponentType.CUSTOM_MODEL_DATA, 0); + // TODO 1.21.4 + float customModelDataInt = 0; + CustomModelData customModelData = components.get(DataComponentType.CUSTOM_MODEL_DATA); + if (customModelData != null) { + if (!customModelData.floats().isEmpty()) { + customModelDataInt = customModelData.floats().get(0); + } + } + boolean checkDamage = mapping.getJavaItem().maxDamage() > 0; int damage = !checkDamage ? 0 : components.getOrDefault(DataComponentType.DAMAGE, 0); boolean unbreakable = checkDamage && !isDamaged(components, damage); @@ -88,7 +97,7 @@ public final class CustomItemTranslator { } OptionalInt customModelDataOption = options.customModelData(); - if (customModelDataOption.isPresent() && customModelData < customModelDataOption.getAsInt()) { + if (customModelDataOption.isPresent() && customModelDataInt < customModelDataOption.getAsInt()) { continue; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java index 8e2781a98..b57187018 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java @@ -312,8 +312,9 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator { @@ -42,9 +41,9 @@ public class JavaMoveVehicleTranslator extends PacketTranslator Date: Sun, 1 Dec 2024 03:22:34 +0800 Subject: [PATCH 470/897] More work on 1.21.4 changes --- .../updater/AnvilInventoryUpdater.java | 9 +- .../java/org/geysermc/geyser/item/Items.java | 516 +++++++++--------- .../item/type/BedrockRequiresTagItem.java | 8 +- .../geyser/item/type/FireworkRocketItem.java | 17 - .../org/geysermc/geyser/item/type/Item.java | 59 +- .../CustomItemRegistryPopulator.java | 15 +- .../populator/ItemRegistryPopulator.java | 2 +- .../translator/item/CustomItemTranslator.java | 2 +- .../translator/item/ItemTranslator.java | 67 +-- .../BedrockBlockPickRequestTranslator.java | 42 +- .../BedrockEntityPickRequestTranslator.java | 37 +- .../JavaMerchantOffersTranslator.java | 2 +- .../geysermc/geyser/util/InventoryUtils.java | 170 ------ 13 files changed, 337 insertions(+), 609 deletions(-) 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 0ffb74082..00270e47a 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 @@ -52,7 +52,6 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.stream.IntStream; public class AnvilInventoryUpdater extends InventoryUpdater { public static final AnvilInventoryUpdater INSTANCE = new AnvilInventoryUpdater(); @@ -266,14 +265,14 @@ public class AnvilInventoryUpdater extends InventoryUpdater { */ private int calcRepairLevelCost(GeyserItemStack input, GeyserItemStack material) { int newDamage = getDamage(input); - int unitRepair = Math.min(newDamage, input.asItem().maxDamage() / 4); + int unitRepair = Math.min(newDamage, input.asItem().defaultMaxDamage() / 4); if (unitRepair <= 0) { // No damage to repair return -1; } for (int i = 0; i < material.getAmount(); i++) { newDamage -= unitRepair; - unitRepair = Math.min(newDamage, input.asItem().maxDamage() / 4); + unitRepair = Math.min(newDamage, input.asItem().defaultMaxDamage() / 4); if (unitRepair <= 0) { return i + 1; } @@ -290,7 +289,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { */ private int calcMergeRepairCost(GeyserItemStack input, GeyserItemStack material) { // If the material item is damaged 112% or more, then the input item will not be repaired - if (getDamage(input) > 0 && getDamage(material) < (material.asItem().maxDamage() * 112 / 100)) { + if (getDamage(input) > 0 && getDamage(material) < (material.asItem().defaultMaxDamage() * 112 / 100)) { return 2; } return 0; @@ -419,7 +418,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } private boolean hasDurability(GeyserItemStack itemStack) { - if (itemStack.asItem().maxDamage() > 0) { + if (itemStack.asItem().defaultMaxDamage() > 0) { return itemStack.getComponent(DataComponentType.UNBREAKABLE, false); } return false; 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 c7ab076b4..d2ae08ec4 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -301,6 +301,8 @@ public final class Items { public static final Item RED_WOOL = register(new BlockItem(builder(), Blocks.RED_WOOL)); public static final Item BLACK_WOOL = register(new BlockItem(builder(), Blocks.BLACK_WOOL)); public static final Item DANDELION = register(new BlockItem(builder(), Blocks.DANDELION)); +// TODO public static final Item OPEN_EYEBLOSSOM = register(new BlockItem(builder(), Blocks.OPEN_EYEBLOSSOM)); +// TODO public static final Item CLOSED_EYEBLOSSOM = register(new BlockItem(builder(), Blocks.CLOSED_EYEBLOSSOM)); public static final Item POPPY = register(new BlockItem(builder(), Blocks.POPPY)); public static final Item BLUE_ORCHID = register(new BlockItem(builder(), Blocks.BLUE_ORCHID)); public static final Item ALLIUM = register(new BlockItem(builder(), Blocks.ALLIUM)); @@ -449,6 +451,13 @@ public final class Items { public static final Item MELON = register(new BlockItem(builder(), Blocks.MELON)); public static final Item VINE = register(new BlockItem(builder(), Blocks.VINE)); public static final Item GLOW_LICHEN = register(new BlockItem(builder(), Blocks.GLOW_LICHEN)); + //TODO public static final Item RESIN_CLUMP = register(new BlockItem(builder(), Blocks.RESIN_CLUMP)); + //TODO public static final Item RESIN_BLOCK = register(new BlockItem(builder(), Blocks.RESIN_BLOCK)); + //TODO public static final Item RESIN_BRICKS = register(new BlockItem(builder(), Blocks.RESIN_BRICKS)); + //TODO public static final Item RESIN_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.RESIN_BRICK_STAIRS)); + //TODO public static final Item RESIN_BRICK_SLAB = register(new BlockItem(builder(), Blocks.RESIN_BRICK_SLAB)); + //TODO public static final Item RESIN_BRICK_WALL = register(new BlockItem(builder(), Blocks.RESIN_BRICK_WALL)); + //TODO public static final Item CHISELED_RESIN_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_RESIN_BRICKS)); public static final Item BRICK_STAIRS = register(new BlockItem(builder(), Blocks.BRICK_STAIRS)); public static final Item STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.STONE_BRICK_STAIRS)); public static final Item MUD_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MUD_BRICK_STAIRS)); @@ -533,7 +542,7 @@ public final class Items { 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(), Blocks.BARRIER)); - public static final Item LIGHT = register(new LightItem(builder(), Blocks.LIGHT)); + 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)); @@ -611,23 +620,23 @@ public final class Items { 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(), 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)); - public static final Item MAGENTA_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.MAGENTA_SHULKER_BOX)); - public static final Item LIGHT_BLUE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIGHT_BLUE_SHULKER_BOX)); - public static final Item YELLOW_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.YELLOW_SHULKER_BOX)); - public static final Item LIME_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIME_SHULKER_BOX)); - public static final Item PINK_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.PINK_SHULKER_BOX)); - public static final Item GRAY_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.GRAY_SHULKER_BOX)); - public static final Item LIGHT_GRAY_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIGHT_GRAY_SHULKER_BOX)); - public static final Item CYAN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.CYAN_SHULKER_BOX)); - public static final Item PURPLE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.PURPLE_SHULKER_BOX)); - public static final Item BLUE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BLUE_SHULKER_BOX)); - public static final Item BROWN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BROWN_SHULKER_BOX)); - public static final Item GREEN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.GREEN_SHULKER_BOX)); - public static final Item RED_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.RED_SHULKER_BOX)); - public static final Item BLACK_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BLACK_SHULKER_BOX)); + public static final Item SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.SHULKER_BOX)); + public static final Item WHITE_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.WHITE_SHULKER_BOX)); + public static final Item ORANGE_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.ORANGE_SHULKER_BOX)); + public static final Item MAGENTA_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.MAGENTA_SHULKER_BOX)); + public static final Item LIGHT_BLUE_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.LIGHT_BLUE_SHULKER_BOX)); + public static final Item YELLOW_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.YELLOW_SHULKER_BOX)); + public static final Item LIME_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.LIME_SHULKER_BOX)); + public static final Item PINK_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.PINK_SHULKER_BOX)); + public static final Item GRAY_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.GRAY_SHULKER_BOX)); + public static final Item LIGHT_GRAY_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.LIGHT_GRAY_SHULKER_BOX)); + public static final Item CYAN_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.CYAN_SHULKER_BOX)); + public static final Item PURPLE_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.PURPLE_SHULKER_BOX)); + public static final Item BLUE_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.BLUE_SHULKER_BOX)); + public static final Item BROWN_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.BROWN_SHULKER_BOX)); + public static final Item GREEN_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.GREEN_SHULKER_BOX)); + public static final Item RED_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.RED_SHULKER_BOX)); + public static final Item BLACK_SHULKER_BOX = register(new ShulkerBoxItem(builder(), Blocks.BLACK_SHULKER_BOX)); public static final Item WHITE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.WHITE_GLAZED_TERRACOTTA)); public static final Item ORANGE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.ORANGE_GLAZED_TERRACOTTA)); public static final Item MAGENTA_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.MAGENTA_GLAZED_TERRACOTTA)); @@ -859,46 +868,46 @@ public final class Items { public static final Item DETECTOR_RAIL = register(new BlockItem(builder(), Blocks.DETECTOR_RAIL)); public static final Item RAIL = register(new BlockItem(builder(), Blocks.RAIL)); public static final Item ACTIVATOR_RAIL = register(new BlockItem(builder(), Blocks.ACTIVATOR_RAIL)); - public static final Item SADDLE = register(new Item("saddle", builder().stackSize(1))); - public static final Item MINECART = register(new Item("minecart", builder().stackSize(1))); - public static final Item CHEST_MINECART = register(new Item("chest_minecart", builder().stackSize(1))); - public static final Item FURNACE_MINECART = register(new Item("furnace_minecart", builder().stackSize(1))); - public static final Item TNT_MINECART = register(new Item("tnt_minecart", builder().stackSize(1))); - 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 SADDLE = register(new Item("saddle", builder())); + public static final Item MINECART = register(new Item("minecart", builder())); + public static final Item CHEST_MINECART = register(new Item("chest_minecart", builder())); + public static final Item FURNACE_MINECART = register(new Item("furnace_minecart", builder())); + public static final Item TNT_MINECART = register(new Item("tnt_minecart", builder())); + public static final Item HOPPER_MINECART = register(new Item("hopper_minecart", builder())); + public static final Item CARROT_ON_A_STICK = register(new Item("carrot_on_a_stick", builder())); + public static final Item WARPED_FUNGUS_ON_A_STICK = register(new Item("warped_fungus_on_a_stick", builder())); 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))); - public static final Item SPRUCE_CHEST_BOAT = register(new BoatItem("spruce_chest_boat", builder().stackSize(1))); - public static final Item BIRCH_BOAT = register(new BoatItem("birch_boat", builder().stackSize(1))); - public static final Item BIRCH_CHEST_BOAT = register(new BoatItem("birch_chest_boat", builder().stackSize(1))); - public static final Item JUNGLE_BOAT = register(new BoatItem("jungle_boat", builder().stackSize(1))); - public static final Item JUNGLE_CHEST_BOAT = register(new BoatItem("jungle_chest_boat", builder().stackSize(1))); - public static final Item ACACIA_BOAT = register(new BoatItem("acacia_boat", builder().stackSize(1))); - public static final Item ACACIA_CHEST_BOAT = register(new BoatItem("acacia_chest_boat", builder().stackSize(1))); - public static final Item CHERRY_BOAT = register(new BoatItem("cherry_boat", builder().stackSize(1))); - 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 ELYTRA = register(new ElytraItem("elytra", builder())); + public static final Item OAK_BOAT = register(new BoatItem("oak_boat", builder())); + public static final Item OAK_CHEST_BOAT = register(new BoatItem("oak_chest_boat", builder())); + public static final Item SPRUCE_BOAT = register(new BoatItem("spruce_boat", builder())); + public static final Item SPRUCE_CHEST_BOAT = register(new BoatItem("spruce_chest_boat", builder())); + public static final Item BIRCH_BOAT = register(new BoatItem("birch_boat", builder())); + public static final Item BIRCH_CHEST_BOAT = register(new BoatItem("birch_chest_boat", builder())); + public static final Item JUNGLE_BOAT = register(new BoatItem("jungle_boat", builder())); + public static final Item JUNGLE_CHEST_BOAT = register(new BoatItem("jungle_chest_boat", builder())); + public static final Item ACACIA_BOAT = register(new BoatItem("acacia_boat", builder())); + public static final Item ACACIA_CHEST_BOAT = register(new BoatItem("acacia_chest_boat", builder())); + public static final Item CHERRY_BOAT = register(new BoatItem("cherry_boat", builder())); + public static final Item CHERRY_CHEST_BOAT = register(new BoatItem("cherry_chest_boat", builder())); + public static final Item DARK_OAK_BOAT = register(new BoatItem("dark_oak_boat", builder())); + public static final Item DARK_OAK_CHEST_BOAT = register(new BoatItem("dark_oak_chest_boat", builder())); + public static final Item PALE_OAK_BOAT = register(new BoatItem("pale_oak_boat", builder())); + public static final Item PALE_OAK_CHEST_BOAT = register(new BoatItem("pale_oak_chest_boat", builder())); + public static final Item MANGROVE_BOAT = register(new BoatItem("mangrove_boat", builder())); + public static final Item MANGROVE_CHEST_BOAT = register(new BoatItem("mangrove_chest_boat", builder())); + public static final Item BAMBOO_RAFT = register(new BoatItem("bamboo_raft", builder())); + public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder())); 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_HELMET = register(new ArmorItem("turtle_helmet", ArmorMaterial.TURTLE, builder())); public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder())); public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder())); - public static final Item WOLF_ARMOR = register(new WolfArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder().stackSize(1).maxDamage(64))); - public static final Item FLINT_AND_STEEL = register(new Item("flint_and_steel", builder().stackSize(1).maxDamage(64))); + public static final Item WOLF_ARMOR = register(new WolfArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder())); + public static final Item FLINT_AND_STEEL = register(new Item("flint_and_steel", builder())); public static final Item BOWL = register(new Item("bowl", builder())); public static final Item APPLE = register(new Item("apple", builder())); - public static final Item BOW = register(new Item("bow", builder().stackSize(1).maxDamage(384))); + public static final Item BOW = register(new Item("bow", builder())); public static final Item ARROW = register(new ArrowItem("arrow", builder())); public static final Item COAL = register(new Item("coal", builder())); public static final Item CHARCOAL = register(new Item("charcoal", builder())); @@ -915,140 +924,140 @@ public final class Items { public static final Item GOLD_INGOT = register(new Item("gold_ingot", builder())); public static final Item NETHERITE_INGOT = register(new Item("netherite_ingot", builder())); public static final Item NETHERITE_SCRAP = register(new Item("netherite_scrap", builder())); - public static final Item WOODEN_SWORD = register(new TieredItem("wooden_sword", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(4.0))); - public static final Item WOODEN_SHOVEL = register(new TieredItem("wooden_shovel", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(2.5))); - public static final Item WOODEN_PICKAXE = register(new TieredItem("wooden_pickaxe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(2.0))); - public static final Item WOODEN_AXE = register(new TieredItem("wooden_axe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(7.0))); - public static final Item WOODEN_HOE = register(new TieredItem("wooden_hoe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(1.0))); - public static final Item STONE_SWORD = register(new TieredItem("stone_sword", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(5.0))); - public static final Item STONE_SHOVEL = register(new TieredItem("stone_shovel", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(3.5))); - public static final Item STONE_PICKAXE = register(new TieredItem("stone_pickaxe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(3.0))); - public static final Item STONE_AXE = register(new TieredItem("stone_axe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(9.0))); - public static final Item STONE_HOE = register(new TieredItem("stone_hoe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(1.0))); - public static final Item GOLDEN_SWORD = register(new TieredItem("golden_sword", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(4.0))); - public static final Item GOLDEN_SHOVEL = register(new TieredItem("golden_shovel", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(2.5))); - public static final Item GOLDEN_PICKAXE = register(new TieredItem("golden_pickaxe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(2.0))); - public static final Item GOLDEN_AXE = register(new TieredItem("golden_axe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(7.0))); - public static final Item GOLDEN_HOE = register(new TieredItem("golden_hoe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(1.0))); - public static final Item IRON_SWORD = register(new TieredItem("iron_sword", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(6.0))); - public static final Item IRON_SHOVEL = register(new TieredItem("iron_shovel", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(4.5))); - public static final Item IRON_PICKAXE = register(new TieredItem("iron_pickaxe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(4.0))); - public static final Item IRON_AXE = register(new TieredItem("iron_axe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(9.0))); - public static final Item IRON_HOE = register(new TieredItem("iron_hoe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(1.0))); - public static final Item DIAMOND_SWORD = register(new TieredItem("diamond_sword", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(7.0))); - public static final Item DIAMOND_SHOVEL = register(new TieredItem("diamond_shovel", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(5.5))); - public static final Item DIAMOND_PICKAXE = register(new TieredItem("diamond_pickaxe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(5.0))); - public static final Item DIAMOND_AXE = register(new TieredItem("diamond_axe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(9.0))); - public static final Item DIAMOND_HOE = register(new TieredItem("diamond_hoe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(1.0))); - public static final Item NETHERITE_SWORD = register(new TieredItem("netherite_sword", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(8.0))); - public static final Item NETHERITE_SHOVEL = register(new TieredItem("netherite_shovel", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(6.5))); - public static final Item NETHERITE_PICKAXE = register(new TieredItem("netherite_pickaxe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(6.0))); - public static final Item NETHERITE_AXE = register(new TieredItem("netherite_axe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(10.0))); - public static final Item NETHERITE_HOE = register(new TieredItem("netherite_hoe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(1.0))); + public static final Item WOODEN_SWORD = register(new Item("wooden_sword", builder().attackDamage(4.0))); + public static final Item WOODEN_SHOVEL = register(new Item("wooden_shovel", builder().attackDamage(2.5))); + public static final Item WOODEN_PICKAXE = register(new Item("wooden_pickaxe", builder().attackDamage(2.0))); + public static final Item WOODEN_AXE = register(new Item("wooden_axe", builder().attackDamage(7.0))); + public static final Item WOODEN_HOE = register(new Item("wooden_hoe", builder().attackDamage(1.0))); + public static final Item STONE_SWORD = register(new Item("stone_sword", builder().attackDamage(5.0))); + public static final Item STONE_SHOVEL = register(new Item("stone_shovel", builder().attackDamage(3.5))); + public static final Item STONE_PICKAXE = register(new Item("stone_pickaxe", builder().attackDamage(3.0))); + public static final Item STONE_AXE = register(new Item("stone_axe", builder().attackDamage(9.0))); + public static final Item STONE_HOE = register(new Item("stone_hoe", builder().attackDamage(1.0))); + public static final Item GOLDEN_SWORD = register(new Item("golden_sword", builder().attackDamage(4.0))); + public static final Item GOLDEN_SHOVEL = register(new Item("golden_shovel", builder().attackDamage(2.5))); + public static final Item GOLDEN_PICKAXE = register(new Item("golden_pickaxe", builder().attackDamage(2.0))); + public static final Item GOLDEN_AXE = register(new Item("golden_axe", builder().attackDamage(7.0))); + public static final Item GOLDEN_HOE = register(new Item("golden_hoe", builder().attackDamage(1.0))); + public static final Item IRON_SWORD = register(new Item("iron_sword", builder().attackDamage(6.0))); + public static final Item IRON_SHOVEL = register(new Item("iron_shovel", builder().attackDamage(4.5))); + public static final Item IRON_PICKAXE = register(new Item("iron_pickaxe", builder().attackDamage(4.0))); + public static final Item IRON_AXE = register(new Item("iron_axe", builder().attackDamage(9.0))); + public static final Item IRON_HOE = register(new Item("iron_hoe", builder().attackDamage(1.0))); + public static final Item DIAMOND_SWORD = register(new Item("diamond_sword", builder().attackDamage(7.0))); + public static final Item DIAMOND_SHOVEL = register(new Item("diamond_shovel", builder().attackDamage(5.5))); + public static final Item DIAMOND_PICKAXE = register(new Item("diamond_pickaxe", builder().attackDamage(5.0))); + public static final Item DIAMOND_AXE = register(new Item("diamond_axe", builder().attackDamage(9.0))); + public static final Item DIAMOND_HOE = register(new Item("diamond_hoe", builder().attackDamage(1.0))); + public static final Item NETHERITE_SWORD = register(new Item("netherite_sword", builder().attackDamage(8.0))); + public static final Item NETHERITE_SHOVEL = register(new Item("netherite_shovel", builder().attackDamage(6.5))); + public static final Item NETHERITE_PICKAXE = register(new Item("netherite_pickaxe", builder().attackDamage(6.0))); + public static final Item NETHERITE_AXE = register(new Item("netherite_axe", builder().attackDamage(10.0))); + public static final Item NETHERITE_HOE = register(new Item("netherite_hoe", builder().attackDamage(1.0))); public static final Item STICK = register(new Item("stick", builder())); - public static final Item MUSHROOM_STEW = register(new Item("mushroom_stew", builder().stackSize(1))); + public static final Item MUSHROOM_STEW = register(new Item("mushroom_stew", builder())); public static final Item STRING = register(new BlockItem("string", builder(), Blocks.TRIPWIRE)); public static final Item FEATHER = register(new Item("feather", builder())); public static final Item GUNPOWDER = register(new Item("gunpowder", builder())); public static final Item WHEAT_SEEDS = register(new BlockItem("wheat_seeds", builder(), Blocks.WHEAT)); public static final Item WHEAT = register(new Item("wheat", builder())); public static final Item BREAD = register(new Item("bread", builder())); - public static final Item LEATHER_HELMET = register(new DyeableArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(55))); - public static final Item LEATHER_CHESTPLATE = register(new DyeableArmorItem("leather_chestplate", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(80))); - public static final Item LEATHER_LEGGINGS = register(new DyeableArmorItem("leather_leggings", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(75))); - public static final Item LEATHER_BOOTS = register(new DyeableArmorItem("leather_boots", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(65))); - public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(165))); - public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(240))); - public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(225))); - public static final Item CHAINMAIL_BOOTS = register(new ArmorItem("chainmail_boots", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(195))); - public static final Item IRON_HELMET = register(new ArmorItem("iron_helmet", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(165))); - public static final Item IRON_CHESTPLATE = register(new ArmorItem("iron_chestplate", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(240))); - public static final Item IRON_LEGGINGS = register(new ArmorItem("iron_leggings", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(225))); - public static final Item IRON_BOOTS = register(new ArmorItem("iron_boots", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(195))); - public static final Item DIAMOND_HELMET = register(new ArmorItem("diamond_helmet", ArmorMaterial.DIAMOND, builder().stackSize(1).maxDamage(363))); - public static final Item DIAMOND_CHESTPLATE = register(new ArmorItem("diamond_chestplate", ArmorMaterial.DIAMOND, builder().stackSize(1).maxDamage(528))); - public static final Item DIAMOND_LEGGINGS = register(new ArmorItem("diamond_leggings", ArmorMaterial.DIAMOND, builder().stackSize(1).maxDamage(495))); - public static final Item DIAMOND_BOOTS = register(new ArmorItem("diamond_boots", ArmorMaterial.DIAMOND, builder().stackSize(1).maxDamage(429))); - public static final Item GOLDEN_HELMET = register(new ArmorItem("golden_helmet", ArmorMaterial.GOLD, builder().stackSize(1).maxDamage(77))); - public static final Item GOLDEN_CHESTPLATE = register(new ArmorItem("golden_chestplate", ArmorMaterial.GOLD, builder().stackSize(1).maxDamage(112))); - public static final Item GOLDEN_LEGGINGS = register(new ArmorItem("golden_leggings", ArmorMaterial.GOLD, builder().stackSize(1).maxDamage(105))); - public static final Item GOLDEN_BOOTS = register(new ArmorItem("golden_boots", ArmorMaterial.GOLD, builder().stackSize(1).maxDamage(91))); - public static final Item NETHERITE_HELMET = register(new ArmorItem("netherite_helmet", ArmorMaterial.NETHERITE, builder().stackSize(1).maxDamage(407))); - public static final Item NETHERITE_CHESTPLATE = register(new ArmorItem("netherite_chestplate", ArmorMaterial.NETHERITE, builder().stackSize(1).maxDamage(592))); - public static final Item NETHERITE_LEGGINGS = register(new ArmorItem("netherite_leggings", ArmorMaterial.NETHERITE, builder().stackSize(1).maxDamage(555))); - public static final Item NETHERITE_BOOTS = register(new ArmorItem("netherite_boots", ArmorMaterial.NETHERITE, builder().stackSize(1).maxDamage(481))); + public static final Item LEATHER_HELMET = register(new DyeableArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder())); + public static final Item LEATHER_CHESTPLATE = register(new DyeableArmorItem("leather_chestplate", ArmorMaterial.LEATHER, builder())); + public static final Item LEATHER_LEGGINGS = register(new DyeableArmorItem("leather_leggings", ArmorMaterial.LEATHER, builder())); + public static final Item LEATHER_BOOTS = register(new DyeableArmorItem("leather_boots", ArmorMaterial.LEATHER, builder())); + public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", ArmorMaterial.CHAINMAIL, builder())); + public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", ArmorMaterial.CHAINMAIL, builder())); + public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", ArmorMaterial.CHAINMAIL, builder())); + public static final Item CHAINMAIL_BOOTS = register(new ArmorItem("chainmail_boots", ArmorMaterial.CHAINMAIL, builder())); + public static final Item IRON_HELMET = register(new ArmorItem("iron_helmet", ArmorMaterial.IRON, builder())); + public static final Item IRON_CHESTPLATE = register(new ArmorItem("iron_chestplate", ArmorMaterial.IRON, builder())); + public static final Item IRON_LEGGINGS = register(new ArmorItem("iron_leggings", ArmorMaterial.IRON, builder())); + public static final Item IRON_BOOTS = register(new ArmorItem("iron_boots", ArmorMaterial.IRON, builder())); + public static final Item DIAMOND_HELMET = register(new ArmorItem("diamond_helmet", ArmorMaterial.DIAMOND, builder())); + public static final Item DIAMOND_CHESTPLATE = register(new ArmorItem("diamond_chestplate", ArmorMaterial.DIAMOND, builder())); + public static final Item DIAMOND_LEGGINGS = register(new ArmorItem("diamond_leggings", ArmorMaterial.DIAMOND, builder())); + public static final Item DIAMOND_BOOTS = register(new ArmorItem("diamond_boots", ArmorMaterial.DIAMOND, builder())); + public static final Item GOLDEN_HELMET = register(new ArmorItem("golden_helmet", ArmorMaterial.GOLD, builder())); + public static final Item GOLDEN_CHESTPLATE = register(new ArmorItem("golden_chestplate", ArmorMaterial.GOLD, builder())); + public static final Item GOLDEN_LEGGINGS = register(new ArmorItem("golden_leggings", ArmorMaterial.GOLD, builder())); + public static final Item GOLDEN_BOOTS = register(new ArmorItem("golden_boots", ArmorMaterial.GOLD, builder())); + public static final Item NETHERITE_HELMET = register(new ArmorItem("netherite_helmet", ArmorMaterial.NETHERITE, builder())); + public static final Item NETHERITE_CHESTPLATE = register(new ArmorItem("netherite_chestplate", ArmorMaterial.NETHERITE, builder())); + public static final Item NETHERITE_LEGGINGS = register(new ArmorItem("netherite_leggings", ArmorMaterial.NETHERITE, builder())); + public static final Item NETHERITE_BOOTS = register(new ArmorItem("netherite_boots", ArmorMaterial.NETHERITE, builder())); public static final Item FLINT = register(new Item("flint", builder())); 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())); 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)); - public static final Item JUNGLE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.JUNGLE_SIGN, Blocks.JUNGLE_WALL_SIGN)); - 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)); - public static final Item WARPED_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.WARPED_SIGN, Blocks.WARPED_WALL_SIGN)); - public static final Item OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.OAK_HANGING_SIGN, Blocks.OAK_WALL_HANGING_SIGN)); - public static final Item SPRUCE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.SPRUCE_HANGING_SIGN, Blocks.SPRUCE_WALL_HANGING_SIGN)); - public static final Item BIRCH_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BIRCH_HANGING_SIGN, Blocks.BIRCH_WALL_HANGING_SIGN)); - public static final Item JUNGLE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.JUNGLE_HANGING_SIGN, Blocks.JUNGLE_WALL_HANGING_SIGN)); - 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)); - public static final Item WARPED_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.WARPED_HANGING_SIGN, Blocks.WARPED_WALL_HANGING_SIGN)); - public static final Item BUCKET = register(new Item("bucket", builder().stackSize(16))); - public static final Item WATER_BUCKET = register(new Item("water_bucket", builder().stackSize(1))); - public static final Item LAVA_BUCKET = register(new Item("lava_bucket", builder().stackSize(1))); - public static final Item POWDER_SNOW_BUCKET = register(new BlockItem("powder_snow_bucket", builder().stackSize(1), Blocks.POWDER_SNOW)); - public static final Item SNOWBALL = register(new Item("snowball", builder().stackSize(16))); + public static final Item OAK_SIGN = register(new BlockItem(builder(), Blocks.OAK_SIGN, Blocks.OAK_WALL_SIGN)); + public static final Item SPRUCE_SIGN = register(new BlockItem(builder(), Blocks.SPRUCE_SIGN, Blocks.SPRUCE_WALL_SIGN)); + public static final Item BIRCH_SIGN = register(new BlockItem(builder(), Blocks.BIRCH_SIGN, Blocks.BIRCH_WALL_SIGN)); + public static final Item JUNGLE_SIGN = register(new BlockItem(builder(), Blocks.JUNGLE_SIGN, Blocks.JUNGLE_WALL_SIGN)); + public static final Item ACACIA_SIGN = register(new BlockItem(builder(), Blocks.ACACIA_SIGN, Blocks.ACACIA_WALL_SIGN)); + public static final Item CHERRY_SIGN = register(new BlockItem(builder(), Blocks.CHERRY_SIGN, Blocks.CHERRY_WALL_SIGN)); + public static final Item DARK_OAK_SIGN = register(new BlockItem(builder(), Blocks.DARK_OAK_SIGN, Blocks.DARK_OAK_WALL_SIGN)); + public static final Item PALE_OAK_SIGN = register(new BlockItem(builder(), Blocks.PALE_OAK_SIGN, Blocks.PALE_OAK_WALL_SIGN)); + public static final Item MANGROVE_SIGN = register(new BlockItem(builder(), Blocks.MANGROVE_SIGN, Blocks.MANGROVE_WALL_SIGN)); + public static final Item BAMBOO_SIGN = register(new BlockItem(builder(), Blocks.BAMBOO_SIGN, Blocks.BAMBOO_WALL_SIGN)); + public static final Item CRIMSON_SIGN = register(new BlockItem(builder(), Blocks.CRIMSON_SIGN, Blocks.CRIMSON_WALL_SIGN)); + public static final Item WARPED_SIGN = register(new BlockItem(builder(), Blocks.WARPED_SIGN, Blocks.WARPED_WALL_SIGN)); + public static final Item OAK_HANGING_SIGN = register(new BlockItem(builder(), Blocks.OAK_HANGING_SIGN, Blocks.OAK_WALL_HANGING_SIGN)); + public static final Item SPRUCE_HANGING_SIGN = register(new BlockItem(builder(), Blocks.SPRUCE_HANGING_SIGN, Blocks.SPRUCE_WALL_HANGING_SIGN)); + public static final Item BIRCH_HANGING_SIGN = register(new BlockItem(builder(), Blocks.BIRCH_HANGING_SIGN, Blocks.BIRCH_WALL_HANGING_SIGN)); + public static final Item JUNGLE_HANGING_SIGN = register(new BlockItem(builder(), Blocks.JUNGLE_HANGING_SIGN, Blocks.JUNGLE_WALL_HANGING_SIGN)); + public static final Item ACACIA_HANGING_SIGN = register(new BlockItem(builder(), Blocks.ACACIA_HANGING_SIGN, Blocks.ACACIA_WALL_HANGING_SIGN)); + public static final Item CHERRY_HANGING_SIGN = register(new BlockItem(builder(), Blocks.CHERRY_HANGING_SIGN, Blocks.CHERRY_WALL_HANGING_SIGN)); + public static final Item DARK_OAK_HANGING_SIGN = register(new BlockItem(builder(), Blocks.DARK_OAK_HANGING_SIGN, Blocks.DARK_OAK_WALL_HANGING_SIGN)); + public static final Item PALE_OAK_HANGING_SIGN = register(new BlockItem(builder(), Blocks.PALE_OAK_HANGING_SIGN, Blocks.PALE_OAK_WALL_HANGING_SIGN)); + public static final Item MANGROVE_HANGING_SIGN = register(new BlockItem(builder(), Blocks.MANGROVE_HANGING_SIGN, Blocks.MANGROVE_WALL_HANGING_SIGN)); + public static final Item BAMBOO_HANGING_SIGN = register(new BlockItem(builder(), Blocks.BAMBOO_HANGING_SIGN, Blocks.BAMBOO_WALL_HANGING_SIGN)); + public static final Item CRIMSON_HANGING_SIGN = register(new BlockItem(builder(), Blocks.CRIMSON_HANGING_SIGN, Blocks.CRIMSON_WALL_HANGING_SIGN)); + public static final Item WARPED_HANGING_SIGN = register(new BlockItem(builder(), Blocks.WARPED_HANGING_SIGN, Blocks.WARPED_WALL_HANGING_SIGN)); + public static final Item BUCKET = register(new Item("bucket", builder())); + public static final Item WATER_BUCKET = register(new Item("water_bucket", builder())); + public static final Item LAVA_BUCKET = register(new Item("lava_bucket", builder())); + public static final Item POWDER_SNOW_BUCKET = register(new BlockItem("powder_snow_bucket", builder(), Blocks.POWDER_SNOW)); + public static final Item SNOWBALL = register(new Item("snowball", builder())); public static final Item LEATHER = register(new Item("leather", builder())); - public static final Item MILK_BUCKET = register(new Item("milk_bucket", builder().stackSize(1))); - public static final Item PUFFERFISH_BUCKET = register(new Item("pufferfish_bucket", builder().stackSize(1))); - public static final Item SALMON_BUCKET = register(new Item("salmon_bucket", builder().stackSize(1))); - public static final Item COD_BUCKET = register(new Item("cod_bucket", builder().stackSize(1))); - public static final Item TROPICAL_FISH_BUCKET = register(new TropicalFishBucketItem("tropical_fish_bucket", builder().stackSize(1))); - public static final Item AXOLOTL_BUCKET = register(new AxolotlBucketItem("axolotl_bucket", builder().stackSize(1))); - public static final Item TADPOLE_BUCKET = register(new Item("tadpole_bucket", builder().stackSize(1))); + public static final Item MILK_BUCKET = register(new Item("milk_bucket", builder())); + public static final Item PUFFERFISH_BUCKET = register(new Item("pufferfish_bucket", builder())); + public static final Item SALMON_BUCKET = register(new Item("salmon_bucket", builder())); + public static final Item COD_BUCKET = register(new Item("cod_bucket", builder())); + public static final Item TROPICAL_FISH_BUCKET = register(new TropicalFishBucketItem("tropical_fish_bucket", builder())); + public static final Item AXOLOTL_BUCKET = register(new AxolotlBucketItem("axolotl_bucket", builder())); + public static final Item TADPOLE_BUCKET = register(new Item("tadpole_bucket", builder())); public static final Item BRICK = register(new Item("brick", builder())); public static final Item CLAY_BALL = register(new Item("clay_ball", builder())); public static final Item DRIED_KELP_BLOCK = register(new BlockItem(builder(), Blocks.DRIED_KELP_BLOCK)); public static final Item PAPER = register(new Item("paper", builder())); public static final Item BOOK = register(new Item("book", builder())); public static final Item SLIME_BALL = register(new Item("slime_ball", builder())); - public static final Item EGG = register(new Item("egg", builder().stackSize(16))); + public static final Item EGG = register(new Item("egg", builder())); 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 BUNDLE = register(new Item("bundle", builder())); + public static final Item WHITE_BUNDLE = register(new Item("white_bundle", builder())); + public static final Item ORANGE_BUNDLE = register(new Item("orange_bundle", builder())); + public static final Item MAGENTA_BUNDLE = register(new Item("magenta_bundle", builder())); + public static final Item LIGHT_BLUE_BUNDLE = register(new Item("light_blue_bundle", builder())); + public static final Item YELLOW_BUNDLE = register(new Item("yellow_bundle", builder())); + public static final Item LIME_BUNDLE = register(new Item("lime_bundle", builder())); + public static final Item PINK_BUNDLE = register(new Item("pink_bundle", builder())); + public static final Item GRAY_BUNDLE = register(new Item("gray_bundle", builder())); + public static final Item LIGHT_GRAY_BUNDLE = register(new Item("light_gray_bundle", builder())); + public static final Item CYAN_BUNDLE = register(new Item("cyan_bundle", builder())); + public static final Item PURPLE_BUNDLE = register(new Item("purple_bundle", builder())); + public static final Item BLUE_BUNDLE = register(new Item("blue_bundle", builder())); + public static final Item BROWN_BUNDLE = register(new Item("brown_bundle", builder())); + public static final Item GREEN_BUNDLE = register(new Item("green_bundle", builder())); + public static final Item RED_BUNDLE = register(new Item("red_bundle", builder())); + public static final Item BLACK_BUNDLE = register(new Item("black_bundle", builder())); + public static final Item FISHING_ROD = register(new FishingRodItem("fishing_rod", builder())); public static final Item CLOCK = register(new Item("clock", builder())); - public static final Item SPYGLASS = register(new Item("spyglass", builder().stackSize(1))); + public static final Item SPYGLASS = register(new Item("spyglass", builder())); public static final Item GLOWSTONE_DUST = register(new Item("glowstone_dust", builder())); public static final Item COD = register(new Item("cod", builder())); public static final Item SALMON = register(new Item("salmon", builder())); @@ -1078,27 +1087,27 @@ public final class Items { public static final Item BONE_MEAL = register(new Item("bone_meal", builder())); public static final Item BONE = register(new Item("bone", builder())); public static final Item SUGAR = register(new Item("sugar", builder())); - public static final Item CAKE = register(new BlockItem(builder().stackSize(1), Blocks.CAKE)); - public static final Item WHITE_BED = register(new BlockItem(builder().stackSize(1), Blocks.WHITE_BED)); - public static final Item ORANGE_BED = register(new BlockItem(builder().stackSize(1), Blocks.ORANGE_BED)); - public static final Item MAGENTA_BED = register(new BlockItem(builder().stackSize(1), Blocks.MAGENTA_BED)); - public static final Item LIGHT_BLUE_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIGHT_BLUE_BED)); - public static final Item YELLOW_BED = register(new BlockItem(builder().stackSize(1), Blocks.YELLOW_BED)); - public static final Item LIME_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIME_BED)); - public static final Item PINK_BED = register(new BlockItem(builder().stackSize(1), Blocks.PINK_BED)); - public static final Item GRAY_BED = register(new BlockItem(builder().stackSize(1), Blocks.GRAY_BED)); - public static final Item LIGHT_GRAY_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIGHT_GRAY_BED)); - public static final Item CYAN_BED = register(new BlockItem(builder().stackSize(1), Blocks.CYAN_BED)); - public static final Item PURPLE_BED = register(new BlockItem(builder().stackSize(1), Blocks.PURPLE_BED)); - public static final Item BLUE_BED = register(new BlockItem(builder().stackSize(1), Blocks.BLUE_BED)); - public static final Item BROWN_BED = register(new BlockItem(builder().stackSize(1), Blocks.BROWN_BED)); - public static final Item GREEN_BED = register(new BlockItem(builder().stackSize(1), Blocks.GREEN_BED)); - public static final Item RED_BED = register(new BlockItem(builder().stackSize(1), Blocks.RED_BED)); - public static final Item BLACK_BED = register(new BlockItem(builder().stackSize(1), Blocks.BLACK_BED)); + public static final Item CAKE = register(new BlockItem(builder(), Blocks.CAKE)); + public static final Item WHITE_BED = register(new BlockItem(builder(), Blocks.WHITE_BED)); + public static final Item ORANGE_BED = register(new BlockItem(builder(), Blocks.ORANGE_BED)); + public static final Item MAGENTA_BED = register(new BlockItem(builder(), Blocks.MAGENTA_BED)); + public static final Item LIGHT_BLUE_BED = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_BED)); + public static final Item YELLOW_BED = register(new BlockItem(builder(), Blocks.YELLOW_BED)); + public static final Item LIME_BED = register(new BlockItem(builder(), Blocks.LIME_BED)); + public static final Item PINK_BED = register(new BlockItem(builder(), Blocks.PINK_BED)); + public static final Item GRAY_BED = register(new BlockItem(builder(), Blocks.GRAY_BED)); + public static final Item LIGHT_GRAY_BED = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_BED)); + public static final Item CYAN_BED = register(new BlockItem(builder(), Blocks.CYAN_BED)); + public static final Item PURPLE_BED = register(new BlockItem(builder(), Blocks.PURPLE_BED)); + public static final Item BLUE_BED = register(new BlockItem(builder(), Blocks.BLUE_BED)); + public static final Item BROWN_BED = register(new BlockItem(builder(), Blocks.BROWN_BED)); + public static final Item GREEN_BED = register(new BlockItem(builder(), Blocks.GREEN_BED)); + public static final Item RED_BED = register(new BlockItem(builder(), Blocks.RED_BED)); + public static final Item BLACK_BED = register(new BlockItem(builder(), Blocks.BLACK_BED)); public static final Item COOKIE = register(new Item("cookie", builder())); public static final Item CRAFTER = register(new BlockItem(builder(), Blocks.CRAFTER)); public static final Item FILLED_MAP = register(new FilledMapItem("filled_map", builder())); - public static final Item SHEARS = register(new Item("shears", builder().stackSize(1).maxDamage(238))); + public static final Item SHEARS = register(new Item("shears", builder())); public static final Item MELON_SLICE = register(new Item("melon_slice", builder())); public static final Item DRIED_KELP = register(new Item("dried_kelp", builder())); public static final Item PUMPKIN_SEEDS = register(new BlockItem("pumpkin_seeds", builder(), Blocks.PUMPKIN_STEM)); @@ -1108,19 +1117,19 @@ public final class Items { public static final Item CHICKEN = register(new Item("chicken", builder())); public static final Item COOKED_CHICKEN = register(new Item("cooked_chicken", builder())); public static final Item ROTTEN_FLESH = register(new Item("rotten_flesh", builder())); - public static final Item ENDER_PEARL = register(new Item("ender_pearl", builder().stackSize(16))); + public static final Item ENDER_PEARL = register(new Item("ender_pearl", builder())); public static final Item BLAZE_ROD = register(new Item("blaze_rod", builder())); 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 GLASS_BOTTLE = register(new Item("glass_bottle", builder())); - public static final Item POTION = register(new PotionItem("potion", builder().stackSize(1))); + public static final Item POTION = register(new PotionItem("potion", builder())); 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.LAVA_CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON)); + public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.LAVA_CAULDRON, Blocks.WATER_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())); @@ -1207,10 +1216,10 @@ public final class Items { 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 WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder())); + public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder())); 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 MACE = register(new MaceItem("mace", builder())); 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)); @@ -1231,41 +1240,42 @@ public final class Items { 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))); + public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder())); public static final Item NETHER_BRICK = register(new Item("nether_brick", builder())); + public static final Item RESIN_BRICK = register(new Item("resin_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())); public static final Item RABBIT = register(new Item("rabbit", builder())); public static final Item COOKED_RABBIT = register(new Item("cooked_rabbit", builder())); - public static final Item RABBIT_STEW = register(new Item("rabbit_stew", builder().stackSize(1))); + public static final Item RABBIT_STEW = register(new Item("rabbit_stew", builder())); 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 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 ARMOR_STAND = register(new Item("armor_stand", builder())); + public static final Item IRON_HORSE_ARMOR = register(new Item("iron_horse_armor", builder())); + public static final Item GOLDEN_HORSE_ARMOR = register(new Item("golden_horse_armor", builder())); + public static final Item DIAMOND_HORSE_ARMOR = register(new Item("diamond_horse_armor", builder())); + public static final Item LEATHER_HORSE_ARMOR = register(new Item("leather_horse_armor", builder())); 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))); + public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder())); 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)); - public static final Item ORANGE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.ORANGE_BANNER, Blocks.ORANGE_WALL_BANNER)); - public static final Item MAGENTA_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.MAGENTA_BANNER, Blocks.MAGENTA_WALL_BANNER)); - public static final Item LIGHT_BLUE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIGHT_BLUE_BANNER, Blocks.LIGHT_BLUE_WALL_BANNER)); - public static final Item YELLOW_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.YELLOW_BANNER, Blocks.YELLOW_WALL_BANNER)); - public static final Item LIME_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIME_BANNER, Blocks.LIME_WALL_BANNER)); - public static final Item PINK_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.PINK_BANNER, Blocks.PINK_WALL_BANNER)); - public static final Item GRAY_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.GRAY_BANNER, Blocks.GRAY_WALL_BANNER)); - public static final Item LIGHT_GRAY_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIGHT_GRAY_BANNER, Blocks.LIGHT_GRAY_WALL_BANNER)); - public static final Item CYAN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.CYAN_BANNER, Blocks.CYAN_WALL_BANNER)); - public static final Item PURPLE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.PURPLE_BANNER, Blocks.PURPLE_WALL_BANNER)); - public static final Item BLUE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BLUE_BANNER, Blocks.BLUE_WALL_BANNER)); - public static final Item BROWN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BROWN_BANNER, Blocks.BROWN_WALL_BANNER)); - 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 WHITE_BANNER = register(new BannerItem(builder(), Blocks.WHITE_BANNER, Blocks.WHITE_WALL_BANNER)); + public static final Item ORANGE_BANNER = register(new BannerItem(builder(), Blocks.ORANGE_BANNER, Blocks.ORANGE_WALL_BANNER)); + public static final Item MAGENTA_BANNER = register(new BannerItem(builder(), Blocks.MAGENTA_BANNER, Blocks.MAGENTA_WALL_BANNER)); + public static final Item LIGHT_BLUE_BANNER = register(new BannerItem(builder(), Blocks.LIGHT_BLUE_BANNER, Blocks.LIGHT_BLUE_WALL_BANNER)); + public static final Item YELLOW_BANNER = register(new BannerItem(builder(), Blocks.YELLOW_BANNER, Blocks.YELLOW_WALL_BANNER)); + public static final Item LIME_BANNER = register(new BannerItem(builder(), Blocks.LIME_BANNER, Blocks.LIME_WALL_BANNER)); + public static final Item PINK_BANNER = register(new BannerItem(builder(), Blocks.PINK_BANNER, Blocks.PINK_WALL_BANNER)); + public static final Item GRAY_BANNER = register(new BannerItem(builder(), Blocks.GRAY_BANNER, Blocks.GRAY_WALL_BANNER)); + public static final Item LIGHT_GRAY_BANNER = register(new BannerItem(builder(), Blocks.LIGHT_GRAY_BANNER, Blocks.LIGHT_GRAY_WALL_BANNER)); + public static final Item CYAN_BANNER = register(new BannerItem(builder(), Blocks.CYAN_BANNER, Blocks.CYAN_WALL_BANNER)); + public static final Item PURPLE_BANNER = register(new BannerItem(builder(), Blocks.PURPLE_BANNER, Blocks.PURPLE_WALL_BANNER)); + public static final Item BLUE_BANNER = register(new BannerItem(builder(), Blocks.BLUE_BANNER, Blocks.BLUE_WALL_BANNER)); + public static final Item BROWN_BANNER = register(new BannerItem(builder(), Blocks.BROWN_BANNER, Blocks.BROWN_WALL_BANNER)); + public static final Item GREEN_BANNER = register(new BannerItem(builder(), Blocks.GREEN_BANNER, Blocks.GREEN_WALL_BANNER)); + public static final Item RED_BANNER = register(new BannerItem(builder(), Blocks.RED_BANNER, Blocks.RED_WALL_BANNER)); + public static final Item BLACK_BANNER = register(new BannerItem(builder(), Blocks.BLACK_BANNER, Blocks.BLACK_WALL_BANNER)); 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())); @@ -1273,55 +1283,55 @@ public final class Items { public static final Item PITCHER_POD = register(new BlockItem("pitcher_pod", builder(), Blocks.PITCHER_CROP)); 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 BEETROOT_SOUP = register(new Item("beetroot_soup", builder())); 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 SPLASH_POTION = register(new PotionItem("splash_potion", builder())); 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))); + public static final Item LINGERING_POTION = register(new PotionItem("lingering_potion", builder())); + public static final Item SHIELD = register(new ShieldItem("shield", builder())); + public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder())); 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))); - 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 KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder())); + public static final Item DEBUG_STICK = register(new Item("debug_stick", builder())); + public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder())); + public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder())); + public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder())); + public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder())); + public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder())); + public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder())); + public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder())); + public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder())); + public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder())); + public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder())); + public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder())); + public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", builder())); + public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder())); + public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder())); + public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder())); + public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder())); + public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder())); + public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder())); + public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder())); 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))); + public static final Item TRIDENT = register(new Item("trident", builder().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())); - 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 CROSSBOW = register(new CrossbowItem("crossbow", builder())); + public static final Item SUSPICIOUS_STEW = register(new Item("suspicious_stew", builder())); 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))); - 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))); - 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 FLOWER_BANNER_PATTERN = register(new Item("flower_banner_pattern", builder())); + public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder())); + public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder())); + public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder())); + public static final Item GLOBE_BANNER_PATTERN = register(new Item("globe_banner_pattern", builder())); + public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder())); + public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder())); + public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder())); + public static final Item FIELD_MASONED_BANNER_PATTERN = register(new Item("field_masoned_banner_pattern", builder())); + public static final Item BORDURE_INDENTED_BANNER_PATTERN = register(new Item("bordure_indented_banner_pattern", builder())); + public static final Item GOAT_HORN = register(new GoatHornItem("goat_horn", builder())); public static final Item COMPOSTER = register(new BlockItem(builder(), Blocks.COMPOSTER)); public static final Item BARREL = register(new BlockItem(builder(), Blocks.BARREL)); public static final Item SMOKER = register(new BlockItem(builder(), Blocks.SMOKER)); @@ -1342,7 +1352,7 @@ public final class Items { public static final Item HONEYCOMB = register(new Item("honeycomb", builder())); public static final Item BEE_NEST = register(new BlockItem(builder(), Blocks.BEE_NEST)); public static final Item BEEHIVE = register(new BlockItem(builder(), Blocks.BEEHIVE)); - public static final Item HONEY_BOTTLE = register(new Item("honey_bottle", builder().stackSize(16))); + public static final Item HONEY_BOTTLE = register(new Item("honey_bottle", builder())); public static final Item HONEYCOMB_BLOCK = register(new BlockItem(builder(), Blocks.HONEYCOMB_BLOCK)); public static final Item LODESTONE = register(new BlockItem(builder(), Blocks.LODESTONE)); public static final Item CRYING_OBSIDIAN = register(new BlockItem(builder(), Blocks.CRYING_OBSIDIAN)); @@ -1386,7 +1396,7 @@ public final class Items { public static final Item PEARLESCENT_FROGLIGHT = register(new BlockItem(builder(), Blocks.PEARLESCENT_FROGLIGHT)); public static final Item FROGSPAWN = register(new BlockItem(builder(), Blocks.FROGSPAWN)); public static final Item ECHO_SHARD = register(new Item("echo_shard", builder())); - public static final Item BRUSH = register(new Item("brush", builder().stackSize(1).maxDamage(64))); + public static final Item BRUSH = register(new Item("brush", builder())); public static final Item NETHERITE_UPGRADE_SMITHING_TEMPLATE = register(new Item("netherite_upgrade_smithing_template", builder())); public static final Item SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("sentry_armor_trim_smithing_template", builder())); public static final Item DUNE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("dune_armor_trim_smithing_template", builder())); @@ -1449,7 +1459,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 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/type/BedrockRequiresTagItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java index c41d14396..cd360f564 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BedrockRequiresTagItem.java @@ -25,12 +25,6 @@ package org.geysermc.geyser.item.type; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; - +// Whether this item should have its NBT data kept in the recipe book. public interface BedrockRequiresTagItem { - - void addRequiredNbt(GeyserSession session, @Nullable DataComponents components, BedrockItemBuilder builder); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index 2e7848318..862325a90 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.item.type; import it.unimi.dsi.fastutil.ints.IntArrays; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -142,20 +141,4 @@ public class FireworkRocketItem extends Item implements BedrockRequiresTagItem { return null; } } - - @Override - public void addRequiredNbt(GeyserSession session, @Nullable DataComponents components, BedrockItemBuilder builder) { - if (components != null) { - Fireworks fireworks = components.get(DataComponentType.FIREWORKS); - if (fireworks != null) { - // Already translated - return; - } - } - - NbtMapBuilder fireworksNbt = NbtMap.builder(); - fireworksNbt.putByte("Flight", (byte) 1); - fireworksNbt.put("Explosions", NbtList.EMPTY); - builder.putCompound("Fireworks", fireworksNbt.build()); - } } 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 0155c4e35..7f0d9099e 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 @@ -62,23 +62,16 @@ public class Item { private static final Map BLOCK_TO_ITEM = new HashMap<>(); protected final Key javaIdentifier; private int javaId = -1; - - // TODO remove these - private final int stackSize; private final int attackDamage; - private final int maxDamage; - private final Rarity rarity; - private final boolean glint; + private final DataComponents baseComponents; - private DataComponents dataComponents; + private final List enchantmentGlintPresent = List.of(Items.ENCHANTED_GOLDEN_APPLE, Items.EXPERIENCE_BOTTLE, Items.WRITTEN_BOOK, + Items.NETHER_STAR, Items.ENCHANTED_BOOK, Items.END_CRYSTAL); public Item(String javaIdentifier, Builder builder) { this.javaIdentifier = MinecraftKey.key(javaIdentifier); - this.stackSize = builder.stackSize; - this.maxDamage = builder.maxDamage; + this.baseComponents = builder.components; this.attackDamage = builder.attackDamage; - this.rarity = builder.rarity; - this.glint = builder.glint; } public String javaIdentifier() { @@ -89,24 +82,28 @@ public class Item { return javaId; } - public int maxDamage() { - return dataComponents.getOrDefault(DataComponentType.MAX_DAMAGE, 0); + public int defaultMaxDamage() { + return baseComponents.getOrDefault(DataComponentType.MAX_DAMAGE, 0); } - public int attackDamage() { + public int defaultAttackDamage() { return attackDamage; } - public int maxStackSize() { - return dataComponents.getOrDefault(DataComponentType.MAX_STACK_SIZE, 1); + public int defaultMaxStackSize() { + return baseComponents.getOrDefault(DataComponentType.MAX_STACK_SIZE, 1); } - public Rarity rarity() { - return rarity; + public Rarity defaultRarity() { + return Rarity.fromId(baseComponents.getOrDefault(DataComponentType.RARITY, 0)); } - public boolean glint() { - return glint; + public DataComponents gatherComponents(DataComponents others) { + if (others == null) return baseComponents.clone(); + + DataComponents components = baseComponents.clone(); + components.getDataComponents().putAll(others.getDataComponents()); + return components; } public boolean isValidRepairItem(Item other) { @@ -295,32 +292,28 @@ public class Item { } public static Builder builder() { - return new Builder(); + return new Builder().components(new DataComponents(new HashMap<>())); // TODO actually set components here } public static final class Builder { - private int stackSize = 64; - private int maxDamage; + private DataComponents components; private int attackDamage; - private Rarity rarity = Rarity.COMMON; - private boolean glint = false; - - public Builder stackSize(int stackSize) { - this.stackSize = stackSize; - return this; - } public Builder attackDamage(double attackDamage) { - // TODO properly store/send a double value once Bedrock supports it.. pls + // Bedrock edition does not support attack damage being a double this.attackDamage = (int) attackDamage; return this; } - public Builder maxDamage(int maxDamage) { - this.maxDamage = maxDamage; + public Builder components(DataComponents components) { + this.components = components; return this; } + public DataComponents components() { + return this.components; + } + private Builder() { } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 0a9c93980..ec094ea31 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -48,6 +48,8 @@ import org.geysermc.geyser.registry.mappings.MappingsConfigReader; import org.geysermc.geyser.registry.type.GeyserMappingItem; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.NonVanillaItemRegistration; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.*; @@ -129,10 +131,11 @@ public class CustomItemRegistryPopulator { Set repairMaterials = customItemData.repairMaterials(); - Item.Builder itemBuilder = Item.builder() - .stackSize(customItemData.stackSize()) - .maxDamage(customItemData.maxDamage()); - Item item = new Item(customIdentifier, itemBuilder) { + DataComponents components = new DataComponents(new HashMap<>()); + components.put(DataComponentType.MAX_STACK_SIZE, customItemData.stackSize()); + components.put(DataComponentType.MAX_DAMAGE, customItemData.maxDamage()); + + Item item = new Item(customIdentifier, Item.builder().components(components)) { @Override public boolean isValidRepairItem(Item other) { return repairMaterials != null && repairMaterials.contains(other.javaIdentifier()); @@ -167,11 +170,11 @@ public class CustomItemRegistryPopulator { NbtMapBuilder itemProperties = NbtMap.builder(); NbtMapBuilder componentBuilder = NbtMap.builder(); - setupBasicItemInfo(javaItem.maxDamage(), javaItem.maxStackSize(), mapping.getToolType() != null || customItemData.displayHandheld(), customItemData, itemProperties, componentBuilder, protocolVersion); + setupBasicItemInfo(javaItem.defaultMaxDamage(), javaItem.defaultMaxStackSize(), mapping.getToolType() != null || customItemData.displayHandheld(), customItemData, itemProperties, componentBuilder, protocolVersion); boolean canDestroyInCreative = true; if (mapping.getToolType() != null) { // This is not using the isTool boolean because it is not just a render type here. - canDestroyInCreative = computeToolProperties(mapping.getToolType(), itemProperties, componentBuilder, javaItem.attackDamage()); + canDestroyInCreative = computeToolProperties(mapping.getToolType(), itemProperties, componentBuilder, javaItem.defaultAttackDamage()); } itemProperties.putBoolean("can_destroy_in_creative", canDestroyInCreative); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 1da3b0e66..b4c963578 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -447,7 +447,7 @@ public class ItemRegistryPopulator { } } - if (javaOnlyItems.contains(javaItem) || javaItem.rarity() != Rarity.COMMON) { + if (javaOnlyItems.contains(javaItem) || javaItem.defaultRarity() != Rarity.COMMON) { // These items don't exist on Bedrock, so set up a variable that indicates they should have custom names // Or, ensure that we are translating these at all times to account for rarity colouring mappingBuilder = mappingBuilder.translationString((javaItem instanceof BlockItem ? "block." : "item.") + entry.getKey().replace(":", ".")); diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java index b65b06431..fdc90c215 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java @@ -62,7 +62,7 @@ public final class CustomItemTranslator { } } - boolean checkDamage = mapping.getJavaItem().maxDamage() > 0; + boolean checkDamage = mapping.getJavaItem().defaultMaxDamage() > 0; int damage = !checkDamage ? 0 : components.getOrDefault(DataComponentType.DAMAGE, 0); boolean unbreakable = checkDamage && !isDamaged(components, damage); 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 3cfd00233..062666f84 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 @@ -40,7 +40,6 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; -import org.geysermc.geyser.item.type.BedrockRequiresTagItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.BlockRegistries; @@ -150,42 +149,24 @@ public final class ItemTranslator { public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents components) { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); - boolean hideTooltips = false; - if (components != null) { - javaItem.translateComponentsToBedrock(session, components, nbtBuilder); - if (components.get(DataComponentType.HIDE_TOOLTIP) != null) hideTooltips = true; - } + // Populates default components that aren't sent over the network + components = javaItem.gatherComponents(components); - // Fixes fireworks crafting recipe: they always contain a tag - // TODO remove once all items have their default components - if (javaItem instanceof BedrockRequiresTagItem requiresTagItem) { - requiresTagItem.addRequiredNbt(session, components, nbtBuilder); - } - - Rarity rarity = javaItem.rarity(); - boolean enchantmentGlint = javaItem.glint(); - if (components != null) { - Integer rarityIndex = components.get(DataComponentType.RARITY); - if (rarityIndex != null) { - rarity = Rarity.fromId(rarityIndex); - } - Boolean enchantmentGlintOverride = components.get(DataComponentType.ENCHANTMENT_GLINT_OVERRIDE); - if (enchantmentGlintOverride != null) { - enchantmentGlint = enchantmentGlintOverride; - } - } + // Translate item-specific components + javaItem.translateComponentsToBedrock(session, components, nbtBuilder); + Rarity rarity = Rarity.fromId(components.getOrDefault(DataComponentType.RARITY, 0)); String customName = getCustomName(session, components, bedrockItem, rarity.getColor()); if (customName != null) { nbtBuilder.setCustomName(customName); } - if (components != null) { - ItemAttributeModifiers attributeModifiers = components.get(DataComponentType.ATTRIBUTE_MODIFIERS); - if (attributeModifiers != null && attributeModifiers.isShowInTooltip() && !hideTooltips) { - // only add if attribute modifiers do not indicate to hide them - addAttributeLore(attributeModifiers, nbtBuilder, session.locale()); - } + boolean hideTooltips = components.get(DataComponentType.HIDE_TOOLTIP) != null; + + ItemAttributeModifiers attributeModifiers = components.get(DataComponentType.ATTRIBUTE_MODIFIERS); + if (attributeModifiers != null && attributeModifiers.isShowInTooltip() && !hideTooltips) { + // only add if attribute modifiers do not indicate to hide them + addAttributeLore(attributeModifiers, nbtBuilder, session.locale()); } if (session.isAdvancedTooltips() && !hideTooltips) { @@ -193,7 +174,7 @@ public final class ItemTranslator { } // Add enchantment override. We can't remove it - enchantments would stop showing - but we can add it. - if (enchantmentGlint) { + if (components.getOrDefault(DataComponentType.ENCHANTMENT_GLINT_OVERRIDE, false)) { NbtMapBuilder nbtMapBuilder = nbtBuilder.getOrCreateNbt(); nbtMapBuilder.putIfAbsent("ench", NbtList.EMPTY); } @@ -217,18 +198,16 @@ public final class ItemTranslator { translateCustomItem(components, builder, bedrockItem); - if (components != null) { - // Translate the canDestroy and canPlaceOn Java components - AdventureModePredicate canDestroy = components.get(DataComponentType.CAN_BREAK); - AdventureModePredicate canPlaceOn = components.get(DataComponentType.CAN_PLACE_ON); - String[] canBreak = getCanModify(session, canDestroy); - String[] canPlace = getCanModify(session, canPlaceOn); - if (canBreak != null) { - builder.canBreak(canBreak); - } - if (canPlace != null) { - builder.canPlace(canPlace); - } + // Translate the canDestroy and canPlaceOn Java components + AdventureModePredicate canDestroy = components.get(DataComponentType.CAN_BREAK); + AdventureModePredicate canPlaceOn = components.get(DataComponentType.CAN_PLACE_ON); + String[] canBreak = getCanModify(session, canDestroy); + String[] canPlace = getCanModify(session, canPlaceOn); + if (canBreak != null) { + builder.canBreak(canBreak); + } + if (canPlace != null) { + builder.canPlace(canPlace); } return builder; @@ -325,7 +304,7 @@ public final class ItemTranslator { } private static void addAdvancedTooltips(@Nullable DataComponents components, BedrockItemBuilder builder, Item item, String language) { - int maxDurability = item.maxDamage(); + int maxDurability = item.defaultMaxDamage(); if (maxDurability != 0 && components != null) { Integer durabilityComponent = components.get(DataComponentType.DAMAGE); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 94368a6d4..ee4d7b3d5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -27,18 +27,14 @@ package org.geysermc.geyser.translator.protocol.bedrock; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket; -import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.ItemFrameEntity; -import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.Blocks; -import org.geysermc.geyser.level.block.type.BannerBlock; import org.geysermc.geyser.level.block.type.BlockState; -import org.geysermc.geyser.level.block.type.SkullBlock; 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.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemFromBlockPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemFromEntityPacket; @Translator(packet = BlockPickRequestPacket.class) public class BedrockBlockPickRequestTranslator extends PacketTranslator { @@ -52,42 +48,14 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator session.ensureInEventLoop(() -> { - if (components == null) { - pickItem(session, blockToPick); - return; - } - - ItemStack itemStack = new ItemStack(blockToPick.block().asItem().javaId(), 1, components); - InventoryUtils.findOrCreateItem(session, itemStack); - })); - return; - } - - pickItem(session, blockToPick); - } - - private void pickItem(GeyserSession session, BlockState state) { - InventoryUtils.findOrCreateItem(session, state.block().pickItem(state)); + session.sendDownstreamGamePacket(new ServerboundPickItemFromBlockPacket(vector, addExtraData)); } } 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 acb8573fb..2368e1ad7 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 @@ -26,15 +26,11 @@ package org.geysermc.geyser.translator.protocol.bedrock; import org.cloudburstmc.protocol.bedrock.packet.EntityPickRequestPacket; -import org.geysermc.geyser.entity.type.BoatEntity; import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.registry.type.ItemMapping; 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 java.util.Locale; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemFromEntityPacket; /** * Called when the Bedrock user uses the pick block button on an entity @@ -49,35 +45,8 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator 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 - // TODO test - itemName = entity.getDefinition().identifier(); - case SPAWNER_MINECART -> itemName = "minecart"; // Turns into a normal minecart - //case ITEM_FRAME -> Not an entity in Bedrock Edition - //case GLOW_ITEM_FRAME -> - case ARMOR_STAND, END_CRYSTAL, MINECART, PAINTING -> - // No spawn egg, just an item - itemName = entity.getDefinition().entityType().toString().toLowerCase(Locale.ROOT); - default -> itemName = entity.getDefinition().entityType().toString().toLowerCase(Locale.ROOT) + "_spawn_egg"; - } - - String fullItemName = "minecraft:" + itemName; - ItemMapping mapping = session.getItemMappings().getMapping(fullItemName); - // Verify it is, indeed, an item - if (mapping == null) return; - - InventoryUtils.findOrCreateItem(session, fullItemName); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java index 970061436..e4ff0539f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java @@ -173,7 +173,7 @@ public class JavaMerchantOffersTranslator extends PacketTranslator - * This attempts to mimic Java Edition behavior as best as it can. - * @param session the Bedrock client's session - * @param item the Java item to search/select for - */ - public static void findOrCreateItem(GeyserSession session, Item item) { - // Get the inventory to choose a slot to pick - PlayerInventory inventory = session.getPlayerInventory(); - - if (item == Items.AIR) { - return; - } - - // Check hotbar for item - for (int i = 36; i < 45; i++) { - GeyserItemStack geyserItem = inventory.getItem(i); - if (geyserItem.isEmpty()) { - continue; - } - // If this isn't the item we're looking for - if (!geyserItem.asItem().equals(item)) { - continue; - } - - setHotbarItem(session, i); - // Don't check inventory if item was in hotbar - return; - } - - // Check inventory for item - for (int i = 9; i < 36; i++) { - GeyserItemStack geyserItem = inventory.getItem(i); - if (geyserItem.isEmpty()) { - continue; - } - // If this isn't the item we're looking for - if (!geyserItem.asItem().equals(item)) { - continue; - } - - // TODO 1.21.4 - //ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item - //session.sendDownstreamGamePacket(packetToSend); - return; - } - - // If we still have not found the item, and we're in creative, set the item ourselves. - if (session.getGameMode() == GameMode.CREATIVE) { - GeyserItemStack itemStack = item.newItemStack(1, null); - setPickedItem(session, inventory, itemStack); - } - } - - 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++) { - if (inventory.getItem(i).isEmpty()) { - slot = i; - break; - } - } - } - 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); - } - - /** - * Changes the held item slot to the specified slot - * @param session GeyserSession - * @param slot inventory slot to be selected - */ - private static void setHotbarItem(GeyserSession session, int slot) { - PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket(); - hotbarPacket.setContainerId(0); - // Java inventory slot to hotbar slot ID - hotbarPacket.setSelectedHotbarSlot(slot - 36); - hotbarPacket.setSelectHotbarSlot(true); - session.sendUpstreamPacket(hotbarPacket); - // No need to send a Java packet as Bedrock sends a confirmation packet back that we translate - } - @Nullable public static Click getClickForHotbarSwap(int slot) { return switch (slot) { From 1eedf1987c786115dee571e5198a69bd93cb0601 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 1 Dec 2024 11:50:52 -0500 Subject: [PATCH 471/897] Fix #5150 --- .../java/JavaUpdateRecipesTranslator.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 7ea66e0a3..3872321af 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -43,7 +43,6 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; @@ -58,7 +57,6 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.Clientbound import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.UUID; @@ -117,7 +115,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap> rawStonecutterData = new Int2ObjectOpenHashMap<>(); List stonecutterRecipes = packet.getStonecutterRecipes(); for (SelectableRecipe recipe : stonecutterRecipes) { @@ -131,19 +129,15 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator new ArrayList<>()).add(recipe); + rawStonecutterData.computeIfAbsent(ingredient.getHolders()[0], $ -> new ArrayList<>()).add(recipe); } 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()))); - - // Now that it's sorted, let's translate these recipes + for (Int2ObjectMap.Entry> data : rawStonecutterData.int2ObjectEntrySet()) { + // Implementation note: data used to have to be sorted according to the item translation key. + // This is no longer necessary as of 1.21.2, and is instead presented in the order the server sends us. + // (Recipes are ordered differently between Paper and vanilla) + // See #5150. int buttonId = 0; for (SelectableRecipe recipe : data.getValue()) { // As of 1.16.4, all stonecutter recipes have one ingredient option From 48ae28432e2e0015889844cc5c6d4001851966a8 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 2 Dec 2024 02:23:02 +0800 Subject: [PATCH 472/897] More changes - remove getPickItemComponents in WorldManager, separate additional and base component --- .../mod/world/GeyserModWorldManager.java | 72 ------------------- .../manager/GeyserSpigotWorldManager.java | 19 ----- .../living/animal/tameable/WolfEntity.java | 25 ++++--- .../geyser/inventory/AnvilContainer.java | 10 +-- .../geyser/inventory/GeyserItemStack.java | 58 ++++++++------- .../updater/AnvilInventoryUpdater.java | 37 ++++++---- .../java/org/geysermc/geyser/item/Items.java | 4 -- .../org/geysermc/geyser/item/type/Item.java | 28 ++++---- .../geyser/level/GeyserWorldManager.java | 20 ------ .../geysermc/geyser/level/WorldManager.java | 10 --- .../geyser/session/cache/TagCache.java | 6 +- .../session/cache/tags/GeyserHolderSet.java | 30 ++++++-- .../geyser/skin/FakeHeadProvider.java | 15 ++-- .../inventory/InventoryTranslator.java | 14 ++-- .../inventory/LecternInventoryTranslator.java | 7 +- .../inventory/LoomInventoryTranslator.java | 11 +-- .../inventory/PlayerInventoryTranslator.java | 9 +-- .../translator/item/ItemTranslator.java | 58 +++++++-------- .../bedrock/BedrockBookEditTranslator.java | 2 +- .../org/geysermc/geyser/util/BlockUtils.java | 5 +- .../org/geysermc/geyser/util/ItemUtils.java | 12 ---- 21 files changed, 176 insertions(+), 276 deletions(-) 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 f85b6e079..f791aab7a 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 @@ -28,37 +28,24 @@ package org.geysermc.geyser.platform.mod.world; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; -import net.minecraft.core.RegistryAccess; -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; -import net.minecraft.world.level.block.entity.BannerPatternLayers; 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 org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import java.util.HashMap; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public class GeyserModWorldManager extends GeyserWorldManager { @@ -117,49 +104,6 @@ public class GeyserModWorldManager extends GeyserWorldManager { return GameMode.byId(server.getDefaultGameType().getId()); } - @NonNull - @Override - public CompletableFuture getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { - CompletableFuture future = new CompletableFuture<>(); - server.execute(() -> { - ServerPlayer player = getPlayer(session); - if (player == null) { - future.complete(null); - return; - } - - BlockPos pos = new BlockPos(x, y, z); - // Don't create a new block entity if invalid - //noinspection resource - level() is just a getter - BlockEntity blockEntity = player.level().getChunkAt(pos).getBlockEntity(pos); - if (blockEntity instanceof BannerBlockEntity banner) { - // Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and* - // the banner might have a custom name, both of which a Java client knows and caches - ItemStack itemStack = banner.getItem(); - - org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents components = - new org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents(new HashMap<>()); - - components.put(DataComponentType.DAMAGE, itemStack.getDamageValue()); - - Component customName = itemStack.getComponents().get(DataComponents.CUSTOM_NAME); - if (customName != null) { - components.put(DataComponentType.CUSTOM_NAME, toKyoriComponent(customName)); - } - - BannerPatternLayers pattern = itemStack.get(DataComponents.BANNER_PATTERNS); - if (pattern != null) { - components.put(DataComponentType.BANNER_PATTERNS, toPatternList(pattern)); - } - - future.complete(components); - return; - } - future.complete(null); - }); - return future; - } - @Override public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer> apply) { server.execute(() -> { @@ -184,20 +128,4 @@ public class GeyserModWorldManager extends GeyserWorldManager { private ServerPlayer getPlayer(GeyserSession session) { return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid()); } - - private static net.kyori.adventure.text.Component toKyoriComponent(Component component) { - String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY); - return GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty()); - } - - private static List toPatternList(BannerPatternLayers patternLayers) { - return patternLayers.layers().stream() - .map(layer -> { - BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern( - MinecraftKey.key(layer.pattern().value().assetId().toString()), layer.pattern().value().translationKey() - ); - return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId()); - }) - .toList(); - } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 6588a22a3..54b5b9178 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -25,18 +25,14 @@ package org.geysermc.geyser.platform.spigot.world.manager; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.DecoratedPot; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.erosion.bukkit.BukkitUtils; -import org.geysermc.erosion.bukkit.PickBlockUtils; import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.GameRule; @@ -44,7 +40,6 @@ import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.List; import java.util.Objects; @@ -128,20 +123,6 @@ public class GeyserSpigotWorldManager extends WorldManager { return GameMode.byId(Bukkit.getDefaultGameMode().ordinal()); } - @Override - public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { - Player bukkitPlayer; - if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { - return CompletableFuture.completedFuture(null); - } - CompletableFuture> future = new CompletableFuture<>(); - Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); - // Paper 1.19.3 complains about async access otherwise. - // java.lang.IllegalStateException: Tile is null, asynchronous access? - SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block); - return future.thenApply(RAW_TRANSFORMER); - } - public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer> apply) { Player bukkitPlayer; if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == 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 f0b554ef9..67e5788c6 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 @@ -38,6 +38,8 @@ 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.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; @@ -51,6 +53,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Object 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.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.Collections; import java.util.Locale; @@ -58,7 +62,7 @@ import java.util.UUID; public class WolfEntity extends TameableEntity { private byte collarColor = 14; // Red - default - + private GeyserHolderSet repairableItems = null; private boolean isCurseOfBinding = false; public WolfEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -123,9 +127,11 @@ public class WolfEntity extends TameableEntity { } @Override - public void setChestplate(ItemStack stack) { - super.setChestplate(stack); - isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); // TODO test + public void setBody(ItemStack stack) { + super.setBody(stack); + isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); + HolderSet set = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE); + repairableItems = GeyserHolderSet.convertHolderSet(JavaRegistries.ITEM, set); } @Override @@ -152,16 +158,17 @@ public class WolfEntity extends TameableEntity { return super.testMobInteraction(hand, itemInHand); } } - if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.chestplate.isValid() && !getFlag(EntityFlag.BABY)) { + if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.body.isValid() && !getFlag(EntityFlag.BABY)) { return InteractiveTag.EQUIP_WOLF_ARMOR; } - if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid() + if (itemInHand.asItem() == Items.SHEARS && this.body.isValid() && (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) { return InteractiveTag.REMOVE_WOLF_ARMOR; } - if (Items.WOLF_ARMOR.isValidRepairItem(itemInHand.asItem()) && getFlag(EntityFlag.SITTING) && - this.chestplate.isValid() && this.chestplate.getTag() != null && - this.chestplate.getTag().getInt("Damage") > 0) { + if (getFlag(EntityFlag.SITTING) && + session.getTagCache().is(repairableItems, itemInHand.asItem()) && + this.body.isValid() && this.body.getTag() != null && + this.body.getTag().getInt("Damage") > 0) { return InteractiveTag.REPAIR_WOLF_ARMOR; } // Tamed and owned by player - can sit/stand diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 45a062468..f5969efbb 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.inventory; -import net.kyori.adventure.text.Component; -import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.ItemUtils; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; /** * Used to determine if rename packets should be sent and stores @@ -73,7 +73,7 @@ public class AnvilContainer extends Container { String correctRename; newName = rename; - Component originalName = ItemUtils.getCustomName(getInput().getComponents()); + Component originalName = getInput().getComponent(DataComponentType.CUSTOM_NAME); String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.locale()); String plainNewName = MessageTranslator.convertToPlainText(rename); 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 256de7799..c595ea1b5 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -25,7 +25,11 @@ package org.geysermc.geyser.inventory; -import lombok.*; +import lombok.AccessLevel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -104,10 +108,27 @@ public class GeyserItemStack { return isEmpty() ? 0 : amount; } + /** + * Returns all components of this item - base and additional components sent over the network. + * These are NOT modifiable! To add components, use {@link #getOrCreateComponents()}. + * + * @return the item's base data components and the "additional" ones that may exist. + */ + public @Nullable DataComponents getAllComponents() { + return isEmpty() ? null : asItem().gatherComponents(components); + } + + /** + * @return the {@link DataComponents} that aren't the base/default components. + */ public @Nullable DataComponents getComponents() { return isEmpty() ? null : components; } + public boolean hasNonBaseComponents() { + return components != null; + } + @NonNull public DataComponents getOrCreateComponents() { if (components == null) { @@ -119,33 +140,20 @@ public class GeyserItemStack { @Nullable public T getComponent(@NonNull DataComponentType type) { if (components == null) { - return null; + return asItem().getComponent(type); } - return components.get(type); + + T value = components.get(type); + if (value == null) { + return asItem().getComponent(type); + } + + return value; } - public boolean getComponent(@NonNull DataComponentType type, boolean def) { - if (components == null) { - return def; - } - - Boolean result = components.get(type); - if (result != null) { - return result; - } - return def; - } - - public int getComponent(@NonNull DataComponentType type, int def) { - if (components == null) { - return def; - } - - Integer result = components.get(type); - if (result != null) { - return result; - } - return def; + public T getComponentOrFallback(@NonNull DataComponentType type, T def) { + T value = getComponent(type); + return value == null ? def : value; } public int getNetId() { 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 00270e47a..459d8adf8 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 @@ -40,12 +40,15 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.enchantment.Enchantment; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; 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; @@ -63,7 +66,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { super.updateInventory(translator, session, inventory); AnvilContainer anvilContainer = (AnvilContainer) inventory; updateInventoryState(session, anvilContainer); - int targetSlot = getTargetSlot(anvilContainer); + int targetSlot = getTargetSlot(anvilContainer, session); for (int i = 0; i < translator.size; i++) { final int bedrockSlot = translator.javaSlotToBedrock(i); if (bedrockSlot == 50) @@ -88,7 +91,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { updateInventoryState(session, anvilContainer); int lastTargetSlot = anvilContainer.getLastTargetSlot(); - int targetSlot = getTargetSlot(anvilContainer); + int targetSlot = getTargetSlot(anvilContainer, session); if (targetSlot != javaSlot) { // Update the requested slot InventorySlotPacket slotPacket = new InventorySlotPacket(); @@ -117,7 +120,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // Changing the item in the input slot resets the name field on Bedrock, but // does not result in a FilterTextPacket - String originalName = MessageTranslator.convertToPlainText(ItemUtils.getCustomName(input.getComponents()), session.locale()); + String originalName = MessageTranslator.convertToPlainText(input.getComponent(DataComponentType.CUSTOM_NAME), session.locale()); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName); session.sendDownstreamGamePacket(renameItemPacket); @@ -135,12 +138,12 @@ public class AnvilInventoryUpdater extends InventoryUpdater { * @param anvilContainer the anvil inventory * @return the slot to change the repair cost */ - private int getTargetSlot(AnvilContainer anvilContainer) { + private int getTargetSlot(AnvilContainer anvilContainer, GeyserSession session) { GeyserItemStack input = anvilContainer.getInput(); GeyserItemStack material = anvilContainer.getMaterial(); if (!material.isEmpty()) { - if (!input.isEmpty() && isRepairing(input, material)) { + if (!input.isEmpty() && isRepairing(input, material, session)) { // Changing the repair cost on the material item makes it non-stackable return 0; } @@ -233,7 +236,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // Can't repair or merge enchantments return -1; } - } else if (hasDurability(input) && isRepairing(input, material)) { + } else if (hasDurability(input) && isRepairing(input, material, session)) { cost = calcRepairLevelCost(input, material); if (cost == -1) { // No damage to repair @@ -394,8 +397,14 @@ public class AnvilInventoryUpdater extends InventoryUpdater { return isEnchantedBook(material) || (input.getJavaId() == material.getJavaId() && hasDurability(input)); } - private boolean isRepairing(GeyserItemStack input, GeyserItemStack material) { - return input.asItem().isValidRepairItem(material.asItem()); + private boolean isRepairing(GeyserItemStack input, GeyserItemStack material, GeyserSession session) { + HolderSet repairable = input.getComponent(DataComponentType.REPAIRABLE); + if (repairable == null) { + return false; + } + + GeyserHolderSet set = GeyserHolderSet.convertHolderSet(JavaRegistries.ITEM, repairable); + return session.getTagCache().is(set, material.asItem()); } private boolean isRenaming(GeyserSession session, AnvilContainer anvilContainer, boolean bedrock) { @@ -404,27 +413,27 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } // This should really check the name field in all cases, but that requires the localized name // of the item which can change depending on NBT and Minecraft Edition - Component originalName = ItemUtils.getCustomName(anvilContainer.getInput().getComponents()); + Component originalName = anvilContainer.getInput().getComponent(DataComponentType.CUSTOM_NAME); if (bedrock && originalName != null && anvilContainer.getNewName() != null) { // Check text and formatting String legacyOriginalName = MessageTranslator.convertMessage(originalName, session.locale()); return !legacyOriginalName.equals(anvilContainer.getNewName()); } - return !Objects.equals(originalName, ItemUtils.getCustomName(anvilContainer.getResult().getComponents())); + return !Objects.equals(originalName, anvilContainer.getResult().getComponent(DataComponentType.CUSTOM_NAME)); } private int getRepairCost(GeyserItemStack itemStack) { - return itemStack.getComponent(DataComponentType.REPAIR_COST, 0); + return itemStack.getComponentOrFallback(DataComponentType.REPAIR_COST, 0); } private boolean hasDurability(GeyserItemStack itemStack) { if (itemStack.asItem().defaultMaxDamage() > 0) { - return itemStack.getComponent(DataComponentType.UNBREAKABLE, false); + return itemStack.getComponentOrFallback(DataComponentType.UNBREAKABLE, false); } return false; } private int getDamage(GeyserItemStack itemStack) { - return itemStack.getComponent(DataComponentType.DAMAGE, 0); + return itemStack.getComponentOrFallback(DataComponentType.DAMAGE, 0); } } 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 d2ae08ec4..4a2d5827a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.item; -import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.item.type.ArmorItem; import org.geysermc.geyser.item.type.ArrowItem; import org.geysermc.geyser.item.type.AxolotlBucketItem; @@ -45,16 +44,13 @@ 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.LightItem; import org.geysermc.geyser.item.type.MaceItem; import org.geysermc.geyser.item.type.MapItem; -import org.geysermc.geyser.item.type.OminousBottleItem; 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; 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 7f0d9099e..c851ee332 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.type; +import com.google.common.collect.ImmutableMap; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; @@ -45,7 +46,6 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; @@ -98,16 +98,23 @@ public class Item { return Rarity.fromId(baseComponents.getOrDefault(DataComponentType.RARITY, 0)); } + /** + * Returns a modifiable DataComponents map. Should only be used when it must be modified. + * Otherwise, prefer using GeyserItemStack's getComponent + */ + @NonNull public DataComponents gatherComponents(DataComponents others) { - if (others == null) return baseComponents.clone(); - DataComponents components = baseComponents.clone(); + if (others == null) { + return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); + } components.getDataComponents().putAll(others.getDataComponents()); - return components; + return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); } - public boolean isValidRepairItem(Item other) { - return false; + @Nullable + public T getComponent(@NonNull DataComponentType type) { + return baseComponents.get(type); } public String translationKey() { @@ -121,14 +128,11 @@ public class Item { // Return, essentially, air return ItemData.builder(); } - ItemData.Builder builder = ItemData.builder() + + return ItemData.builder() .definition(mapping.getBedrockDefinition()) .damage(mapping.getBedrockData()) .count(count); - - ItemTranslator.translateCustomItem(components, builder, mapping); - - return builder; } public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { @@ -292,7 +296,7 @@ public class Item { } public static Builder builder() { - return new Builder().components(new DataComponents(new HashMap<>())); // TODO actually set components here + return new Builder().components(new DataComponents(ImmutableMap.of())); // TODO actually set components here } public static final class Builder { diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index befcfa4b7..ca2ebcb08 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -25,20 +25,15 @@ package org.geysermc.geyser.level; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.erosion.packet.backendbound.BackendboundBatchBlockRequestPacket; import org.geysermc.erosion.packet.backendbound.BackendboundBlockRequestPacket; -import org.geysermc.erosion.packet.backendbound.BackendboundPickBlockPacket; import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.erosion.ErosionCancellationException; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.concurrent.CompletableFuture; @@ -124,19 +119,4 @@ public class GeyserWorldManager extends WorldManager { public GameMode getDefaultGameMode(GeyserSession session) { return GameMode.SURVIVAL; } - - @NonNull - @Override - public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { - var erosionHandler = session.getErosionHandler().getAsActive(); - if (erosionHandler == null) { - return super.getPickItemComponents(session, x, y, z, addNbtData); - } else if (session.isClosed()) { - return CompletableFuture.failedFuture(new ErosionCancellationException()); - } - CompletableFuture> future = new CompletableFuture<>(); - erosionHandler.setPickBlockLookup(future); - erosionHandler.sendPacket(new BackendboundPickBlockPacket(Vector3i.from(x, y, z))); - return future.thenApply(RAW_TRANSFORMER); - } } diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index 6baf9c2b4..a85462108 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -192,16 +192,6 @@ public abstract class WorldManager { return null; } - /** - * Used for pick block, so we don't need to cache more data than necessary. - * - * @return expected NBT for this item. - */ - @NonNull - public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addExtraData) { - return CompletableFuture.completedFuture(null); - } - /** * Retrieves decorated pot sherds from the server. Used to ensure the data is not erased on animation sent * through the BlockEntityDataPacket. 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 2b0f257a3..26b6aad96 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 @@ -28,6 +28,7 @@ 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.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.Item; @@ -119,7 +120,10 @@ public final class TagCache { /** * @return true if the specified network ID is in the given holder set. */ - public boolean is(GeyserHolderSet holderSet, T object) { + public boolean is(@Nullable GeyserHolderSet holderSet, @Nullable T object) { + if (holderSet == null || object == null) { + return false; + } return contains(holderSet.resolveRaw(this), holderSet.getRegistry().toNetworkId(session, object)); } 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 index 3c6e02e53..0e0d117a4 100644 --- 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 @@ -25,10 +25,6 @@ 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; @@ -37,6 +33,11 @@ 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; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; + +import java.util.List; +import java.util.Objects; +import java.util.function.ToIntFunction; /** * 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). @@ -87,6 +88,27 @@ public final class GeyserHolderSet { return tagCache.getRaw(Objects.requireNonNull(tag, "HolderSet must have a tag if it doesn't have a list of IDs")); } + /** + * Reads a MCPL {@link HolderSet} and turns it into a GeyserHolderSet. + * @param registry the registry the HolderSet contains IDs from. + * @param holderSet the HolderSet as the MCPL HolderSet object + */ + public static GeyserHolderSet convertHolderSet(@NonNull JavaRegistryKey registry, @Nullable HolderSet holderSet) { + if (holderSet == null) { + return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY); + } + + if (holderSet.getHolders() != null) { + return new GeyserHolderSet<>(registry, holderSet.getHolders()); + } + + if (holderSet.getLocation() != null) { + return new GeyserHolderSet<>(registry, new Tag<>(registry, holderSet.getLocation())); + } + + throw new IllegalStateException("HolderSet must have a tag or a list of IDs! " + holderSet); + } + /** * Reads a HolderSet from an object from NBT. * diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index 22786a4ee..2434d6d91 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.skin; -import org.geysermc.mcprotocollib.auth.GameProfile; -import org.geysermc.mcprotocollib.auth.GameProfile.Texture; -import org.geysermc.mcprotocollib.auth.GameProfile.TextureModel; -import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -36,6 +32,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.skin.Cape; import org.geysermc.geyser.api.skin.Skin; @@ -46,8 +43,10 @@ import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinManager.GameProfileData; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.auth.GameProfile; +import org.geysermc.mcprotocollib.auth.GameProfile.Texture; +import org.geysermc.mcprotocollib.auth.GameProfile.TextureModel; +import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; import java.awt.*; import java.awt.image.BufferedImage; @@ -105,9 +104,7 @@ public class FakeHeadProvider { } }); - public static void setHead(GeyserSession session, PlayerEntity entity, DataComponents components) { - GameProfile profile = components.get(DataComponentType.PROFILE); - + public static void setHead(GeyserSession session, PlayerEntity entity, @Nullable GameProfile profile) { if (profile == null) { return; } 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 15c19c542..ffaae13d2 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 @@ -76,7 +76,6 @@ 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.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.SlotDisplay; @@ -252,8 +251,8 @@ public abstract class InventoryTranslator { //only set the head if the destination is the head slot GeyserItemStack javaItem = inventory.getItem(sourceSlot); if (javaItem.asItem() == Items.PLAYER_HEAD - && javaItem.getComponents() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents()); + && javaItem.hasNonBaseComponents()) { + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentType.PROFILE)); } } else if (sourceSlot == 5) { //we are probably removing the head, so restore the original skin @@ -1020,12 +1019,9 @@ public abstract class InventoryTranslator { // As of 1.16.210: Bedrock needs confirmation on what the current item durability is. // If 0 is sent, then Bedrock thinks the item is not damaged int durability = 0; - DataComponents components = itemStack.getComponents(); - if (components != null) { - Integer damage = components.get(DataComponentType.DAMAGE); - if (damage != null) { - durability = ItemUtils.getCorrectBedrockDurability(itemStack.asItem(), damage); - } + Integer damage = itemStack.getComponent(DataComponentType.DAMAGE); + if (damage != null) { + durability = ItemUtils.getCorrectBedrockDurability(itemStack.asItem(), damage); } itemEntry = new ItemStackResponseSlot((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), "", durability); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 3b33f5909..e72de744f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -30,7 +30,6 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.erosion.util.LecternUtils; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; @@ -158,13 +157,13 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator session.getLastInteractionBlockPosition() : inventory.getHolderPosition(); NbtMap blockEntityTag; - if (book.getComponents() != null) { + if (book.hasNonBaseComponents()) { int pages = 0; - WrittenBookContent writtenBookComponents = book.getComponents().get(DataComponentType.WRITTEN_BOOK_CONTENT); + WrittenBookContent writtenBookComponents = book.getComponent(DataComponentType.WRITTEN_BOOK_CONTENT); if (writtenBookComponents != null) { pages = writtenBookComponents.getPages().size(); } else { - WritableBookContent writableBookComponents = book.getComponents().get(DataComponentType.WRITABLE_BOOK_CONTENT); + WritableBookContent writableBookComponents = book.getComponent(DataComponentType.WRITABLE_BOOK_CONTENT); if (writableBookComponents != null) { pages = writableBookComponents.getPages().size(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 0694e2ac6..7cdcbe8a9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -49,11 +49,9 @@ import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; 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.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { @@ -156,16 +154,11 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { GeyserItemStack inputCopy = inventory.getItem(0).copy(1); inputCopy.setNetId(session.getNextItemNetId()); - // Add the pattern manually, for better item synchronization - if (inputCopy.getComponents() == null) { - inputCopy.setComponents(new DataComponents(new HashMap<>())); - } - BannerPatternLayer bannerPatternLayer = BannerItem.getJavaBannerPattern(session, pattern); // TODO if (bannerPatternLayer != null) { - List patternsList = inputCopy.getComponents().getOrDefault(DataComponentType.BANNER_PATTERNS, new ArrayList<>()); + List patternsList = inputCopy.getComponentOrFallback(DataComponentType.BANNER_PATTERNS, new ArrayList<>()); patternsList.add(bannerPatternLayer); - inputCopy.getComponents().put(DataComponentType.BANNER_PATTERNS, patternsList); + inputCopy.getOrCreateComponents().put(DataComponentType.BANNER_PATTERNS, patternsList); } // Set the new item as the output diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 8fd365d7f..f08b90765 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -58,6 +58,7 @@ import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; 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.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import java.util.Arrays; @@ -103,8 +104,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { contents[i - 5] = item.getItemData(session); if (i == 5 && item.asItem() == Items.PLAYER_HEAD && - item.getComponents() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponents()); + item.hasNonBaseComponents()) { + FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponent(DataComponentType.PROFILE)); } } armorContentPacket.setContents(Arrays.asList(contents)); @@ -147,8 +148,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (slot == 5) { // Check for custom skull if (javaItem.asItem() == Items.PLAYER_HEAD - && javaItem.getComponents() != null) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponents()); + && javaItem.hasNonBaseComponents()) { + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentType.PROFILE)); } else { FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity()); } 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 062666f84..284296209 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 @@ -112,7 +112,7 @@ public final class ItemTranslator { NbtMap nbt = data.getTag(); if (nbt != null && !nbt.isEmpty()) { // translateToJava may have added components - DataComponents components = itemStack.getComponents() == null ? new DataComponents(new HashMap<>()) : itemStack.getComponents(); + DataComponents components = itemStack.getOrCreateComponents(); javaItem.translateNbtToJava(session, nbt, components, bedrockItem); if (!components.getDataComponents().isEmpty()) { itemStack.setComponents(components); @@ -193,7 +193,7 @@ public final class ItemTranslator { } if (bedrockItem.getJavaItem().equals(Items.PLAYER_HEAD)) { - translatePlayerHead(session, components, builder); + translatePlayerHead(session, components.get(DataComponentType.PROFILE), builder); } translateCustomItem(components, builder, bedrockItem); @@ -391,7 +391,7 @@ public final class ItemTranslator { return ItemDefinition.AIR; } - ItemMapping mapping = itemStack.asItem().toBedrockDefinition(itemStack.getComponents(), session.getItemMappings()); + ItemMapping mapping = itemStack.asItem().toBedrockDefinition(itemStack.getAllComponents(), session.getItemMappings()); ItemDefinition itemDefinition = mapping.getBedrockDefinition(); CustomBlockData customBlockData = BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.getOrDefault( @@ -401,7 +401,7 @@ public final class ItemTranslator { } if (mapping.getJavaItem().equals(Items.PLAYER_HEAD)) { - CustomSkull customSkull = getCustomSkull(itemStack.getComponents()); + CustomSkull customSkull = getCustomSkull(itemStack.getComponent(DataComponentType.PROFILE)); if (customSkull != null) { itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customSkull.getCustomBlockData()); } @@ -466,39 +466,35 @@ public final class ItemTranslator { builder.blockDefinition(blockDefinition); } - private static @Nullable CustomSkull getCustomSkull(DataComponents components) { - if (components == null) { + private static @Nullable CustomSkull getCustomSkull(@Nullable GameProfile profile) { + if (profile == null) { return null; } - - GameProfile profile = components.get(DataComponentType.PROFILE); - if (profile != null) { - Map textures; - try { - textures = profile.getTextures(false); - } catch (IllegalStateException e) { - GeyserImpl.getInstance().getLogger().debug("Could not decode player head from profile %s, got: %s".formatted(profile, e.getMessage())); - return null; - } - if (textures == null || textures.isEmpty()) { - return null; - } - - Texture skinTexture = textures.get(TextureType.SKIN); - - if (skinTexture == null) { - return null; - } - - String skinHash = skinTexture.getURL().substring(skinTexture.getURL().lastIndexOf('/') + 1); - return BlockRegistries.CUSTOM_SKULLS.get(skinHash); + Map textures; + try { + textures = profile.getTextures(false); + } catch (IllegalStateException e) { + GeyserImpl.getInstance().getLogger().debug("Could not decode player head from profile %s, got: %s".formatted(profile, e.getMessage())); + return null; } - return null; + + if (textures == null || textures.isEmpty()) { + return null; + } + + Texture skinTexture = textures.get(TextureType.SKIN); + + if (skinTexture == null) { + return null; + } + + String skinHash = skinTexture.getURL().substring(skinTexture.getURL().lastIndexOf('/') + 1); + return BlockRegistries.CUSTOM_SKULLS.get(skinHash); } - private static void translatePlayerHead(GeyserSession session, DataComponents components, ItemData.Builder builder) { - CustomSkull customSkull = getCustomSkull(components); + private static void translatePlayerHead(GeyserSession session, GameProfile profile, ItemData.Builder builder) { + CustomSkull customSkull = getCustomSkull(profile); if (customSkull != null) { CustomBlockData customBlockData = customSkull.getCustomBlockData(); ItemDefinition itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customBlockData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java index 456b6507f..700ba0532 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java @@ -53,7 +53,7 @@ public class BedrockBookEditTranslator extends PacketTranslator GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(); if (itemStack != null) { - DataComponents components = itemStack.getComponents() != null ? itemStack.getComponents() : new DataComponents(new HashMap<>()); + DataComponents components = itemStack.getOrCreateComponents(); ItemStack bookItem = new ItemStack(itemStack.getJavaId(), itemStack.getAmount(), components); List pages = new LinkedList<>(); 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 6367b2d14..1d84c169e 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -131,6 +131,7 @@ public final class BlockUtils { return 1.0 / speed; } + // TODO 1.21.4 this changed probably; no more tiers public static double getBreakTime(GeyserSession session, Block block, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); //TODO called twice boolean canHarvestWithHand = !block.requiresCorrectToolForDrops(); @@ -160,7 +161,7 @@ public final class BlockUtils { boolean waterInEyes = session.getCollisionManager().isWaterInEyes(); boolean insideOfWaterWithoutAquaAffinity = waterInEyes && - ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1; + ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getAllComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1; return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); @@ -173,7 +174,7 @@ public final class BlockUtils { DataComponents components = null; if (item != null) { mapping = item.getMapping(session); - components = item.getComponents(); + components = item.getAllComponents(); } return getBreakTime(session, block, mapping, components, true); } diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index eec0d173d..eca9756e6 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.util; -import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; @@ -102,17 +101,6 @@ public final class ItemUtils { return original; } - /** - * @param components the data components of the item - * @return the custom name of the item - */ - public static @Nullable Component getCustomName(DataComponents components) { - if (components == null) { - return null; - } - return components.get(DataComponentType.CUSTOM_NAME); - } - private ItemUtils() { } } From 77ffb6098ea78c1f1df33199f28a98795225e40f Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 2 Dec 2024 02:48:54 +0800 Subject: [PATCH 473/897] Better immutability checks --- .../main/java/org/geysermc/geyser/item/type/Item.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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 c851ee332..fde742efa 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 @@ -63,7 +63,7 @@ public class Item { protected final Key javaIdentifier; private int javaId = -1; private final int attackDamage; - private final DataComponents baseComponents; + private final DataComponents baseComponents; // unmodifiable private final List enchantmentGlintPresent = List.of(Items.ENCHANTED_GOLDEN_APPLE, Items.EXPERIENCE_BOTTLE, Items.WRITTEN_BOOK, Items.NETHER_STAR, Items.ENCHANTED_BOOK, Items.END_CRYSTAL); @@ -104,10 +104,11 @@ public class Item { */ @NonNull public DataComponents gatherComponents(DataComponents others) { - DataComponents components = baseComponents.clone(); if (others == null) { - return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); + return baseComponents; } + + DataComponents components = baseComponents.clone(); components.getDataComponents().putAll(others.getDataComponents()); return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); } @@ -315,7 +316,7 @@ public class Item { } public DataComponents components() { - return this.components; + return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); } private Builder() { From a19e7cb9f42f5753d8db22c1ebb7ef314b8554e2 Mon Sep 17 00:00:00 2001 From: Arno Keesman <34793978+arnokeesman@users.noreply.github.com> Date: Mon, 2 Dec 2024 21:06:06 +0100 Subject: [PATCH 474/897] Bump cloud-minecraft-modded (#5181) fixes crashes on fabric from the previously included Fabric Permissions API --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1e942df77..01fffb29f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ viaversion = "4.9.2" adapters = "1.15-SNAPSHOT" cloud = "2.0.0-rc.2" cloud-minecraft = "2.0.0-beta.9" -cloud-minecraft-modded = "2.0.0-beta.9" +cloud-minecraft-modded = "2.0.0-beta.10" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" From d956354b7f401664de7103228bc4f7ec5213802b Mon Sep 17 00:00:00 2001 From: BugTeaON <99161186+BUGTeas@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:03:09 +0800 Subject: [PATCH 475/897] =?UTF-8?q?Feature=EF=BC=9AMake=20custom=20effect?= =?UTF-8?q?=20information=20visible=20&=20Support=20for=20customizing=20it?= =?UTF-8?q?em=20name=20via=20'custom=5Fname'=20tag=20in=20'potion=5Fconten?= =?UTF-8?q?ts'=20component=20(new=20feature=20since=201.21.2)=20(#5176)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make custom effect information visible * Support for customizing item name via 'custom_name' tag in 'potion_contents' component * A little optimization of custom effect information * The effect information should appear in front of the custom lore --- .../geysermc/geyser/item/type/PotionItem.java | 13 ++++ .../geyser/item/type/TippedArrowItem.java | 14 ++++ .../translator/item/ItemTranslator.java | 78 +++++++++++++++++++ 3 files changed, 105 insertions(+) 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 89e60b325..4cc3756cd 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 @@ -34,7 +34,9 @@ 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.BedrockItemBuilder; import org.geysermc.geyser.translator.item.CustomItemTranslator; +import org.geysermc.geyser.translator.item.ItemTranslator; 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; @@ -68,6 +70,17 @@ public class PotionItem extends Item { return super.translateToBedrock(session, count, components, mapping, mappings); } + @Override + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { + // Make custom effect information visible + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + ItemTranslator.addPotionEffectLore(potionContents, builder, session.locale()); + } + + super.translateComponentsToBedrock(session, components, builder); + } + @Override public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { Potion potion = Potion.getByBedrockId(itemData.getDamage()); 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 09e4ee21f..9e212ebef 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 @@ -25,12 +25,15 @@ 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.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.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.geyser.translator.item.ItemTranslator; 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; @@ -57,4 +60,15 @@ public class TippedArrowItem extends ArrowItem { } return super.translateToBedrock(session, count, components, mapping, mappings); } + + @Override + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { + // Make custom effect information visible + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + ItemTranslator.addPotionEffectLore(potionContents, builder, session.locale()); + } + + super.translateComponentsToBedrock(session, components, builder); + } } 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 3cfd00233..97cb3df2f 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.translator.item; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -55,6 +56,7 @@ import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.auth.GameProfile.Texture; import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; @@ -63,12 +65,16 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttributeModifiers; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectDetails; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; public final class ItemTranslator { @@ -324,6 +330,65 @@ public final class ItemTranslator { return MessageTranslator.convertMessage(attributeComponent, language); } + private static final List negativeEffectList = List.of( + Effect.SLOWNESS, + Effect.MINING_FATIGUE, + Effect.INSTANT_DAMAGE, + Effect.NAUSEA, + Effect.BLINDNESS, + Effect.HUNGER, + Effect.WEAKNESS, + Effect.POISON, + Effect.WITHER, + Effect.LEVITATION, + Effect.UNLUCK, + Effect.DARKNESS, + Effect.WIND_CHARGED, + Effect.WEAVING, + Effect.OOZING, + Effect.INFESTED + ); + + public static void addPotionEffectLore(PotionContents contents, BedrockItemBuilder builder, String language) { + List effectInstanceList = contents.getCustomEffects(); + for (MobEffectInstance effectInstance : effectInstanceList) { + Effect effect = effectInstance.getEffect(); + MobEffectDetails details = effectInstance.getDetails(); + int amplifier = details.getAmplifier(); + int durations = details.getDuration(); + TranslatableComponent appendTranslatable = Component.translatable("effect.minecraft." + effect.toString().toLowerCase(Locale.ROOT)); + if (amplifier != 0) { + appendTranslatable = Component.translatable("potion.withAmplifier", + appendTranslatable, + Component.translatable("potion.potency." + amplifier)); + } + if (durations > 20) { + int seconds = durations / 20; + int secondsFormat = seconds % 60; + int minutes = seconds / 60; + int minutesFormat = minutes % 60; + int hours = minutes / 60; + String text = ((minutesFormat > 9) ? "" : "0") + minutesFormat + ":" + ((secondsFormat > 9) ? "" : "0") + secondsFormat; + if (minutes >= 60) { + text = ((hours > 9) ? "" : "0") + hours + ":" + text; + } + appendTranslatable = Component.translatable("potion.withDuration", + appendTranslatable, + Component.text(text)); + } else if (durations == -1) { + appendTranslatable = Component.translatable("potion.withDuration", + appendTranslatable, + Component.translatable("effect.duration.infinite")); + } + Component component = Component.text() + .resetStyle() + .color((negativeEffectList.contains(effect)) ? NamedTextColor.RED : NamedTextColor.BLUE) + .append(appendTranslatable) + .build(); + builder.getOrCreateLore().add(MessageTranslator.convertMessage(component, language)); + } + } + private static void addAdvancedTooltips(@Nullable DataComponents components, BedrockItemBuilder builder, Item item, String language) { int maxDurability = item.maxDamage(); @@ -448,6 +513,19 @@ public final class ItemTranslator { if (customName != null) { return MessageTranslator.convertMessage(customName, session.locale()); } + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + // "custom_name" tag in "potion_contents" component + String customPotionName = potionContents.getCustomName(); + if (customPotionName != null) { + Component component = Component.text() + .resetStyle() + .color(NamedTextColor.WHITE) + .append(Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + customPotionName)) + .build(); + return MessageTranslator.convertMessage(component, session.locale()); + } + } customName = components.get(DataComponentType.ITEM_NAME); if (customName != null) { // Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition From 289a74975d607312e5860f028a71b3f6022d81b8 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 3 Dec 2024 17:25:48 +0800 Subject: [PATCH 476/897] start implementing new block breaking --- .../entity/attribute/GeyserAttributeType.java | 3 + .../type/player/SessionPlayerEntity.java | 9 + .../geyser/session/GeyserSession.java | 5 + .../player/input/BedrockBlockActions.java | 5 +- .../org/geysermc/geyser/util/BlockUtils.java | 246 +++++++++--------- 5 files changed, 150 insertions(+), 118 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index 1e050c840..833f2f46d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -51,6 +51,9 @@ public enum GeyserAttributeType { MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f), SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), BLOCK_INTERACTION_RANGE("minecraft:player.block_interaction_range", null, 0.0f, 64f, 4.5f), + MINING_EFFICIENCY("minecraft:mining_efficiency", null, 0f, 1024f, 0f), + BLOCK_BREAK_SPEED("minecraft:block_break_speed", null, 0f, 1024f, 1f), + SUBMERGED_MINING_SPEED("minecraft:submerged_mining_speed", null, 0f, 20f, 0.2f), // Bedrock Attributes ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f), 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 9d5bc011c..7543e05bc 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 @@ -286,6 +286,15 @@ public class SessionPlayerEntity extends PlayerEntity { return attributeData; } + public float attributeOrDefault(GeyserAttributeType type) { + var attribute = this.attributes.get(type); + if (attribute == null) { + return type.getDefaultValue(); + } + + return attribute.getValue(); + } + public void setLastDeathPosition(@Nullable GlobalPos pos) { if (pos != null) { dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition()); 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 ef6261ead..9b49b3cfc 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -523,6 +523,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private long blockBreakStartTime; + /** + * // TODO + */ + private long destroyProgress; + /** * Stores whether the player intended to place a bucket. */ 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 index 061a04b77..ea386ebcf 100644 --- 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 @@ -32,6 +32,7 @@ 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.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; @@ -88,7 +89,7 @@ final class BedrockBlockActions { LevelEventPacket startBreak = new LevelEventPacket(); startBreak.setType(LevelEvent.BLOCK_START_BREAK); startBreak.setPosition(vector.toFloat()); - double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20; + double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20; // TODO afdaöwelfunöwoaenf // If the block is custom or the breaking item is custom, we must keep track of break time ourselves GeyserItemStack item = session.getPlayerInventory().getItemInHand(); @@ -169,6 +170,7 @@ final class BedrockBlockActions { 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 + GeyserImpl.getInstance().getLogger().warning("abort break, not creative - item frame???"); Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector); if (itemFrameEntity != null) { ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), @@ -180,6 +182,7 @@ final class BedrockBlockActions { 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()); 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 1d84c169e..52a4a6df9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -27,156 +27,168 @@ package org.geysermc.geyser.util; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.geyser.entity.attribute.GeyserAttributeType; +import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.item.BedrockEnchantment; 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.EntityEffectCache; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; import org.geysermc.geyser.session.cache.tags.BlockTag; +import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; import org.geysermc.geyser.translator.collision.BlockCollision; +import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; +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.ToolData; public final class BlockUtils { - private static boolean correctTool(GeyserSession session, Block block, String itemToolType) { - return switch (itemToolType) { - case "axe" -> session.getTagCache().is(BlockTag.MINEABLE_AXE, block); - case "hoe" -> session.getTagCache().is(BlockTag.MINEABLE_HOE, block); - case "pickaxe" -> session.getTagCache().is(BlockTag.MINEABLE_PICKAXE, block); - case "shears" -> session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); - case "shovel" -> session.getTagCache().is(BlockTag.MINEABLE_SHOVEL, block); - case "sword" -> block == Blocks.COBWEB; - default -> { - session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType); - yield false; + public static float getBlockDestroyProgress(GeyserSession session, BlockState blockState, GeyserItemStack itemInHand) { + float destroySpeed = blockState.block().destroyTime(); + if (destroySpeed == -1) { + return 0; + } + + int speedMultiplier = hasCorrectTool(session, blockState.block(), itemInHand) ? 30 : 100; + return getPlayerDestroySpeed(session, blockState, itemInHand) / destroySpeed / speedMultiplier; + } + + private static boolean hasCorrectTool(GeyserSession session, Block block, GeyserItemStack stack) { + return !block.requiresCorrectToolForDrops() || isCorrectItemForDrops(session, block, stack); + } + + private static boolean isCorrectItemForDrops(GeyserSession session, Block block, GeyserItemStack stack) { + ToolData tool = stack.getComponent(DataComponentType.TOOL); + if (tool == null) { + return false; + } + + for (ToolData.Rule rule : tool.getRules()) { + if (rule.getCorrectForDrops() != null) { + GeyserHolderSet set = GeyserHolderSet.convertHolderSet(JavaRegistries.BLOCK, rule.getBlocks()); + if (session.getTagCache().is(set, block)) { + return rule.getCorrectForDrops(); + } } - }; + } + + return false; } - private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isShearsEffective) { - if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0; - if (toolType.isEmpty()) return 1.0; - return switch (toolTier) { - // https://minecraft.wiki/w/Breaking#Speed - case "wooden" -> 2.0; - case "stone" -> 4.0; - case "iron" -> 6.0; - case "diamond" -> 8.0; - case "netherite" -> 9.0; - case "golden" -> 12.0; - default -> 1.0; - }; + private static float getItemDestroySpeed(GeyserSession session, Block block, GeyserItemStack stack) { + ToolData tool = stack.getComponent(DataComponentType.TOOL); + if (tool == null) { + return 1f; + } + + for (ToolData.Rule rule : tool.getRules()) { + if (rule.getSpeed() != null) { + GeyserHolderSet set = GeyserHolderSet.convertHolderSet(JavaRegistries.BLOCK, rule.getBlocks()); + if (session.getTagCache().is(set, block)) { + return rule.getSpeed(); + } + } + } + + return tool.getDefaultMiningSpeed(); } - private static boolean canToolTierBreakBlock(GeyserSession session, Block block, String toolTier) { - if (toolTier.equals("netherite") || toolTier.equals("diamond")) { - // As of 1.17, these tiers can mine everything that is mineable - return true; + private static float getPlayerDestroySpeed(GeyserSession session, BlockState blockState, GeyserItemStack itemInHand) { + float destroySpeed = getItemDestroySpeed(session, blockState.block(), itemInHand); + EntityEffectCache effectCache = session.getEffectCache(); + + if (destroySpeed > 1.0F) { + destroySpeed += session.getPlayerEntity().attributeOrDefault(GeyserAttributeType.MINING_EFFICIENCY); } - switch (toolTier) { - // Use intentional fall-throughs to check each tier with this block - default: - if (session.getTagCache().is(BlockTag.NEEDS_STONE_TOOL, block)) { - return false; - } - case "stone": - if (session.getTagCache().is(BlockTag.NEEDS_IRON_TOOL, block)) { - return false; - } - case "iron": - if (session.getTagCache().is(BlockTag.NEEDS_DIAMOND_TOOL, block)) { - return false; - } + int miningSpeedMultiplier = getMiningSpeedAmplification(effectCache); + if (miningSpeedMultiplier > 0) { + destroySpeed *= miningSpeedMultiplier * 0.2F; } - return true; + if (effectCache.getMiningFatigue() != 0) { + float slowdown = switch (effectCache.getMiningFatigue()) { + case 1 -> 0.3F; + case 2 -> 0.09F; + case 3 -> 0.0027F; + default -> 8.1E-4F; + }; + destroySpeed *= slowdown; + } + + destroySpeed *= session.getPlayerEntity().attributeOrDefault(GeyserAttributeType.BLOCK_BREAK_SPEED); + if (session.getCollisionManager().isWaterInEyes()) { + destroySpeed *= session.getPlayerEntity().attributeOrDefault(GeyserAttributeType.SUBMERGED_MINING_SPEED); + } + + if (!session.getPlayerEntity().isOnGround()) { + destroySpeed /= 5F; + } + + return destroySpeed; } - // https://minecraft.wiki/w/Breaking - private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock, - String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel, - boolean insideOfWaterWithoutAquaAffinity, boolean onGround) { - double baseTime = (((correctTool && canTierMineBlock) || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness; - double speed = 1.0 / baseTime; + private static int getMiningSpeedAmplification(EntityEffectCache cache) { + return Math.max(cache.getHaste(), cache.getConduitPower()); + } - if (correctTool) { - speed *= toolBreakTimeBonus(toolType, toolTier, isShearsEffective); - speed += toolEfficiencyLevel == 0 ? 0 : toolEfficiencyLevel * toolEfficiencyLevel + 1; - } - speed *= 1.0 + (0.2 * hasteLevel); - - switch (miningFatigueLevel) { - case 0: - break; - case 1: - speed -= (speed * 0.7); - break; - case 2: - speed -= (speed * 0.91); - break; - case 3: - speed -= (speed * 0.9973); - break; - default: - speed -= (speed * 0.99919); - break; - } - - if (insideOfWaterWithoutAquaAffinity) speed *= 0.2; - if (!onGround) speed *= 0.2; - return 1.0 / speed; + public int getDestroyStage(GeyserSession session) { + return session.getDestroyProgress() > 0F ? (int) session.getDestroyProgress() * 10 : -1; } // TODO 1.21.4 this changed probably; no more tiers public static double getBreakTime(GeyserSession session, Block block, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { - boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); //TODO called twice - boolean canHarvestWithHand = !block.requiresCorrectToolForDrops(); - String toolType = ""; - String toolTier = ""; - boolean correctTool = false; - boolean toolCanBreak = false; - if (item.isTool()) { - toolType = item.getToolType(); - toolTier = item.getToolTier(); - correctTool = correctTool(session, block, toolType); - toolCanBreak = canToolTierBreakBlock(session, block, toolTier); - } - - int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(session, components, BedrockEnchantment.EFFICIENCY); - int hasteLevel = 0; - int miningFatigueLevel = 0; - - if (!isSessionPlayer) { - // Another entity is currently mining; we have all the information we know - return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, - toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, true); - } - - hasteLevel = Math.max(session.getEffectCache().getHaste(), session.getEffectCache().getConduitPower()); - miningFatigueLevel = session.getEffectCache().getMiningFatigue(); - - boolean waterInEyes = session.getCollisionManager().isWaterInEyes(); - boolean insideOfWaterWithoutAquaAffinity = waterInEyes && - ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getAllComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1; - - return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, - toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); +// boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); //TODO called twice +// boolean canHarvestWithHand = !block.requiresCorrectToolForDrops(); +// String toolType = ""; +// String toolTier = ""; +// boolean correctTool = false; +// boolean toolCanBreak = false; +// if (item.isTool()) { +// toolType = item.getToolType(); +// toolTier = item.getToolTier(); +// correctTool = correctTool(session, block, toolType); +// toolCanBreak = canToolTierBreakBlock(session, block, toolTier); +// } +// +// int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(session, components, BedrockEnchantment.EFFICIENCY); +// int hasteLevel = 0; +// int miningFatigueLevel = 0; +// +// if (!isSessionPlayer) { +// // Another entity is currently mining; we have all the information we know +// return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, +// toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, true); +// } +// +// hasteLevel = Math.max(session.getEffectCache().getHaste(), session.getEffectCache().getConduitPower()); +// miningFatigueLevel = session.getEffectCache().getMiningFatigue(); +// +// boolean waterInEyes = session.getCollisionManager().isWaterInEyes(); +// boolean insideOfWaterWithoutAquaAffinity = waterInEyes && +// ItemUtils.getEnchantmentLevel(session, session.getPlayerInventory().getItem(5).getAllComponents(), BedrockEnchantment.AQUA_AFFINITY) < 1; +// +// return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, +// toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); } public static double getSessionBreakTime(GeyserSession session, Block block) { - PlayerInventory inventory = session.getPlayerInventory(); - GeyserItemStack item = inventory.getItemInHand(); - ItemMapping mapping = ItemMapping.AIR; - DataComponents components = null; - if (item != null) { - mapping = item.getMapping(session); - components = item.getAllComponents(); - } - return getBreakTime(session, block, mapping, components, true); +// PlayerInventory inventory = session.getPlayerInventory(); +// GeyserItemStack item = inventory.getItemInHand(); +// ItemMapping mapping = ItemMapping.AIR; +// DataComponents components = null; +// if (item != null) { +// mapping = item.getMapping(session); +// components = item.getAllComponents(); +// } +// return getBreakTime(session, block, mapping, components, true); } /** From 650cb8d4733f52fa19020a0cf4c8631e205b65fa Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 3 Dec 2024 18:35:02 +0800 Subject: [PATCH 477/897] remove isValidRepairItem in favor of component, remove unneeded item tiers, deprecate repair items and tool tier in NonVanillaCustomItemData --- .../item/custom/NonVanillaCustomItemData.java | 10 ++- .../java/org/geysermc/geyser/item/Items.java | 6 +- .../geyser/item/components/ToolTier.java | 64 ------------------- .../geysermc/geyser/item/type/ArmorItem.java | 10 +-- .../geyser/item/type/DyeableArmorItem.java | 5 +- .../geysermc/geyser/item/type/ElytraItem.java | 39 ----------- .../geysermc/geyser/item/type/LightItem.java | 1 - .../geysermc/geyser/item/type/MaceItem.java | 39 ----------- .../geysermc/geyser/item/type/ShieldItem.java | 7 -- .../geysermc/geyser/item/type/TieredItem.java | 46 ------------- .../geyser/item/type/WolfArmorItem.java | 5 +- .../CustomItemRegistryPopulator.java | 18 +++--- .../geyser/registry/type/ItemMapping.java | 2 - 13 files changed, 19 insertions(+), 233 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java delete mode 100644 core/src/main/java/org/geysermc/geyser/item/type/ElytraItem.java delete mode 100644 core/src/main/java/org/geysermc/geyser/item/type/MaceItem.java delete mode 100644 core/src/main/java/org/geysermc/geyser/item/type/TieredItem.java diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java index 2c283780c..2fff247a7 100644 --- a/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java +++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java @@ -80,10 +80,9 @@ public interface NonVanillaCustomItemData extends CustomItemData { @Nullable String toolType(); /** - * Gets the tool tier of the item. - * - * @return the tool tier of the item + * @deprecated no longer used */ + @Deprecated(forRemoval = true) @Nullable String toolTier(); /** @@ -108,10 +107,9 @@ public interface NonVanillaCustomItemData extends CustomItemData { @Nullable String translationString(); /** - * Gets the repair materials of the item. - * - * @return the repair materials of the item + * @deprecated No longer used. */ + @Deprecated(forRemoval = true) @Nullable Set repairMaterials(); /** 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 4a2d5827a..5cdb6c4ce 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -36,7 +36,6 @@ 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; @@ -44,7 +43,6 @@ 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; @@ -873,7 +871,7 @@ public final class Items { public static final Item CARROT_ON_A_STICK = register(new Item("carrot_on_a_stick", builder())); public static final Item WARPED_FUNGUS_ON_A_STICK = register(new Item("warped_fungus_on_a_stick", builder())); public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder())); - public static final Item ELYTRA = register(new ElytraItem("elytra", builder())); + public static final Item ELYTRA = register(new Item("elytra", builder())); public static final Item OAK_BOAT = register(new BoatItem("oak_boat", builder())); public static final Item OAK_CHEST_BOAT = register(new BoatItem("oak_chest_boat", builder())); public static final Item SPRUCE_BOAT = register(new BoatItem("spruce_boat", builder())); @@ -1215,7 +1213,7 @@ public final class Items { public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder())); public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder())); public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder())); - public static final Item MACE = register(new MaceItem("mace", builder())); + public static final Item MACE = register(new Item("mace", builder())); 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)); diff --git a/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java b/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java deleted file mode 100644 index a8832df1e..000000000 --- a/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java +++ /dev/null @@ -1,64 +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.item.components; - -import com.google.common.base.Suppliers; -import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.item.type.Item; - -import java.util.Collections; -import java.util.Locale; -import java.util.Set; -import java.util.function.Supplier; - -public enum ToolTier { - WOODEN(2, () -> Set.of(Items.OAK_PLANKS, Items.SPRUCE_PLANKS, Items.BIRCH_PLANKS, Items.JUNGLE_PLANKS, Items.ACACIA_PLANKS, Items.DARK_OAK_PLANKS, Items.CRIMSON_PLANKS, Items.WARPED_PLANKS, Items.MANGROVE_PLANKS)), // PLANKS tag // TODO ? - STONE(4, () -> Set.of(Items.COBBLESTONE, Items.BLACKSTONE, Items.COBBLED_DEEPSLATE)), // STONE_TOOL_MATERIALS tag - IRON(6, () -> Collections.singleton(Items.IRON_INGOT)), - GOLDEN(12, () -> Collections.singleton(Items.GOLD_INGOT)), - DIAMOND(8, () -> Collections.singleton(Items.DIAMOND)), - NETHERITE(9, () -> Collections.singleton(Items.NETHERITE_INGOT)); - - private static final ToolTier[] VALUES = values(); - - private final int speed; - private final Supplier> repairIngredients; - - ToolTier(int speed, Supplier> repairIngredients) { - this.speed = speed; - // Lazily initialize as this will likely be called as items are loading - this.repairIngredients = Suppliers.memoize(repairIngredients::get); - } - - public Set getRepairIngredients() { - return repairIngredients.get(); - } - - @Override - public String toString() { - return this.name().toLowerCase(Locale.ROOT); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index 0a25a8d4f..ec87728a9 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -30,7 +30,6 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; -import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ArmorTrim; @@ -38,11 +37,9 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class ArmorItem extends Item { - private final ArmorMaterial material; - public ArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) { + public ArmorItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); - this.material = material; } @Override @@ -68,11 +65,6 @@ public class ArmorItem extends Item { } } - @Override - public boolean isValidRepairItem(Item other) { - return material.getRepairIngredient() == other; - } - // TODO maybe some kind of namespace util? private static String getNamespace(String identifier) { int i = identifier.indexOf(':'); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index 8c63eaeb0..480385d07 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -26,14 +26,13 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class DyeableArmorItem extends ArmorItem { - public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) { - super(javaIdentifier, material, builder); + public DyeableArmorItem(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ElytraItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ElytraItem.java deleted file mode 100644 index e5d94eb8b..000000000 --- a/core/src/main/java/org/geysermc/geyser/item/type/ElytraItem.java +++ /dev/null @@ -1,39 +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.item.type; - -import org.geysermc.geyser.item.Items; - -public class ElytraItem extends Item { - public ElytraItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); - } - - @Override - public boolean isValidRepairItem(Item other) { - return other == Items.PHANTOM_MEMBRANE; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java b/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java index fa10b08b1..d176ff367 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java @@ -60,7 +60,6 @@ public class LightItem extends BlockItem { return super.toBedrockDefinition(components, mappings); } - private static ItemMapping getLightLevelMapping(DataComponents components, ItemMappings mappings) { String lightLevel = "15"; if (components != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MaceItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MaceItem.java deleted file mode 100644 index e7b9a8684..000000000 --- a/core/src/main/java/org/geysermc/geyser/item/type/MaceItem.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.item.type; - -import org.geysermc.geyser.item.Items; - -public class MaceItem extends Item { - public MaceItem(String javaIdentifier, Builder builder) { - super(javaIdentifier, builder); - } - - @Override - public boolean isValidRepairItem(Item other) { - return other == Items.BREEZE_ROD; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index 14d41a073..98ef80d95 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.item.components.ToolTier; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; @@ -54,10 +53,4 @@ public class ShieldItem extends Item { builder.putInt("Base", 15 - baseColor); } } - - @Override - public boolean isValidRepairItem(Item other) { - // Java Edition 1.19.3 checks the tag, but TODO check to see if we want it or are simulating what Bedrock is doing - return ToolTier.WOODEN.getRepairIngredients().contains(other); - } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TieredItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TieredItem.java deleted file mode 100644 index d998eb0d4..000000000 --- a/core/src/main/java/org/geysermc/geyser/item/type/TieredItem.java +++ /dev/null @@ -1,46 +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.item.type; - -import org.geysermc.geyser.item.components.ToolTier; - -public class TieredItem extends Item { - private final ToolTier tier; - - public TieredItem(String javaIdentifier, ToolTier tier, Builder builder) { - super(javaIdentifier, builder); - this.tier = tier; - } - - public ToolTier tier() { - return tier; - } - - @Override - public boolean isValidRepairItem(Item other) { - return tier.getRepairIngredients().contains(other); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java index bd97a6a7d..52ded0407 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java @@ -26,14 +26,13 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.item.ArmorMaterial; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class WolfArmorItem extends ArmorItem { - public WolfArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) { - super(javaIdentifier, material, builder); + public WolfArmorItem(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index ec094ea31..3d2ca4ef9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -51,7 +51,13 @@ import org.geysermc.geyser.registry.type.NonVanillaItemRegistration; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; public class CustomItemRegistryPopulator { public static void populate(Map items, Multimap customItems, List nonVanillaCustomItems) { @@ -129,18 +135,11 @@ public class CustomItemRegistryPopulator { public static NonVanillaItemRegistration registerCustomItem(NonVanillaCustomItemData customItemData, int customItemId, int protocolVersion) { String customIdentifier = customItemData.identifier(); - Set repairMaterials = customItemData.repairMaterials(); - DataComponents components = new DataComponents(new HashMap<>()); components.put(DataComponentType.MAX_STACK_SIZE, customItemData.stackSize()); components.put(DataComponentType.MAX_DAMAGE, customItemData.maxDamage()); - Item item = new Item(customIdentifier, Item.builder().components(components)) { - @Override - public boolean isValidRepairItem(Item other) { - return repairMaterials != null && repairMaterials.contains(other.javaIdentifier()); - } - }; + Item item = new Item(customIdentifier, Item.builder().components(components)); Items.register(item, customItemData.javaId()); ItemMapping customItemMapping = ItemMapping.builder() @@ -148,7 +147,6 @@ public class CustomItemRegistryPopulator { .bedrockData(0) .bedrockBlockDefinition(null) .toolType(customItemData.toolType()) - .toolTier(customItemData.toolTier()) .translationString(customItemData.translationString()) .customItemOptions(Collections.emptyList()) .javaItem(item) diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java index 8a2c77f28..d940db6e0 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java @@ -52,7 +52,6 @@ public class ItemMapping { null, // Air is never sent in full over the network for this to serialize. null, null, - null, Collections.emptyList(), Items.AIR ); @@ -68,7 +67,6 @@ public class ItemMapping { BlockDefinition bedrockBlockDefinition; String toolType; - String toolTier; String translationString; From 9e276c10777ddf73dacb4d35769f1801d42882d6 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 3 Dec 2024 20:37:05 +0800 Subject: [PATCH 478/897] Feature: 1.21.50 support (#5180) * Drop pre-1.21.40 support, start adapting to 1.21.50 changes * fix camera definitions * remove more old workarounds, make it compile * Add 1.21.50 data files * Add item tags, update block registry populator * finishing touches * Don't add items to the creative inventory that we don't have a Java mapping for * fix readme typo --- README.md | 2 +- .../type/player/SessionPlayerEntity.java | 8 +- .../SessionLoadResourcePacksEventImpl.java | 12 +- .../geyser/impl/camera/CameraDefinitions.java | 15 +- .../level/physics/CollisionManager.java | 34 - .../geysermc/geyser/network/GameProtocol.java | 48 +- .../geyser/network/UpstreamPacketHandler.java | 22 +- .../geysermc/geyser/registry/Registries.java | 3 +- .../registry/loader/ResourcePackLoader.java | 9 +- .../populator/BlockRegistryPopulator.java | 35 +- .../registry/populator/Conversion685_671.java | 220 - .../registry/populator/Conversion712_685.java | 439 -- .../registry/populator/Conversion729_712.java | 152 - .../CreativeItemRegistryPopulator.java | 28 +- .../populator/ItemRegistryPopulator.java | 21 +- .../populator/TagRegistryPopulator.java | 12 +- .../geyser/session/GeyserSession.java | 4 +- .../inventory/InventoryTranslator.java | 20 +- .../entity/SkullBlockEntityTranslator.java | 5 - .../player/input/BedrockMovePlayer.java | 29 +- .../entity/JavaSetEquipmentTranslator.java | 8 +- .../resources/bedrock/biome_definitions.dat | Bin 37653 -> 37891 bytes .../bedrock/block_palette.1_20_80.nbt | Bin 176786 -> 0 bytes .../bedrock/block_palette.1_21_0.nbt | Bin 177397 -> 0 bytes .../bedrock/block_palette.1_21_20.nbt | Bin 178977 -> 0 bytes .../bedrock/block_palette.1_21_30.nbt | Bin 180490 -> 0 bytes .../bedrock/block_palette.1_21_50.nbt | Bin 0 -> 192451 bytes .../bedrock/creative_items.1_20_80.json | 5812 -------------- .../bedrock/creative_items.1_21_0.json | 6214 --------------- .../bedrock/creative_items.1_21_20.json | 6214 --------------- ...21_30.json => creative_items.1_21_50.json} | 3049 ++++---- .../resources/bedrock/entity_identifiers.dat | Bin 8314 -> 8378 bytes .../resources/bedrock/item_tags.1_20_80.json | 784 -- .../resources/bedrock/item_tags.1_21_0.json | 802 -- .../resources/bedrock/item_tags.1_21_20.json | 806 -- ...gs.1_21_30.json => item_tags.1_21_50.json} | 126 +- .../bedrock/runtime_item_states.1_20_80.json | 6274 --------------- .../bedrock/runtime_item_states.1_21_0.json | 6398 ---------------- .../bedrock/runtime_item_states.1_21_20.json | 6794 ----------------- ....json => runtime_item_states.1_21_50.json} | 1288 ++-- gradle.properties | 2 +- gradle/libs.versions.toml | 6 +- 42 files changed, 2563 insertions(+), 43132 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java delete mode 100644 core/src/main/resources/bedrock/block_palette.1_20_80.nbt delete mode 100644 core/src/main/resources/bedrock/block_palette.1_21_0.nbt delete mode 100644 core/src/main/resources/bedrock/block_palette.1_21_20.nbt delete mode 100644 core/src/main/resources/bedrock/block_palette.1_21_30.nbt create mode 100644 core/src/main/resources/bedrock/block_palette.1_21_50.nbt delete mode 100644 core/src/main/resources/bedrock/creative_items.1_20_80.json delete mode 100644 core/src/main/resources/bedrock/creative_items.1_21_0.json delete mode 100644 core/src/main/resources/bedrock/creative_items.1_21_20.json rename core/src/main/resources/bedrock/{creative_items.1_21_30.json => creative_items.1_21_50.json} (84%) delete mode 100644 core/src/main/resources/bedrock/item_tags.1_20_80.json delete mode 100644 core/src/main/resources/bedrock/item_tags.1_21_0.json delete mode 100644 core/src/main/resources/bedrock/item_tags.1_21_20.json rename core/src/main/resources/bedrock/{item_tags.1_21_30.json => item_tags.1_21_50.json} (99%) delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_20_80.json delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_21_0.json delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_21_20.json rename core/src/main/resources/bedrock/{runtime_item_states.1_21_30.json => runtime_item_states.1_21_50.json} (96%) diff --git a/README.md b/README.md index d0bcb1fdc..83a1d5c0b 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.2/1.21.3. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.21.40 - 1.21.50 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/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 9d5bc011c..6e5e55f03 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 @@ -39,7 +39,6 @@ import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.item.Items; 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; @@ -235,12 +234,7 @@ public class SessionPlayerEntity extends PlayerEntity { // the bubbles visually pop setFlag(EntityFlag.BREATHING, amount >= this.lastAirSupply); this.lastAirSupply = amount; - - if (amount == getMaxAir() && GameProtocol.isPre1_21_0(session)) { - super.setAirSupply(0); // Hide the bubble counter from the UI for the player - } else { - super.setAirSupply(amount); - } + super.setAirSupply(amount); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/event/type/SessionLoadResourcePacksEventImpl.java b/core/src/main/java/org/geysermc/geyser/event/type/SessionLoadResourcePacksEventImpl.java index 5ed0f8d22..5bc0dd0bd 100644 --- a/core/src/main/java/org/geysermc/geyser/event/type/SessionLoadResourcePacksEventImpl.java +++ b/core/src/main/java/org/geysermc/geyser/event/type/SessionLoadResourcePacksEventImpl.java @@ -36,14 +36,14 @@ import java.util.UUID; public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent { - private final Map packs; + private final Map packs; - public SessionLoadResourcePacksEventImpl(GeyserSession session, Map packMap) { + public SessionLoadResourcePacksEventImpl(GeyserSession session, Map packMap) { super(session); this.packs = packMap; } - public @NonNull Map getPacks() { + public @NonNull Map getPacks() { return packs; } @@ -54,16 +54,16 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE @Override public boolean register(@NonNull ResourcePack resourcePack) { - String packID = resourcePack.manifest().header().uuid().toString(); + UUID packID = resourcePack.manifest().header().uuid(); if (packs.containsValue(resourcePack) || packs.containsKey(packID)) { return false; } - packs.put(resourcePack.manifest().header().uuid().toString(), resourcePack); + packs.put(resourcePack.manifest().header().uuid(), resourcePack); return true; } @Override public boolean unregister(@NonNull UUID uuid) { - return packs.remove(uuid.toString()) != null; + return packs.remove(uuid) != null; } } diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java b/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java index ee20c14a2..346b971cc 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/CameraDefinitions.java @@ -43,13 +43,14 @@ public class CameraDefinitions { static { CAMERA_PRESETS = List.of( - new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), - new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), - new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(false), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), - new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty()), - new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null, null, null, OptionalBoolean.empty(), OptionalBoolean.empty())); + CameraPreset.builder().identifier(CameraPerspective.FIRST_PERSON.id()).build(), + CameraPreset.builder().identifier(CameraPerspective.FREE.id()).build(), + CameraPreset.builder().identifier(CameraPerspective.THIRD_PERSON.id()).build(), + CameraPreset.builder().identifier(CameraPerspective.THIRD_PERSON_FRONT.id()).build(), + CameraPreset.builder().identifier("geyser:free_audio").parentPreset(CameraPerspective.FREE.id()).listener(CameraAudioListener.PLAYER).playEffect(OptionalBoolean.of(false)).build(), + CameraPreset.builder().identifier("geyser:free_effects").parentPreset(CameraPerspective.FREE.id()).listener(CameraAudioListener.CAMERA).playEffect(OptionalBoolean.of(true)).build(), + CameraPreset.builder().identifier("geyser:free_audio_effects").parentPreset(CameraPerspective.FREE.id()).listener(CameraAudioListener.PLAYER).playEffect(OptionalBoolean.of(true)).build() + ); SimpleDefinitionRegistry.Builder builder = SimpleDefinitionRegistry.builder(); for (int i = 0; i < CAMERA_PRESETS.size(); i++) { 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 69f88e2a1..ff6557935 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 @@ -416,40 +416,6 @@ public class CollisionManager { return BlockUtils.getCollision(blockId); } - public boolean isOnGround() { - // Temporary until pre-1.21.30 support is dropped. - 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. - } - - // 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; - } - /** * @return if the player is currently in a water block */ diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 463cc54fd..378dc5078 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -27,14 +27,9 @@ package org.geysermc.geyser.network; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; -import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; -import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; -import org.cloudburstmc.protocol.bedrock.codec.v686.Bedrock_v686; -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.cloudburstmc.protocol.bedrock.codec.v765.Bedrock_v765; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; import org.geysermc.mcprotocollib.protocol.codec.PacketCodec; @@ -51,8 +46,9 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() - .minecraftVersion("1.21.44") + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v765.CODEC.toBuilder() + .minecraftVersion("1.21.50") + .protocolVersion(766) .build()); /** @@ -67,24 +63,10 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v671.CODEC.toBuilder() - .minecraftVersion("1.20.80/1.20.81") - .build())); - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v685.CODEC.toBuilder() - .minecraftVersion("1.21.0/1.21.1") - .build())); - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v686.CODEC.toBuilder() - .minecraftVersion("1.21.2/1.21.3") - .build())); - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder() - .minecraftVersion("1.21.20 - 1.21.23") - .build())); - SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v729.CODEC.toBuilder() - .minecraftVersion("1.21.30/1.21.31") - .build())); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() .minecraftVersion("1.21.40 - 1.21.44") - .build()); + .build())); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } /** @@ -103,22 +85,6 @@ public final class GameProtocol { /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ - public static boolean isPre1_21_0(GeyserSession session) { - return session.getUpstream().getProtocolVersion() < Bedrock_v685.CODEC.getProtocolVersion(); - } - - public static boolean isPre1_21_2(GeyserSession session) { - return session.getUpstream().getProtocolVersion() < Bedrock_v686.CODEC.getProtocolVersion(); - } - - public static boolean isPre1_21_30(GeyserSession session) { - return session.getUpstream().getProtocolVersion() < Bedrock_v729.CODEC.getProtocolVersion(); - } - - public static boolean isPre1_21_40(GeyserSession session) { - return session.getUpstream().getProtocolVersion() < Bedrock_v748.CODEC.getProtocolVersion(); - } - /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * 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 1ac38aa35..0cf161c6a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -77,11 +77,12 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.HashMap; import java.util.OptionalInt; +import java.util.UUID; public class UpstreamPacketHandler extends LoggingPacketHandler { private boolean networkSettingsRequested = false; - private final Deque packsToSent = new ArrayDeque<>(); + private final Deque packsToSend = new ArrayDeque<>(); private final CompressionStrategy compressionStrategy; private SessionLoadResourcePacksEventImpl resourcePackLoadEvent; @@ -133,8 +134,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } session.getUpstream().getSession().setCodec(packetCodec); - // FIXME temporary until 1.20.80 is dropped - session.getPlayerEntity().resetAir(); return true; } @@ -209,10 +208,12 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { PackCodec codec = pack.codec(); ResourcePackManifest.Header header = pack.manifest().header(); resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry( - header.uuid().toString(), header.version().toString(), codec.size(), pack.contentKey(), + header.uuid(), header.version().toString(), codec.size(), pack.contentKey(), "", header.uuid().toString(), false, false, false, "")); } resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks()); + resourcePacksInfo.setWorldTemplateId(UUID.randomUUID()); + resourcePacksInfo.setWorldTemplateVersion("*"); session.sendUpstreamPacket(resourcePacksInfo); GeyserLocale.loadGeyserLocale(session.locale()); @@ -233,8 +234,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { break; case SEND_PACKS: - packsToSent.addAll(packet.getPackIds()); - sendPackDataInfo(packsToSent.pop()); + packsToSend.addAll(packet.getPackIds()); + sendPackDataInfo(packsToSend.pop()); break; case HAVE_ALL_PACKS: @@ -311,7 +312,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public PacketSignal handle(ResourcePackChunkRequestPacket packet) { ResourcePackChunkDataPacket data = new ResourcePackChunkDataPacket(); - ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packet.getPackId().toString()); + ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packet.getPackId()); PackCodec codec = pack.codec(); data.setChunkIndex(packet.getChunkIndex()); @@ -335,8 +336,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { session.sendUpstreamPacket(data); // Check if it is the last chunk and send next pack in queue when available. - if (remainingSize <= GeyserResourcePack.CHUNK_SIZE && !packsToSent.isEmpty()) { - sendPackDataInfo(packsToSent.pop()); + if (remainingSize <= GeyserResourcePack.CHUNK_SIZE && !packsToSend.isEmpty()) { + sendPackDataInfo(packsToSend.pop()); } return PacketSignal.HANDLED; @@ -345,7 +346,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { private void sendPackDataInfo(String id) { ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket(); String[] packID = id.split("_"); - ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packID[0]); + UUID uuid = UUID.fromString(packID[0]); + ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(uuid); PackCodec codec = pack.codec(); ResourcePackManifest.Header header = pack.manifest().header(); 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 b0ae0d6aa..61bb42454 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -70,6 +70,7 @@ import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Map; import java.util.Set; +import java.util.UUID; /** * Holds all the common registries in Geyser. @@ -163,7 +164,7 @@ public final class Registries { /** * 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); + 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. diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java index 800a3d22c..adb64b8af 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java @@ -45,6 +45,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -54,7 +55,7 @@ import java.util.zip.ZipFile; /** * Loads {@link ResourcePack}s within a {@link Path} directory, firing the {@link GeyserLoadResourcePacksEvent}. */ -public class ResourcePackLoader implements RegistryLoader> { +public class ResourcePackLoader implements RegistryLoader> { static final PathMatcher PACK_MATCHER = FileSystems.getDefault().getPathMatcher("glob:**.{zip,mcpack}"); @@ -64,8 +65,8 @@ public class ResourcePackLoader implements RegistryLoader load(Path directory) { - Map packMap = new HashMap<>(); + public Map load(Path directory) { + Map packMap = new HashMap<>(); if (!Files.exists(directory)) { try { @@ -100,7 +101,7 @@ public class ResourcePackLoader implements RegistryLoader, Remapper>builder() - .put(ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), Conversion685_671::remapBlock) - .put(ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), Conversion712_685::remapBlock) - .put(ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), Conversion729_712::remapBlock) - .put(ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()), tag -> tag) - .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), tag -> { - final String name = tag.getString("name"); - if (name.endsWith("_wood") && tag.getCompound("states").containsKey("stripped_bit")) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("stripped_bit"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - return tag; - }) + .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) + .put(ObjectIntPair.of("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) .build(); // We can keep this strong as nothing should be garbage collected @@ -427,6 +413,19 @@ public final class BlockRegistryPopulator { } } + private static @NotNull Remapper faultyStrippedWoodRemapper() { + return tag -> { + final String name = tag.getString("name"); + if (name.endsWith("_wood") && tag.getCompound("states").containsKey("stripped_bit")) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("stripped_bit"); + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + return tag; + }; + } + private static void registerJavaBlocks() { List blocksNbt; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/blocks.nbt")) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java deleted file mode 100644 index c72ea64b2..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * 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.registry.populator; - -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.type.GeyserMappingItem; - -import java.util.List; -import java.util.stream.Stream; - -public class Conversion685_671 { - private static final List NEW_CORAL_BLOCKS = List.of("minecraft:tube_coral_block", "minecraft:brain_coral_block", "minecraft:bubble_coral_block", "minecraft:fire_coral_block", "minecraft:horn_coral_block", "minecraft:dead_tube_coral_block", "minecraft:dead_brain_coral_block", "minecraft:dead_bubble_coral_block", "minecraft:dead_fire_coral_block", "minecraft:dead_horn_coral_block"); - private static final List NEW_DOUBLE_PLANTS = List.of("minecraft:sunflower", "minecraft:lilac", "minecraft:tall_grass", "minecraft:large_fern", "minecraft:rose_bush", "minecraft:peony"); - private static final List NEW_STONE_BLOCK_SLABS = List.of("minecraft:smooth_stone_slab", "minecraft:sandstone_slab", "minecraft:petrified_oak_slab", "minecraft:cobblestone_slab", "minecraft:brick_slab", "minecraft:stone_brick_slab", "minecraft:quartz_slab", "minecraft:nether_brick_slab"); - private static final List NEW_TALLGRASSES = List.of("minecraft:fern", "minecraft:short_grass"); - private static final List OMINOUS_BLOCKS = List.of("minecraft:trial_spawner", "minecraft:vault"); - private static final List NEW_BLOCKS = Stream.of(NEW_CORAL_BLOCKS, NEW_DOUBLE_PLANTS, NEW_STONE_BLOCK_SLABS, NEW_TALLGRASSES).flatMap(List::stream).toList(); - private static final List MODIFIED_BLOCKS = Stream.of(NEW_BLOCKS, OMINOUS_BLOCKS).flatMap(List::stream).toList(); - private static final List NEW_MUSIC_DISCS = List.of(Items.MUSIC_DISC_CREATOR, Items.MUSIC_DISC_CREATOR_MUSIC_BOX, Items.MUSIC_DISC_PRECIPICE); - - static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { - mapping = Conversion712_685.remapItem(item, mapping); - String identifier = mapping.getBedrockIdentifier(); - - if (NEW_MUSIC_DISCS.contains(item)) { - return mapping.withBedrockIdentifier("minecraft:music_disc_otherside"); - } - if (item == Items.OMINOUS_TRIAL_KEY) { - return mapping.withBedrockIdentifier("minecraft:trial_key"); - } - if (item == Items.OMINOUS_BOTTLE) { - return mapping.withBedrockIdentifier("minecraft:glass_bottle"); - } - - if (!NEW_BLOCKS.contains(identifier)) { - return mapping; - } - - if (NEW_CORAL_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(0); } - case "minecraft:brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(1); } - case "minecraft:bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(2); } - case "minecraft:fire_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(3); } - case "minecraft:horn_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(4); } - case "minecraft:dead_tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(8); } - case "minecraft:dead_brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(9); } - case "minecraft:dead_bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(10); } - case "minecraft:dead_fire_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(11); } - case "minecraft:dead_horn_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(12); } - } - } - - if (NEW_DOUBLE_PLANTS.contains(identifier)) { - switch (identifier) { - case "minecraft:sunflower" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(0); } - case "minecraft:lilac" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(1); } - case "minecraft:tall_grass" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(2); } - case "minecraft:large_fern" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(3); } - case "minecraft:rose_bush" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(4); } - case "minecraft:peony" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(5); } - } - } - - if (NEW_STONE_BLOCK_SLABS.contains(identifier)) { - switch (identifier) { - case "minecraft:smooth_stone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(0); } - case "minecraft:sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(1); } - case "minecraft:petrified_oak_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(2); } - case "minecraft:cobblestone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(3); } - case "minecraft:brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(4); } - case "minecraft:stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(5); } - case "minecraft:quartz_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(6); } - case "minecraft:nether_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(7); } - } - } - - if (NEW_TALLGRASSES.contains(identifier)) { - switch (identifier) { - case "minecraft:short_grass" -> { return mapping.withBedrockIdentifier("minecraft:tallgrass").withBedrockData(1); } - case "minecraft:fern" -> { return mapping.withBedrockIdentifier("minecraft:tallgrass").withBedrockData(2); } - } - } - - return mapping; - } - - static NbtMap remapBlock(NbtMap tag) { - tag = Conversion712_685.remapBlock(tag); - - final String name = tag.getString("name"); - - if (!MODIFIED_BLOCKS.contains(name)) { - return tag; - } - - if (OMINOUS_BLOCKS.contains(name)) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("ominous"); - return tag.toBuilder().putCompound("states", builder.build()).build(); - } - - String replacement; - - if (NEW_CORAL_BLOCKS.contains(name)) { - replacement = "minecraft:coral_block"; - String coralColor; - boolean deadBit = name.startsWith("minecraft:dead_"); - - switch (name) { - case "minecraft:tube_coral_block", "minecraft:dead_tube_coral_block" -> coralColor = "blue"; - case "minecraft:brain_coral_block", "minecraft:dead_brain_coral_block" -> coralColor = "pink"; - case "minecraft:bubble_coral_block", "minecraft:dead_bubble_coral_block" -> coralColor = "purple"; - case "minecraft:fire_coral_block", "minecraft:dead_fire_coral_block" -> coralColor = "yellow"; - case "minecraft:horn_coral_block", "minecraft:dead_horn_coral_block" -> coralColor = "red"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("coral_color", coralColor) - .putBoolean("dead_bit", deadBit) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_DOUBLE_PLANTS.contains(name)) { - replacement = "minecraft:double_plant"; - String doublePlantType; - - switch (name) { - case "minecraft:sunflower" -> doublePlantType = "sunflower"; - case "minecraft:lilac" -> doublePlantType = "syringa"; - case "minecraft:tall_grass" -> doublePlantType = "grass"; - case "minecraft:large_fern" -> doublePlantType = "fern"; - case "minecraft:rose_bush" -> doublePlantType = "rose"; - case "minecraft:peony" -> doublePlantType = "paeonia"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("double_plant_type", doublePlantType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_STONE_BLOCK_SLABS.contains(name)) { - replacement = "minecraft:stone_block_slab"; - String stoneSlabType; - - switch (name) { - case "minecraft:smooth_stone_slab" -> stoneSlabType = "smooth_stone"; - case "minecraft:sandstone_slab" -> stoneSlabType = "sandstone"; - case "minecraft:petrified_oak_slab" -> stoneSlabType = "wood"; - case "minecraft:cobblestone_slab" -> stoneSlabType = "cobblestone"; - case "minecraft:brick_slab" -> stoneSlabType = "brick"; - case "minecraft:stone_brick_slab" -> stoneSlabType = "stone_brick"; - case "minecraft:quartz_slab" -> stoneSlabType = "quartz"; - case "minecraft:nether_brick_slab" -> stoneSlabType = "nether_brick"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("stone_slab_type", stoneSlabType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_TALLGRASSES.contains(name)) { - replacement = "minecraft:tallgrass"; - String tallGrassType; - - switch (name) { - case "minecraft:short_grass" -> tallGrassType = "tall"; - case "minecraft:fern" -> tallGrassType = "fern"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("tall_grass_type", tallGrassType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - return tag; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java deleted file mode 100644 index 45963cb90..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java +++ /dev/null @@ -1,439 +0,0 @@ -package org.geysermc.geyser.registry.populator; - -import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.type.GeyserMappingItem; - -import java.util.List; -import java.util.stream.Stream; - -public class Conversion712_685 { - private static final List NEW_STONE_BLOCK_SLABS_2 = List.of("minecraft:prismarine_slab", "minecraft:dark_prismarine_slab", "minecraft:smooth_sandstone_slab", "minecraft:purpur_slab", "minecraft:red_nether_brick_slab", "minecraft:prismarine_brick_slab", "minecraft:mossy_cobblestone_slab", "minecraft:red_sandstone_slab"); - private static final List NEW_STONE_BLOCK_SLABS_3 = List.of("minecraft:smooth_red_sandstone_slab", "minecraft:polished_granite_slab", "minecraft:granite_slab", "minecraft:polished_diorite_slab", "minecraft:andesite_slab", "minecraft:polished_andesite_slab", "minecraft:diorite_slab", "minecraft:end_stone_brick_slab"); - private static final List NEW_STONE_BLOCK_SLABS_4 = List.of("minecraft:smooth_quartz_slab", "minecraft:cut_sandstone_slab", "minecraft:cut_red_sandstone_slab", "minecraft:normal_stone_slab", "minecraft:mossy_stone_brick_slab"); - private static final List NEW_DOUBLE_STONE_BLOCK_SLABS = List.of("minecraft:quartz_double_slab", "minecraft:petrified_oak_double_slab", "minecraft:stone_brick_double_slab", "minecraft:brick_double_slab", "minecraft:sandstone_double_slab", "minecraft:nether_brick_double_slab", "minecraft:cobblestone_double_slab", "minecraft:smooth_stone_double_slab"); - private static final List NEW_DOUBLE_STONE_BLOCK_SLABS_2 = List.of("minecraft:prismarine_double_slab", "minecraft:dark_prismarine_double_slab", "minecraft:smooth_sandstone_double_slab", "minecraft:purpur_double_slab", "minecraft:red_nether_brick_double_slab", "minecraft:prismarine_brick_double_slab", "minecraft:mossy_cobblestone_double_slab", "minecraft:red_sandstone_double_slab"); - private static final List NEW_DOUBLE_STONE_BLOCK_SLABS_3 = List.of("minecraft:smooth_red_sandstone_double_slab", "minecraft:polished_granite_double_slab", "minecraft:granite_double_slab", "minecraft:polished_diorite_double_slab", "minecraft:andesite_double_slab", "minecraft:polished_andesite_double_slab", "minecraft:diorite_double_slab", "minecraft:end_stone_brick_double_slab"); - private static final List NEW_DOUBLE_STONE_BLOCK_SLABS_4 = List.of("minecraft:smooth_quartz_double_slab", "minecraft:cut_sandstone_double_slab", "minecraft:cut_red_sandstone_double_slab", "minecraft:normal_stone_double_slab", "minecraft:mossy_stone_brick_double_slab"); - private static final List NEW_PRISMARINE_BLOCKS = List.of("minecraft:prismarine_bricks", "minecraft:dark_prismarine", "minecraft:prismarine"); - private static final List NEW_CORAL_FAN_HANGS = List.of("minecraft:tube_coral_wall_fan", "minecraft:brain_coral_wall_fan", "minecraft:dead_tube_coral_wall_fan", "minecraft:dead_brain_coral_wall_fan"); - private static final List NEW_CORAL_FAN_HANGS_2 = List.of("minecraft:bubble_coral_wall_fan", "minecraft:fire_coral_wall_fan", "minecraft:dead_bubble_coral_wall_fan", "minecraft:dead_fire_coral_wall_fan"); - private static final List NEW_CORAL_FAN_HANGS_3 = List.of("minecraft:horn_coral_wall_fan", "minecraft:dead_horn_coral_wall_fan"); - private static final List NEW_MONSTER_EGGS = List.of("minecraft:infested_cobblestone", "minecraft:infested_stone_bricks", "minecraft:infested_mossy_stone_bricks", "minecraft:infested_cracked_stone_bricks", "minecraft:infested_chiseled_stone_bricks", "minecraft:infested_stone"); - private static final List NEW_STONEBRICK_BLOCKS = List.of("minecraft:mossy_stone_bricks", "minecraft:cracked_stone_bricks", "minecraft:chiseled_stone_bricks", "minecraft:smooth_stone_bricks", "minecraft:stone_bricks"); - private static final List NEW_LIGHT_BLOCKS = List.of("minecraft:light_block_0", "minecraft:light_block_1", "minecraft:light_block_2", "minecraft:light_block_3", "minecraft:light_block_4", "minecraft:light_block_5", "minecraft:light_block_6", "minecraft:light_block_7", "minecraft:light_block_8", "minecraft:light_block_9", "minecraft:light_block_10", "minecraft:light_block_11", "minecraft:light_block_12", "minecraft:light_block_13", "minecraft:light_block_14", "minecraft:light_block_15"); - private static final List NEW_SANDSTONE_BLOCKS = List.of("minecraft:cut_sandstone", "minecraft:chiseled_sandstone", "minecraft:smooth_sandstone", "minecraft:sandstone"); - private static final List NEW_QUARTZ_BLOCKS = List.of("minecraft:chiseled_quartz_block", "minecraft:quartz_pillar", "minecraft:smooth_quartz", "minecraft:quartz_block"); - private static final List NEW_RED_SANDSTONE_BLOCKS = List.of("minecraft:cut_red_sandstone", "minecraft:chiseled_red_sandstone", "minecraft:smooth_red_sandstone", "minecraft:red_sandstone"); - private static final List NEW_SAND_BLOCKS = List.of("minecraft:red_sand", "minecraft:sand"); - private static final List NEW_DIRT_BLOCKS = List.of("minecraft:coarse_dirt", "minecraft:dirt"); - private static final List NEW_ANVILS = List.of("minecraft:damaged_anvil", "minecraft:chipped_anvil", "minecraft:deprecated_anvil", "minecraft:anvil"); - private static final List NEW_YELLOW_FLOWERS = List.of("minecraft:dandelion"); - private static final List NEW_BLOCKS = Stream.of(NEW_STONE_BLOCK_SLABS_2, NEW_STONE_BLOCK_SLABS_3, NEW_STONE_BLOCK_SLABS_4, NEW_DOUBLE_STONE_BLOCK_SLABS, NEW_DOUBLE_STONE_BLOCK_SLABS_2, NEW_DOUBLE_STONE_BLOCK_SLABS_3, NEW_DOUBLE_STONE_BLOCK_SLABS_4, NEW_PRISMARINE_BLOCKS, NEW_CORAL_FAN_HANGS, NEW_CORAL_FAN_HANGS_2, NEW_CORAL_FAN_HANGS_3, NEW_MONSTER_EGGS, NEW_STONEBRICK_BLOCKS, NEW_LIGHT_BLOCKS, NEW_SANDSTONE_BLOCKS, NEW_QUARTZ_BLOCKS, NEW_RED_SANDSTONE_BLOCKS, NEW_SAND_BLOCKS, NEW_DIRT_BLOCKS, NEW_ANVILS, NEW_YELLOW_FLOWERS).flatMap(List::stream).toList(); - - static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { - mapping = Conversion729_712.remapItem(item, mapping); - String identifier = mapping.getBedrockIdentifier(); - - if (!NEW_BLOCKS.contains(identifier)) { - return mapping; - } - - if (identifier.equals("minecraft:coarse_dirt")) { - return mapping.withBedrockIdentifier("minecraft:dirt").withBedrockData(1); - } - - if (identifier.equals("minecraft:dandelion")) { - return mapping.withBedrockIdentifier("minecraft:yellow_flower").withBedrockData(0); - } - - if (identifier.equals("minecraft:red_sand")) { - return mapping.withBedrockIdentifier("minecraft:sand").withBedrockData(1); - } - - if (NEW_PRISMARINE_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:prismarine" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(0); } - case "minecraft:dark_prismarine" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(1); } - case "minecraft:prismarine_bricks" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(2); } - } - } - - if (NEW_SANDSTONE_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(0); } - case "minecraft:chiseled_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(1); } - case "minecraft:cut_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(2); } - case "minecraft:smooth_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(3); } - } - } - - if (NEW_RED_SANDSTONE_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(0); } - case "minecraft:chiseled_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(1); } - case "minecraft:cut_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(2); } - case "minecraft:smooth_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(3); } - } - } - - if (NEW_QUARTZ_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:quartz_block" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(0); } - case "minecraft:chiseled_quartz_block" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(1); } - case "minecraft:quartz_pillar" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(2); } - case "minecraft:smooth_quartz" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(3); } - } - } - - if (NEW_STONE_BLOCK_SLABS_2.contains(identifier)) { - switch (identifier) { - case "minecraft:red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(0); } - case "minecraft:purpur_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(1); } - case "minecraft:prismarine_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(2); } - case "minecraft:dark_prismarine_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(3); } - case "minecraft:prismarine_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(4); } - case "minecraft:mossy_cobblestone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(5); } - case "minecraft:smooth_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(6); } - case "minecraft:red_nether_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(7); } - } - } - - if (NEW_STONE_BLOCK_SLABS_3.contains(identifier)) { - switch (identifier) { - case "minecraft:end_stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(0); } - case "minecraft:smooth_red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(1); } - case "minecraft:polished_andesite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(2); } - case "minecraft:andesite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(3); } - case "minecraft:diorite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(4); } - case "minecraft:polished_diorite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(5); } - case "minecraft:granite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(6); } - case "minecraft:polished_granite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(7); } - } - } - - if (NEW_STONE_BLOCK_SLABS_4.contains(identifier)) { - switch (identifier) { - case "minecraft:mossy_stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(0); } - case "minecraft:smooth_quartz_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(1); } - case "minecraft:normal_stone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(2); } - case "minecraft:cut_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(3); } - case "minecraft:cut_red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(4); } - } - } - - if (NEW_MONSTER_EGGS.contains(identifier)) { - switch (identifier) { - case "minecraft:infested_stone" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(0); } - case "minecraft:infested_cobblestone" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(1); } - case "minecraft:infested_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(2); } - case "minecraft:infested_mossy_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(3); } - case "minecraft:infested_cracked_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(4); } - case "minecraft:infested_chiseled_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(5); } - } - } - - if (NEW_STONEBRICK_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(0); } - case "minecraft:mossy_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(1); } - case "minecraft:cracked_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(2); } - case "minecraft:chiseled_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(3); } - } - } - - if (NEW_ANVILS.contains(identifier)) { - switch (identifier) { - case "minecraft:anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(0); } - case "minecraft:chipped_anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(4); } - case "minecraft:damaged_anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(8); } - } - } - - return mapping; - } - - static NbtMap remapBlock(NbtMap tag) { - tag = Conversion729_712.remapBlock(tag); - - final String name = tag.getString("name"); - - if (!NEW_BLOCKS.contains(name)) { - return tag; - } - - String replacement; - - if (NEW_DOUBLE_STONE_BLOCK_SLABS.contains(name)) { - replacement = "minecraft:double_stone_block_slab"; - String stoneSlabType; - - switch (name) { - case "minecraft:quartz_double_slab" -> stoneSlabType = "quartz"; - case "minecraft:petrified_oak_double_slab" -> stoneSlabType = "wood"; - case "minecraft:stone_brick_double_slab" -> stoneSlabType = "stone_brick"; - case "minecraft:brick_double_slab" -> stoneSlabType = "brick"; - case "minecraft:sandstone_double_slab" -> stoneSlabType = "sandstone"; - case "minecraft:nether_brick_double_slab" -> stoneSlabType = "nether_brick"; - case "minecraft:cobblestone_double_slab" -> stoneSlabType = "cobblestone"; - case "minecraft:smooth_stone_double_slab" -> stoneSlabType = "smooth_stone"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("stone_slab_type", stoneSlabType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_STONE_BLOCK_SLABS_2.contains(name) || NEW_DOUBLE_STONE_BLOCK_SLABS_2.contains(name)) { - replacement = NEW_STONE_BLOCK_SLABS_2.contains(name) ? "minecraft:stone_block_slab2" : "minecraft:double_stone_block_slab2"; - String stoneSlabType2; - - switch (name) { - case "minecraft:prismarine_slab", "minecraft:prismarine_double_slab" -> stoneSlabType2 = "prismarine_rough"; - case "minecraft:dark_prismarine_slab", "minecraft:dark_prismarine_double_slab" -> stoneSlabType2 = "prismarine_dark"; - case "minecraft:smooth_sandstone_slab", "minecraft:smooth_sandstone_double_slab" -> stoneSlabType2 = "smooth_sandstone"; - case "minecraft:purpur_slab", "minecraft:purpur_double_slab" -> stoneSlabType2 = "purpur"; - case "minecraft:red_nether_brick_slab", "minecraft:red_nether_brick_double_slab" -> stoneSlabType2 = "red_nether_brick"; - case "minecraft:prismarine_brick_slab", "minecraft:prismarine_brick_double_slab" -> stoneSlabType2 = "prismarine_brick"; - case "minecraft:mossy_cobblestone_slab", "minecraft:mossy_cobblestone_double_slab" -> stoneSlabType2 = "mossy_cobblestone"; - case "minecraft:red_sandstone_slab", "minecraft:red_sandstone_double_slab" -> stoneSlabType2 = "red_sandstone"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("stone_slab_type_2", stoneSlabType2) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_STONE_BLOCK_SLABS_3.contains(name) || NEW_DOUBLE_STONE_BLOCK_SLABS_3.contains(name)) { - replacement = NEW_STONE_BLOCK_SLABS_3.contains(name) ? "minecraft:stone_block_slab3" : "minecraft:double_stone_block_slab3"; - String stoneSlabType3; - - switch (name) { - case "minecraft:smooth_red_sandstone_slab", "minecraft:smooth_red_sandstone_double_slab" -> stoneSlabType3 = "smooth_red_sandstone"; - case "minecraft:polished_granite_slab", "minecraft:polished_granite_double_slab" -> stoneSlabType3 = "polished_granite"; - case "minecraft:granite_slab", "minecraft:granite_double_slab" -> stoneSlabType3 = "granite"; - case "minecraft:polished_diorite_slab", "minecraft:polished_diorite_double_slab" -> stoneSlabType3 = "polished_diorite"; - case "minecraft:andesite_slab", "minecraft:andesite_double_slab" -> stoneSlabType3 = "andesite"; - case "minecraft:polished_andesite_slab", "minecraft:polished_andesite_double_slab" -> stoneSlabType3 = "polished_andesite"; - case "minecraft:diorite_slab", "minecraft:diorite_double_slab" -> stoneSlabType3 = "diorite"; - case "minecraft:end_stone_brick_slab", "minecraft:end_stone_brick_double_slab" -> stoneSlabType3 = "end_stone_brick"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("stone_slab_type_3", stoneSlabType3) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_STONE_BLOCK_SLABS_4.contains(name) || NEW_DOUBLE_STONE_BLOCK_SLABS_4.contains(name)) { - replacement = NEW_STONE_BLOCK_SLABS_4.contains(name) ? "minecraft:stone_block_slab4" : "minecraft:double_stone_block_slab4"; - String stoneSlabType4; - - switch (name) { - case "minecraft:smooth_quartz_slab", "minecraft:smooth_quartz_double_slab" -> stoneSlabType4 = "smooth_quartz"; - case "minecraft:cut_sandstone_slab", "minecraft:cut_sandstone_double_slab" -> stoneSlabType4 = "cut_sandstone"; - case "minecraft:cut_red_sandstone_slab", "minecraft:cut_red_sandstone_double_slab" -> stoneSlabType4 = "cut_red_sandstone"; - case "minecraft:normal_stone_slab", "minecraft:normal_stone_double_slab" -> stoneSlabType4 = "stone"; - case "minecraft:mossy_stone_brick_slab", "minecraft:mossy_stone_brick_double_slab" -> stoneSlabType4 = "mossy_stone_brick"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("stone_slab_type_4", stoneSlabType4) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_PRISMARINE_BLOCKS.contains(name)) { - replacement = "minecraft:prismarine"; - String prismarineBlockType; - - switch (name) { - case "minecraft:prismarine_bricks" -> prismarineBlockType = "bricks"; - case "minecraft:dark_prismarine" -> prismarineBlockType = "dark"; - case "minecraft:prismarine" -> prismarineBlockType = "default"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("prismarine_block_type", prismarineBlockType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_CORAL_FAN_HANGS.contains(name) || NEW_CORAL_FAN_HANGS_2.contains(name) || NEW_CORAL_FAN_HANGS_3.contains(name)) { - replacement = NEW_CORAL_FAN_HANGS.contains(name) ? "minecraft:coral_fan_hang" : NEW_CORAL_FAN_HANGS_2.contains(name) ? "minecraft:coral_fan_hang2" : "minecraft:coral_fan_hang3"; - boolean deadBit = name.startsWith("minecraft:dead_"); - boolean coralHangTypeBit = name.contains("brain") || name.contains("fire"); - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putBoolean("coral_hang_type_bit", coralHangTypeBit) - .putBoolean("dead_bit", deadBit) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_MONSTER_EGGS.contains(name)) { - replacement = "minecraft:monster_egg"; - String monsterEggStoneType; - - switch (name) { - case "minecraft:infested_cobblestone" -> monsterEggStoneType = "cobblestone"; - case "minecraft:infested_stone_bricks" -> monsterEggStoneType = "stone_brick"; - case "minecraft:infested_mossy_stone_bricks" -> monsterEggStoneType = "mossy_stone_brick"; - case "minecraft:infested_cracked_stone_bricks" -> monsterEggStoneType = "cracked_stone_brick"; - case "minecraft:infested_chiseled_stone_bricks" -> monsterEggStoneType = "chiseled_stone_brick"; - case "minecraft:infested_stone" -> monsterEggStoneType = "stone"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("monster_egg_stone_type", monsterEggStoneType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_STONEBRICK_BLOCKS.contains(name)) { - replacement = "minecraft:stonebrick"; - String stoneBrickType; - - switch (name) { - case "minecraft:mossy_stone_bricks" -> stoneBrickType = "mossy"; - case "minecraft:cracked_stone_bricks" -> stoneBrickType = "cracked"; - case "minecraft:chiseled_stone_bricks" -> stoneBrickType = "chiseled"; - case "minecraft:smooth_stone_bricks" -> stoneBrickType = "smooth"; - case "minecraft:stone_bricks" -> stoneBrickType = "default"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("stone_brick_type", stoneBrickType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_LIGHT_BLOCKS.contains(name)) { - replacement = "minecraft:light_block"; - int blockLightLevel = Integer.parseInt(name.split("_")[2]); - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putInt("block_light_level", blockLightLevel) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_SANDSTONE_BLOCKS.contains(name) || NEW_RED_SANDSTONE_BLOCKS.contains(name)) { - replacement = NEW_SANDSTONE_BLOCKS.contains(name) ? "minecraft:sandstone" : "minecraft:red_sandstone"; - String sandStoneType; - - switch (name) { - case "minecraft:cut_sandstone", "minecraft:cut_red_sandstone" -> sandStoneType = "cut"; - case "minecraft:chiseled_sandstone", "minecraft:chiseled_red_sandstone" -> sandStoneType = "heiroglyphs"; - case "minecraft:smooth_sandstone", "minecraft:smooth_red_sandstone" -> sandStoneType = "smooth"; - case "minecraft:sandstone", "minecraft:red_sandstone" -> sandStoneType = "default"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("sand_stone_type", sandStoneType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_QUARTZ_BLOCKS.contains(name)) { - replacement = "minecraft:quartz_block"; - String chiselType; - - switch (name) { - case "minecraft:chiseled_quartz_block" -> chiselType = "chiseled"; - case "minecraft:quartz_pillar" -> chiselType = "lines"; - case "minecraft:smooth_quartz" -> chiselType = "smooth"; - case "minecraft:quartz_block" -> chiselType = "default"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("chisel_type", chiselType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_SAND_BLOCKS.contains(name)) { - replacement = "minecraft:sand"; - String sandType = name.equals("minecraft:red_sand") ? "red" : "normal"; - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("sand_type", sandType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_DIRT_BLOCKS.contains(name)) { - replacement = "minecraft:dirt"; - String dirtType = name.equals("minecraft:coarse_dirt") ? "coarse" : "normal"; - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("dirt_type", dirtType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_ANVILS.contains(name)) { - replacement = "minecraft:anvil"; - String damage; - - switch (name) { - case "minecraft:damaged_anvil" -> damage = "broken"; - case "minecraft:chipped_anvil" -> damage = "slightly_damaged"; - case "minecraft:deprecated_anvil" -> damage = "very_damaged"; - case "minecraft:anvil" -> damage = "undamaged"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("damage", damage) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_YELLOW_FLOWERS.contains(name)) { - replacement = "minecraft:yellow_flower"; - return tag.toBuilder().putString("name", replacement).build(); - } - - return tag; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java deleted file mode 100644 index fbc2233bc..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.geysermc.geyser.registry.populator; - -import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.type.GeyserMappingItem; - -import java.util.List; -import java.util.stream.Stream; - -public class Conversion729_712 { - private static final List NEW_PURPUR_BLOCKS = List.of("minecraft:purpur_block", "minecraft:purpur_pillar"); - private static final List NEW_WALL_BLOCKS = List.of("minecraft:cobblestone_wall", "minecraft:mossy_cobblestone_wall", "minecraft:granite_wall", "minecraft:diorite_wall", "minecraft:andesite_wall", "minecraft:sandstone_wall", "minecraft:brick_wall", "minecraft:stone_brick_wall", "minecraft:mossy_stone_brick_wall", "minecraft:nether_brick_wall", "minecraft:end_stone_brick_wall", "minecraft:prismarine_wall", "minecraft:red_sandstone_wall", "minecraft:red_nether_brick_wall"); - private static final List NEW_SPONGE_BLOCKS = List.of("minecraft:sponge", "minecraft:wet_sponge"); - private static final List NEW_TNT_BLOCKS = List.of("minecraft:tnt", "minecraft:underwater_tnt"); - private static final List STRUCTURE_VOID = List.of("minecraft:structure_void"); - private static final List NEW_BLOCKS = Stream.of(NEW_PURPUR_BLOCKS, NEW_WALL_BLOCKS, NEW_SPONGE_BLOCKS, NEW_TNT_BLOCKS, STRUCTURE_VOID).flatMap(List::stream).toList(); - - static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { - mapping = Conversion748_729.remapItem(item, mapping); - String identifier = mapping.getBedrockIdentifier(); - - if (!NEW_BLOCKS.contains(identifier)) { - return mapping; - } - - if (identifier.equals("minecraft:underwater_tnt")) { - return mapping.withBedrockIdentifier("minecraft:tnt").withBedrockData(1); - } - - if (NEW_PURPUR_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:purpur_block" -> { return mapping.withBedrockIdentifier("minecraft:purpur_block").withBedrockData(0); } - case "minecraft:purpur_pillar" -> { return mapping.withBedrockIdentifier("minecraft:purpur_block").withBedrockData(1); } - } - } - - if (NEW_WALL_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:cobblestone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(0); } - case "minecraft:mossy_cobblestone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(1); } - case "minecraft:granite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(2); } - case "minecraft:diorite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(3); } - case "minecraft:andesite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(4); } - case "minecraft:sandstone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(5); } - case "minecraft:brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(6); } - case "minecraft:stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(7); } - case "minecraft:mossy_stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(8); } - case "minecraft:nether_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(9); } - case "minecraft:end_stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(10); } - case "minecraft:prismarine_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(11); } - case "minecraft:red_sandstone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(12); } - case "minecraft:red_nether_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(13); } - } - } - - if (NEW_SPONGE_BLOCKS.contains(identifier)) { - switch (identifier) { - case "minecraft:sponge" -> { return mapping.withBedrockIdentifier("minecraft:sponge").withBedrockData(0); } - case "minecraft:wet_sponge" -> { return mapping.withBedrockIdentifier("minecraft:sponge").withBedrockData(1); } - } - } - - return mapping; - } - - static NbtMap remapBlock(NbtMap tag) { - final String name = tag.getString("name"); - - if (!NEW_BLOCKS.contains(name)) { - return tag; - } - - String replacement; - - if (NEW_PURPUR_BLOCKS.contains(name)) { - replacement = "minecraft:purpur_block"; - String purpurType = name.equals("minecraft:purpur_pillar") ? "lines" : "default"; - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("chisel_type", purpurType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_WALL_BLOCKS.contains(name)) { - replacement = "minecraft:cobblestone_wall"; - String wallType; - - switch (name) { - case "minecraft:cobblestone_wall" -> wallType = "cobblestone"; - case "minecraft:mossy_cobblestone_wall" -> wallType = "mossy_cobblestone"; - case "minecraft:granite_wall" -> wallType = "granite"; - case "minecraft:diorite_wall" -> wallType = "diorite"; - case "minecraft:andesite_wall" -> wallType = "andesite"; - case "minecraft:sandstone_wall" -> wallType = "sandstone"; - case "minecraft:brick_wall" -> wallType = "brick"; - case "minecraft:stone_brick_wall" -> wallType = "stone_brick"; - case "minecraft:mossy_stone_brick_wall" -> wallType = "mossy_stone_brick"; - case "minecraft:nether_brick_wall" -> wallType = "nether_brick"; - case "minecraft:end_stone_brick_wall" -> wallType = "end_brick"; - case "minecraft:prismarine_wall" -> wallType = "prismarine"; - case "minecraft:red_sandstone_wall" -> wallType = "red_sandstone"; - case "minecraft:red_nether_brick_wall" -> wallType = "red_nether_brick"; - default -> throw new IllegalStateException("Unexpected value: " + name); - } - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("wall_block_type", wallType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_SPONGE_BLOCKS.contains(name)) { - replacement = "minecraft:sponge"; - String spongeType = name.equals("minecraft:wet_sponge") ? "wet" : "dry"; - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("sponge_type", spongeType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (NEW_TNT_BLOCKS.contains(name)) { - replacement = "minecraft:tnt"; - byte tntType = (byte) (name.equals("minecraft:underwater_tnt") ? 1 : 0); - - NbtMap states = tag.getCompound("states") - .toBuilder() - .putByte("allow_underwater_bit", tntType) - .build(); - - return tag.toBuilder().putString("name", replacement).putCompound("states", states).build(); - } - - if (STRUCTURE_VOID.contains(name)) { - NbtMap states = tag.getCompound("states") - .toBuilder() - .putString("structure_void_type", "air") - .build(); - - return tag.toBuilder().putCompound("states", states).build(); - } - - return tag; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java index 8e42887ff..01dcd38a6 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java @@ -37,6 +37,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.GeyserBedrockBlock; +import org.geysermc.geyser.registry.type.GeyserMappingItem; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -50,12 +51,10 @@ import java.util.function.Consumer; public class CreativeItemRegistryPopulator { private static final List> JAVA_ONLY_ITEM_FILTER = List.of( // Bedrock-only as its own item - (identifier, data) -> identifier.equals("minecraft:empty_map") && data == 2, - // Bedrock-only banner patterns - (identifier, data) -> identifier.equals("minecraft:bordure_indented_banner_pattern") || identifier.equals("minecraft:field_masoned_banner_pattern") + (identifier, data) -> identifier.equals("minecraft:empty_map") && data == 2 ); - static void populate(ItemRegistryPopulator.PaletteVersion palette, Map definitions, Consumer itemConsumer) { + static void populate(ItemRegistryPopulator.PaletteVersion palette, Map definitions, Map items, Consumer itemConsumer) { GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); // Load creative items @@ -68,7 +67,7 @@ public class CreativeItemRegistryPopulator { BlockMappings blockMappings = BlockRegistries.BLOCKS.forVersion(palette.protocolVersion()); for (JsonNode itemNode : creativeItemEntries) { - ItemData.Builder itemBuilder = createItemData(itemNode, blockMappings, definitions); + ItemData.Builder itemBuilder = createItemData(itemNode, items, blockMappings, definitions); if (itemBuilder == null) { continue; } @@ -77,7 +76,7 @@ public class CreativeItemRegistryPopulator { } } - private static ItemData.@Nullable Builder createItemData(JsonNode itemNode, BlockMappings blockMappings, Map definitions) { + private static ItemData.@Nullable Builder createItemData(JsonNode itemNode, Map items, BlockMappings blockMappings, Map definitions) { int count = 1; int damage = 0; NbtMap tag = null; @@ -89,6 +88,23 @@ public class CreativeItemRegistryPopulator { } } + // Attempt to remove items that do not exist in Java (1.21.50 has 1.21.4 items, that don't exist on 1.21.2) + // we still add the lodestone compass - we're going to translate it. + if (!items.containsKey(identifier) && !identifier.equals("minecraft:lodestone_compass")) { + // bedrock identifier not found, let's make sure it's not just different + boolean found = false; + for (var mapping : items.values()) { + if (mapping.getBedrockIdentifier().equals(identifier)) { + found = true; + break; + } + } + + if (!found) { + return null; + } + } + JsonNode damageNode = itemNode.get("damage"); if (damageNode != null) { damage = damageNode.asInt(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 1da3b0e66..e9901c620 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -45,11 +45,8 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtUtils; -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.cloudburstmc.protocol.bedrock.codec.v765.Bedrock_v765; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; @@ -85,7 +82,6 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -111,18 +107,9 @@ 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(), 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)); + List paletteVersions = new ArrayList<>(2); paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v765.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -207,7 +194,7 @@ public class ItemRegistryPopulator { noBlockDefinitions.add("minecraft:structure_void"); AtomicInteger creativeNetId = new AtomicInteger(); - CreativeItemRegistryPopulator.populate(palette, definitions, itemBuilder -> { + CreativeItemRegistryPopulator.populate(palette, definitions, items, itemBuilder -> { ItemData item = itemBuilder.netId(creativeNetId.incrementAndGet()).build(); creativeItems.add(item); 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 index 24cc270c9..dd654531a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java @@ -33,11 +33,8 @@ 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.cloudburstmc.protocol.bedrock.codec.v765.Bedrock_v765; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.item.type.Item; @@ -70,11 +67,8 @@ public final class TagRegistryPopulator { }; 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()) + ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), + ObjectIntPair.of("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()) ); Type type = new TypeToken>>() {}.getType(); 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 ef6261ead..cfb981b7d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -2241,9 +2241,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public void closeForm() { - if (!GameProtocol.isPre1_21_2(this)) { - sendUpstreamPacket(new ClientboundCloseFormPacket()); - } + sendUpstreamPacket(new ClientboundCloseFormPacket()); } public void addCommandEnum(String name, String enums) { 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 15c19c542..78322c529 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 @@ -261,9 +261,9 @@ public abstract class InventoryTranslator { } } - if (shouldRejectItemPlace(session, inventory, transferAction.getSource().getContainer(), + if (shouldRejectItemPlace(session, inventory, transferAction.getSource().getContainerName().getContainer(), isSourceCursor ? -1 : sourceSlot, - transferAction.getDestination().getContainer(), isDestCursor ? -1 : destSlot)) { + transferAction.getDestination().getContainerName().getContainer(), isDestCursor ? -1 : destSlot)) { // This item would not be here in Java return rejectRequest(request, false); } @@ -411,14 +411,14 @@ public abstract class InventoryTranslator { boolean isSourceCursor = isCursor(source); boolean isDestCursor = isCursor(destination); - if (shouldRejectItemPlace(session, inventory, source.getContainer(), + if (shouldRejectItemPlace(session, inventory, source.getContainerName().getContainer(), isSourceCursor ? -1 : sourceSlot, - destination.getContainer(), isDestCursor ? -1 : destSlot)) { + destination.getContainerName().getContainer(), isDestCursor ? -1 : destSlot)) { // This item would not be here in Java return rejectRequest(request, false); } - if (!isSourceCursor && destination.getContainer() == ContainerSlotType.HOTBAR || destination.getContainer() == ContainerSlotType.HOTBAR_AND_INVENTORY) { + if (!isSourceCursor && destination.getContainerName().getContainer() == ContainerSlotType.HOTBAR || destination.getContainerName().getContainer() == ContainerSlotType.HOTBAR_AND_INVENTORY) { // Tell the server we're pressing one of the hotbar keys to save clicks Click click = InventoryUtils.getClickForHotbarSwap(destination.getSlot()); if (click != null) { @@ -587,7 +587,7 @@ public abstract class InventoryTranslator { } craftState = CraftState.TRANSFER; - if (transferAction.getSource().getContainer() != ContainerSlotType.CREATED_OUTPUT) { + if (transferAction.getSource().getContainerName().getContainer() != ContainerSlotType.CREATED_OUTPUT) { return rejectRequest(request); } if (transferAction.getCount() <= 0) { @@ -780,7 +780,7 @@ public abstract class InventoryTranslator { } craftState = CraftState.TRANSFER; - if (transferAction.getSource().getContainer() != ContainerSlotType.CREATED_OUTPUT) { + if (transferAction.getSource().getContainerName().getContainer() != ContainerSlotType.CREATED_OUTPUT) { return rejectRequest(request); } if (transferAction.getCount() <= 0) { @@ -1028,15 +1028,15 @@ public abstract class InventoryTranslator { } } - itemEntry = new ItemStackResponseSlot((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), "", durability); + itemEntry = new ItemStackResponseSlot((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), itemStack.getNetId(), "", durability, ""); } else { - itemEntry = new ItemStackResponseSlot((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0, "", 0); + itemEntry = new ItemStackResponseSlot((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0, "", 0, ""); } return itemEntry; } protected static boolean isCursor(ItemStackRequestSlotData slotInfoData) { - return slotInfoData.getContainer() == ContainerSlotType.CURSOR; + return slotInfoData.getContainerName().getContainer() == ContainerSlotType.CURSOR; } /** diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index 77f58f5d6..be0f8560f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -35,8 +35,6 @@ import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; -import org.geysermc.geyser.level.block.type.SkullBlock; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.skin.SkinProvider; @@ -58,9 +56,6 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements // Could be a wall skull block otherwise, which has rotation in its Bedrock state bedrockNbt.putFloat("Rotation", rotation * 22.5f); } - if (GameProtocol.isPre1_21_40(session)) { - bedrockNbt.putByte("SkullType", (byte) (blockState.block() instanceof SkullBlock skull ? skull.skullType().bedrockId() : 0)); - } if (blockState.getValue(Properties.POWERED)) { bedrockNbt.putBoolean("MouthMoving", true); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java index 6abb3899a..ce8afa269 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player.input; -import net.kyori.adventure.util.TriState; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData; @@ -33,7 +32,6 @@ 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.level.physics.CollisionResult; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.mcprotocollib.network.packet.Packet; @@ -88,14 +86,8 @@ final class BedrockMovePlayer { session.setLookBackScheduledFuture(null); } - TriState maybeOnGround; - if (GameProtocol.isPre1_21_30(session)) { - // VERTICAL_COLLISION input data does not exist. - maybeOnGround = TriState.NOT_SET; - } else { - // Client is telling us it wants to move down, but something is blocking it from doing so. - maybeOnGround = TriState.byBoolean(packet.getInputData().contains(PlayerAuthInputData.VERTICAL_COLLISION) && packet.getDelta().getY() < 0); - } + // Client is telling us it wants to move down, but something is blocking it from doing so. + boolean isOnGround = packet.getInputData().contains(PlayerAuthInputData.VERTICAL_COLLISION) && packet.getDelta().getY() < 0; // This takes into account no movement sent from the client, but the player is trying to move anyway. // (Press into a wall in a corner - you're trying to move but nothing actually happens) boolean horizontalCollision = packet.getInputData().contains(PlayerAuthInputData.HORIZONTAL_COLLISION); @@ -104,7 +96,7 @@ final class BedrockMovePlayer { // This isn't needed, but it makes the packets closer to vanilla // It also means you can't "lag back" while only looking, in theory if (!positionChanged && rotationChanged) { - ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(maybeOnGround.toBooleanOrElse(entity.isOnGround()), horizontalCollision, yaw, pitch); + ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(isOnGround, horizontalCollision, yaw, pitch); entity.setYaw(yaw); entity.setPitch(pitch); @@ -113,10 +105,9 @@ final class BedrockMovePlayer { session.sendDownstreamGamePacket(playerRotationPacket); } else if (positionChanged) { if (isValidMove(session, entity.getPosition(), packet.getPosition())) { - CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), maybeOnGround.toBooleanOrElse(false), packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT)); + CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), isOnGround, packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT)); if (result != null) { // A null return value cancels the packet Vector3d position = result.correctedMovement(); - boolean onGround = maybeOnGround.toBooleanOrElseGet(() -> session.getCollisionManager().isOnGround()); boolean isBelowVoid = entity.isVoidPositionDesynched(); boolean teleportThroughVoidFloor, mustResyncPosition; @@ -131,7 +122,7 @@ final class BedrockMovePlayer { if (teleportThroughVoidFloor || isBelowVoid) { // https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground. - onGround = false; + isOnGround = false; } if (isBelowVoid) { @@ -151,7 +142,7 @@ final class BedrockMovePlayer { if (rotationChanged) { // Send rotation updates as well movePacket = new ServerboundMovePlayerPosRotPacket( - onGround, + isOnGround, horizontalCollision, position.getX(), yPosition, position.getZ(), yaw, pitch @@ -161,7 +152,7 @@ final class BedrockMovePlayer { entity.setHeadYaw(headYaw); } else { // Rotation did not change; don't send an update with rotation - movePacket = new ServerboundMovePlayerPosPacket(onGround, horizontalCollision, position.getX(), yPosition, position.getZ()); + movePacket = new ServerboundMovePlayerPosPacket(isOnGround, horizontalCollision, position.getX(), yPosition, position.getZ()); } entity.setPositionManual(packet.getPosition()); @@ -183,12 +174,12 @@ final class BedrockMovePlayer { session.getGeyser().getLogger().debug("Recalculating position..."); session.getCollisionManager().recalculatePosition(); } - } else if (horizontalCollision != session.getInputCache().lastHorizontalCollision() || maybeOnGround.toBooleanOrElse(entity.isOnGround()) != entity.isOnGround()) { - session.sendDownstreamGamePacket(new ServerboundMovePlayerStatusOnlyPacket(maybeOnGround.toBooleanOrElse(false), horizontalCollision)); + } else if (horizontalCollision != session.getInputCache().lastHorizontalCollision() || isOnGround != entity.isOnGround()) { + session.sendDownstreamGamePacket(new ServerboundMovePlayerStatusOnlyPacket(isOnGround, horizontalCollision)); } session.getInputCache().setLastHorizontalCollision(horizontalCollision); - entity.setOnGround(maybeOnGround.toBooleanOrElse(entity.isOnGround())); + entity.setOnGround(isOnGround); // Move parrots to match if applicable if (entity.getLeftParrot() != null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index 11178115a..e1ff7a5fc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -29,7 +29,6 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.FakeHeadProvider; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -79,11 +78,8 @@ public class JavaSetEquipmentTranslator extends PacketTranslator { // BODY is sent for llamas with a carpet equipped, as of 1.20.5 - if (GameProtocol.isPre1_21_2(session)) { - livingEntity.setChestplate(stack); - } else { - livingEntity.setBody(stack); - } + // and for wolves + livingEntity.setBody(stack); armorUpdated = true; } case LEGGINGS -> { diff --git a/core/src/main/resources/bedrock/biome_definitions.dat b/core/src/main/resources/bedrock/biome_definitions.dat index 2bd58d0a33a9ea50e55361a77e3832a66cdc771a..e59a99ce2a5c5ffc11489ea1a9d42285e77f137a 100644 GIT binary patch delta 926 zcmYjPUr1AN6lVV?)2U_IEWJ(Bh{7=%Ld*q*KPy4PhtU48x$?HsySv-Ht2t813A`w33);?E(bN6T_nq_c{m!{lGy2h4{iA0F z!_2*UzF>GmAYrlS@(fH_zu-6R68N2>cSv%{Hb5X-yq(&z#SGf*tJo^p7(ZWX(xanN z{(w4?RSe`ZGY@TkO@wb;fThX?KCs16=!goyxBftnoXD3d^(3sMT6wu6js;IvJtSve z^;=>}gf#*>=S>0=wJ)&;y6V57-Qk8``0c7^Jh9tk#AvWrr1p({W(1ISF@CgBBR1{Y z_KyX@{Q_q`yWb;ucYZ&KnYh3|dQw#Qsu}$DSozbYW0cW$ph$1GYf3OC2SmA7RKp@P zdj+WQ?tz}c8qAb`-Llt+4t%xQNs~VhelUaERt23Fhsmf0RS|UUG_YV`yua-+9tt)( z7!S2i($zLP76?4=%#fV0Fur`;NJWXz#&?|X>q_n6pd3;om&Je<3x*X~+f)huL^%u( z9^vaJPm@QtU!hkeql}mJ)X_$p&V0wz`4Gz4S42)r42I6(h9HOeXs7~LoG;*0Kdo+B znxr>+WIutaNa0t|IhoC-1SK&L3aY&#I32aH^N<}}ry2#bB^;5psHhg@@~W|jD)s)? zDnr^`gSlreE|Tj7%}F2`-GuJXZ3!$HtAmKx35t~-KQ@q|?cFXDdNBRC z{GLgkyu!ldNwOF!c|$eOT>69TPL%zjv$<4YqCCe!qd{ee%QFY8Bw*Sr@YF$r>9lvp z1_jwSMLl199|=C1ILygZT*f8;2nV&r0{;5#_^RqO&*-dnNKjW(vBhQRZ80sVgknLx zBdm642H5+mX{NQ?E!0@Z0T+*WxbyeXPgZEMxku`Az~?N7{00|QPnrdG*1x1zf=r{p zaKkV^S*CH4#p|YdPA6;v7tUBX$dl`F*V%x{?TB=TqOnL+y_Db8riG)~FlfZux^y^} z+zrb&PvYvi^X$|T(0Q!6U^_3g>cY>BG4zXX8IGv}t}C=4$ZG5l7tn^+0$A?k&5fzU z?B&-2EJh>ie}c&)@LqI=Y4c?di>p`mk${$ffOPjaNl~C~{~lb4ySZ~l!BYMcND$z(hq+#)`b>r;j;db8>GC0(~*G@NUO$vCB um?7Ajoaaw@@2(Q49JK!jGA#LBpbR~vt}#`{is3t)94Zlz86gXp0`U))1vAwE diff --git a/core/src/main/resources/bedrock/block_palette.1_20_80.nbt b/core/src/main/resources/bedrock/block_palette.1_20_80.nbt deleted file mode 100644 index d330c7d6f984d4cd4ec2202c475f9c266a1d93e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176786 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 diff --git a/core/src/main/resources/bedrock/block_palette.1_21_0.nbt b/core/src/main/resources/bedrock/block_palette.1_21_0.nbt deleted file mode 100644 index 57366fc57f4456dd195497c435f5e5c7b397075d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177397 zcmXtAWk6NS7M7ImR6^;H?hXk-x;v#oLQ=XUrMtVkJEU8>1?g@iB;MKE`}j4?%&KqI z9A*xrVF)k4AEcFZ7h&v0ynbv^Trn{y5jadZWVNIA8@>5gFR|WW#U#Pf(uKAB`Q?7v zZgi@vK2vXW+U|116dWxhLv=&tGEQ;&c)sHFcGu-|2T!AStpC85-#p(wZey~P5b^76 zb3$iaPIzNWi}7cym#|IfN%V!fbyQ;|bBjuemz0WAD6wX1m8mFUI@G7s>^6UT3SdrA z62H8+<+~eg-f@Cr3X&;{NTg>IDo8nOdduS)LC2AgSLzC#p{!r6L>WDDtC!-P9kg7A zil0Qxn4%OKfE4mhqUa8GY%MfEQAs*KCy-d-x77h`=gYdPwU3Nx!FY3@lR3-OofqsZ z(liJ}hQyRu7-qVpYErO|-RcyaPVUS95=&##9?q-qk3HY=`>N#ZRKFH7*b379ws|SC z;Y}!bSpWOh`OW$1h#Uh4k^T#;%x4bi-rL8^#qVpi6VlZEr`sx*pv_=-K^V?W&_c$*zxnQT>poBu$%# zML|a*6n(t6mf>Au#Qqg}dGhZuP6q2Mfe;p6?^e#QBI&kzIpM+M@BXkxi{VkKNacKL zLGh@3{*jP5`EB|U)Gtxw8biyqa@U)FtQS?H$%=H_`*-gv zGxA`(kD|qZQanRQ8 zVxZfEu}`0NNz!#1*gnYN8oeKaq$8>&ph?q>2kATIs^Sdizd38lEP}PG;qB&ES-7Kf0G(Sx3$2l7lrO zW%d0q>!D9Sp9E%U<-6L7@Q!T}VC~-ATG7_A{ep+M)!Hf5olv)OrDlogNB|rZxEI)p z&(k-SO}I#@Cl{*UR*zhLPON~8T<6?*i2f!)25OSxo6bA?xEUN`>2d(?8#qMq%m_*~ zeNEGHp`3MDqw9E+Il^r5{N4llkuobL>r-(+@YmvBMHt{3rO2^AsPJp&d;TDZ4W_t6 zlQnolrt#7_IkP{?HYpu61C+|}kZ~_uqmv@MM%QSoTnB|;wUniEyEDb{)U&(` z;J#)|H0z!=N?*OblbRBdypP)wPXA$AaiLA(F@MomZOVAAP0}_uJDE7Dv$l&n2Y)la zs2^1{_2$+l-J6;hbblg=>#`Blk#oQg^AE} z6e7;ffDh4dDNN*ivaq4xdr`FQ^s8$;Y?{$s$-!*ylk0YC=)k)p1fDpem@aK9g`|n^ z2ptxRq5BCpu(D2x)E~rRD8_`u#6GGRS?mZ6vX!!+T7E74E5Bw!lq+(4`*1~Nv}j%Y zJ%f+$Yg|l>)J&Zxk4XHYx|-^Qh7|Ib2lGJmU_*)5+-488l3Bzocyu&`0@g?0q8J|K z?xxTO**l$}7~U~SyymoZUieV`PV`-P&J~tQ$O^iw&{PH++ua7L*=}&sh?BwDF0C{Jp3u#amD3C@`d-vzCr)`96Ouka6V36Fm-jyzfSl ztwwh8SYya0OfkYg=&RezHZ>2`E&95QmiN{&6rJiy_Of;1ttArLfkLu>ECvVM%WF+M z4q`=RI|aYmX87c6TIawg(1Ca7H@`w4K3f#VpCR<<`9^R?XP}VNUl;K4i#5&&pP1dxgI$?`4z^;tw zw8cve89}93z@Z=T# z%>D-S$C-z@z$*s!E?;?LD{{t88q^iITc=w-9omq=7K4hs)pw1VyDQV4TNlsfZ{tsL zVR>z0=;gAf9AQPH`Sl7Ibk2=Jlqd!?8L8m#8*P-(Jh-uQg_P_RulB1 zU5HV!3JH^n_<)o#>)UNa_68W^sk^_rl9LO5si;@NrDe`uOTmGT^V7w_NuvzmqmCOt z@{O_!8iJ;Cyfg*BD7HsW@4=)w=TGb(J?*bZ&j+Y~B%>+bamkP7AFyjKpbmxGTw0~r zqd-a&W>9DL76?Q25KxjTTWIPG@t>X>(S_B$nD!}XJJx}*Z_Ul)%rSEo%coL+bhrGz zbG?>v&u1abE6sr0Q- z*7I$lmPMo?&00r%|08F?Ktil+Tk%s@|JH&-4dwREZ4C)V+n+Y1$M9-dh#S(vU+LPSA;%j2 zQh@nH7s$#eYHdKY|MPw>tfp_rCMQ~z@$QcDoVIvdW0rBr^Nk>3JyEHebcAhhVRnM? zEPeDq#x3lOL)qZ({olQX841RLYuwY{Z}X-d$`-65ae50=6O6AJy+4Y29G z`9-{N+R{@)-c@e;hmQ~2vW0i#-|!|vytj-Si}kK@EiNOECs*&@S5Z)4{n_C)v2U-U zLX#0JR=IzF_Rxe}EX7Y-AV8ij9h=&$e}4dcq06V4kKa?(MS|8TW%6f^p?V0J#uSr_z(Uk%HW!FtLxXJG*oDW zvF{ga>YhAJaZHVQ{b=}>*uDG1e^^UPVr*O14pAm6CZX;l zS2vL`Y7+&)D(d-I7C`StEzL1^#*&UK#Z5C~ zC@gW}%RTN|FHMjNbUK}ren|3*wGu21-pWalQP`t0I^Q^k8G%t)ShaZJ=u{^yBPs)1 zRYdDodz|=eP%lfR*NrA-!eC1=Ncny3(fD-`SybQN!j8wMMTu4+byG9nEJf!+Rz096 z_)RyRKgp;f2tswf{c?y^CVGZgW`E!iYk*q=BcIiqPjZQ<1|cn&uvH2*!1a?iSVWj4 z@q_I5RfQ^c0oP`lD@e#R0@tw#Qah@Iy6Grh$aj?*5>*5wl|Up=N;AEZ0)+l7Zu0}T zEi@XUeU|K3flvfDCv}7aY}cQn1K}Xt+;3Gwbj~Fa0GSd*X>Adp%%0yNs^AnA${xd8 zK-AtFT7h72ZDsUZCWP?i8EnTpI$!#?1$3~P!iNcK+8BT>EBjRG;(+w^YghXJgq|S` zx@Ceww}~TVVN0XPU7=go;$uML7bp`yO9KQL_UGH8prLgwY;xEDv$RYuLDFsr|E@>suoGGmRI35JCccXT{12w|=dzg>iO&15l@B3nnEfU1?>nQI+ zGzf#6+)Xj4noX;W1E>eWB74~jz*6C><_&SkcJ(t@=ciQ?bx|Nxd@XHZZ9yJ_Yo2QH z01typKJ@=AU2iR#Sp(UP$$40Ps6uM?rH-1eoY4Z+l$NA-rUKQp@stn&fR1t~m(~W? z=#;KyfB{seQnw3&T6WqxBLBA8x^yrAVAP>vSqcd1X7e2#xIggJ$exe&pTjk0ok1V* zyJ=q2b<=I3WeCrQJH&zk>WBB8Q4$OS51U_TASnlZ+&QQtj8|R*7*X6LUIGxO4Z~&l zOzdAYVHuS`z;`X|{|*A8;r!6&1X8M-{ayc;F}_hGyUUY?~gi&Z|{+zDA)HF*Y%wr0)4PByaxTPMtt^|VB>^CBFiC0gB&ZyJukpG6IL^) zJu#0fMq2cxezUmg>wZNr2}oyLrrtb3e*-W(6ONt;1mF|an*GcR25~?7rUR%(-tlp; zRos9|AnZD#&XL;-bG7TgBp#+;u(<9f-#O z85`4EC-s9kh0QG6--KX3LJ-)qqk?ZFe}4r*XuXq8S1Lm*K;Gank!14d7BKF5xV#)3 z+1Y7fop>67@Zg>3-KIg5DDuiW^!Hu>(0w!U^Bxo2sL<rcU=a z1yp-OfBdbRC8nTnNO7PY2zQZ5d=JcU%_iW3b72c=kaj_^$`c(N(QrM`Row7`7LX^b z5dap;XwfSyFQDpLMus)nW~KHrn5FyhtLBlbU>o{C9$K-#RW<;O-y82RyXm9#ZS zf|ih(sf8JV-Z5FO9Qqey&sT2$$$i7(X(jv5l)Lg_WN_r_zK!u&@*5CsUGch7xFGAU zYdz%{TWAMJQ-C|2`)B>Ft5wu%P?rZ)i!(WpxahA}FgavS;V;bb`wtz6kZQr`RxF~Le%5CQSdRV|{nc(sF@X1i7Toq+LEcIB zo4@`k+tf(^2nEuz3oc}ArTVO6M-eZ)9tJ=kT75a$beb;)z}nTkf9nt87WK4e`(IxD zw0Eu^0Vgp$8}G$H)-<*42>-V^_g2^poLtbc4xh|OvW@P*BNFJ<2z1KqqZSQYV$I0&-m8Y;=_X ztVUhk$QfXxI}#8a-|JQfH_o@{T7iAu?(8>bE)y<$E+p#|ZXGTYAcY5N47R^z_#V}M;oFLq*tDQ zN}fbT1BI(Ep*vFptFAw{gB9ILz{&S$9FdSZO4NnTz2ylF))zzJzX*tGxy)CbHUJqgkqWVYh58Xrw}p_=)ow)22o^3Bjg_^%>W|-%> zuV=F$x8`iAQ;^#?s%1jY;w(a-X_*K~BS9vqA;pGkHS)iVXYA1Egt!E905Obt`~X5a zvGMi)_UFuh{N5om4Dftm+v2aN{DQ3{ip>@J`)%z!h&mC^^}-$;0;s?#f8oE*=IZ6( zuc!_KPRh&WQ-U2Bg{H0o9nzN|S)XrD_<#6ae=hBSF1Ii&oB;=`R!+UggBW1VyX3zk z1DmkUOu`s!sRG&=Ebp1=EQqegzFs3SSjNloCq_UtWCR2w!8Z5vlciy=d%d z5fF7Tv7zu+1u2TaVaHt~j~r0RXP0e07DO-?Cz0!4bQH0dQa}zp$o#&QhfBYu5g-X# zf@DL=4ED@7xdnTupfMjU-~LPedd?P${;#0ojm-xepY51c-x6D4z46bB{YAFI_65vH z6`duhMpEG`d_UGd$*Q{2Ue*7l`nn&wYOZY zcQXI_<_>K}({dTebj3m+TH3Mz(%hHp<902Xy#c@qJ!z!9+9{jh?J zvc6$;NB;j*aloZ%1aWD?9kNKf&YyiQCU9%go<1E=jKKNIWPoVWvIUD(yQ&^=sB*MUy442m3@my6Z$TK-zZE&CEbT1%Up{>)!?S zoc~8ZYAbB*Uw_me>Hp__8sB}nwXgqrxLsv=Q)LyzkI>QvW*6N5Z?xk3x^@CC;F+T+ zy=^rS)FADFBnU92zAb}SyAQOznDVrx8axc_QDL6^wgt}*Y62JZ|H7cY#H+9UTc1jx zP8assNh{KSp&wp$4mXeUuQzaY`nvyX#|FEB|F1ZQ6N%`bAl>?4wXB>%=wIg@xiN$X zI%?&O=gns{FrMByR)qfjst;K2xp94L=eYw`3_DHg%zxfa+`a1Ztfo@Nb%2vMsI-Ky z2mm+SZYi{L0ldOm(Is_E!DB&8`VQnHASB)(ljRSQ06I=*PMK>jK))+|N|OWj9aIgh z^Fo19cedg2{SF*4KX@?c%o~HY9}G2Q{5u7D7-zB@1FWI8>)!sq(rN0T(t@gQdAf0- zgCmquZleDjpXE{kL$MZ$kSRR5G`0*zjj%*{=nVt_KP@#2)h0TSLTB^3+w=Kf)3up6 zxi$n1z$5q11r9w+G^C0-YLKm7QF!?X!=?5n! z2;!7|w0%E-Yb04@C!UEM5dqt_Tx~amZ>R4^E%P|zB%O=wSa9DKdM74Qr(F}aWJrc# zB@t1Gg*!;S?qlK$Rl1b55R{o_K!PVi~bHrq17R?`df1!HL5R*T$YyQ}>e`^ex4dc=j9k`Z%HhQ!5 zrSiS+=4!)jKosx8U_o2N@m94^|;Uso5mA=c~-tw59XG9f`phlZ^c8Yz&x6z3T=SqCZb zM~G_ZBffFOtL*ij*{~kk5@i~kqq(q6%6nbmY=cI=SHT5T)z4J;j{q?h%`_v^6R)>;#C z?s??lGC#M{BQ*(X>YW}J{v9@~0~fAh`ILYsrN#EFb9%tAkDmp9?7&)YFuv<1J+rY; zCXdsv6q?yXBgj-azDAd`ZFx7*X@;wwjMp&-%eWS5C-2p+Jq}xuj{95hVbZ=GQO6he z_m1Z)5>rbS$m(An_;U989b56Hj)rmFCt?WRrnPRV#pnOV|mFwbtt{E?V z_L6*cbt+$u>jy^=F7&mVcmBbgWPxdITF%t`LlJ^gUW*DH6d>i01-1lae^OU_b|30s|M&0MCh3}(pt&NBer#QZI$z1_>MCdzrB&=xk{;_ctM?y< z{JNY+`%qEpH$JuTd2u(&(^jf=nuAhm>q%<_AKvsK^?=<6oC7ZpVihl~*~s=a2Q1NY%RUZPr(K3o~gf0tzZ; zQDc=kWa_NUs!{8huemrGLN!j)Q5{|B>XmY&Bq?wdQzB!PSwxHZrMZe)KOU2~Z7z2f zROV9$#?SAc>EL1&$0;Ed!-j+o$Oq&s{5uNrmK*d}7mMAG^z+hFE`#4eGpEw`DN`w( zVVY%PWE2^Gx58oKO+CVeceTO+^lYt=E7>ee)KZ@IP4|#+iLK{?FDAVt`+1z71=BAG zFsZ*|mgK}^*`u^Se<3|T>#p9tIi1W=4c2qhC=7GXW2e2rwZa<5%(j40)v>lVg{hKN zY<-H$@K!qWrTvBeko2j9K}IGAQGp`Syyl0BcG6E{76x&W^!S&Q@wWr%f;Y86o6c!W zRk83z7u&o^p3e4?cq>9%{FCrXv_+d&g44apZHk~5v-7Ylaui5t zRV2d#J!y+oWLjgkF&_L+D9W zd&r>;KGjJ5jcK7d3gd-izcq97WPD;hen6LEkFW%`Jna|v$im>;d&A(UMdy~>ADjrVdFqd>)U?JmS zLI___j-{EWLr{pJcqM=`@n<=+L&zz)gPG-X*9(#*iWs4vKD;VM(ri)%Og?VTt%7zR zdqm+Z?D>m&UDIc!T*jD?yq^jb(u*)I)5JDD(8-mUMt42CMTPsm8K_i#Sul>M0dH?9 zk_nH1@!J8L;XKlplGaJ5DOy}npQ)U!5lCGsTUA#gqojr1Z3rTl*8;Q@`=)gg?tLOTNlIE@$Do$6g zLxm?@tO56Zdpk!EH{djNN<*|mEh={wLr>F&nV7UdqggthX0#^lmQa<;AcN?}@A4!q zHPY)Pr{jT3@9dQrOld)$qG@V03IKK8*=G>!k!_ z-0A!=-SniuQW9qSO+qNv$V{BC(+qz!!%Ly3qCYu-6OH%7X1$clDe#OabQA|Nm4b!= zN^;nrGwj<3;=bseiiBM^l*X(pTPfULyc4i{g0da{ZmdT;g zrG>2;+xFje!tP5~O>&kbrf;RMy?=R9vF_Gz52xrSitReS#v91m@vTVbD}_Vs8`n16CM+W+1C-{D^R(n&RK*&Cn{-*?<^&FXi7*cvISBe8;CY#+~|R@3fK$^?Ufur=RwVl4uCJa`kchKl?05 zZe^&PjTk;HWn?_SWe)ZFDj_F3qrWl@n)tM#QyeJcX%zH+_s`5^G5&&J?%D_1*qt`p3zS1-`{ns#xiTA z#eBA5d-IGEUf!Wi&t7A$c?;Z2G(&v9D@%(dOSmU-TNS)WSf;-EtHT0see_8xl1-~p zgpBs?WPfS1xs0}{*A=NIsIBBG7h)XwBf>|LJ}!teHHA3Ut}!n0nsu?Fs}d|Y-28H7 zoG|S6zEa1YU6U5i8Ylr`_VtJf(TJTKu9n`uXd}WnmNb z!F()L_QzR@uU3t}BEx1#RL|n+Jx5RHEK=nVYmT_lrI?47BR&SdqeDJI9ek4(ikfKE zqTCLXCKwZsterty6)dr#WF{?;u9@>ht8+7ojw$hx^%TmKSZJOvG@=&OnD+24)I#=q z^+kF3_51zx6O>)2^3Zq} zs^<6_2kugV0o7aCevHyes)hsxlk};j8$RGEmsMX|Vj}pI>*V>im;jtIxUF6UA6c0} z>*8}3s>1`nytFkKo4QU-hJE8#|Ui zt$IP4YkmTKUrree;#DXtGzX(uuK@~8QbNl9k}WSh&Ltt7l7cerEG!BQb`TDN$fJPM ziZVQnAa%+s9kZp^C^Q7JsGh8+*zh>v1rl<4<2^oplPb4&>nf|&wEi6_z()WZb`V^0ko}+!Oc1Z&*Cs#>XJE@7 zUq)zrgM!N~_P+eH90&|@+f|DR6qr-)4_@EHxl7pcv!aNQ+#oNo|Fu+nhg}S^DAc6tIW!N9!hpL~_Y3k#!A*NjXamma;xZB)v zyXL?J+}vRENDas;`Q?~M4HL&kol?SYTT2hHJ{aTCL;!@=|022QgBUpDFT$1_T8K=Y z@)fHksyKBr2r_pWMxV_4$rB>4U2buZ-4U2nNz9X7CCqZL%PEd9Q*-JCz-e6aqkuF|T%b1&BuTUf{+DL=QY6o%Fug?hh$IE5Ek= z4p=i?N*@9+a+<1eL4yois*mbF=NDq#oc8^rX=f`QG%BwUt&!E_dCA2i`< zT;$kiZ=8hf0kYy(e{uRDn#Fm@RXhL+S?bo_qreyGq?wnj_S|0r@XX%Y4=I9cg0$9T z0B3%5{PO-6+ub1r4%uhUYm^d!#l%-!e3*Nw#w64Y;EMPR} zr!79v3=88zWfTR$G;>R}_`6A9&ntZ!S9d^Z*%q!2Fl>g`Qe1tY=t!wk=#(wCCKNQSI67|X1N3qlqd12PQ{qOP+cu3cnEx7f=;hv=C+ z;hIaB^}r3Ws)g`9U^$1yQt2mv>v#7j8WMn+wzTd!1g42Gg2$z7-dUZZe1-PO_dg+b@wAWg@fel7Q1QI0AALBE?DNQ9w z5N2;Ju4p63=3)9~gz0K5Z%EYs^?)jX;l786b6|>2+}8*JjBvatP?X{O_6!GJkoC%ulN&4)+_a18OZ|KvQW6uXt zB=cYMOd0#%q5*Qeo3->*D7pY_Sq5~$G<3kxUqZ__JRD@a&3tLQ$ZE1lwT~k3A%FGEAT4q75N#Kag5aq5-@kPQvJ(1XV&oopQiX>3{`j z^+PbQ0SFB`GVf{uK=Qr4HA}38I}J6Yf(xY%{n7)($iZ>4wIc`vL+EYG0(B}tqUEz8 zDb;0%QkwZe6~E8Wjsmbe;Q2lY@#=wxf(eVGAi=`T67ArAc0P(*;c zLn2Ylc-6o(v3th(FBVg#JN`Pu7qLQe^oeUy5YSonZqf)BK*F?auL^7<$hmrKy1eg3 zLJD?Hyha@blmWT)&gaRDHK5NePUL0Oy?|7#F9;xp1fK(h-QyjR48A5f$+H-{|Fr<{ zQUmU#am!!{;N*2mRWugicnHpcopGyRiupA3HGt*!xkmJmIm>4bOX;HFlMm9Sn6e)h z951*;KGVSoDA%FmXa$z0C=z^27GYILs*0pe(SaFy_3bYM5OAtf`(NLKNs_=}Qqx#D z7*g+MfN+UJK9)=+M`>?J!4C<1)2~oz!20mY zx$)QXWI>#t%>i^7GE6>T(C@$h1w)uc_a&$Jg7x_~7(jRE zN`8bCm^zI$g#v{oUzcAGh!D%)yt@Mc&C*o`xAJ+}a7aPJIK#lq80crS*b*7y8bI`) zw&Ichx}?GB7eF;gb3;1$o45~WcdsCPYJVm;c%{V#vFC>Sg9~f>3pv0yn_NMx?Z?Hu z)F~+|wb0Yc89)$oj_a4U63XmFQM-f13jO z-`SQl!vis^&(~?pdRjUZQsDYfDZ?2Aln1P`1~b+GAll-Tskx{QWq=qXE^klW*N|d> z^eH=Oy8i<2*t6x^fA!9JR`-YF3rRpnaXyrIX5rZ#G3CCFNL9eM!)N%2FW&!9Gs!RJtXpQR~yBf{oCNtujJvkYccTt=a|W}k_6|X zhj`@Ym?HJAogXL1P=Y<^e{LK*!OgFe`&piU^PgAp5K~~#+fVpHB1l$?=O$hsEVvl_ z?+JDI%tNMzR8NY|n&cGgAF{_dH_>bBXNH}Ow_2}9nfQ`aa_;PaPf!wNGgoMcSFWUj zxEHJQzIe9V!vO`s=YoXh&#o-_5qMVj7{5;iX+O%k8fADE zyb!kIBweK73^B$peBn!&;j!en%ssdz?Zl1{xw(nIDSKJ8WiQOnmQJ0(TAuD&Esg4@ z+_Z~MJ#O57GSWU?Cw8+P zCPeYLl>6D-Rn=C9YK@>>^l5F>J_T!YR%#o1G+pvnD zb(ZSqm06peYkU&yzZ1G+cRb4*EXl4X34{chALAU770UB)$ePnQt*;r{yiND{{A$?q zI$PO2i)$l9^)EMoujkm$>CAOqCD=5OP-}Ov_V@259dG0r#j$YmMJ%>a<)O3oQ>`bJ zM>rf9v0aUgXv-f?XyH=ri z>Y;_^>!#mWsf#T-PP={gpY6!*hljLU&(#R()NI4k3JeHPv9i1+ZGK;MpWe zF6P3vHmLF^GKR(#J1{U+g`+yW*U{7S@9$Nq83dX*D!iPZ{JXQP zO<#F38RU0oQ5A6F!QrZ3YJOra3TX}#7b!k(Hhqm^Y2;v}_>%-Zt$+YB{$r^4vtrge zoP%H{x-To8%7e(1xd{7`b(h#i;rS@5+MY}?hdCj}LNKpVqbP1<*3k!fQtDuX_SE8q zi`o2yvyjV9GaZEzZ9a|?A{K6BCIW0Vx6_JSE(W47M&L`&JsTXd5X>JPIZz1kTC|EZ zy<~=`+?sJJ@4^#DEDp!LP?v~k70b1?@00gl#YCEV5pTWu>@*=|W((#5SNN00% zlsCEW)spifpjrBLZBT59eXa5t;w2}I?n30|U1w^U9&gY8bhCaTwGZrPDI%ue^;ZACUt;- zX4nr`9k{c}mco4_oMd0J;)Wxb8{&^1KxlUVRi@XB-5x23*|@a@*NT}r#RUa2F15&~ z+hF@~P`!AWlYdTVc)if%)s5jHf&G=p*oWnBc$5~|7zze{#ohZ$uHWqaPup^t?KfV8 zo}<+*mwM?+2je}pEa|Qa zn?p%~f^L+uk}t&}Jl9%F<|MqWW=h2rj0t%8mg99RPT!^y^_|g6^j|X|orZEsd!>`> zPGZ$hvVDSEN;}~_T-LhhT#e;_-Jb)8^T5n(daufm6PKc2*q5^-XLD-bhO+wIY|F8i z3I}JtKZiInoBdgn?MI=FAl{&PlX(zXJBMe0xBL>6JqrIoS4^@_F(FcDAm*!PX$uQn zN9VKCnW~}J_fyWt<1L9zX*FK5@%0FFQ7Kx%l)`8AJ1>e2p#?Fzv+n!w38<=I$ePla znqv*2p)k4!I`Lc#W_&|_`)|X}hQ+N87s1RS9=M!ZZD~XHo!u#p2V=p}z_t~`%iYnk zMm|6Ble{j?ic2d?)m?r-NS+3)R;3wj5TbC;w-ZbpS z%&6Oy0=@j5PZGHJ6>3VDmI0o`qKGRl0!xTIzL|y8g?JGE9J+`9kjQP_3eAVT#&k8aAf$9{pJ970U zY}Z*Kj>lCDL;#g9uU_=*f*Z7q4o#(%LH#D=lS-Zjo=9eJ@4}EJJ?qKzpeJAFX=DR@ z_p{|XrvZQd=*oQfM4NtIjM$Ll=G`tmuG8bMQunL(@Y~8%2QnV~WW@*}?~shYr=v&| z{zlA|F<@@wCq%K_yS<}gPEsEpGPr8u^!SE|veReBN-!q*=fDcu|L!L$VR(PzQ%q`? zf#5gtBD3{k71}s^O!y4x=OO$8fh3cgh>qf^0$JH!la*KSN_dJX^3jl6M%?@;%LR+` zilKrJ!%kiw!nj87#zoRmv8d^!ty}(5Vz)^BW<`V-O)XmPoIh@Nbnfp{YCf89x_BXS zzFzzB63IeQp1*k`v}w>??KPdScQltMW0*qdEaY2D0~nJ`6fe1LXt}5#aP29j0@DmEZ|Jiuj#IAD>Rw48w|d-txZpdbfKqQv{ou8nPO_JuXv&-9uG~4shj>DcymLYht4g=pzL#s!4HsqB&8V4VG-?`@JX&wjb9`ux94Ubu;1&Bi2iylFnvA|HQJ+v{9dr6 zj(IopZSq8dHo?VydA!>*%8*CR%8w|s((C5GW*^Kr-|ICc-fm4qF6YFpM9C{AN6H(1c z19V?d(;`A=9|~k-2^XBu9W?}-<|B6QEbOVnhaMHF8UGLxKqDkpc(t1iy#+?Ok>kwa zKF&zrUWh)rxtn~${29@WA#C1Qw`(cEkVLSIEqo?e)e%nl(h%XzC{bJ^ZZ6(}Bmuih zbGjlj6~-@umgl^73d5~9D+9-nxRSn3%1L3P!d@YAXXr!%RiR9m*9t{4Buuyu9nRX^ zf7$Y4ip-sMj;PLe+2s>>W}}tpmaLf++Mha!3EA+cs{CGhnn$?8)}{IW^}Vng+fopn z#50B&a68gf&cX8(t>3x|B@V`J!d&8hTX2aD`D&(a3bvM>Aa}`3uuhaFosP z4Q{`&!XM;YTdubOICiU-?D$u_)NB<#a76U7#72eAk78;QA2Y-cDAOft_0T`J&K1vM zzqm8aR?M;zonwqnC#-g|&JoGNVJ&g(ml-s93t@*Csd@vlQ+)C@;@fM9sz=^Bj$CC; zHOHU{4Az2w`&lMh^Hq(rFV6Qk@)I40Wr*3XYE0oPGo&V)Z%c>DR7tE_@}sn08CCLR z&DfiquWMBm7L;j|bmY=~uLAA)e$u=m94V{W$d5F~_j3_6ef5jZ0(=Y2r|pZRyRQLV zcuO$Sr0yea0w}FypSGc;EVQVHs9wQJzcr>4boLS8Fj6z^@$~qrmQTM| zO?#Li8DA@(xFGyRxR|^I@;qYCC@Ov=H!11Q23DyJWMiJwVJJ5Vxuf-P%QlNzJC1$R zxWyNrYX&Ce!LjQQqM@;`TinZOU*yOe@p_Hih4+oEywBC?TNMY(g$2cKIU7RYeU&~` zBcaC4ITc4~`-)wTJ(-CR@G^gsuFz=*7fFW`}jgn;egv zr&+Jvg>0f$5p`=a#r!k>Ej|8+c+X{$MNxO3u}`7T+CPRr6FBh4o_~m_1@*h!^tG6C z?u*h6X$yR+0$sCROi<<~aS4c^EwP-xa#pRTgXLlpvPT6~;J%CQ z!+b;a;4(dmR`m$^x@an2C8oMumfqG+I*kZ%5-Fo=Smq{;sLk=g zBWSH*oRe=9kThS%|4FRZ<$_o|p`HKkpX{K0ROPax{YrA z2^V@Z?qHZPTf`!0kXKkuZTay5L=dgg)5-f~b4;4=uA^z5sE&byOO#Vz4N@_{Ag&{H zxNLCJ72Z;N)4UrfR}aQyE2nRvuzFCL?i<5+#@l}gbq-`EXw6fKeTLhxH@&t3W37xf zgBQlpX7H*Mja56G-fi$;xxU7C$45yr??OtRzSVEAm_NZWx%LOB=j*w;Rcl=?44(Lb z(xE>>)>)90s6JWoIahOjj8b-MTTuK{!cg}zPVoNaOY#=^o>hS@l{Xw#r5MLUJf9)? z_MyY;jjR6rAHJlRU)Kn~=IS3w3UsWGqvxD1A>=emoy`Vdfw5pPi@wag7uwT%3ibFf z9(C}XG)-vq?!1lF$05& zNE`K_-KqvYh=i?8-veTs9FeYH+FTS2E5j884s;m$7Q?R~xHA`K|1=CforH29BTu|g z*e#B@O`()ag*l2-@ZEw^b8ZLFpnuZ-1)|>JN$+^S zVzhd@WP1(haarmo7pqqF!D3+~L3x{h@$y1?yZ^XQct+o(JU? z#;OYKz_j7bop6(M(2t6q!KZ}utxAK(jGtw+yuj%AU`unMIsaW$ZoB%xP9Xr5{beoh z(Q*BlB1J3DMlo#l2O7Db9sxTOkSA+z)sS-IQur;tJ7i6h7v>dJ)JYVdx|9E%qrJq> zo{?b8AlA%ygDDlmE+T%>WLK;~fLS=#Kkp&*yY8&8!E2RxZs!HVLvp*g6I1*BC-0hX z?-@d}@>15~B`%11wk_-V@kkV+e>GwvWdYwxpLY5=wLS8La<4Ao-`vo!AJGGI@YBE# zO|nz$p+>?g7k4D00P-iNlD*M}+sE4n%Xp!bjXx2|_|(6aq{2SyTMIiGt>GejSS0R* z1$(HrC1`P<9!)3|bM(L&x~5Ta5Tb5hjw(q?{>{v3Wfq_3y?Y%vaXEU=ku6HAX5zJ) zEH2-58JtH(QA3mcA!oD%rET=N8d=RlKEKD*mqnd&q}%T@;g>O967h&Zp!-W(4rG}w zRt?n1jL1>wS~J2j=}(2rroKE?D1Y`fQkd8XGE)mLQZGc`)^;s;(XAD^w5GuI|53i{ zey%FiG_V$mmq#vtGQ}fUmfsG;F8%`%Ar$|oLaXWl@~&CGr|gWIw)~V)M~^?pq@J#W zy(RlsHL2qstdeZ>`lSx!A8}M)sE_${nIHT#Pa=WOgb9DY27Sod_$@>VnlPN`Db|u1 zGQN+M4Evo;t`(?*C!U&!gJu=Qv~_V!?C5eni|f9JvZGV$b-cS0LXAO-t%>{)X=(j! zvg_Q4y%wm)ZJlv$8xH5A8Di{dzO9UEG@GX6w6WB|Ayk= z@$O)1C03B~iw*XAv_xt<5dEOo8PJU+2%wc!W)hzKlGF@zbuv)h16kZdGQ`)3NwL;2aCZSr> z^`arVGgkd4;%6nd&RVLw?aEYvnb>Nc8B=CT}mL0z(1R>IVq>~z7!(3V18_Jz>4pMn zmStart|sKvUU`YQC_>MV3&Qr1U6p)yz{-EBY4g3SO%b-w72px2V?`EFO^#Njdqkt{= z$r1i4rEOsZNE-YXO!)o7%u(HD7#s+VJP9tIgZ^%e{M$vImu>5>S8(!|Fmf@wqJ=ZK z-$vP9jrCK0gun-e*CA$oaEzaDZIy7~8aBNBFVUTOw;pJLRHIB9VF6+iOi;hKh6e?# zaw}-x1c8-*w1RsLdzJ~ueG1Xsaj8GFlSS;`w*B>vOHj`#kCG4#Xe7&ve*Mn;?H!<; zpS$^GcNic8uLkbaLz_UI=;(W4rhpR`59Ir_MhI_&<#;gM;5ZYArOQld5vZ`~4A!Lw zm-q(+V7KECy$$2%fs8d`yHz0of?LQpw1R8~js}ZKV7zAxXa-y%Mj}DV|VTTq>~4X7%pWK;t9hB>{>iT>jr@)0@Ql2$^jD`FyOXWFT!_7 zXv*t)7_RJPA7)b90Z_{qq#*ihwq>-VU~mbC{@jSXallTsuQ)&udaQ@}L20;SnhYC2 z64?rfn=PZqOH?d`JNQ$sI332(Gp!{%%e9@o0L=1gRU840tRljJ*Tg#sUBo z_Oa9R0Ydg2#SO3p_Adz16Pmk?QSxVqG}m!BcmIzHpS$8Yd3c7Ix*po=rf>BYeF0>b3}IAmZbU`LC?nmRn}Jx zL=Y)$t8yedfj$Fcyd>4x1j)#Ykl}@Az-9+g7(%}0N1&PwR~yo)Kx7@VscQ~wU=V#1 zcJcMqbg_SMWIo8{U*;329H^^tKv1$3f|t@JW@rdpzyoT&aG$Oowg(iZ@?WOm+l^k*tjfg#%piD5#6>Fk|+*^ z4Ce!Fr-*cy1r*skX2O1ln15xpCEV!AgwDvXT-3;-^R zhvnaJJj8Q&e%0b1=qq+a7u;ykbGT;#0{?xc(_{oij8>ofCih3riiNMnA6$fMxenka z;(&HxebW$N8zS$e&${MMTzGz-1|~@*Wg|H-0NQW!W{K4!5Kq^*p(BW{jGP3Q?Eaz) z1#*VeBAmI9+zWQt<&918F}nmMKtzLR*#Cbq&kg8ovLm{ta5pzIIZ(KdM}!T{D<|$* zKr8X&eRJTb7ml;?NI+PL9}vhv=z~Alo&wj80bEqRx7+~>`SpuF>SO!M?}!`;yTOW= zK(F=;L7X=h$;U4WM~sH#eJ-os2&S ze&_20gD1RKy8w@eG%q|^0}$5T)I1bGin-K7Xlq-02x5@$PhMU9H>c5=`2H*9pKU(; z>Bk@-mt_RepaBy(Z+oziU&6YrG4Mf}e;twVXP}eywpkP^TlN8+VEmo{diNM?t?7gUNw@#4*Y{(vv59wI{hp)%pDlwuNuNvt7o|ge--KU2B zi}n3Oz;$isr7$A>=fbM_PKd_0E!=#z;fxSDP#93D_;2pLY{s60V}Us-JHO8ZiT7h< z{!K7nu(Pzdg`EIIVB7Rmy)E?tO4YY_OfW230P=YB^e@{sqMyHi_&626@gK;i!X?_r zv>@>^oLtHT;lIH;>ry%*Bp>rRzC$oxc+oX4@b(m7XzXBxFN0RyP8?4dK|xgRS!#FK zIC3-GX7-VWFd}!S;dnEhEyDf?pW57KF7H5*KJ|kzaMvP*LWI^R++lbraJ({2G(d~U zshuGFR2XE7Z&iXIXzw4ENaUy*;5eggxm_E;TVsG3ui|i-2^?>bN!n&``UKksRUs+u zd*Nne|J$`J%PBOb%r_}>X9yzpIdJ9zlm#9{bf$ZZ)m&r2bQ)5KFa%&edumJTG~ z{X>obyaQ}izN5lFj^h#Mr+=_J4sO7b!}nbX<>_%hs7NcFtRCh9iU@iXw_id&f@3hr z`Q=<2;yhsSuu#P@aDD1~amvD^2F4&{@F9JY4Ww~j?+x5YqrBi0Jn&!k&urm{f^&vl7%qPR5|nUz z8>S8Ww(x+s!Ki5Q?K&)4OsWUCz!(%Kk`p(B1#K$Bfuh(fPP4TU*#Cb&Yv{7S=t%Vx zC&o8?>G8!j$u#CoV5Hx5atA~52l<}IYB8dPx702sM6XEgTQ4~S{Hy1QzZ+j1{^}15 z!Z$w%SU?`!%wICM5jLSH4BX4j=dwCG%16AR_Kwbjj__HQ@{pNvhU9CaQcI867_7X= zY#H$qjh^ROkw=epXSMT=y(@*ax-#NEDJqYgN>jRrZ8+9wzkY)IGTOsa;J=TnCNWDb z_JNo1eWV9&Nk7SoQO#5Y@8ZeD#W1Us8;lnzhpskFB)rc3Cl4Fxeh49(eRMhQE^fTT zYD~o>efm?ZQ@u|vON_U{u11r_Db<+x1DzOtBK5`5-Olf*zJe?*6D>D)XG_x;_rPy~ zMo0#4HdK2C{^IP8^*A^EIyWCWru&Pa2BfAzs_^^`p*$t+$l^8`6Qh=9_eM zdgU~QGf%KQxPP6D&Uq|7Pj&WYhe&0)Br+C}Je~=}s`zUzRvvFzy+3@xenX&j8GI&D zNe?e0XC>P+{{Xus@X{Ym7tV+%n$E@G`=p&2-JOw$U5$3J9xN#%a961=S4>5wI*}x7 zqxSrbTYgLJ_;aMfm(5wWv<-V7OK$CI>4Q)&)_RsiWRNV3ebP^G$F;v{-2-2h^^LR% z3@(VOAmwLzR{yQtTC5PL~3U&6o+0Up@t=?BTV@ zgXFl=8)Wuu{Whzai38o2Ueu!oj?(CC(o^|0h6mCD^114=)IW1Q?hW!k+h0$#tDSg> zG#HUa&PC>Y3(zX8%xj#uCSKrejox=0ztONS)_k#fN^cID4Y3w(Li>XsMmV&oS~Kea zupu?(zg8!4ChQ9`i`@1kb+#M}Qd6p4399(L7g4D_geCT-a1mMwVDC#U+N7@a$n)ud zmDrgsXLb|l-?zJ+5%h*1CM}uu+zoSYNG&jteFvfaw zf@HslkCa4<&xUvD`ZNQ<9rXAbD_+qtgZUriJ#wScb& zp)E``rJl}OV=pl>U%upaF9O{yMBgp@Vn(#j6WtSUr8M>>lL^T=!>WzI6?@3TOzF)m zrt7mI54E#7zu!;PT@%CDwQls)LaGtYie(gG;JL|e*iJc6Ki%--=@wKeB}Ek>Ub^y0 z!D{j{Y3aPFciyo9>xd^t;Ci|7WZHo`m=gO56BwAk9(3&2oLvX=3_xw9nx$AB+^q+! zvl^~UnvScH9me*Q7U+d7A;5aO`^j%5VuT-$5Vy%~M z;SfK;%+Di(2^zUZ`u#a%)-QUo%bsQc)zQ5w*&@STeC+zlt%M7fG=U+;PcnHL?XLykG?o>wAZ^50%)b1FV8 zePv!ryPr^&3Zj0cm$--7m=6^3O+}j?E{M^OSi9=3#*-xn>L+HcV>sXr{u6Ocut|#2 z&b$m@6lkDM*-GiVg(wsnzpwr^EA?BlFZr>)99fcvBL5D#Zn_Amtdwy}!894_(FeYA zW}>)~N;{*`nQP%cag`diZM6jVuP+(lvo!`3*E1lS%UC2oZuFmpEun}Ig`QGTo`j36 zv~0<~7+r&jEx+2Rr9)D!xSn=VH2;bg{xICTDe`sj8E!+*o zt7mZ29WZtmu>{tj4+dm;f|Zq|05$XAV%G=+f%bLE*Of*90;(XInsC`_zc^pbGoMSL zfkE3PfQA(xM_!BADLt>nD958EXBmR*Qic4|6sq*)oVWIdEzP)(>+!{q+n6!FWFX>c znHUnBbsY&~&@zqD-Zmz%LH-@QUP~IMy}-m@YWk-1t%nVW6WSay9q<(|!1u*n<;nm| zk{2E=mAYG77=zIlrt-NpE)t;Nop7ir!rC@U=Nza)(&lg|M+bRqpFAcn@mEXITsY<{ zHJvcLnUVrS`MN5Vw6s_{>rk7)yyn^s6tS_FLrYBipe@jP8gC-%N5HmO)NGyM!7AD^ z7EY-oITRvVW4v8Sg~XwBBIkdh?pg!@Njpi74z>}|cb+bjjldqF3KDxobPsme%`b|P zMCz_t0N=K&RGAeJ%|>#pkguW2yemfK>7~Orgcv}|3_6Ot@c560V{f!dXmR+`{RNYI zgQ!U?bUGQDs5)a~KILL&WdA9#k0l~$%(kG^W_Ze^=X!jqZur!UJQsT>{grf%y7Y6b z3dwwB+O4-7?)^J&wTEfKf668;mkBWCdYB}gXenvDmLa`(HzoX^y?DIeyNOW~pXLRsDyuISYngQfw> zh)bH))NA(OnaSE?&_E#_I5jcPDZSX55UGT9moeF3^WGbRDNxZ2rN&V#U4vz91ANlZ|o|;{> zlH^h1kVBN8x#a&H+>Ad5kY_wE>fuN+sl$0EBxfViRS+{fOkBZOHvaS9C=PMX^I%SI zVJZTt{fbpDeBm-yQwApW%LSuWz5;$TXi`voj#xo~QNj+A%xLUaqnEz8sDEA8e7|-f zxxPo5aTE)Fiu%|PsWle{6}}qf`(0RUz4e1O=v&ZyQ0hF>FXP};!?&;AuIE%V^`MC{ z9(9X~9ksVVY9e@|^94HYo*H?ZGGa7;&1-J+8Rour>N(T0x3{_M1o0HMPBoqtAyLSA zYPYWcFZ9tciQ@I6T74ng&SGR2I|_;h$#+$cCg*)G?ery}HmJ(_9%QJ>t>W1ac`fFH zMV5sUMm=Qg3f$wI2{Bfbg4SF(u{UPF55_nzpyw@JYG$YBaD6X^7cH-wvc$tV3)ByM z4kl(H_kCau z68grR*ZY`-Dz2+zLT1Mz{T$*2&*GfCCW`1N@tPTkzaX#6#9Wb{`VjsF?!cfuUc$)v zM|B?{Vy{R)yFY~H%wgTrP=D89^>pl(_9)4BVOWel+>O^~uv!^BHnlO>ugRP(87`V& z)B+w}KC5GIl#cqRt#qi~dmI$m7byTaj(MNyX_H$}H~ zEpj!9^wD=@(7Ne~eY97Ep1i_vDy4 z5bRvZvu9VgnqRxzTpM+a)F5$(T*Upc6 zkQN^QNO}b`St?Gwjko7+=cu=LV3u;mmAQ5mznoH=d&ad?&T{EKey?dGy=|(uLk;+V zT_q_jdPv-M=GZF!N__H$y6JdN91H$76V(Rd6D@xmj$F_xuc7WzH+>Lg8h^*uef4_G z=aw{zLaCmysOi1L_co^F-i4Km^r08f5%-?(t>HFuQ}wH3Eqg8dG2Vg~Y1`%`Iptgl zYY;KMaA)2Q3sQlOP^71_X3tZUlh^9?FQpBgWN(8^2G~ zzwN4Q1i2|j!hdkRIFIe!P0A6%^F_X6PR@4uWa-Vl!w^cZ#gCIAf~rC~mG|SE^yO&Y zZKzkyg!`?a4`tU32C51%H;yhc?k{ymOU6d^*8-H<12q+_j(fB{oSQ(%X#r0Kq);&a zOdqFQJLjJ$IXnE2h;Ncc_^0juD&AxFr_~UE)*pF#ipzdE`IiZUn$0%x)9pCL+<9I( z4o-e~(~R-OKn_`%4Cy5#WFJs>vgHWE`Y^hM6^twOM=%KmE%p8Hw*utSCT}7*MuJeV zWo`ZyOs0`z3vpZQFoqd3b=^So^9cadmz&cJN8&Ssv(B^cG%s`hEauy?V;;3W*CS&= zW&XAkpIMZZ9GugwqNzKtFnXRavk~0wq}kwZc+fRqq^sw@1Knl}-?1SLdFKbz4pniJ zf|~la!suqbAZ;ccfTR#p!-bSARu>z@@r6YAb{4+LHrrOas>G+^w9UaF=)m3fub10k zFEd>_)2T{R+b6@405xHLn0)9_w2Q zr=a1Cmt1)4w9zv?(3rbVGq~1ZW4}(gqdm57!kdNDHjA8K7dZw!##5x}2s*8feSs8H zB_hsgUHknJuB`Ww`xWOWBVrNWp{=1?xjHGJ7$jgRSNQyPo1(ssaeY0Nq*PaCvB?;@ zLZ!tGf?7tr0ILZsqfid4n~{Pc5;_JfT5|_R{j*I%L|xCfntYJ+H$w(6-WE&!8P)Dr zfYXPj;B!1#uUj2k#S_;PvpXlF5DMgOVjI@!iZz5fs72PL;EY3sz%PK&iAap=-K^iy8<0TCPkl$jD7ZeUB zSd2t~KlNt(j1DJ3!vKa3=L5+TgF%l5JwnP%l+qEEU>bV;{c0foJ;ypfi@S7I&uGv% z*DV|$*wim(5@(c*Iz)(NvLFFETD0Ts)8bPEJrA+5Phu)Ks!y8|@qGOXLhe}Y-qn8g z_eU{f48`4JdUtgk8xPd(i+6ptkM3Vn5%tv^`WZ;BBgqAD9F!E5i~J7hi9D?G(ZB-2 zR?4t@Rv;0P@AnJXS(L&=1$|SFo$adPf3DsbVLd?|)FdH#q28o`*b6UC_{$Zvv;c3m z?xckU5xwNuB(-Tv=Qm%rxSz2rdi*SI-#0D0sY8b5;B60(F8z-U5`V1 zuaH!nEuXfe5H2ChPSjNNR8myK<1=Nt`c|JULS>j@GcJ#5LQo(b# z&*giJ+|PptTx4Q0camwNvq$}^pwxE_k zujNmf0opnIMvqIr_Nw&tXxkA*a#PQVU(- z3ap&R8S`CPSyV?K_QJ=cIBhaZ&x+%fxz74%Dw4R)_%iX$>$K9XCBEbAjO@$b2s62?fu_~oc?ga6o9a;wT8^_K~z z)H7+B!yy&?M%LhH+6YC6+&{;pEM-kugS4oGxz_|h7Oo;ij^L5VELn@9x3|E|bbNfLf2EweSG@*GMzHMX>#%s zpw)PFohVUcz>@x0EwRLJiXv#Ozd12LKGl-?n&0P@|ITB2+LuSKI5hLynDzhBYic;W z@kkUBP3jJP=O+qPGx|E8*D^VI0f=^nLbabu=C@IwsIHoo)Q>j{h$*p^?J48aP8$#! z$rC-q#Kpzu(K6Si*QcXkUe0~$ULUl3{vtX)@15<^>K9q0A9oCIOBa>C1WWeBb;odt z&#z_#l?2{P1@nX{Z{qVr=Dkz@>^v~=+N(vg~b;dZN8)c0?-u=p2(CLjVQMHFYCm3b8JXW#l|#n>WReF57+R7UL?LG$FYn_>KN%cQdlCJUJ2<;T6zXzj+T2>V z8Rh6m*xT6C!hq+O0UOl3bFa#p>;z~(vnJ{~!9u$GS*@E}-VB8JOlZ5y33SmsJ=s=C z+fcr=G9ib*!yhzTrNy4z`Ynsi$uU+e&V@VMhc%iAv4`9q7LNymMh4WLccrzu7UKjo!bIJZ7Y4z-;$k9ghzuj7yC^7CkNB zaRH0n+1j07+;W4rVX!kFqQ*kPIBh^wMXh?Rrs)It^QYF-f(rEUqD%K(rij=dKp_KV zu;jyS1Xywpf3p>^hQ-4|4LXhN}8c`P``Yys(W&$an{3 zzl=g(5ptU-q(xbLY0+|UBHAgyRQuB>W2lieojK3(<)bC&r4D{(JG3lD`+1qMF1R2F z<=ADg=}!}&0|SfcD3g_0+ENh+6^eKV>RrXf#T4!@^h&7PKbj`{2yb5{+5Q8e`q@t?tlYlq_YY zxsxEh;_4laWgq4|_?)8;9h_-~B=6+fW_kWxu8`9sSw0=QN3uxra}5$5`n~7?(yWr; zVeJK%5G>LeNqEnBJhK2Pg8N*S22%Fsv^2&gsh>{M8h%|YvM#c8nQJ2D&Ta8{!C7)L zZ8&pKtud!Gb>P|&OgX79SOjpoK~5g3HO6vtXGjJ2r)iF7TxP00J_gUOOz8_YC8?K@ zE@ppREZS3?I^c{xsFU_|5#%gcwT;sd0f?$o2PNbUPo+ICb*;2p#I|6zmSv@7xid_= znoD^tjmS-!r8T#j_@|7KZ82Vi@z zIeff&4?H}0Ve|5X5bnR1zzb|77jpC3BobLsO-~xG_h*EUF<>tG>X`#$}1w1!& zTM<_)c$0I&VRl>a-okuVL3(ANs;TG|cWj)p+xbx`{Gy#&`9MBxg?I$l>o3b8&R>;@ zjNOYFc;yLF(-XH_$9+&sFmr+|EZ!ylXA$GSP%b4WN(wT~&_m6=|2k^8yB?EU2Zl475i6cUDtVUR!8YlTAd{ z_fQ4tp83T*q-wdEllDF?0^QtI$(oa`){;1=GE+n9mt#G_6dPqh9N#7P@|?489JSFu zEw&m{n-&iJvnx_LhDqm+m#Yh2r1ZK@Dmv)aU3}Kbua8C_cCny~yrgROOa z#eD$n%j#a8qcNi_aD88QIP}P@rYLu@m5?pD=0EN6jA=X=HtaP8rt%lkI1LN!<1vzpm_^Q1e2fqyFpA%f&= z<@IAwJ5u&5j{f$|(!jtA_N%INzaEUyudgF3(*HeWwBir_%#(Pd#KF21st4N-`my#t)~EuD|EFV;z7MDJZxZVjRmEU)}G$umv1FeFW zIe*7z0w-S=Y0E$^-tHDxV#~UJ^W>?|yW>)$4Av;mkjr;<6;5rpv z{#omp6tBeA=reL#s8^M1Q3dwnk&~;do82SOvPpeMs^lz?zLXAA@XXju2>i-#Bj!BgLV=u!^P-qPX{~;;T{Sq3Oa6$-VS-GUhzT~AnTAYf zu+d72=BdEKBB3^j5$8!ytjWIorL_n4Td-hu`m59QL;Tn{xdOc$wjhfFr0=wUQuX4& z)!6yYdV9?^lWt6&#Nd@cLX1{Lt(9xe3vt`R(k<^l3O|sBzAjV z*Cxsf2K=GW>@)FEH{nbAM?|tF!j{ec7b^-S8(SCI73mzU`)4Z(1N6`|Gui#WD+(18 zg7{POxJ&02#L#60e}m`Ic}+!iL)Q`=1_2^%ZNmCRrbm$xx+P9|i__1F>f^@0crLE+ zwZVg&^|Lil6N-1cKI0)p_sW!zwCh&bRAZ8Q=P9#Ye5dABqWE5x*hd}PC|Y%*IGXoX)3@}*SffqE%L~K{o`kCnJ+77DJGdAnSq$o(erCEpE+&{Z*%q9 zh`2lyax6#$Jt|XBh`mN$GP(1-NE!iziHr|8-XT3QV8uYGiE}`uoR)~rm78|LGX2XL zeR%OE>>>{B&d|zjE`940v!75r^}X$WXpFjYQapXO={HVC6~H;-&=krG(GtScOjd|q z6ALC_GLf(3TQ{?7{RgH&+9U!Y4XRqcnE0oypR0d{^Pq8RI0yB17StjmI2$&i1F|q* z9HLrHO#6`Om20Lea<8^v`!6!^nN{&9Ou4=rUoYC-`O^Z8Kna$gP<2x&$wkC^hoRo) zPr}G2=5%LuPJ(aoS50N0w?RMgw>JS564(sFsuK$ByK@3t{Y zY{zNKu{=Ba`fN8zS`gP6nZL0d^kQ3QH^*2A(^VFIp(KhfV!0M~=|%s15eVxZ*gL%W zr%VzXMW<*!Nr}i90o-Go|0tD%o{F7jufXMb|GM?A$%3P2Mm)lkkcK*3c1 zb5@nkESja`-48T?%~=a?4THYC|M^G=>z2AQ1?Bg={ma(o&T~L8>1F!v9KviU{qV53 zR-{VKbGZ^Gf(x)fTRTX0C4;FpUS}x>Q7^j$A&n_q9L~|s2B=;>$-3eE^8ApUetWl+ZZIf=KF4CT&qM#eUF3~( zu9D$ptICjLF`T!vO9M3bM+Tfk--ZN~)Ss)-i4infjT>W`n*MQy%$(+SR^|iHc-!HO zQu_gHaj5#u?SqVbX6zM1Y$_yQ{<>TgE5Q%2hO+2$z7)o=lF6cAw_0(nmc(ZlOBN~z zeIDOqeTFE7&${rsoab>;YSI&Awl!812w)a;o7||(dX#}wvIPIRR|X0-k*{GaO+%ge z5`+I%hPpxdObV^N-+rlCt5gH)Ne-|nNmQ5DexVQ(w>k*3S(g;c7K%!L-rV1-dhFYw zFK_wQv>JGX25h5T&*Xu%=Py2~Ne*n+HC4wV%6^%@T*mUFQLGZ% zP??#=;!7hlRoRP%DLXpGAAnI}!De?egwd)w;X~FODn-C3Wv<&RaResfYe7~;(K$)WvYy(B!@6t-! zMFH8Qt*Idyfyih?n^HH2dq`^~s`$sqZU&F|gV6ohVcMf(v%1jr%XXJ;P_yA+uURFJC=U{%~Gx;~1v2h$~k`qTZYoBQ`IoMLv zf7&S0F85YsOHIL0R8099uTWm(G$MDj(XRPXhsFHHg;aGF}59&CKs zS}(lYDpT6J7p^~^{!)8vOtNG|gtK2>$d}?0) z#ky;fK*L|Y(BnVv>#|}*K?|(SCrK2+~F@z{nFBen7LeQS8Gp%3SJa>+}5}iiTA0jS>63{ zS6DPANfRbwf3RkS$E@W#y1C%W)+mZ3^KD()YGrF%O#JkB%VElH*-wvXY~pLm_QI>b z=gZwqvO2RqyiZxJDV8qmX-Tc*h`zDoz2cU9g~3<&Wu*;LpZid$8cg-GOuOK^pUovJ zr!No(A1>zv*DW4rfk0YU^-Hfx(^^-#R%>756vW*d;}g$ud{!vjVHBVFa}E4JufPk^ zjQO=dAXP1Fb(KUo4YHuC>?5iyoeVYHt;~4Fe623ChIcRo;wZ80%H%zn{X->B3aR`znO&(8P#Ty&ij4)hgqS)394t?Lx@RPtpi$kJ> zb2b<>@qTMe?)Ia%S{Rr92^|Bhv4zj}EZ3=q#XoydzdA?B&!E=)x1;mTmQG+@QB^>R z=VIBfhq~%Rxr)srrVhGe9nD%sPZ`T*`t!BPj9E3=c^&C3mq>VASaYFDa7zw{KJl#` z9donN$E&#cvQVq}$^AGc#(AB=pw-C+qGO$^x)|)1oF_&r{FQat!K;(8yWXDVbuq76 zat_DH?knqJP+M}AoG|#x>#_q@C!x8msDNzX>SR~mN3|oS9Z|b|%l>(htGIs?Ivx|I z2am7fp3bw_7eQPj#6E_fm0mCaPdE6e=7kW(Ys25-H|`Hv)V+*_V6A-fi199Qi= z$D8E=10T%q%q52$=DU9XFj!QDk`nb9;kI_Ym>Y@kozgr{76ksPdtj~QI-yg*?3)(; zVa{0{Gl&D`gquWir@uCLe&z7*W{X2yg)*Ql{^KA#?rPy_z=$gU&V%^D z=gFJasI!q~7tHkYvE+&FsDhP>EwO@RsjkPe@X(Ji2gkUdWhG8?Z5K!Po~PM9+1?LU z^vA@dthalO{&4NN)v3|Zm9y}%^fvO@nUcvZt&1^ML6s77eAh!3t*j!WzgxeK!o^zC z(=Go%&uQqh7!IxtB3nPo3uTMmAIlp?4ziC=E%A@<3hN7JiM)Ass?}V{Tl7Ux*PD$u z=R(WM;yoR2y+#XjjG zWRv&Dw}Tl!P#jc=tX~ucb7FP-sWo~-uw?1*%w2@;f{AdHuBsoQ&0uxAa~{6#oj&~3j3U~hxnFyR-^)PZ8;g5-nOLtOVu)pVGCF;T z){L?p*BO;~obQR=pBn$uPAKvk>#^cz>#CVI$AlE-*-yfr;YHb5@qVs57j`ns%l7$t*z{0Qk3^CjyMO z6dB}=j@Ysbh|J3_-liNo(oBig@I)@*Uynep;JcY>2M1ugbIka!r64ZbGzt&;U0c5vED6-|7VGQ=FZEX;)+P}^N`Ve zKV=UVD8>;@`J)fvl)pUD(Q-2=NlV|H5aK1MTiVUbt}uw4G=~HcORh3dh@`&G9}|G7 zG;4^6(4XaYX(KnIpr}>Z$vk?pMTpl z4V_w{u=3-{OPP4~@x84dPd=SCfwPFCA5TH_SQ=}F zem3a`{SQ*v#>5mRO?lyFz44Y>kI*VyQDqb86Tg{>*jt$jSUqzY@?D>Hb-1S7W?45#k`cYm%`@LV{tiL2l$UXP#FNE_pZ&pKw`G*fzng*b1Igrk ztoU%#f)_h}wvzV|G|ByKSs1`;7}wL=g9H$@5^Xdy0|q4{9>xB%VyW67nggCH(~KS) zhPm&gMp9rO!k`z!yk%DXk`cRR-u8|uNczYbhK<&-#y(G@&aoaF_I>OnB>>unEH8~< z)mucVRB9Z55m{lN;Nk5iXO>2kidIWWH(5yb*D@qan%1$f1(~p48X~`g&TNJSzSHag z)$;G4mmSwCAJJG?B%-dsHWbP0#762f@fRzC{U(o3z*v(`4BRBdYqrInyz4bT zc=zP{;}sT#M()dPUKeF&ea|GO#PqX*=uDM!>)BA=N0N)vQWJDNkmU}6l1LtaLv~_M zuIsC8>hsj8G~Stn>)9N{I&w>YgvcvbK1iPabpCqSfn-0GkB+YlYi6&J7FDN4unfXu7u3iFD%W8;v^C$frWDF${ZVp zg(4f~WBpO|#l2_k?wD`_FgjZz}^N%xCXG0jpUzLSFFJQ8TpzJ@c-K1CHkkLiEX zHS|%NHd>^)z-+n1Zuo=SgBps1;WHW?HuHpYN6chX38NMYP>$v)&4t_Zfd+e zj$HVa@yk>ZvX~Wr2C?Z=f?prCbt{cbViYOD4s?4+hZBh(LIE{-+|H%QDp=iGE~oFm z3M0l)jlx#w8%cURnjE&O5&tTzZle*a>XK)w40wAk*HI8ppf8AaZ1Ys!1|ufO(N!F7 zGT2&D9sCmnTOI>B&&@D%jLSYDq!_vTUOfgTKgS@3|KlP91;qjv*|j)QnXd?Ek(SwR z%u{7R$CtZEblgvWf&WtaHZ}YXix+I(eA5v@`p5$9!X@w|_}M@jk0 za?-CFe?y{1_AB&)Ly-~eQ(k*=!w+1TzzkBW-j4Bl3yhwk-+x7RL)k^Ck=Zb^?xc3# z+wN2Q%}9$n)&-_>3&hassS<>-d8X!QP(8+#ZJK(zdo66q{NbxCd$6!UszV}$KyJzC zD}Bdu%uXlA!8nFr0rGgSRiQ}7KSJ)%Hr}A$&h?K-&^`{g5(%WK`$~eo;kU0xJ8)DH zgOfucP{dlJS1SO@yZlQ!IzYewh#$c~lE zc1^67z({$%a;|*A8`va=CA2hfS#t09!|_o#jj9Ck+bq6>eX;Gbx&ee!)-A7LAQX@BX*3|3$`cI zye<5~Kj{|S3((I~_}m6i9G*;npc=FP{K)EN0R14Fxv4%zqfPI({QmIo&6LklL1PCn zywCy7|Hso+hE>%yZRtj&q&Y}QH`0PA4I84`~911?X?y@*PdtYnS1Wp=YwpX!BsBNbsr`M++ax#525$xHz5XGtMh1Ff=G*S z_Sv_+uM=HDV+#VBW$?~4Z($ulO&mK4>Pej=9d3-iVI5B2#H-3DV}h`ln&8z`al(8E zlPWu_7_{59>j_CTF5nVx+6Zwqmls@YMQ@c@Qj-+-DY$hjEDOT!k7sUwB0m84usBGR z1(A7jV}yO_Z`?Y?x1@&oKC;iS5IrgbrchDO3Jr6JEy!uU(T#V>sY0;y0?CTg%eLS_j<1QFn4?2av1TGK+7;A#_~nGg73)oe>GY4ZP;9#gVOa zUvAfvQIPC9wtdNbyutiOJor~aLWD&rxq0we|>vBA>eBQRu<>Knsh%-pqc z8DXA&CnhovPItq!t31PO<6+Fgqbn1uORm)WcLmWZGJK^oaY9KC9HWc#@MFQm27|ojfKE2-Wf;hql1H$KlK!kVu24fhu!$tt|c+qQp0LKK2phxG{oLJ zQ(>G)c1xCiA#o?lykRs{q9H_S(({oRPDCMxM>qZ1wWz>Oh^(GnrN9ht ziU%>S=El=|_$j`?m`v24dv{DnQtTCc3mvz{hz7H1VP=nrK7mRVXz zRQcjExn3B{RqKq?NHCiFL`C~^>G^fkIE6`em}r&fg`2?b{ki1QLUotx?=lGSirg9U zX3M!h?_Vu?rP_ln6@8Iw0+Lal>e`Lyluc@P4oy-<}0|>qQw|Y*S#;Xq9#$W zGx>1$deZ8H|Uut{lXuXc|88%1)DZDXI>g+tBH?UV)D(0mQv`jS7 z>ams8tn~X*UyTd)?RlIms!^zn3Cfz0t$5{ta6?ib=pG=5Q#xHwh^r+nGS4p=bqC6k zo%snURd(B?t=Si5z>220v#~Yl z3H}9LZyv7NoZj1{fZ?;LGTU1M#4*^3B-laa!W3iCa8@W6zNg1$oxh|Ba@Xg>8H#F5 z#}u%il%;%sl%U*3d0RZgQ1%FOWqwxLxz7P#zu z2jy6WkZoKh-UbCp{ektR(BwLY9~NdEhBfC)c|WYZZUOtf+dl{507_kddnra`Nm=fV zALlaaqBx++qq%dgvNL8BV_ZmF`8CV)B~`m@-fY}QXZuU?lt= zdXwM;1C;v0*=dB(gz5Ln(x>O7U(&~07HU+k{N+TTRnSpjz;)c4`6M>zFyKa90mq}a z(+Fon6U@H0>0&}L#&oRUK69e2EQwI9PMHK$E7|x9XNo(-LRhtA<+51NWh)!fxU^>R zFlg-7?t`^p|2s?RXo7I-Pn(DLK-{QW;ABL8Co)P$ljClNy0AdpT9bIq?n>GZ;7QtH&k^M>RhtsZhA|!=p;M9-P&ooNquF(t`Tu zGq&hn<*vL503oij(j0;?=)hG@wQ=aE(r31dN(*JX%s1ZPX*CWjyAWUb$t1w03%8v_ zdGr@p5n+CJ_S2tI)!iE5@*}b|d&u^c0v6=(!0`|Uxrv$6x=ra*ju%);s%WnNT(-N> z(RGp&{1THd@o|;Pa=mizLNrW*1KmJwEy_s_*Z*~;xMI{7_O41k=(Dd+9D>a`h~ zT;=rwrrnvnAd~}F*NUI1(6H9sYPU{X9*cXeZ*ftWv{JemES%dOOy!@*~)F^OX>n@73l5G(WI1JRAq!k_By=wq^Z=ElqB^H<4Y^w zLQPQTXl7shmO67LLQA>T>*M>D7@l&=(S91v*<>6t4G}ZTDW;jHiBTXi=A>^Z%|ex4 z&73!`XrRoR>&qZ>Lh*dke=c*`+(}_=rw7i8u@i!@hL_+7|}qV(M7ISfvj z4xf|Zi}IJLg}aA<0>^Jvn*4zd);_7-oTa&{u2z zxpgxvg?MLxv13z$}2tu*^JJt@XNtzgaXLw@NuQbwB2I^~iV6!C&{W zP7E&`KG)*ol)+@m>C$jK91-_rDy*(|ke-eBoBc+OZP;h?;5UuKeswjUAAkD~ySIF* zg<$s8GD8#m{(J_GOtV5aLko3m+LE+;zyz5U-*=qC0TGN@_I_n9GmD!P#E(5d8X-># zHbFR=-l115B>+K7QMj#H5f`HPg!?D+$a*37`7ZdA*st!^)i39s@UiboC(5hk;EOG| zzO=zgISLUKyEgi5Tgn)3!KK3jqIbaX z4`v@Ti#LW5SIQR$dnTE{G@Mjl$|FBBYdjAXV_kl8o6f>NRIKX9=Tbb253;!i;YPO^ zwlFa~4Xpe3u|f$kJheJUsf2QFpXv|}Jj-H3F5pODZ#JLj*&p_*U~hgra!RyKR0R|t zi2_^0fTvwxRyqKyPO}>70Ec^M0IqyC`g%=gc`(AX&&wucAdYW#Hc6%S9IVWaO)6$G zC#AYmlcZAaPrM?Ba$!^YY!_|_@CfeH=_%rlg@nKzX1DrL`^)HdGKU38hZUD}X*6eyRw={YJ5OJ-|mljAH*_RN@$JVM5n22KeEW*&d zoj8Udo{zU+>^+L-V@;p8PkgkQ257pGfSDzJ08PS`5l?2a*iZKWUxzLF(u)>}cXtOI z(o4J8{6gdpiZ7*bucMj7#UHPn!S0H@y3J@9-~lbiJ9548#hB%?Gj{*RB%lzh;=|>r z43yVo%HI^(4FD%dDKR~?1x9hnzc(_du7S=k$-8YSP}ksFBclbef>xJ)h;UTa@^KH~ z2}4IcOuUiQQcx97DfwMUs6Z8pHtjt$pBR|bfal28I9w-ye@YaHIM*J2D|eW{Uz>05 z4&aM}NWR9XprijM`Ns0J(>72fU#Fep)8Stbu}2NB4@^eUeG(S%Xg?!n&%NUBnfco} zeJ%kUaA4=U@ZgBs`v5CGah69QYZ9DNZom6wfUYcg4bX&V*%Hs~$jg9LV6e1EbeXJxyIz=`v%n@p^#EQXbCtD^_K%1Xk z-Lryl>i)8qUB})}fKv1hpFKrY?vp6CFm*|L+hGS6$ zEL>t26Y6GAgixw`m+X;;UZ`00+m1^O%^KNU{meCV8ab(`S=yb(K+eK>=T}kCPYbL`uvwGM?%Fr`t44=gb3n42MfT z)0u4^=pR{hWKH&mK-6x>0>bT{Enswucj|`7dxgPkpIu!MP#aes0no&=Ywp{FBKyX| z)Ss3^-6_2dH`WoT9~t{JCF&KF)sWW0E!M=Cfm^+od1xS+|619iYhQT7#BHtM z6|`jejxWI##vx@YBn)4!v0i0m#Fn&UZV0$K)kk01v8uD-zIN1|=4GI#j@(K0KAoVK z@(KGkvV&T+kd9tl1JEIZ0{N) ze~VOT0IKb+obf|1i1MpEGT6V*R|S)*CK%i^-z=wy*lD?04iExt-J{;r@rQd6s2-!W zF=^8kH5#D#iuWpqx^9#~;=D!qJ5VM3z}B;|xl`-h`#vFF%%tVoiGT<;?Uu zKtb2Ztey&>D8Gu;h%kCYZkscu)gU_DDktAUQqQfD9&IoUB z!1zTLw9`i?6U-{}9B2R5`tv+gqU2Ni5Y5|jbhw^)W2?u&H7Lh~_xNmykw{Le@_zqc zpXR8nsmfEb*Sh4MCRr6Gjt&6d(K}w+DDSZ*%W|j$xB@OKdm-$$r z9K!y#dURkY3!W8Q7FicrKm=d5*lPpg3Gi&b{a2#@d$3)PNAIEirP5Yrav{;)h)MWC zIat)Xke3nYPtAoWKKRRjZz)AVg|@J_eQ=Bk=r*jGrkSwE5GWaJ)+_jHU{1$3v%ec4+xsr0a<$IbaRpEWtk$OuEo-Hls-X@V%C-w$A@h zrp;}GZndQwoo)XGSQ=@!n_W!88(z7Q&QvkpnW*w;&pA+A@!rm*VYb87gB_*CUgqJskQk!nN(3Nj3k-7+BR?(G{ z?elvd1u*4eJo+rQ&HM4U5(|=!WH@fFcA|NVB^P9I&3~~oak1c<7e38rQ@+GWW<9Sc zQ}2Ehhw^-WTVnltU+G9P*LcJY^l*1>`Mu+-HCBWHzVG={<~M%j@h`$shv`^_TMx6(kxC7&X z67)>Ku4zb)X3Go}b2xbKJwLj2b~PcOE=Q}wTh+6p2~HHZ9tIE5H4bnA>QC#^cMyLQ zP=AJSLcA0&!4t-Yhp}1n!S6{R4zS8I@g?Hbu@s>8lq01ZY@QQtWtSEvRL(OcJR1go z$EbT99)Jb7MC|!F-s^baC0@1KRT}@{{d-JpH8g>1e6GBTu!U0HlqqctYWW|AM$xH=#`p_zvlt3{5pAwYrik#b;*^xb@0ff!o z=^`H@(eg0}G-*!b=_yvgjcV#?I}##5bg?jg^r>k_Pnlt6coX)ROueYKt?$J|3psQnnbK(S?F=jIGb^(TvgRgD|9s%f)FH~vNf@Nx`>hZIji z4eG&p~7!O*+p4O{!Vpgws~Y5<-sd_a6Xb z7#Z&c69^$PPcPi{EkdpWG@bmk{@#Jh#f3^#(*9Wz`wDS+*jGmEvaA?z3o=PJ>ot=y z6#u)~j-d+#47gT#rQf#;-Kb$ZVrSjQz;|#pUcN;VjezKIzaT<-9Tg@{7vRe%{ONpi z*-ZiAkM!~HBys<6sKPRS@b%3~g5jT?Ucj>DSR%V#`ip?-gf{cc#Tr?~(FTA*O&x#!fM7)F^Cz2UZ36$J z@&+F>m&R^nCc}tF;TQH00^ws8&@~z%ttwxZ5yc7O{s3K~|ap z)59i1(Mbq{d~a^(aX{axzoY0R%}*{N7~E5*vOn)j0&)>@#E9>c8$754=B)O$H>+m- z3Mf2bXTnKUsNLiU&qb&eXaQtNM`wR6=*aYMdpl% z5@2xa`^G*P#(+DjFWD5_??JdVy31&tcwGuyqgbV-(uO5MU-lzs^7|}5)`U0uA!@EC z5BpqPSXa5~{WX=`v`@~iqwmqHomRGXzKFv*i4BUA(!IB3Cl{!(%uXSe?b!m8DbuA< zH}~)$*bMgy*r*(l=Z$%~=UlBC8oz{f!m$|4W198ajHF=hqW*5di)(O&bn|VSRtJ@6 z3lhfp-;(<8)e=YwW?$rWikgsz|0<{R(%TVz@F>veSa?Bb$g@OS5O5O~A7DrWUQP&# z_SA0D)#*SZXrA9@`xewG;8^6ENP>C?{y$)gsSx`sIKt49&|@1yN3gcyAJ%FcB3#S& z)lU`h#}+Lf&P55EzyliQ7piHMhifqWWsoJtwh<>saPR&=9tL{K&ShUMXjWlXJ9uX}gyv!t_u#v`a7TH|ewN@jjuyuciSd># z+@son8(;$DvaJ(O@f%N1@(z(|GV?X(O!Sr|8S`D)B;Zz0ejY&ZPGGiZ$I8p9I(Gs9M*m;ef@N z>1zv7^qf){@xkv^$DAji)5GjNW9JnCk`B4*>6;z`R1@-Mx@aGyEw~yy-Pd{d0MkP- z9#9Kn+~46lq_i;*w!zkHdN3rkBdQ`qlohIz@@I(6QQk z0E@SgN$6u^zC@*r;&KvoQcKW3*h9wEBx;8z7dc{y;qJqP<&^mW*&pS_Y_Rp{>n0Bd zM}TEAh#(elM-)F5x52hz49D3g*q|c`EB%M@5Gf}O^(E~p{SE~Dc0kKo;9nQ-Ht-0Y zpJc2w)1W`8)vr$^&KCk+zmo)Wte=SzNN4y>bGMN^5#F*N@h>WbjG!DwbQdXQERc&4 zHlIUjXO9JZPiLX%F6}Fj@l==6J2jY)?A*#C)?O;`3yw+$?qYn$_mB`FULQ<^CNETn z@U|m2BAO1BYKpL%%!ISei}Gz1-7kcTa^sMGnHbZEK~;!!$Jh+{^?in?7BeMYiIe1%Nx1NP^qeC+7hV> zyEv!y*^Ar`nCG{*{df$n3Z?aAlN6r^pPk>cqQZ@+YcIar8?US_M1pGXfu;+?_sD$zNvwnt!bt5SfumO%_$|0R^P-wqG*7B(-n)^K!j z9HqMGONqr{NgT}b5XYOJZ=e>oM(3qa!HF<<`#QUd*X)?k+o!=2&g##_1u>=c;G{e2 z&%a?PymY_j6?l3SD~^NNh+h_e8M{FTJAB)fE+jPb7$nehho%CEbZZ@O5f~u&TY%+B zjB8RiPic`KI^{)-YxSUOf%->Q?g%=Q0^h{J8T`XZZZ3z6z}X`{Y@0x@(qFl3srvyB zwo-%!cT&an?w{ExZf>ic$Yn+HQ4d;!=f&5xulcg4MzS`wD@EoHr3--7l)ZLAB;x>SLXn;ti;*CN85nJ>;!lBirKO#|ZIO>p3Zl(b zpkIq0JQ0D}eD7Xf3P^pELNz+`JKl0*+_>SQu{McG2oP3L4>NaKwH7k=2_@l(9Q)_F z;!Xj0iq1dGoC#{r!agm|?l$YA^B;T)V9EB-=sfn?6vIz#E2CvM27;xU&ZHdi)$k9l zu-6BnTQy_+tFrleHcI(%RO_+~X>Qiit`IDZ4qj{f=6b?jt5Pf+@#}~uu|K!meRm&K zB(0dxJvWDfgI>8$*&K)}Hn^j`irJ{}^5@gKKPtRPh!1I zu&4Zp2fYN~O7?s!zL0Mp2Y5c+T{~!pf+7*mszJK1Z=(R%SPfQz?)W+qLYbn6&p&yNbIs#D#dxKp~ z3Q#ef7wo0|>b0$fNL|v(`ev{g1&0lBI->7jD%)%XCRIP8A=5zZOW0>kBUQuPSrf@J z2$N#VNti&CQj!vd|H$>X4Y2Q(=f}OhcQNx9fsLv4JM2f2Xg;q=Hc0Up<`91uI!>Dj z`Y^m>sAs}bOi1$QI?eod{N7`2$c?wJ*h}4Qfk{>T8GnRxB1q8JU+FXTM^v!^CRG=> zW7i7W(6UByo0Ofr6#oszEo?w}F7PYvympZSur|swACan{OoTo5`sZ;j>C+{;_ozqMbXvOE4R|>({O)pNX}X zYc&>Zt@7N=DO94&>FjqrlUt}nc^hMMrPVe%TIn6T*8)+Y5*3OXDVZ9nMS!Z~^!tg2%rops43(&fQOC;S z`S@NHd+(#L>V++*FGzgf-O%V;ww9Ja6pV&ie1{_BJqc|N|K;muUXA0B4ufD)zVx67 z9Ti@VR=0$t`n3X8;5g>%C-O~*|k98GON8J)hdau1HGuJ8}XvtoJg zr30zwMB@g6w%LapqZrTpJDwc@zZN7JpD`TUuaAGc6vUazZG)}QR*nuaZlXaxm}gbQ zsH(}8cJVkGqVJrp%Q2gb?|%UGj)t|p=qNr^1W^bVy~c(F5N{T5?dPHd5RuV8x$&V} zo}auiG=t<1Rh!8rS^pE}nM%xJr6m`ta}GPMVOfBu)$r1-%#^iXK+AVFdM4&mic*YM z=I3}SLS^;5_;2yEccKuzo7yy_@DLQ%f+CN`^2GO3feUy@kpFlm1WEHK=q)~{H-q5< znw2M$Do}f1Zib_*2}Rxg%ijqC)E%x~(2j}4r4lo!lL|Mz4cq{A2P+6ZT+SfxGpa^wCLBkv@zQ)eWS`G2xJotnZ$hX2U&^60xlQL?;i#fK}SC|RB_ z8(aK_1r<>89a2VzzqlWz7P4p5kd650D?umERtWFyBKaSCH$NaTZGw`_thxDRm7O#L zTG!xvSYLO!F}BkAICCo-eC*ap9z)iPTvW~UoLlr2lm+iSY^6Li(7Xb%#PRFG-9;#o z){_g*c}W7KnlU^^QvY&DfICzbFZ`N85xriKA^jlW48P|%#6f_j2KYPa&$7r6w1UOJ z!7`WE?5-@+L;WQY^{V@s4R#_9fPBlxjN}gzd@w0XpBlSNNbwl(cN8L*fvoY4g&I!N z3&a?5m7x-x51OX_$KTJ15_i^Iv4e0SbZKdcFhhdI?>lQ@}3!zkbBdtXL zRpntwJXlv>6Nkxmdlr0ET^ENbwQ%u&NQH`}O0Sk$!wZDT~V)ao!s#)a%j7@-64Kf5h zD<4ZZ9Da@m295lrmH>pD!G|vtb^L&(%ay3}<^g%=XJoTsu$nfgkVMPJHWYK>4Es(<*X90TFrO357B2>jgF#pr(F%)Ig z3v_3bQT6pn>zd9fc=w##&0dt(fb#p>RVd@V{pJ*;I9h1?V#rw`5UP5eMub(7CsI71 zNY{Hgd&|yTLJ)G8tL^+MRHSK9c$G!p9|K&*;;qTIQ8ZYUq}rB0ft zQsOXWJNReNx4zi{in>th&g`ZC5O-Z%{`4GGB&I`NUGyh@mddhAu;QzqHlQgb`{Ge5rXxhEMtvKdHm1!xyC*7cSoy{x5$= z{+?en3PPH=j+~UmGnEqnQXH?ZrW`;o3SC#Nkm7&*oxRwS3T9o1#kZ?b30f#FwJbj8 z%&>?6nJODHmaGpn2!fVMJ2>O?Lw*9Hc{R(3FUVvZzl z6){B%#iTFcoj93(q$n40E|Rs=h>e1xP=Upg`K_@K*^)YuqaujA+jsiXLDvTon|dPK zT7lyR?{TH_I(4i^!`#Qu0?;7>&p>v=2=SW;1x3jc1?h5tgA@3M&pD=6a5@GAbHxP< z7r6Jq#@R29oOYd>8lZKQ)bV}KCCrw^p~#5lPl&j)JP}v~9~_!v3;{>%LoO3`)j8DgDD-(+99ZL(y>erwE1YHuL>T^%jXr%bS zf{n%k3=&k8cF`L@f_!C8=5xeqMMju@NW8C5^?DK{s1o#a?Iq+-0e{$Ff9JKmnR3xK zkb+X|*>{f&p=dmJ?Tuc89h^!={%`#J3@?iaUpQe+`CWV#q|NoLf=QHQTr1k!nsCNw z?AlbwJQWkeni4S0e|{-&y96dtW@SG)F;V`EByWnmz_aZaF4mOtV8M!aRM}IKyoK*x z_GjMHc<+j`jqBGi7)0fKG%$!I`O6ZO((&Gf$1ytH`838FGr_rNwZW3eDd%I7pVuj9 zUI`RY5#AM)fqO|nOeaX(Jv^`nNgJ{}v5Mw_5jHJ6GxsVMw4F=CdaUXAWD!|u^!=7GPY{#o^1gQGSU0rbjv}bv_~%dR{t5LWxE}X zZwmt=2lg{(>8xFmmyjIq5xZob?uVx^;tIn}{nFe`4j{*i!^P!5P1B0MoG`pyN*>cB zQR?R@g&JepF^sl`qJ*rRb+Iy4b z?ew0Fk)=6Dvo_Rmqv1Q37|iQu(@hddejS5t<3B4N> z08h0yq|EW(LTZOB#OFB-Xs~u~`)}(5QAmMj{II|QC3X1ZbG)QLo^osV%V1?nW}KsjZ$KT)ymc*_F4la+>tY6#mG9A{i&v=+&^icj7!x4r+-QI%qH=BM zb|lc%;F_uCJn$m<$RbOVgF9i{UX_F~#ky{1Mv$9qV2FHiw$GY@SVJyQvxMR4 z{g3jTF;6)+S8C#NtHXZPALzMQuK6n$=#dm;X!KMkpqkcawTf=YWJy#*=&Ov!LuiDl z8F6n@5HilIt$O5UK|4tMEPYWl3DQ!X*p&%Nh-d{W8MRI7KrIJN-StJ=S}6BDm>8Hw zVA4{6FmqwyG=>2MrdjF32r|%6D&85>PN79rOVa@#1dcyyLc>f9j5KYLeps79+(iBA zS$AwjVz4#`oC+S;j9RSzdpHI^Cl+L742S4IMA|oYW#Yp0u3@{ z+9#VK%rZc|R2-|Jb=ZbVdk3pn%?SV&md7sz+9`1C0%WQgd-8z)j0H-24e}oIL3(bV ze%05HW>kxS4lZ<&KFc`-Qrs1H4n3D-10%HB$u+f~Py@CpF0bk(gFU-0m1uM}dhHO; zl)8X)k16l)!=@M*SfbHg*_@E-6py>jE&S4e4AerxRoQbxA7pKT=q?Ts3@P1EqPtj0 zcK*(aQy}(>`essL?dkz`*7?$OCgP(K7^89LjEEEbq^{|jfan-V*kFD4!F$wP!GeYY zt0qWkyqw^1(mC;cRiFX+ba@BStAvvIwi{mv{%2sHsvvTwOZg0;l0KMiF{k`y`J|#O-qJQ)i{Gu*hc=C&wm;X3}3;ez+~%$ zbAp~uZ2VIoj(gLTo}>B+tZD3iNs2_w(8L0H+|aDI-QcnmGz~jqgTR=Khh%h9N2?|2 zr&(ZrmP0qi`2VMB#a~nU?g)cfT%EznhYVxZkW5d-B>N_D42bjOYIvzSVi$mA2yc@q zAAtmY@8`J}_40d^WyLaN{M|F3a;X5E*xz8zKtsXMsp4SkXJ~A)F1H2?QalT`r zr&mf~?S320&)mo0vk!V#y4cH@5Fq{Sc!pr|l~PAPDNSE&gnJJ{A9ffG;QjdoLL*-D z3KK#mvKVXs6uvRb7AYKEASo?E}2T_VU)2b~qa+EGSeJ(^?DEz}S&8|SW{|(hT-`=)p#n^$q*svFvAdh(dl@2Jr#j_^pXED+O zVMKeo@ztFn0KBS2m(FefJ6Bs}m#7>7=4xX;H~IfmgFfw`Tj3eP3L%h=i|QRo6av+l z-?d9mg`{?IW-X$r9m*l!&!mR*w1Mv^B-R>^p@y#2FWu~k`%r>RhPtJGIs*+z1pbYS z>LV~A5jYkRUsD7$cwKq$K_~}GS@!(Kq!6_B5n$3le^7`GVYvb(5~|W7w%y1cy1%&p ztb@uB+jCq3_cp@Ev-26XFJ7N@W1Bl;I%=lYvtZl_HB*~y;1r8>I}avxKm2PEHuVKw zpZs1Kt!L6}O+eb6RGrlMK{K`Lx2bynH&ZJu?&gv81141-dC1GSagQQ`eXh~p*iDEb zBDzF-JqJuU=NZYpFymcz6O8sGgHqm^8U>2lZt6%JO5vkrWhl?(=+oMgfl$cj*TmUd z2!&Eg9JK@?7l7Nrd*q7&yu9%o*+D}GSxe=JyJ|J+Ln82e&o_(Kv5>5R#;jB@!|!%q zc%vuhgNPpekn=!Cp^W7LoDIvt=W9cBg-;*?1}lE#Q|f_KcUbCkGL`52;|N+IMej3+ zv@^X~c_aQKFT=2KVt4j8liJ7xG_6GbgZm@)CS`dzXHn5VD(1W8DIFCXpVd(UyUlM2 zmneaqeh-VkC8TaBO`mB*4b&R1{?4qqzM{t7D^8Srnu`t%)UIaw<^ES-H@4^^=KYt) zcSM%nARKEob2JY?2vruho_3~nCu$@zQlTlc|0@T;iL$RXLtq2yiw~KH9x|Y&o+d<& zgh~KlDehIa3VqTHRn+SyL+5}u#?^~FiX4owriLxhIUD#;_6f@RPx;mkyR19~QYj_d zV~gj{fXd;DoRDtxzXP>3_f4BRq3=8#Y_+^Tw4{!0?$o(&IE=`jI+s969j?w2LX#k& zgWP=kr94z8troPn-UFDFqdj)eO&kK2<0|Ksa2pYr`XqZS2x+>GXazB08QWL=Qz6Wgx<=1w#E z`bN-Nl=K^zx&0=&$8rYK3^N_ZOx1Xa_?P_3Y#6iJjp?RXsV5hzD0!R}U$FbqIIb2&N!%AEX5QJ6Lmn>piiXlJYaiE??;1 z?OByCT`VVRgvKcw|3WQ-jJx+72~4pcE3%!ns|~EaXzw7z9gK@UqUQ|AKzpm*u0gOf zx@H?<5eN)&N+eK!_D!sWh{H6UsA?Yp2XX^qSgvswFnWpI~nQul(w@^?YlY^C8P-bqBf zjwyD8#UzrLh2i(kl5LVSaTENH{6K>pnk)7qE3M{@XhQ*_W)jw^DLpilgXbtb%sV^$ zbTZpgf~b)zE#P%DT5KF8lzQD}MTujzmS; z$n#$+(K#K7*41N1m{~20+$0)P%JCwpzRSCvTjCr1;L|sIQX~GvxFa1w&cTzSz-mE? zEVlJx`x7UnymVY%ua5+GSLJqk=`|(;tCsq<+lR(HU^Q@d@Hu+SkbCXeT|abgCYM%c zYO|^`D;^8UDorvjTL}I}6@#);a}w(?)wPFtW|t9jQkvidm#*uq@FuHjS1HG~9!FZO zyWNU#l+KUOxDn^)Gpt=UP7lUs)@FzjT%auhMFAG7mSk8#qOU()BBL+hakPkCSNC zq~dNTA?{nzRGLoxzq}YMZv#&-Hq%t+*KK9XeLTOMc!OJH9nzRLX*~nXYI(tbEUWhI zw)$9LRc}+t#;wde&d9ytp^Uesb-m2=j<@TNFi zJ;Gr=Uvpn(GJwa`tbVIfF)@AJ+3`%Ugy+TIhHpQOmb%os6N#9PHZ<43vILRwfzogM z;_iiMB=}i^{A{W?HSfBT@mD%L-*p*epzS)27t%4lKK0P{u(U4857K4O)m6FsJx|Ww zL+4KS>%AXlK#LVq7tZ8caOi?LKK;bMbjK~te%&kQ&MPj3U?O4FOx&?!{G0+7`(ahZ z&wOn z7mkGS(|+fI6+6v!@So@rS6t)c_IA*@_8=&MRr9;FMwu(f9F1uC&`k$k6<;h6Jod3gdQ>3i@|VuucurpW{^V z4m`uPGwHb>od5aq* z$0nhx;4tr(A8`E51I4JB3Q>)k z65v`9MnWe<0`K(`fuB@V+j{@u@db~y*0$~UzB~e!ZVp;aEbRj?IJoCq$IkC@HsCQ0 zoC|sM+#rH^t-NTT(VzvvsF<_8h|%+xdOoVo&q?=ZpBt%)J zgU2pdlS;!pUxvxkMxy`ujRRY|OIT4`&W>d}eT2iAZ}Xhv12tYdoaRVUNX9|ok=xsY z^pzFt%;Y5FV(|y&-4W1{wCfT1O;cKQaEP+n`ER(QhY+ck^W1xl*N%nYaOBeJ^G*NR z_=pviZ+u!?d|!cOMc?#6X(eIjAv05(8Er?9vLi+i)?oNbw#Q43kTDwW*B<_~*|j<+mRs_0)xsRGRNB({BU+O!e0b_)V4rZW*A- z5|unr%2tDXsfTfNePc!+W~-?=r1Sf!y7R$D@=?D$s+!Ryy?S^zv53nU)6~?wE)A7u zXs(9boK8JFO+%(#9Z_0%!11L+jbNwvsK2PhVqd~`wUnI=@3RlNi)oR<8Qadc8O?fl zN#!=(YJ&a4-ua8Y3JHl2ZOPvGl8&Z#_fLp@mfXT>_JyT`H}*}k@mhIjqtT>kPxn~A zbm+C^xa9XYq*?5Hjdxyl6#mY`d_4Ii$AMcwO}A77{SjZrhZK+Z-qZ8COJy_)8in=O zV6kMNjGgq1o#i_V%;xmcCJ?nbnQhw&dro^kwyiODj zTg4oKk3Kx1J{gQMmz48*o2yGfH}I2;+>_n}v3O=H%lL2hMZU|a zZfcja1Ys%p)?GigDy&9%mwLgkI|Z~X;Jw>OXxGCUx_RZy(Hd=+W*XuTfCFe`GkC}3 zS#f~y^R`ka*i;|#uHw9(KYdz4fmJ!{C?fAt3LJ@>TajY3C!8BxFFTav_o^89RD{#? z_8-Hm8+_c7MiH(jQgmGE=4e`a%SLy|x@>?$o}VHfK78nM+Uv6tLE&q0O5v8xAaw<6 zF{2I~!g|EUSgcp^Gnx4^X#}T2*T1LXg(_k@d{$7ML--qp!>OE8-e0%EcC5_6B%`9~ zg{FmYbs43a*}>It|1fsO;(0FnhEaQul-pXWEmc~IR(;e%;2L;#&TmZ5%%~l3(Ief8 zS(&>Y;G!D*I&rzKR|)^Xs#jjsW!NuGRz-HSDQ`a`=LrsD@M6z9*0vO|+a>XE(>T}E z+vScRkJ6nAB2xygGwj1;yE@wFOA6Cx`$I}$ z_iq`Bu!<>9!p^K zjkd3xS6bzh%Ox~tKBZb+2b;j#9>H>6gW2irL8J>7NhZ~Uw6AqA;Z!X8oI|IiZO?eH zM@p7jz$ee^hhXhSzO}D^$GHkB@f!3eUpj+y`qoI{zfL~SKtog-6k^sCQ)5F7U@LDz zCiAE1B|xaM&s?{URYB^6d(pjJReb78O`?*Qe;xY*>&=BPHH=-Fm|<=i1%D0U2|t%K z01z6)*+pV6JqDnr_jM%ocpG46YR8AVbsH4=?RDbk;?zjKN@>h7|)Y}O6GbR*bW@=Hpdw9Ilk5E$L(Z(;(Uz8Oh)!G;Cn7C9f zr^c&@+{>0IDltrK<Fsc?1}-8v5eP{@mwC@z8Wn*jeBd}L*BrC z%gKU!FA>)(FFDDmLLeuRPIdy^K7X?CpSM`0<=0i zF%5L>YBdn@NDxudJQTp5&bdQR{}W`u5P80qN;mNb5QaGVaJ0hY!Ij_ z^o~0ouY_k*LSd=gyEL!$v%ahYyy4@a!!C$LZx5Ot-@*8>4MJY3lMkn^?|(q=aDG3w z=A44W-_*3po4ml7U0LwUqw8+vN)+zY%~(Lo z7b+h6R00aQ8(??FXnzwAuu&(K>GhucA5~WsR#nr5B}73=KnY2u1O(|$m6Ve14haeA zMp~tjPEkQRrMnvx4&A9VNY}sj;CJ!g%`y zxpG;y?!rqgR}_yJphiVW=w_2ID$v2A1Qn6d?$`I&yQZZ?vXw>Zz6VUDpmwS>-%SfX zW5;vA!)5a%P6>}^rUvDvasO69&lJ?Q{<@kD-#_6;kC4G;Q+ueJP6Z263w>4>LYN{0 zl`Bb=BN@Ym7prWL1in6-3$M(-kl0Y%$E*280Z@fw9A!Z_9h0O(q8dF(IS|U=Lyrp5 zMEmw?wdn^QHQ~m~!skuFaJS<;b?L_$dKsbp&6v@&!p{Mpdi49xVj5Z2P1LRclJ$h` z;$yFOOAkjX%lA-oGAOH*7vIi4nn`GCfSaA5Zn-p;g^o{>aZ z{l(uYt6mYG*WWFaTLR7Q>}yR+y7kSj1L@+5)ywr|)P|ye6 zop9Mgt5}W8mppHFcFrERx6&~ZLot&=x?Lwj4;LZjMPwZ_nQ7=c9y7PUddW4Y=Hp+h z%q(3?^9&LrR+TpUYGbGcefqH>KZ3~yH9zTTMklKN zsJ$epuYHSCx@C$A_cf&ob{Ti*?XzDH^aGXJM*2`+V^ler;a?~xLWXAiNPugf++=ynrAQ|=TNkoXL)I!`Ig$`!b~s!pHYdz31?C=89YvDX{iyP+oaR~zA# zTHgq6Ju@AX-in~Z$@hf!M%G08D7=;_sBP7Fg$`Yc5)gTUj^c2K%VLwCC5)_!_8DB; z-7B)VzB^5-(CYfbkyOI2xpGVkH9N{LfB4;ud^Vu2CRca=xwz!4ln-i?Ys@3vrYACV zNP96)>u`2k6P~A_;@b;e`Dq)l$`4oX5dGm}sZ(9W*QZpAvH4T#sVzj*=~$DcH_2oF z_4uTs_FP%Wx9L*1-nUv$a&sZ*rZXlY@D>VgK5T`eCQeWdk# zNw0r?ITz~#D_vpyRoCQ=v7Rqfj~@~Ca^HykJ>2oj&gbj-g_6-M z`6KJ)qUyFY{HqjSk<4CkWoZ|8{=B#(&Y-G(N>Q#TvhDUFudD1wB~rR4*}}-u*ZV9l zdx8jXRvt!Wu2bA_&3#u}u2~pgfvu80;CA9_ zn!hr>a#dJQKa$4VuLu)uY)&b=)pgTRu8gmD+z-jrS-4U!nGO%dm-kNLYTx%}HaMQ$ z*j%`>@!UhZ!;L(>QxMY1j7V@|qa7Eiy{!W^Et5zW;?RgfaWm?buHZr;_U2mY;i(Ka;0t z3_rYGTm6||0vga0X_v4_5Zb@PAN-4TX9*To_-OPLvR=SfM=iEu1)j-|KAIkYO>iRD zh)jh|5a^Hn!whX}_l^{t?7LPdY0s?U2rGPABYJ@Y6izKH{8PC0G`EQkeu&HKt;rC^ zOn@V&Z&!Xo$5V})Dw0_Lpc}Z~n^blN&onNDds~9R{MqYKU`$G`jPv4}*zPHGt*D5VHy|41DUiN(H3R zna7u$qNeCtqf;+dcPH$|588a~U|9M__;%+%P%BpIWy4)*nGLqecBg(OKJ$)iBRVPXY)ZMmBpeYA`?Uv*G%>@h#R9F-l~iJG8uzOE9 zbjSDhUv1^>DzKqe1NyKqQgH>Etj+#v)~A}$3kf9Jb(S3k*>`d*@O1`Ye z4ffIbY?()_6$6{1a`?rQiB|9S^K{e0kvtuApyk-+PWfHf2HV%-mI%Dhut1l;bG!pe zA6$?F9{wT60|rj45<&i&KoT1l>Nat%9eK026c6;C|8g<|jwl#^*82jc>TQH+@55W4 zF24<-2ELt6ow!KDMm6r0Sfpm%Pk}NebrT9)U|m+~SxJ}y@J;)wr?>=2k*YZ@`R6bb z@mlNt@Wa%`QiB7JRu~slx4I1$;E##^947Jih7KwRtqp6JYDgEIx<8v6mjhRFSPgl+4;`s${tzi4j6_7% z#mj#P6WJF|8Nw0u)cZsfF=qvi;yW*M@jqt?9=t82h1F#9!sjHCdH;pW4C)dZUBuR}H5ULxeeaW2k{Ahq z-C7emBAFLxO70KWXn6=EZ3$X6@6%EW_;w_9`~e4LRTmjo?oSVc;bt@LAr4|73ujxs z&<+Y&Fim!g=K>uGv zZ@T?Dgm#F@vdZQZO%Nfue}GaENvcIxmYt+W-~R@L6@$Cye$SJSsKAL=%M8{IloPj+ zfa?uHz3PpU0Q>ak4XZRn=n5-$GTxQOElEKgZ(|-chb2q_u0Ke9y_-)!J8ArqO$G-Y zrMGgEG(6CMK0!tZ3f@R|&?;|r1WK}xRsoB+5pl0A6uT;nQ6`{`vg^iio%bsN{4T796on@J4#Ol6_AQqFJJ%nfx54l~6g3f0G~x@1U=$ zS7d}AD(r93X08T6R+{nnij$*jv}yn0+?;A6M=qzy=wqImv?F7v)fG!cjei zNoenjKUiOv5D1&{a%(K+ARrLVAIhWw1%#S3I9i8r0S!HKaOQ6)7zR$Ir9j+g*hi9* z>d+%4H>O*C=mrgIuk=SLmoo^&iB%y>_Y{zdS3mml`gDM(TVy#!KStpNG-bu6qG8N2 zxN`az5xwFp_kcsRy`uSuJw0Z=^oC4yTh@MhB-xQVpm`0nzd%)`d#2BqoxhHgkt6 zVrD3_6$HP07-B2{__`cfmSBqjWu%3A5ss(<01(+9q2{%LZYm4O|y&Nh-$ndj&LmD!y|hje}N~D6HaADO?v#wm$K8SYq5s2(weg3b>`+7tEWkYl7h%A>ehC+YV4v;m+`MfRYQmBr zeA{tHpVjX#1bj_U`1+t?>tC(@*3qL5E=5Rv8(NP*1srDF;(7&2YAriWAZXFqn|EEc zz*N?Su7LBOUDSeP?D zvLMIkaG+5}OWWR8yDYzOxr_?A|Nde2o8Jr3R6q$B3K0S*W!?L_=4V1X4zb}`&b z{&>#4Da8lfiG*UzSpgXJ-QcD>XqW1)CISOVK0BzIhiN_kGHgyMmua1m27=1MuVpCd zzs#3eV*D@f*sHdkz|BV?b7Nf%$acftXq}k)3OB5^GQ+%0N7x#q)f1A`iiZp6OuxAk z%j@JIpBOUM(4B$nwL_`0i~x=C_We8-4iL1@eyQnue*FT8;r#J=zxZErd(`hG|4VLt zapr~?ppk7nlnB1C9WV_q+#k@oyNim~P}x4An+0taypwX?49tP;<Q|&lfAqvuCe?(bXvn^ z>8-nNz>1k4>rMYss;EkjdYuPU8J}n7$Or=kNa`@9_B$`oQ`c&1Pp@yi?4``ceZWrZ z(t3|hz8j*TuuY%fuHVLhGf3ouFG2klC9vc^X>udqJ28;6<0nSezh-%O7DsG&1c@-Ao?C-&HbB<6o3DSrFE6c%S1pX{HGIoJ)w68#G*Xrj4SjbrcxctX}TR`qc3W)j^+l?{2l*8G8wAHo(SY?YEl`e&iZ{YKw5`9!s?Eq%0#bMO__!_JC1U15+(gdx9zeL(I}Z z>zn9&=gfPRSh0a9v%N0Z6?0EFQ4I69kT?SiSsLpk9))J#lE|^6hjBD zKU5tk?#=RW# z;q83?k-lFB@|)@gRJHW($nI`E80&LwWfP=kdM?SU=LaG0?u#`E&GKS51mlZt{O!q7 zuvP0Kkui8tk}~%riWBjUb}B#HQP%IV0>+6%g$t$MZ864q)zsTzHa|yt12R;~egrlJ; z;{z;cFNcv$O0?L`jB*8bzU+YVzQD%{n10-*iF84jVz~xJSsQivRst`54P8dho9{kW z#?`z-vmySZ{KpAoqo{YoPc2?!Tum&cH~ypL)kv&2yE8^Q>ae5MD9gw#I8%<}%KL&J z4|!tNA3Vn<_E&wDgTcP?FzE?G1GDcfmkR?3oU!bfvpj1#NJn<*7`GT$Cz*H@qj9H5 zk@e>L4BO&vXpE6dS$02%Yt!*p^|v+x`T&1%j`2-BN^8?@+Xy&XcEQ?1(sU}Iaq^?eAz$qViMLeDi<0wQ9O!jdE4hk9NKfjC`CgaXJZ zkDBVENV5C6OaXr1v*hAHkucV6&p>br9V*doI2=SMnSngTl-EntBf&{iN;?+I)-uFx z;34;g!z`?Wzv4&15UU5(QcVM0F^F#R@k6CUErYj4$71wq%#Tghbu{35Qg^SSP-AkC zsGdOlV_J+B(4W>e)0Sstim8XeFX4I^C5l>XcJFh}nAT_~Q9Uk38hM>4C{Q7GgiTd1 zp{xpd80hylA+HE8Y@=4(wHDtgiKG@6kC{Zq^{1L5R_hFBwE^YdCA_wiCmvK&Ja!~* z_FdYr?g>YvvT3KWbV#|Ttc*;}{^vXl!!-OvG*_+h2D`(fG=aFPVF_>Y^81#g5LN>;5-3SfwQzPd%u#^J8ejLFj}yBeshQ z6rnketCjRP5fpo}G0(6O%HK9vWiuHTI=y-!j7_t@FEmq>z8-Q#%;}Dj+*^QtE$k?K zN9hC=?aUo|X`fd{+1tI5z+01(Re|O$BhZgC{GJUn>HL#7$^8y5;hFkvY_)OP@;$`` z`%4XC9`nglah5Luhoukg2LDKK)<|iY2@9d~7!xPv6G?p72qK(|FgZFE=sh3!COK*= zoLUxDl_ncmSsiyu@}|j5iMou%_d-{5XPf~2$?k7g{Jtxz_s^Yl&b|kpq{-rU{%L(E zb8yzte%`0x*&AIKr<=Qv{sWojt)N3$@zd>7Xse(&!7_u*VezE9z*g=)m<3>@Z)Hzh(#k#bnq zb-m7SeS$x(pF7$0=HbDg@GN0R>hPbn4PY<3=&P8_2K%->9BC8hFV#r4detS65bAi%4 z)BlKxnqyFH^I)-Qch%1dv%uCdyck$vwZ-mQS^+cH~nUnSs4jGO% zVcbYzci4yX-;2JvUt4y2P_+-GN7Ry*SKkyb;_2yaCh53$hRJw%o=i-;H-&xB)(g`y zwEKD<%1HgRaxt7aK3pze?Li~o!C&Q(xjS#M^p~-Cs?RCZTiZy5TA5>aj|}T`;?to2 zkbKmj9J>lS2}C=+)uB_iRPw09%=qf>(2f=tpVl^yX61LosTsOCZ<|Z;R4LL;feXip zBK_Gk8KO&W_nPA?tu*Z;(#N&^Zu_W@Zn`sO;<6gK3W#H1tBPlwM!c~he$1mu957Ul zA!P7n&e(*&t+EPX`en|_gkVCYzA`BD(Kw?>#(K^HNm$qy)PP?{HcaztlF|xeNlxAB zURof+FPcDm2kKil>8<{1;&%>3#-yiv>R9r^58svQq!^Hr zNugte4&NQ&;ful}AW!>Vmzw$Lv1o?qr=AmDzNk!O0%?kq`ZO?i(3C?C)*~t5+_H6` zrlBW2i{GY#WrClkCS(sN~+-vH~tiK);tg2fJj>^~4MbOr8CzJ_gFatY7V5 z0_Ee}A%yl0UtBO0vdb-Pb-=RGq|Y{BSvJX%=K$<@gk_}~Id~THmN^t)7u;QvODiGq zzVJo>b>SA%GOURw!bV>eEIZMGzFh`SDU>_$v;z?(myu=wf}xolKT@);7a{rk28#1w zYIAbH_z86s>{GK(cpilrJf!ljGtB!YZ4V*y_hn7&L2l?0B(U?7z`jvfSd0h~#$$vv zIWTX~s}BPaWDRdJK(w3Y6$((pCz!d>rmiO-1t0m>5A`MWm(irqi51eyd9)2h;xULA z%pcBR0sMyXf0S@hgOyHa<$2Zyz!W!0D#VIF7v%rbRZ~606FhjfsZ^}=8)Uu;62`58 ze7!Ed4P-c*!-LWe-X1g4CK&8mk-M!@=SiI4q;lqMk)G|T8Y z0o>FH8t~VfxZwR67C-XxI_>~d;wFCO1zp?!<$+_Kgf*BoBg5f>pxuJb+M%Eg1;B0S z%w9x(NyiHX40h;NE8ja&7`2Z)lQE9CfdDl-#$-p*5O~Nl(``a6AtC+cMnK;gULc6P z4c_=fN0BJ_@!CZ?>v}u`?0~{*n>NA#U}3Q4>Wqj42+!Mxehh#d2!i69W8hN^9Ek?r z)s}fwc(AKt=S8G>isWGEP;;5*%K(P+^Mo2k){^j9JbTbjaW^{rdH?K!q=C*j@&z~o zuA?KvY347z67Ljk6Wk*Xk{L{d@IE$&h*exIz=1>`R~JAALbm+}Z*_1Nv~G;!v5#Zs zdo~Jmaf5fBmrjOzk@^IrWPh};gVEzn2=w^^^_1G=$M6jBjLq81MfD{lRxFNrmL14Y zcim-N9~bEMpe72q_@1Q(>dcthofdje9`IGf(~903FEFMf)?@s zn%i25uLGj*AN(!`qMNh7=$O5S&5QRcpT`8plS7#M5)WSgl*>B53q-uNCmI1EJhkKG zR^^>~q6G?ofmoW1 z4tUC>TfqW->;pN0ATu*2fCUd;{7j7_C3~ETOrXt@;s|_DFjl>)14wXtO@?&(m53QU&={%mf=n;QbM` zLnH_zYB0SkHo65M-*Ntx%n#0J$}=|f8s~zD?!Y2)77*<8!&a2*RPrF!ehp1(giiqU zpJVSh;DZozOVUz=5U5-XnB^-Wzs%~DXqKG_G&3S=N{7M7KC)t7r^JMfes`)sjyl26(8A61t(op5;qB;AX0wFVi}AI_Ln2#)H4O>AuywV%+qP0s6az~0x_|m()I}` zQs(S3bOu!nH-x7X~k*La`R`r;UneU%RkHr{=PN<h)4dK^}>cseT2GhG?WBc}VMN zuPs#glnYO+iQ$-R&UsxJnkvE85=lyszGHEc@EmNC+h)8EwM%J*LDJeE??D069sdDo z?}K+&3h~wkf=OwGOOES|pUo1|?1M|aZRNnvOdw<)g`H@ckGlnK55-=bnHBo+^N`3+ zf!3L5csG^d%=9+2TM7xo2C-V$1RBN0-=uqB_a^CK@*-@4OJrk@d0r?nTp9PKe-eO6 zqS}IUhp@1vyc+?0Uh<)-_qkv-MU6GSL(%)DJW!eMpO&(4KyATq~JIK9!ln6Y}QD(FN?Jy6g)`o*?7E{7r z#izNvXg==|(RHT${Ax<(p8;i{Cx3XZ7mTK8(}_V{0N8#oQ0UPOV&w06d@|&}ED}bf zhHlZ10HB^Zd9Z|Q6%1Dp3~&BopaU>@rN2$JfY``7X3CrwyFOi7a=n1eM^%iwMS^xn z(0u~V$aeNK2IxKkEE$MfO#{0I&C{H1zyZ+7KP(4!Orvp4!WW#!B2>EAw-Ac~a26fE zbN#A;;|kT5d2E58t52b@?NrdWui>jI9)Vk|*Y6HsMeRU6CS?0FB#cw3I~o#CL0-4l zZM5^Wb>WQ*B<;qhfC3eFNZbN>W-oWho5 ze=5{=Y@G>B!w23T>7irH-woABdV1~4gM8yq{!F--NqP&v)r5;(+5SE^^zRV3zTvu* z!)=@>0QsUm8FW!wfw`|xsx$RSG=EJw8-Bw=3zwB&r+ayHt5RW0={EwJ7tzW=6D$(m z4d#b6kFtn|83>+V*ZE1SkRgAw9{9Rok+QX`0(wv~5VUoI=EhVr~T5s3M@56Ok!A&dD5wzC#ay6`SKx9JJy*jA$ z&lg0v5T$B>sXt6TaLQ>wy$SE-NU<*1f&J3cQ4elc@3LmTvVn$Ksq`z7^OhgTmY-^c z$Y5Q6oMrNLW35%;*U0Jz!6cpcvIT$+-QmqiHml&Cy=8DFb%F!?-Efm44FzmAMbvb; z6@@|)k4}ZT$SkLbp`hB5n_Sdk0M-4tOd$S%=(_s_=df5p=r`;1)HqMOfc{J2=%--= zx18q9@{t2WvOaKN!3_;O>-V6GpS_}wSdd4E#$+=%Q(YFcqJP2u#>%77Z7u=!WZrg_ zvmO{DGk-??2{i4R6EMSjTF~&foUBH`lWy5!IUmO9&qRiRkqfM zV`LyxV|G&hx;cMq8m`djN?QDwTJ4dPUZ^m zII6BtNE)0L{~pc1B+u;b3p%)g0z~C_-tB{~SWWaFHMU%zgYc1FWywppP8$=`zI7%L z`8ktr*IE7)qo)GfRB%ZO22r7C^ARHNDRB5h=t$n^cW{HV>S0Sec=Z5GwG%W>QZLf;s}Y1{DemrL0u zy-cj|lO)aU!T3?BPgKYI>=xmF>or<$oYyh7cnOn5#`O@_Xy?rKxUQGYH|dHRWFYb7 zbJ1^EeAV=DjjcW3Ax6tB{~lL=W7;B2!U+1X!ksg%AV(ki?@1B-*@An3d5h-=pC9LB zinpoWdKZr$XN5-&@29AFzcEhstE3F@!OMdY@WBh$3ZYfeMsp8}OnI+nkN)_y#{N|p zGq>R%9*(oHdo23Mp&^EgAu9?l;|sKdJadDjJ=*0T(K*6+IEEztsB-zXqX(_LRR5(3 zJ;Wd4`Fi0u5SUxt+PE_m=%4MV>z2aMs+P-nPMM}d>MiPrDvwn(bvVhxhaHQGMnU7w zPiP&?cO10ZeqJM?F8T55d!2`O(dDji##7V&k)akMad*Zho~4$Os`jUR>geL!S@WJB z4IIkwK5G1Nsson!-}0e;j()- znTAL5E!atL;^Q0Mvk-5Wv_tIS6I7Rgwc(5m1HOas7YAqrJufRY=XFX@88HzaCHaQ! zJPj5&DHGhvg;=Ur8^+ljw6m5cRIc-S?6)Ak-j8D{*XS<>UTk=KXH3G>+ZAO@;^Jan zamztVrJ5>Hl6bxm0xwnB?h%LFBJMg@r%r8%^gqo$KQAMhZPfQhxq+W0VLebZK6#_@*xee7 z&xZACfh-$+*!kk%$NcWV)%G%e`r&W$1>&|>97z;Tq*j=rf~0-($9-``&lYb;D7C-t zV>B`+oj1?f%tlNQkr~}hBiERTnPMTZ;MCQ zo#bVJ)kIgJRmA7*t(UIb>Kv~Z(iLxZ2+{mj@#XXLk{^GLvNBdfk!Nm_p<~tMWPWm;?etKM~uaA)*ObM8gnun1nohc2XK6&TM6x@{v7vA{f|Hsjn zib`1S^gH;*cAEE;{-zy`mM$MD+lc;VbRuidrN(4i|Nnml`?JDFGTZz*MFJfKdOYre zy?*-lxA)9ixbMHHo~3tSy2pzlnm1s2olibDgk0PGg zuPql*O^n)^AyzKyyh(C8)4-Hhz7#!e?+5&t&PPa!v>EZos!OOQm&IszUW&2W354Uv zw9P+>P4X9;8J)XnB0h={{Zfp|#%kvs8=Yln0&PZwGnb2K$V|nbOey-Md@Nmsesk{0 z1Zer>+|6Z$tnqMJX!)C+clJ!13u^FkZWqz<6tBN3(F&cD4{Fml_@ADHL0d1Nt)HbnAV>UDV24FGswmf@5Cm{-HPh~seB~mP4$Hg0G24O4!f#gVg!Isi*$V@QO+80MKX=MOX1wqC z7b~MmM|@msQM_J)TDJJIb~e|ZAFsMoU+AGIu#4CsE+W|E)2ds zc=g5&Uru!|mtBk6Nl$I0*!oWm0{kNQoIEEuDQVaSO_!`;R_Be9CuByasiT{$8;vIR z1r0-=jlP_x8;4rer(m`{*V*-pD*ZYt^Z`3+&o63p=!%{gBTp40Z!nei8LM4P3`NYt zz7`e@hgfKYcUbo(DkGlfWjBs=mx&*_x5cWXq1wvlJsmMgbYr{ShKEbU+P+JP1mJQlRjf|OcGi;aO%NVTljM#ZtvRVSbG|z z_QpmwenL`TB!I&i$1I7nB4z%Ep;CiW%#$GH;vSl_mYE+-VvnLaW=9w#p7{l|^X5rY z1pVj;Z}@$X%kx*~*|5{D=ZII%(@Y)qhAgdFWiEtys5da42-VStO6oKFEAL7yzH^6Vta2$lLdvz+0D4oV-xIX zIIp!}9wcBBjM-eZ3}Jr?@1|2&zE|+m{4!clnN@EFXS{nQ(WJ;~u2w=~fr#3@8`gkCog=VQcC8nb2$W6P~TuYwk=56C9Rjphd@wqIUIv3cm1Y1vx%y|~Nfv}kCs zbdL25e~lvj2t)1aIA|hnM_bYE*(PIVknt01pV!9Q){IYH3*GkN_&as_B9?;+RV2}N zWlU8j@h&oDXkV#K9gQqHQiSPJwcA+KivJBsCAZXRBdKVy8(&VQ({zizXi(kwxuN7N zulchK_r`0DzoYK494x3Jn#qfsjxvcv$dvhgTbJ!orhzvkBd3$oG=C1`-gum2iFQjS z@c}ZWHP8IXcoc2W4au6Ydy-aCrO$4B+0=MTUG(L*f%68AnQrqt&zg1-bgbLI9F*5< zYs+;oZAniT;>;#~JP6dYI@|C6{8F|Hug36nmNC$r(>FudNP&|fE$qrQGSB7B_?Kyx z*;Fo$q)1{nMJJqhMsY7s-Mi8Yge+wB<3+Jw(@alI+Z?=*Aj zRYSkF53t0&kPmy%_j=6Y@lDF?qM)eKMe+AvMTM0p&tTtfyJ-A>S(9o=W zlOZass}?hIv{kRV&VzEF$!;b%_51g`mde%fS9y7@J+Jaodx?wmL!!y{y3cO49wJ`f zMYr(mYR1pkx3h_pX-KZ>`78-6vFxK_3xw!7MB%@V6sAN9zluiARk}EHwpRH+BInu->W6JyOk)ZtQ z)4;Cf(W}hE7k(CJ-zU+H(vvw^g`@43!cacPoqQvH_O~JBF2@(@@tN^rReV?4LHn2J zBPjf=YSHEj#L;9M1FEvkcWFN2Pl>C^ex?fb7%_cl$(azpSw{40r;C_{9bWg#=KjkT zcwI_^S9o#aOOc%OTaxYl`KpI6>#CaY(%1v#t@%kW7gFsESaZ&N(R=I$DvF3k7LBEH zOETGtEsa=n%qD*h&!<{K&ja>#_-qHtpyyNaPC`@rOibeC3(s9zYN#uI~M1*(}%{@K^lF>iEMU0(0F3+b>FcZw_Q3k9-x)0>pfeKM#)pVw=%PE zanXf@n3RyA*ttYu4y91 z`^mZWaKtbCFm2XTE!ZHMiQ$N`+h#@0o5wpJ`f3{co};qS&oJq>4*YZ(a#fS|N6%U1;<)nsozdPK$`8ed@5x`y5UIK|wvZ5)m!`1hVXFp~znyMB z`)J@;#+J9a-fCl^TQ|{CY${n@_{sI)eTSz0=*RMv5k~U$()|Oj1hqn!Jgq807j|yb z{nR$`bRb{}GURgn#b~~j$^M^v;Rjpfvn{|jx;W3E-dr^SL|l&(Gc32^PVCVK`mR2` z7s53jf4qWVGfodjGFN~ZLsEgRcCf77O~g>%Fh{>8DVRJy&ULDy433HtsA^-R>ySc}&? zaNhe(CTSSc(>k3(3u?IZ%4nYLlV*I8j@ZN{ejoB&*h?YG{p+N4SA>8BeaI-?tYMce zG#bbZbE+_=Pkj_a7jhJ+!G<|-w;QD)zbO{8>8-!L**c#$8v%ZZ*Lk|fz86~pbg%eK zAxxjfHBD^PRm3krzm2a$4Bb&44uw<1jMkf-YOqah&0Pkuqq7PNt=K)@>1e9+PID_f zkXx^_Rao&0?9j@pCzf+1NO#$=?^+N_z3F^Dkl;7r`7p=HHhHIMr`6(j;L+Osk~2CE z*8azd-mND%`4ju~!whSGH2Q37?3eb?V{)xeTc`&0j=avk`x$xVUS6H*AarYlEf2$| zw~0;ZHe9x(T~yv;VP4+DKiC$$d!vjkt6Zq%zULT zt0$D%=Ey|6tj)Ify}!HSl}%iZ=8NDSc*Jgjg=9T5qbS&$&52qT^>unr5s@f(Y&5sF z;NVk&7#wtxt1L=`2Z7%Cuj1iBweif|H{$tJLTK*n+#B#H-E&(=AcVL)&_|V}ZOz?u zI1%04`yxZ;c;J_TOD`T;Wxu=sMnc-u4)YhY@41c-g9p)ZitPAL`MA%16jZ)=lr z{#l^DVQ`=Q?eMZ?z6h%Lc>gle<^wt2#3-ux;5=x&S$1pdBQ^RF#lJ$d&n*(t1MBRF*+heMu0^@FiFNL6e>ZiE!?j)u zm-_BqkP!UgTfYyJVxe@b_iLVwB!m6!TcT`^qhpTv7rJVhf2^J=Xqz3Ua`C%wvDN-I zx*X56Q)-^(@J(q(_N?<5p*p?sYk=02g`aMFMzXntHdUfm*U5E@(H*@f(FKjweY~x% z-|7*Q;Aj(p0HXTPab&lZAf$8+%b|r^v4omeBDOtc~2Hz zEaxth{$YvHSs#T2wBe{>yr+My)R7h1Fna=RSU#`jg*JE$Gw-j8A|3+d{+6c<`dilB*_Z_?ZIrO#A_$`Dn&sk-#%gO#+Ty!-I(Qh5lhuolbN) zefz)Cb{?=wZAiiXMDb`MO4H4(``b&Z-bd%$Dt{ZbL`2D@1Kz4gKec3 zE#!duw~^BE1`vl|cy2R8=}SC%k!h&iU>B>e3HA1 z9kywQ;qRn1uySPREgx_71p25psIq{$TQUxrGSSd!O2y$^(smmhGxeBVh2O0 z5AWG?U-OOpuHMfBhLq$*O&*=I6pXi%=_d&=*EjkkFKZN@Q`mG3>;iKN(?7rSKs=*l zkx|UaR1hhrS|5s1r)XfUe#W;X0Kg4zpBJa<(m`_~`va50fb16jnUfJRiJQkatNaHk zh%IN`dxqBrizw___rOQmxZI$v;rtj_BIu@x2BTb5+1Q={g#elNU!JBPl;8xudov)& zNTMJx%UmkE07@LfF-iYWY8hC8{uKs6IB~RH0WpGUnj7#5t*WA7@XNI70uGj#VSt;R zjXwek8f{@^vzuEA4DeAcpE5ubX%cMh3)5&P}|V03plQ2_C?Tuf%E z1z1&c^HW%W^~2$m<&vsd7KBeU%gA$0<83r3EdU&$wONmEDS$ikdmKRn^j{I?r79%J$ z&Jo7E6nup>#iu9%b7n*)?)?%14_#7rHE+QN+ddYhw4?`|Cz0HXNI$^4A$_yiPBQt@ zo{EmgcfY^I9fSa%idONPJwUeXO|avKzDfa6n9m*ii~n(YH>CB#4+bd!_hb1DnR+-$ zgmx#f9Od!LBu$8BqLAi$Z}|gIUdjE3Z=I49Ug=YCxKsg1C^_D)isA5aCa*=*!K7nl zt*=*H|1oDHJAzhV(w4;*+6Loem^Grm89b3^qz+gkgyiJ4*F0gzgPKcNnY%H*X32^) zV7g&Gj>x{IV`IwuHshE2BEFj%sp7Nbvv!%J_6_>%WkdkqPItBsO zp}vpz$Q|IRJt3y?^ff=o`Ig|4DMDJzQmY!01@0Fy82-Gt!ux78%qYLwqcQ6CnRP1 zz;1|rKCK?kSr83qW%Xu3LBKClW7+r@Ak4b3CDfg-S(QI|_=?-vz&X79Sle7J0}(9! zCmy*YJ{`Og1#GWg_Ro_rH@6Ny%hn7l2oT;oU0UIkhH%fxFPS4)zjq&i{RC&p5K2wJ zBdXIpRRn79_p!7=d}Vto93EdXYl=580nII0$RYk(Kyc$2Q|Tmdm0o8s<=`(L9CwX* zdzOVjYvk{vI5zRdna>_n3L;Sh7j@`>-V1Rkdp`BA{dRnG%?NJCW{CP2dCd)+97)#~ zM}{oQ{?agY6k7j^gh~YRs(N8!GWyevt^kM;ELUf<0t(R|mEXxxa9GDou{~i0O@n1@ zdX4!jF_e6BDyD4fnSk}!cy_j}3+34@9^dyLqAdaAGvq#5XxKx*w$1!}9{PR&80vue`P%U$ZpmvyMT>0G%`hrUvJj^B~NIOt` z2Zs%%b8es(Z?%E|kMBi??h&wgUMZ{ql)#o*hbr*?2eF(fJ?Lh#gStW^`G#ZjCoH5> zs~C?FDGFu=OP0M>0YvAgpZzn3?h>%WUGaHR8x6QHyy@P11bd_}7n_$Cjt3&>Q`zH> z*dh>)P?rBn4Z3FZilEX?CAI+89mGWSJaoCfr?AVmiohjuPWST)^cIsZjb@ZQ$uQ1% zjp)XI`TMJfWZ_60H0-uOWTFA_UW!Vg|LDkdo{!#wcAAZcqfS8s@!%BnjIFte$$Xx+ z!0+WaA6a|2o*@iUAP7gdl)MIF3_{83wsV3EYmH#0E+6usf?b;1eqxb%6bV?){CeR= zFz(PBI(BK?ivKZbpKB`@hoyro>m{G)Ft3jQ;q{6$VaPy%U0V_fc|52@2rh>iv^;D$ z>?H9PfpEe*6fAW7qZoG9mofiiHKz~$Y8Piwfb85s#r96N{;Mego1uR)=92^inm#rk zl7}kEyo60R=w&C02z>**$mJI=CFi^@rEcf>L&siVR}@zgxEdXw7CpHRb_?8s8GSwI z!g53n>J{|SWEu>KyUpVNv1xxh zzJMA)#%&KKZum76!6FJNHFkg#Du-*^mP0 z$>`xSf}jf&*&8||B(C57;om}@4H`>!Ttym8Rdp=?eWa2FoZgVja(@I(-J6}AcXYcZ zWlr8V#p(xdoQUUZ`Tzr+JdZl_d^3p>c2y*;l6hT-6;#muU{ziqrgu|yFA`u^ADVd` z>LRGf4168H&Zlc$0Sy4V{Xf&|xnP~!)|oiC2?Y1@f8sodhYEsYf^zJk8L(8~HD?s8 zcmX1wr!2F-gq?h*-Ee6DS(tt3wv6xu%LsJ#iz|S*2h6J)Aj3pZPdNk$s9{Uf^Lupv z(d8Qxp2=R*zc>f`#nwt98Mc~S|R8u$MIey|CR6%1`-K?A_d2|2F?YzDlPF9M;wg7 zMC4$R4lNVtWgGrTHxHfzb?)V8EbKSty$&2s+Km&B18p1 zZJUdj27%lCoX+&Rhj^mBj|+nm25Ra(MeqMz0Dac&Z4gFrpeD*p3{Szqb0D2iaM$wr zJxKbWP7U@^mTN(wOkHq7LAP=hJQ|~a>AWVi$oL zccLbjwBbo!Ciyt0_tP~pDrfF-HP+S6US>vjf93LsYf!jw9?boq(>*IpZ7SuN9xjc) z@674tv|C&5R>vhtADg|GMfX$RZrJi!u*gPuE3(wzGc)tD2}+dPS}f(`Rb$p43|$$bV_&EJ!e1fcmIvEW=*e| zai7iFWhxII2Yv1HI(!=1Qs&Rk+xFk)Dvs?O`+sJB`XE3vme6v-|2ZUl**Q|1W$8?0 zo}aJW!@7D|kNAw;7t=$vF1SY!^lG%3Ow+IJ**}4`uR2u1W$;KZn?#Qc{QUH~*2%6B zq%Tj3O0EYPLs@ayNX%-@-J97v?R?YeIpbz7-tbu{_eW}4Uwqz>h_v z;~TKo8k5&4M<67w-kl*Vqm#@LbfA6OwYjgZ88kD&D8V?eZ@KCO4AtdSlACVI+MwPUv7`-*!!uVIbg2wsa`L+p~$t-BrJ`)!rk zTmtJoPL0&KmL|me&r(IddOOYaNIhWtr8L!@wX8cpYUC?3?>JZ^y7EP*1P~75 z57al$!!*@81V4fc?=v%yfJezqq3Eb>K#frJ0;=9|Q;`5(?aFQsK>Ao6^q?JBI(@sh zQ!-dH&!*;4Q(*1tTWAK@I_rku8a?JWSiF3M+eLHkvJOF~!>K6-?XfO1gKV4)K7Mn9 zJEH{2^z9t(!th&baKqQ3nowJip%IM|oPC;SBQkKO4~+h)j$ z<{h*5eKHA)o|H`=_ieODEc1l=FM&4*@38;_H6+{)>OEi3-L{Lxf z*|HB^O}Khr+YiJMMy@{5zS;5hfnGm*n|z3P6lyhX{zDyFSj|_2X_BjltB>+rn|TDOX-7PfDAu|v{6qB)BM2%^eelq@L;}4?6r{e?OY82p z8%)+}kv5RX({U-};G_}9naI-$g3gUIN)maRE`@5VJQC~^dFny96Z5-{M4lQD)Kcq{ zMjl=E{3|^xcS&!!j+&pWDCiE@9t8CbZPRO9hJc`sus&J!OD_;q zA^sArc4>FGfgMhEXG^wOO2>$zb4W+LJeBPG`17E{tDc|RjX!hPDF-%Nr3oL`CEwiN z_r#;sD9kZ)^?!f!2f8NlZGOO|UJ}0&^v;#Vhkb=}0n5c&$#LX4;W!zXslz%xGGjQ4 zTz^U^v)v|ottJ0dv(r$B$Gyu@LYVAZ6~#OvSg+$rWF>!GZ?1oZi3G(^tdF(leG|t5 z(mY+h;qOv+*{2{9CKkW)e3pBwYEp;(X^G6i#q0dl(yw~1--Y^_(!CxwlJdS$8f&b;r(P2qYAEz~crArJmI z2&r}pO_;~6`xkZI(ohT+xYnqC?b?;d zjPTw4f9pgb5KLOQm&qW|>BkdZ8C(h#-&t(YtyMd$H%dcAu`{Z9U5;tk<4J*j#UKxY zgSx^dd@EGou-8Y=@~p$oyeXZx+v=s@J2Ro@=@89>><^Uoni$t{lW#y)3`I=4_e$$H zZ$DVu4gtYhAb6w%H5`oR0l_oat(^UVBHmGp{CKVY&DEhgNlS=TB{S@?AUNaCP7PvF z6fK>e!8Se}{`@YRdPIlDGj)Ami0EqFh&If&DhN4I z0A4`4-pYA{Cj)I~xyipOn&ok)&-fRV942v6s_ZUh;EL|&m^QSv1VKar?dR3qY4Ru{ z)RZp4-VPI!q;CiU$}kI0TT&0!61nEky2S2K7Q*7$FxeD*{F+&jX=o0<{_$LR*$H66 z;>7f~-m@#>tHq(?>Aq4)Fxf4iims@OwE_P(6*Ua#jD?6qFlD>>j3-UKwc&uVe7)0j znSvQ)aX55T65(fVb`>qGiD*$QfMGlLR2xFQGnmZFcv>DH8xkvZJhqW|WvzXlaEp48 z9_|v8N%BoYTkfpc>cv^F-ID)O4>2c_8J$r{%*_Gf=FeWc4+!O;&_aW?-c++!KOTRi zi^kA^IPBfGIyC%E7loN5(rD`A4S1zPGgCL(YWrE1_A5PHi2>~*a>1}^oGC3$Ybn$>ngC|vr$-m?99%ul2Xv+cfu4YJp-o%`!ojx;*R`2xZi357=Fo zk56oSP#?j4IrrVg8G~j5c%`uEdjAa_N7iy1hc%bI(-sRVN)tnQx~?Wm=Q&wg>bG}*ZXFeRBDVR}R97+G?f=fa!Ah(=JKsqYcLc<)2f|zH|0ND2WD3oqCpAHG@?7 zty!y#4G!`^g;gZg{;mD2a~S4edoA;qZTxsFXt__etFw;BZX>V83fImoLzzX#>l80R zM5`Z8_SGECkC9JK=z?+lMyAGG$8C*;T*5F#U#-V&#dF>nWbHgyjHGC-#Ag@;#+;_7 zI;d%yGeRWTpH-nh$Ig?zQ4eS4(07@!4tI&?rdh0(TP}e7bxsvm(1N4@QJOou!28_l z?G@EZt%4;o;eLJu6+Q7FY%JsoQqe?uW)dJ1qa}Pt?8ymA>`^CQ;~4O1 z5~lHCUL1iv!}uCLo`=N?I>^E@`wDjj3#^_X@9%u-xT*l_XK>!wCS759e_Eu5fFUw| zC4wda&g?Lo<&wJEVeW!3LH4gsX#nM3|07(5<+)5rZu4>(s$UwPz1B}ye-LLTWOsuQiS zr}5Nb6={_y5B!G{T-BikmfPZr^!4>}*#h=d3Ok?=J1K;r&yZOQ&61IoY+)41wSzzH z)W(hB>Y9{>C0O@s74$Xabh35+q@?KE=ZT%;y0{e1$v-{cA?Eu3X|p~qsWoLZgyrt; z#_S&JQ+>7>RL*K_czP~Z!pI8VuWjHatWZMt<~?$0s*wTBYAa*~M)O#@c-Iu1<7YSUWzi|IqTvq+w~{K0TpL~k zQ5-&SRI9JGT7R|pyYGt_W2No#gD2VN{ep+a1s&6h-uKQp7c+E&PzLNT#v;CWN0oId z>MZus9F~CK(N6lS`i2EA%Y=bA&sDDF0X0xc`||{%vO{)r9hEC%Maih5HU*V)V}MSR zb(}2XUyJfO6?vr$d%ZA%2p9qB#7Z<;NH>QGdrX9?- zjR7$b#i1(=mCGy6J}T5>ct`x_b;WK1h+)!1vMUE6RF{aWwSOP=uX zjtW6)Dm^C`wDKao6HwlXxIVJb9Cuov4m%PO^gh-jgRt0o2!{)>Dvz7c5J7d*ANk^m zgWy++^D2-s+K77q5*;kN178;qqgM&Psj>ZiN0un`dxH$N>3dYP-1s-#k3z8s6;VuN z-hBU58qFO2n8HNNqCul*=DUfg@P-n_ zP-fUzxB^c+#E>Oaa=HRf00IBP4db*ULj^@v9`8hg0-ZDU=&V+88Q2S=I;!4VjYk83 z)8ePyX7t**O*v*;*bc)X?G7<}99@*ya&&i3*Uxt$}hI=y3S0=d?WM?I4OKb`wgVqcvn z6C!<{Fnwua>`Q&yfE1xWqON|>3B;TF0WhxdJ;_xj$WJpYz?V&iV+l>q2 zb+daTB~K}9|08C0c4_k?Jk&^F}j5_DZsxn8fEm3V-(D#A*@OA{UpCgS!DXV zSJ};d!uWs1mi6HaUwS2OhQ+@TI^Ih^&JY+HeWNqnu{ww` zcIY5xZ%`>upep8e7|o*fS#OV|Z@}Ic+IKRQ%=v71h!Sdy27O&+4L_;t>)*Z;4f(~s zu^y3~Y;O_{dd9Cs8qYzZTBdCqteud7 z`xcofneOb1Y=R8^V%V;}K1MdQzb4FhlxYqG>-{pbH|z%WZ;Q*iEnUx|k}5BM#pSHw zT%OYvek{m=J|n{ht#pqMz@X zix{8!(U_XrL4`R?yoSEK$CeS;hn7rlfreVhZu5{9J@xZr{ddqrj_4||hwC(E2{UFv za)S^s7M|cBUY{<}!02V~bgSWmQCdwfNt7bzZlNIbX-$awPfRyN~i{XV|@&e3P(3+is_9L zk&E8k4|){uOutucFqu`E4+$7HuTZRulLf8kCJN(F^N%nnV;#lEew2{%z6w2)z#0<^ zJvi_DaZq7Kp=*!SbAw>MjF!!$w1IE%{Tl(iFstwB^$#i~k`9f&ke%v@kofJYNfB!K zVI&R(anK(T%()Eec{fa!7Gb1IH(4f2WPcxC#_=P!I!;3Md_x$WNnu=yD97DjXKK+h z#PJehJ;IbY>_b&ztGP;E+T~ZsRV~>{N3Xyo&`Eg+!v7*4Xg)vfU>~6&o$?88JdCD! zt<9T>TrGobn<&L=gAg}R;mdRwc@08_01hRF(bPc$LZoO^b$qnHiNJ1JlCo=zTYe~qk*y!EbcSr^6Ygp+RcWD1nXM^MH|npg6odA-PTt*Q2ll#Jmx1HD#Cb5wM% zhLGvN-P7A!YZn$>Fc<3Os-~u#vJY`Keb@T(nk7N9kb(J+qGH)DT5J`P7qhNo{dybB zDx8{P+NT!D8BUneK}+;WiD8alv{w_BR2wo*L_pjqM1wX;>4*&B%WAKpT}M`tDxH%{ z0mDM-u|1UWCcH5x67zCz2mgxvl-goHe&0BajQnHa+o1W)gNPk{69>XXFbU_8fhI@4 z;GDxwKb;!v_xq`kxK*c5(x@ehW&Ncb1tiq5PK*LsQ(J5Bz4mN&(b*}#e3@Dl>Nqg^qyvkmM_B?QLkQ(5OU|ri^|oappBr zQhn^kliJ-4E{)*VR6SU_lX$mutrDf7>U3xGu6v1a33QgR7Fdu&1ihBYs(m~W2B z0TgKuFve(o>0~ro^lX_D1s|2p8ay&O*=~prW=nP?W|2P%{aHt+6-gfX#eNh8K^W0I zABfFpSnb8y6ToO@9CG(;=C^pP9GP`pCJ(X zJQ~i>%dTm33}@maj`(Q6B!gkIfS#0gsYiFjCW3zq&HIkwh)r03#(lAM*D;*ak2uT$ zxmnDHZUTBV=5agS5iyWZhCN%vx+#oIf_mjT9AD9ygD7DJFKvfy#&C4Tbcr(Y7%x*f zG4$^nsMQaBtPXASs>uTBf3uY-lH6GP7Q5J@W9jytg)m8ZDflM#>BFQ8ProMQ$%UwO zLK%?F9KI^%d}NgUZiiM9h4Dd%*dQ})gABJYQA!j97J@*h>}@p+lD$ueGP#hPn$ZFv zbo&O`;cT5f6awlM4=km;LnGvod`NN;3rFan*kA>iVs(Q|VtLV#7(^iqM=771Wq<_& z)8Qzme`q_(fG(So^|eDAzsYcb2@G+k_!(zr(*LJ}N_Z@eBwbkX4rx6|u%C(F!#e2S zAN@BN~Avb}w!oa-dem42L09aFr1H^`tvu|$m-6EAWY75F4G$ztX}C-G|= zTkDYo_F+~ncEAXo)4GT6W<6Q-P)YKoSylJJL?T}*{FyE_zNJm7l5wta(>MRs2C|8| zF5dV%Z&qbJji4GI>ZsCrP zaYiCxBBJ+kjZ$=3L0!Y|rb9Nu=`U)JU^$o^b2XOV08CEsViXN~*G`H z*$Y07FR^5w)`xo+SB&{&-l3-PYNX)>6whG^T~wtZzgDz*b0dTnD%)k-RGcL}5UXg* zGNXRzqT*@jolUi#@i3Jpbs7F>Uv@EmlNlef3Ux-}g2uJLny1kv^)ELb;RE?hFd zD9ppQm%D_66D}^Wqw4cN&Z{%muvFIcz}_sk*^Ba^yrPoIpLS8t{aN_3P;7{F2BDZ= z=_$+~$R`p|^7Qqg;O|GwmY5WinR-pBYkA@>BA;2iRoI}>zR^iMN$;hMwoCkrX@*6^ zo2Q!S7_*zVL#d`v{Ta<|kIo{Pu`V(XDgz%r6AB~+Ar9;GZ>uGyKL-#6xn7TPIup@K z?OP-~aqzKu6n#TERv3n#9aYDPBtux5lp`+^#yi7|7%d&w!!vN6v8}?KRi;-7oyw8f z1|RkI)~=k&N$?DpuG zowZ(?P4UhfM!cYP^$X#A!ep?=vnY97*I~$-R7}+l(^U4IMXfW26KOuuD4+T z1BbUuJ&< zzO)r)n~61)lnt9U*t^dFbE^dRhY9)cMRIHc9G78)R%|Ol%3(Zi0efpfs{e`|gJuz&p|3*p;@5W6Glvy4!4rj(<2zvp))X} z;zdz2!H(L~J#c@W#M4Ny`fBH>*#1QMd}t-^;~M~ZwL>T+^YlEyd?ck%v7+cFQ^ zU!tPHWI*MmW+z~vT8{LqTg((>2f_}TrHa)!BIcg@$VhGR)e!yAPErxUYaZ|Q*I~PI zi>|#ZYWeTbDhrZXl+2<|PE4XSR+oq3ZC|^0-d!K!m~Iy7`DFE^fLGA;l|J)Ql)bCrL)C< z(m507ccP9(d~bNf?wZHwFjhjba}4&U(ZHL;xN*s1r!eeKS7Yy>m!fic-?jfvCSYUy zWqpACnu7hQZk7VJw)Nd(y$J=n#=(-6oq-*kj!}Qscxe&I(IpA#tJOk8xCMyseVuxx z>f&Yl?-2g91cc$T3lhVNlPt@^P!ST=XWZfS3fEY%B_RyBQ<;3d3f-OAxP6tdf}A{; zaKx(>(HfTPA@;1n^A$nVPWB+S4zH6tDhgb)qHEL>s8(d=fVp^ZEjagC*SlEmkr(b^?Njz zOoxdx8{qtt@@}I1c`Q+&CeQwkkb(hOMzd?>_+^lF(`Fe`UuoVlJs^fWXZJBGXt>pg z=*br{8a>5~yxRv*oe?g|c|*iVTZVWw^z}=4-?zURL7N+=6x@D3H;MXCcw(hj!ixpE zVyRuK&<27lG}a)BfT@0VdB1_;I`1}@oi8S3e`h(i+CASV*j=Wa7M?rL>CJ|Raz0mj zu=-)9uW;4sOJp2FGyYF09oi8LyK{^i&Mvt&3DE5fWRbd0E@^)B~c!GGQ zyu2H8#@uJu8gjwuEsMBjHf?BsC z$lh!&K7(8-)$(#Qz^YlOAPYHfs{+e-Y-0Ea$~W-Eo0ZX9&-&unlAR}?&hYHFeb>7! zh&TH@M$Qjk6u*)#ah-O{t+oe*mpg6m% zaPT`=2D47yz?{c6Lj+&8<5NaN{Lf)!kI*H{Oye)IT_673Mp(Eq8$NFzh4lTiwHX(x z`X$;Q%8Ib6Yf0$f{YnuzWRinROr}#YXrV8as_%AC%dd{3HdaJqnk-kVj)euA_?4N~ z6oR%Kp0<*sRK z6R31Egb2z#8Bab@oQcOP!Wj7zP7b%BeWJ3y%b=0n=I%qzL6KW7WL3|0eTgP>_9}2BPmpk(wqy}1S zj=~8?eYeY39JZ8%A>yzBy!Y7S@Avue)XYDQz~N0rF1BVJ3ml{Huw}~<-HiV^3cm3l z8boirUV?TZT-cY)XJA%*bao)&k@ytj0V70UiGaQ=;<0uzG9ZGH+;%CIX~s+r=gLgU z>N5#tj0D&0a{$@5Hh{1 ziWpHl!4C9e_`#fLft352X_J{~C>*KKoTF_xMS>fHR`jZClbKE^T;CVnu-~~QUvqdDB6nrasB9{>ypBqt|;_oF>|A!H=^F7 zeure5eWT4{2AV3YQGGs`-7XOn(w_t=m&$ZlVuAW8UKz}egLFz|$mmBbu{a|<9LFOO z|G3!;rE*VMq_}m6PM+%Yx>6RO&St$pR|E%jP^muL4y932=(J*r*M^ejOIjbvGETDqMF#K4rc-Z3c!%x&f~$@{=yw72bo0UCaMu#brt z%`kwmi|%pL04!3uI$r_?j7eoM?so%YoCm)R9e|av+zTooGMrWIEzeRd7#jfDCd2Go zsl(E8N$ac|zt^nfwn=_;iA7tV)T(m7YvN%_uev~ zg!0Cdf7Wpl|0^&kBmUB=s%P+A&ql@r^!X`GM|;NKbI|`@Le!D`MNHVrBgR$VxbS`s zwa{I6;r~rSdktxw#D?nR=9ogp5Ahg9j5M}{fnGlF&eMkHINK25-eed4-t7Sgx4a;v zZF??g$oCKkZ5`*^CJ8giQubfc)7||N79)R7?vshjiLdMpi$o~(k6KHjwX=cOL6k|Q9G?Tp zV;4f}%bh=iW1r^bpues*tZb4tI<;)tG18Ok&?}Fi^$#yYGLPr^x)P+e1af#ukG>mS zd*Kj;*K{3E@G;YW_aRcBxhPoK>_gVVdffhb#a}UJuY+$L$ZjQt{F5IbPQ%R;Vr4upDEljNnlFhlF4QkSZp$5=>4Bp zDV4>7lGVv&VvyQ34UqSUpd~t96p;?Q%qLD}%&C}7! z5m#_)#k~MekbY~=8wr$@7jiiBY-cNNs|ggkuCSHnGP4`jDzks+*+aGiG!6v@=sUU@ z=PiSEuWBrCDC?cP2Fq1jSlX=qp|&M|Qf?zUL|moywlp~n1>R-e!1c2Ck7l`uPv!ol zV7NF@-Yw!S)SGrjPrk2&F|i0&@LkwCT5vEmkAJKKJuM^QHA|ACX|;z!&tmvTa?)5S zqAH`em8Q{E_I2_RdNWNv$CN(vW~g?GVIbm8Vv;IUh3Ks*pd1pS=Ts1Y>2|KPzn(5q~3WrZi(l6gqaZ!qpWE2+}{ zs%7!(FoR0I*5|BeoVoR?L%@VEQ5K3>R&a59DcM~ueS`4|$(b`NEhYFN4Z$Y!3qjYs z$)3J_$j}&b-*gQsGfKE7k4dJz%;X5u6-U6Ol-5lp0&_GX)uchNmUfD});IS=T6!wO zJ$vZglny2#NfSa>xy%QGS{UXlH@{0OEzslg6iR5S$%Sl>mlSuVAD86_$Ps#b7cjf( zlvG8=dlv>fsD!MSa&+x87P}I&e|QmOw4Yknct4Og4h=76NgJeDXEVNFNg?&~7wnQ^ zeI$PWeLU@STU`KOKw!;%(8&N2)!)wx|IwQPF@*GeNbP;3E6rz_&!2~g=GBHbOZ1oa z>ml+-edN`VWj}C!>?yj9Bx_W#AnTbnbto@{(D! zDk5h>g%V11b_#h=OJn1n!)d?gpTocnC39VblIb6-yyEn_pj|7z;3c{>Y9}E_KC;t{ zVjGS2N&JZQc*9HF^{n32H|CE;fBi6e>AZMZy%}yAdCyLB)ugfc(Q!4|{6k0%S^{xm z*p|je)LEatnh%slbL@tvZnNUyi&aE#N36dd7S{`31#9?ZuJ$(?rRcsjH$%V`ilS2O z1%81UDBn=3Eg#4m&dtMNc*Da<8rYg9i+<4HJHTNsoWioW+AhF9a@X%&*jw&&ebVGf z-QmAR;Ffu=cVihgJPi-`?29`u z?f8RXA{9eBS74@_RwZ$xHXVh;<38vv#Pb~B;b2{H=e*Q)@H^=Q*)T2-oSaX%qt*cG#3dG;zbX_0( zaukT=h`5j}EZqwPf4P)Xyk4{Ir=rB zK-@erMX0`O!u}`d|5*kl!sLnyou5SLy5`I8$1-_KE~_HjEiP}ScNe1%d}!YlX=5UN zv;XXAtb2taC=k}}ziXLNWCxLt6K|+&a)m)65cbBk_qAUQn?|htLJsM{_FR6j6(Z;3 z6A$jN8un+5n^7O$G0 zX(O4p@NVWf5g;X3Q6GrWw!OkH>K{p3v_;gQnKm*k@Af6^SCW1|E3u_UDCT^|MWCwu z))IW!S37NpM$&`H9FT^!!0<99k#EtVBM8r4<`p#`sgPc*YtPik<=>p2+Bc?9$)!T9 z*k80(pDp9Kz_56ecX8sp;Vm;jAhD8CB*d5U`*UZdMSJqdwkF-QzQ&wZB=(g@5{?GC zQn*L?g~8g>N(Ez#ie-E9m$cf2UG+4YyL`g|nu~7EnD5)HI%Db1;nTPh8gssp*p4}q zGekU==xB95!4Z9-PKMh9b1sJo3EvgjbjIo)nd>`>ux?DY2fVbMR!vA~m)#gMJY7n^ z-p=F z?}Ofi<)C$nuZu6vTZyP3iLPlgJ2!*tbAM8v=I;F2^&K!?Vx>0NlT<(CvNDRN(<)OD zOAR`1IXq~D3v||{A`VvVQp2~ms!JPYl*);hFE62jl;uY0Xg08WC(+&L?ph&Mp3a}) z_U`o&3x`sbdYv`!;L$=Cg zfzW0nnKZl*Lp%ctW%qK?43Cp&771G=GC-DN&($B57+JedrmJ0H%!`BCThXj>xf z4!4^ary(?DA#SMjSS_4U+$7_>QNL>~e_%6yb9vx~CgDH()*d3nYs>8* z22(MxmV(^16ZKvr{G~DTwVNQO0E;M9J?P0Wz!3J>>^4FCQ$VFcTejvwn4YQ-z8)PS z>81Xn0KQ(X?F{~(1QfXBZ0Y^6KR3v5YR^q#h}C8I$km`1`)P+NtvR}#!s#guRax-$ z7_Du_`zs88WQkUf6<#@IXyMT&DKm)7xIe|u`Opfkiaz6)s*=c%k(*E)L}*lwwipYm z_F(%;bSG^U+5aI&M_JZvYI>;&ry#5sBU~h@9t8nKc&8RMh?Io&*;cv^`bjc8W)&ps z_XgOqJZ9s!ychj+S#DFfPpkGle5f?mCfmFcm^n<(3J7v{Qdw~A8cU&2*H`5e`@FI~J+9-WgI(wQO|dBWPz^n^z&RY5{8`FCgRy2aG27+7;I&HXreSe1}@UP{MU zk6l+j1wFd6FTzXQ5fOb}lA_jP_QU>kVd{8sk&FyHxyVJG zgUqF0SEerU_CkGUd+--wNb39}n-0S}6_fA(-cexP~g5EBe&Y<@trw3i1 zp!vffPm#c(B23LyC0h~!XDbQ}cs@(>qt=|33nX!>8o)%if_O=+B6tjdS;%;(*bISz z#D`P!-n>&anT2wuI)kckg_k4sVicXn-`_5?LVA^~n)yhbKSYdb_azSaaJk;;1pT2| z$3aZx{8T7kOwy0rqLZ6n{(A7Yich!3sYNXQAEyn~NSYV!L{K!dC{gC)FMTtq+GM)# zKKbG5TsgE;nA+ZqJv12sv{MOu`CkkZWsDG=2r`YSEfOcDvHl6#y5brpP7GuHJC#`_ z)JvRL!umIosc{S15l%Y=dNI#syU6vpBO0skgs}Y;iN6KfPgB{s@+*G>v|rn9brmyz zO~AbxJH_2bku!wde6SZ)kL)4DMpPCR<#v%1gkAVMM8kW~D}F0~a)sD0(idy)lr^PX z9kplOGOxHGTFG@g2SHfKsg72A7w$=S0tjvYv8%L8Fp4*<(j#EM9oer^D&=IaAlX|7 zP9W*2*Wv@1Y_-QKyzmOdPlH_zNp(q@C3?R-ibw0j)xGRIeK983@ocI)5{yb`c@WnD z$-1|*>~RAEWOoz1u+J#ZS4N!1EG%XY)n+-g~(!vEgCrHN4cDd_-_h16@M2? zQ6@g#JuM`9$hE8O4^xx{eIoPd5XPPGGLR-aXWc<7h%E@be@aA3TE9?7p4^bwh^&4P zih_S{P3@n#&iA~L>=z(SK2>?PiH48AXL_Tl>{nssLGYXi>?zuN41xNWkpFb?C@+U?xE6qf$ z7(*puR5z$A_VyNkF!{eGiy}m@K)r}ISKkO~m@I*%vK9*v)jiBs6wd)bbe`2(Oel)! z03(}yv)%U>5Xg(Zw%+rf%C)tOfXWZtlgEHS=}zr9fT%O}0TM^~H$0EOUmQBO9+>Ig z9_Tp}SUmiv<*V=>O#aJt^imDbFQ7$T zMIX$H#Fd5!u$fBv)KMP1*8M6K#tRbojt6phOve-8<&4{`(+5`6=>73uBtWtf`z0Ts zac|s<5Fi3-@~`<{3+W!9Ay`F}sq2745Fk zj7bCbA8TvBfCE>%iueJpEBAMKfR7p$8qLGO zO#gWA3w{JPN=`}=F_iwIbc3ppk>~`hF1<-@zy)k|=?S_8bY5s%ml^=;Z1veaPb1CsMkqd^=3u&?j$72PLaVk{v? zE%@?L#)P9@tlX}Ta!_TUTZfi|0{_v�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

    YrJkdVHz~Mle@U@uoaxq4WA>+KOf4 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⪻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

    u zzP!8uLWEf}yc4~AGxw7Hcd$MSM{pON~ahIX$hAWdbNOd-aocSRF5 zAv?F%ltqFvf7oBsx(JQiNJ(NjIbXAWWGfY%>M_4PE6EprWHY@1esUJXm44?zrJ7Xr z)DynDvsimX2|dnJ;n}gjCim-FfF(9ZYa(azCVCuer_YTFrbFGA1@jI>7oDRMYv%)q z!`tX{V=SXbZ^$KSiT=*MhO6|2Xevv~2JLNmFa7hDasdtHxZf1ESsB3=AJ6&NnJblP z_wC1df+qily9-Zp(ESl(vk1JwuOH=J#EnjO1A*+Y6dj_aiVl&`j1^1msL-K-B4U4w z&{AFgr$SSo%=hZ>zM(NuYFv}PaJZ4I(LOX4xe%2TMV~r3B~{OUGcUt(ADKyD{Mb{> zf*PG$mR&5h1xCaEPD$MT&%1n9GaDUS$23N70U=Dr&k~@YIOpc)9;Mh$t<2pgvweAh zH3hS0`V2Cvt6QNm{W%Cql)|k}+^7sntMq(Sbd;e;+f(Vz;Mzb32D>$op~(bFF}I-b z(7bCPuK2y-_)<;j%XFWtW3fuE{pOUdCm_CfvB{~(mK5APnVQmO&`kT&d-Jvou1LmI z80vcT=!%@Z(of&OZuj-C$;KVGZ!e29rFjEVC(%y5qr)kA^a`<`ib!o4j0naZ3l<;Q zG^H`2nFdh5@eK?lgwoIYdads?r!b-zbIy}LbD}Gv^-2#-n*Xq6ctSRIOFlH^r7J84 ztQFj?CHsd{Vkby24v!oD9i7yLlW2b^G*Ft!=QA6zs}k-zL`nLI0b^U9j+;JHi&A>n z>R(~y`xJyf-3BCAVVn0FErf967tEtQ-$_vVUWq+vqRuu>veEovWv+18DF?BX*sS`n z9>HPe=>^o9^?RVI>9W=NI{K#hDm?MPbFdi|aJ-nSQ_ak)u&V+6XP;deI`zb2wbbes zGtPqxb@f^nocxL5b|L+Isk9J0zv*McLJ09gE>J+RCheF;x^r791gRjt*LG`~VgXh+ zV8;1_Gq#{bTEWw7XIhCCvu5+UMwh_4r?g<+_PRd;&O|@;?5PoFj`q$yh3IDFq zOo>ZU=F#aDtgQZTj~j*~N<&y#b-0&_WofMyEWGGkTQ|qQt2zMF%!VEbujzCvQG=V6*e#CU#2KGqcf@*-T|}8ifS8jeV7@VrOKu8T+}5pRi=7W zqE*S}seBuM(Kf8{)=t}CecYD2j`jOF%N=Ms87da%3j@n~Zh6OtnIS+yp(?#LjGp?A zX15Xp2G)xRI=@p*_@TkWdN;&8=UHrYu*eKr(!NwsX7|&4=((y3tFiI<(hS`??Z~S& zb3L9h0wyJZX~IHTd7NbG6)H~?m!_|(WQEpNQ)B4F)@y=$TBmrOigI|Mi<$fH8~ zJ>jaCE;f$OvnIikw81EjMU6Hi3Q4YXm(L&9DR|`-3V=5&CO0WJZOo>4eYAyJa%XAU zC(5*V(R}v3*v{3#w@eeG!Lz69Rv1)(w|G#}!|Ea&Jo7~j=sVVG@5|ern-mW7jL0T| zqt&X&X@*#y=?QtTFtnh@2pr8udT&%sY@{+@T1K6hTI(>yTwGRYKss?~dh|xDP#1a^5t*nl|OS~i%W~q(=*Bm6muk$7(0qN_Z zbDhvOvets|S-B};`6oOzyqdh&5XO9v2~o@;T6cFlxl`p~5Y(uG&ZyoBFaq6!m1Bqv z`cTX8#0Wy&gB4@RJPG=b{mScwUt*JClOAUvXa%0Q!Qp4@UifS>^{x;F##9*i z>?)fAOK}w;k}(SB>8;y}{kSxQ-e z$1gR#K9p);=_>(KM?xB%wBt2a_Ve<4?>=G3!oKBS%)iRdiNO@umpKi6@ITdc#(W=b z!yQ=d?hrf$_Edd4LU@1~I%4l;ZI`K9|L=UPVfV>J&ki)oh1HD)C_%rqr1!c$3)L%i zcW*2!e(GNkOz3Um?%vQDcG+jYbCLiXAXqV~`J+(2)_8V4V49YZ1rX7qh&hWng^XiV zNS6+;>OxQGtjkV(pj@fl;2hRQ%HeCgo?(pCxTk-pCp~AXsD<;C%(yWpYgZa{mhM!7 zdMZuoD1rN)KkZ}A-Wab26pWcMkR3*|nrQGK5**|+q?B>DVuuzI^>F{XR6|7LAVxVT z?dD)*bQ(gI6JsMJStM;U(MMS?0vl6>Z{AuQ<_5?9#dLc^Jwd>}rMs)!623$+W9r(s z3A9?%)90)wRW#sUrL?1Qj?({5l}L8t?EJ&bo-~$pE)S>UAR_g{k%zq|+HN!`2{uEu z225JXWrut@j*s8uSqh9Ems^A7Y_%`-*PhST4!GjrYfCX<4tC>>_5`0Qz3qA;&GACm zjzQ7#l*xJ|6!4EaW!lrBDTSOci&f0Y>)O9Y#p(<;VY!l+C0p!RuIUw*lf)I_T9D4Z zc##)DXp%p>etgq7ji#3V@k>K-MPJD$?xSUwOLHm;GQnErl~RN|;OWgi;a^n_ND7o` zqm?@oLFKsvf8E&XED9nzyoma>h;tsNbfSx;5uE&6$J?_@Y@y3X8W*I0$vm6+k4BuJ zP|Ch+1Lf*H`o+!7u6p*=mkv^#LW8+b&^4?Tx6O}2CGUDP{<2iteR@`By`mc_iZ!_C zUCC-ItB+@uI#E!|cm#riy{i^!;ws^i9EZu9p7YweXk&(=f6?55Z08IFkbODQEmT894+d z8>ktVJ<58peQKG(o=$@njMrPc658JCX_P25Hl?G~tz~A&u$AL=7hz!Ifx$ z75`*iv{eWjk>!5AGQ={X4Ne+F{J7;4txhrgOhPp0$@eZ^qcY$&DPE2hPsv?I1U}%H z7oJ9Kv0ogLj5QsKW&bUb%VEiJ;=k961+Hzujt)8@A%#e$>PZ6ANd5yV*sXvm5>grk zQG_v+2VrZK^fD0_0A&AeNBw%_IM(ZdhKoi!! zpZy`C+7F@xucn{{H?WzR5D1ZM(UmMvPe=lmbk?{Pdi@?n@(6b6rxB!H{z@A33 z47k9E9D*>DOXB(qY+rPz1RD?yVygKdio_>_y;5mOaCo1Y8>e7Tq{Nf%1gdHZOyGh7 z!iQR7D&=5G@Hz?+P|2o5p(#SD`7iLofD?>G)~5W5l~4+ml0-_-n=9HZ^N{3A(4e?)QWVV4NULXtoQLJ%a}`ii6oA4NboePXZuoodL&YeSOuRGz* z6i_OKP=wK!4+Bql#$*2>rc??h5A$xYC;BG=#&`brSwWQ|A(e6fWul3E7-)i^fh;)z zl`_B=19?smio2L^S^!`0K7Bc+NFkmq)Q&1v`c??on{kYheVb=iF%=?d^u>Z9-~tt= zCPz^vD$vjFIDyZRkC=$H5fj1s51eO#FZgD510`L7K z!2qaaB1qT0n36fPJk>++!yH)w(Hn3Bjd#ooWdIZ$(k0B{GyMF= zf<1Kbh>05Ap9Ud(S)%^k4j?7207y_v;oB6nFoogwc%>l0^~G62pE#)tjW>XLUxFWi zS7>&`|MFk(a}}_^@~r1G6Ur%21b7{g$2y8guqrutOl~0g5>V+9knkA_e#*_QU4NuR zEP;g4_idg?i4rvj{*t?jgW^Lh_^=2jP-o{&l5`lZ*UIHe*xL z2ryv$$da|1b|K1DaQ=!k&L_?x_N@3{2-Fwu3O+OIM96ba0dToW@6oZVefdhrua1D- zVUTm0cp!>YQ@OX_Z2Nbzb8DgpP?t|OCy;DT;O*DBIn>r{z>r} z^h=quV}G;|NnE|pYVP#2G2etW5>(Rv0=?6>4eVGldxP`{LXm1L_ZHWK9FEqBh#4m^o3merpjEi1Wn9o;_&$ z$~noKxx79>d$uxxtlU$Fh9O>nq>3+lRU1N!|2bX&vWhRay9q*8^f}(-igMBB!wwBE zNrisBjq_8?2E8lH~bOjOHt}DbIMOvE%Z9F8FJD zb9Z8hMwiYl?WlF!AM!sQ`N|kTB>{oNRrlvHu;W^14P{7Tn<_~f9egL2@DU1-b0<9U z=x1%E7YU48+C@{b39?4jw={sM>d^mg#3FlmJo*-R9=R(E+2tG-eO~{1?ey+=N%r`7 z^wW~h)0YpoosyTAQ_G`FACVJ!z4;&JEM*KIZb|dM{U2rBSy4)BcRZN#8GN`y}N9w

    _lt`Ik|{2eDdV-QL0nzTYbQ6h zaB#dV1(WR^$O~3&J!Ks2e>9ry2Y=vM%ES7?Gqk*PlIl&1sbN)*92rKy8QhF8rupw$ zxV=9J<1sH?%HNN*xoAr*JOnY-^<{Z(T@esOGyGa*a4;?j`u*keWFO`M%~Uu9(Zo7J zDR%lTMKrvK-+!6t9CW++z#<^?=1W3N*y-6j-`Ya<*TvELioGWafO?K5(Wz9uAb*3E zZZXl%`E}Di4c(521VSmc$h}3k!u?yiBNe`lKG2yC*4j)B@k+u?W;uPP6TZ#kO|04R zCeIg1lzXGi%U9Wv6%^j&ky&N`+%E7j6A1E@GnFOOg*(Qa@oMGU#YcJRaZ=rLBK@`j z1hl!ULx9J`amH-1-=NuOff_-`U^c=W8ymWA{-KS##*W7)kje*1@b5$wdI>+)Y|h?D zf7C$fpviROhDC*++*1z6n?GuwFP`4wb96-G4(=MUFcI1q{)-Y~@`m$xK7f*$$PE0%30Z+^eLC5xJ4&r~*m z==J~w!UNPC2VZHsHw-M3D6USLjNGa^t_?*Y;DlcT1vld;)1v-%F!krU1ED*~9P3KFAuv3OOxo4>^8TK?G1h41MUQ{Y0^HwA?mQ8KLHahXkMY-ipCY5dZ>KYn_8xM;W4t`Uj3Fdc!II)>Mx)T(aNsJ-e=#x|++-I> zfS23W@q42i*{ZTl?I2fYs5x{tcB3BWwG8RsSdGr>2IV&&8H7LcqjxZNUHi?66l&Ia)r)|qwYOZhk>WB_LKI5arYKhh?ud?8Y?PYU{J^8{5$X3`NjGVQaD5 z4Bj+RZ1me|q*32D;d*M13!x#(b6c*fdOQcfKvh!H6A`Y5ka-$G9DCXx4eT_Hv4-u* z0o&mjXwjHCs~g_SUX#7^xzK>U!k%u9c`K$F^DRW{6r%VRDZ3U(yuDtY=JyYXLBh15 zAi&UZcrgrWEMMyyj9dG4h~QOAy**(jYHv*9#_A7b6A3*2z#`b)G*fe0^dq;CRJNc0 z>0;40X(Lgo2=`~fZxq@AP95{8qm3d>2-zLHH8=T%GfNb8Jzhl?*wQrv(hlmZTMsXDfJ>c4=kceK{>Mv`v%%Pqa0o)f$(BFf5Hgn>o50)wE0YLXq-H=82OqJiMX$kSPv$$?8u} z+f<}ip#e@Y`q$swRJX3|WkiP}CZDyhorGmN1AJX;8Hhal@|ESm*`zxO@YKD@sp0<> z&ELBJPci*nzC{C|IMn%magWWL1X&tMYv$&=lDDDvS-f3|*TVf>EjPMf3&k3} zSNnt%$3mxIi1f+8j`{cF8+`j~Qq^(SxleF0hPv=IxyOfgX}ejyot{&NIZgLt@#vEy zQ9IA>U_0A!KpND=Of!Sd&*m(}05*%Y6j^+&DVkn)R_k#Dgbj4m?FwwRgH_3?HxU=e zp~$D|nE`#G_SoG)kLxYtY^aMvz^f7NY61aGPHQPPRPE(-y=`39<5Kag?%|hY(bzW{ ziR+I&Zz2u1Nu(Bq9|-qmuCv10m+CACmkumbznN=j9GqpJIpRCx+Z3@Pf0oFl zy$cZqh|R3O^%EI}#wQCD!NDpXc^Q#kZF!`wF3WFm$8W`r#zN2FS{86e{!CU%k&dan zejfWbjc=*n!zIuRTwrl7?CZc}E-|!LZO4L_liiXwEiSgEQ1are#5!};_6f(Mg&{F>o<=0FyP<+lg3wkJHFmNfSLd5AQ)!6frtEhpRMxyOs3x{CF*ZVg$n-8bDudJ% zpe2L3ZrqWLsVv-xu4?X$#+Vltl2mFfTMz>f)k6S3yatXJ6Xmj;a<3D7s$2a!U&{3} zRswvk)5+OuYLKiZ*m=&V(o<7z>!>}iFzxXUniKcfIY`LLhECMGI$#q^^x}vS4m_%t z>*SDb{ZDT8Ul*~8f^|E*#7M{XyHlMO;1gm}94oOTJPY3d(RbVi>tYKY66WiR;;S=v zD^VC$n2X{Ki>OF3{k+Sl)~=@m^IkyjMK9-GVvR8A@*?@+I_lny-2iVn7pYJ-pwi?; z0xaykT#dfM+_x}Er~C3-mrKT401&z5ej&mKp`j=$l2yOg=A0nF*xxn%G;frz$SXA@ zLchQ$RD9M(Vb1Ga);zD(T%NIT5>53hz&u=CkuLOGF06onY6EWv+_zz1nX6td7p9gk zS`{5T%1lT|C2~Ddn^>7}v8Hcx7iY}@shw20HZYqTAt{$7jdTgPgm=W(Z)lya1x5-k z5X;G26ykQoBl&Kp5i%1s3FLcGeK41r9MpSE4MB=T8orl6(6+TCU5JPS(LWZ)A={>R zG_V`DH(Go^+q>(LNlGF}0k<@k%)18RarC84^U6l`p=1U16c=^L1YxE7ccslj?Ge4j zvzU-e1ZDD=lIR%Ap$%x z)A3SutOW8wT>=ayqFF=@-4*q2#Hl=+kE^2aNS52j?&O7sxSqa8-W{*E>|ZF?aGTc^fW_Xp~55$F)fSx>nVQZa(^o z{ThDg>I@}2U7N&x0^ohOgpNm>#Exr#Zp8On_4x23?YK9{&{xHf8Kh4?zgbF^5w#>5 zehBPvn@pj7p+E9^prlf}SO?eytD%EO-~g747!hY(l|@73!8LZ?N0Mc-9QAD*#m`QG zXw?n;FAvEJLVU6>Umcg96qM*lanG?_IPB%xRP74^$ATxHIXH~WC-?>Kti+i%+pU>^ zO^CVeJAN*3l8b=2NNn;?@czE2|HdbA4z^A^0Ky||Av1Hv+8hK*TJ0V&h(7p}AB^95 zMvSBdaF+^C+IxKx2CpPoV*FYt5T}d+IB$pnbE_#=2aw z6FvJSnc9gj{3Ug8eIGZ(Do}7^qgebJ7teLV}0PuZc-o}r?tsI^ju%Q`|0XC0ERf{*g5O?)3Wzix0LS~ z3$2}Bv|{GDGS1IH+mjF}T6y&pj6Ct_Rqv?(tnB`$7F%ORMZkcCpW{AH8z&eYFF^p=N}c6# z+j&_4&7|%Fgl^CY`q&9YRQQR~$}jal%c@!=cl5`x1P)GLWZCWO1nfYik8?|j$Xv{> z{vtJZIm+tL1{HA$q@?eTuU*vkcfVK#_VeFHxoMK$5CI>WB!_o^%8F?xcQ+M)e<_X5 z$0M_`?tK1_)RP7X$@O(05+`~JeHbXah`fZZ$*s%rb0iP(I0VwhNg4CKU+J;tPW@Q! z3?qq87iADXVDHj61Mtc9{o&F{nX4=&AD1LemJVb4t4}Pl*tsvxOevAQz+Ur|#L4Bs2?_INZ7lVH=`+ z0gO`lTsJQ5>+=FL-xA1vnP@w}6(L3>tnpCo&{V#YlVw((X>XPHevljE9iNd2+mr)F zxVw4(wr45=lfrP8X<=f zc$tSRIWtm1hHf7?^ zw88QlC_1LR@sTsb@`B|BAw~)HMWVs_sX~8T;j%y80rha+yF>5e@#(XnV?1k5~@-_)&UsC zNejYCBS zW-GNx{vM6ja01)B|5m(_gimxY^VC2F<*zVUEX`L2<0Ofj%YeZg8*q#TQD_w@c&I;Z znqwLlYg~Uy*(Fq|_-BVgFlRES67blzdva)CM_7k%<* zPa%px5!gROZ4`@vd*~hyNtiQ z2|aiX5zV;5ao$k>HE<{Vf*-zJr<{AU2%LMWmoH84-k*GLy=T2h=Htzj_juV+8Mu>5^nhF?QDXFKKuT0buUapVl;*<2&MJ%hr(hQYmk{~-t-S9Q@o*0-GzOf zVOw*kMMu(DN0R08z#^Stc-WZ8@O|3#zXdxc&ryzxhr>QTZtj_v`LUbysnmz3_Khq} zgh=}ejlwy5e1;kFU>wPRb2r4!n@j$v-fzE#=ZXz|)QD6e!t(7WlA}SMK}4U2yfZ}c zFeqk^;71=o|2o60n4Y-*z!wkij^V2p80#DtT%md!3k`JU5;Y=0n!YOm)JYV5ZuDxy?;(@h>7_v~ou5Fl= zP8GZOnS1@9I$Ym6Uesb!?>mzmw)WP4*yJ#(ake%c-b99))!SN>zBwZ0J!)vzSUTF` z^3>EvnHVmlBv~R}uw8Gx!ERK3d^tT6-*()n6O>e4hm<_zubnMgnPAM(Q!+>Ox>GSR z@;6?!2d0L-{>#Lg#)3kZ^NN~`~?$vOmOvc?(ceF5|m(W zMv}1_#Ixo?ER3<7H=xevxi(U#Eb6VZf|HbPWd)6Pl@O7UqW4CGC}#VcT(vE_1Xw~gI3rzu7LP9estu(w;4a2LC zBi%2_7R_keosW<4*DR|k8|rhePVYM%Ar7pA`?WOp3mo|1KZaf+J*<8=di~3VJ@yb0 z!zLeW2%?tX@$391{Aa`ZtN%7as@V#Ejo4x?UaE*s#au&8L(F%&Z$ao$c-S4n za2SN#NN=Sb?O@CKgsE}WD@V+Pd3vNqih;*=%L#!_iS717>1EQxbaSUM9RgV2Ih;2e4nXZy zl;3!WVKSTrh^#3qY^pz`98@(`~oFK6iT)~(dWEK_W|Q?Sb!EA z3Kv>BVkY#V=`K-rT7;>HAm`J=##fwmD(#RP2Ex?HMPxR>8_uHCC~T(-TtGGqxu{|L zciQO&U*KZTSQ4M&5o_ceAt5mYd}1c(ZZm5={1d)G{FI%N(YPDRhbI;Eex>^y@M7q> zMqS=lqGrtFP`*0sZP{;R`0CI-r~*2N8u?)##9vH*Z_h+o-4-OfOv}iTc9hXhO%9Gm zL3Zpb(2vx66s;O|8j6Hu3%4)yg(EA39~U5L(1XDTlt)B*Regt5pkxP10}s5X(IWbK z^^Xd*C0W}MGs6X}qJgsRC27%6A(Oy(VN*1ySjnx@1y#Af!G_H}3LL6`a*Zlo7UEn> z9#&*0UbK6H+PuUzgzZF3RT!XyEwNtyrIRTupRbq{+vk_-RjtTHRt_YNs;X9vTW=-A zfChcu1iEx7=t5^1nU$}Q6yMjoqyLnp!t|MOj9-+iK8@BCgG7}lovM~Dgxu)f#@q)r zZ6lA2*Su!n(Qh(?i?KRIjubE}ojDj0VtpI8dVR3lEh&5kHWWs#95gg;@A}$l(9{7% zL?p%#-b_&#I-;yo79*P}#Dl7_U`}TUF{i9^1PJmE$pz8Gw$T1Tb+(I%r66ZI@FJjEhKm>WdA0s>&`{hrMTF`1KyRn2y_o4T zntlL?m4Dw=soM+VBjL)1##%tj9ULgK-j^A_{240VfY_k_z4g&RuWOmJ*;l`!_;}p; z)PjJV{HwJd`>JAVtG}n9XRClRc^bw#kX9q)M$PH)e8dJHyuH41cTjvk=ws+`i->e* z#;CW5{~&mguG)$<^(>R8gor@Q3`u#m!%PS~iir`YyILACbO*+C-Xe(ZkZx3s zQLHJ0zQMDV;2@zXM|(s*;EAaK2rX4UG9gkFW8I8 zrnq`}MgPKCR@geA%BNe%$lAyO|& zjYVfXwh=G~35lqs689Gij=27TpOO)4#8&HUV*OsltPqB)>UbnD+GZyq!Ez%xR>@$@bBoz27f9Hyhq5^c0)rAtA%fhD&d-l@c)=irxy@DpVT| z@#{X8L<|LgVZtywU2~I_HFxfbK@{xbS-L||JqC?YEpc0d!B5IS&5sFEw_ViKE^vo` zPruc#vnQTm)7{Pzdl23$imI}QFS`C@)uOy8RemThd(g3jpVm%t81?lN8!5z^=W9~o z7ku~&7pROe=kiCsr`dlO$9vsaIr}XZ1#$r&CuS&`hC5DYm8Gab^$iK~#3C$_cu%u& zXjoJhN7Dh6tz2P0haG(t)xI-YxIA_=Q9n?eYS9B&&YNp&M^RTow02mbKW@CX64Dp7 zV%caRZ7u)DVoP@%(PY*&5gX;d14Fr3sm9!EolV^QQaSIpfjs4qH;&Ruuu1ppo}nan zu%D*`YpVxmp+F$wr(<#AMOXowFMerZH8Ut~=ldPnt3u>9 z>Kj!IQQzVpvwxN%Mh@RYN%ccDUpJ?6Fs(Z?a5qRH?V|4<^LCADO(^nqmm5a+=4QMh zX3a&+Yv@80OY~~cJy|^-GZZDNyu7l-e3Zk@6S4I-rW?$}__ z9Zn)~E{1k7l(cKJQg!6JgJ6HCoI+Fd>{@E}ln)n z(2TBL&8rOg43cxPHoq-HwV;#E$-#`SZ_V7^2^HD64?&(oi-BD|d{GaG!Smte4vhUa)jq`O!qjbR@=6l>!WEjjl;NZX(A zXjr9gBLOD-glWJ6qFr8IQ)bvI{@{ag3#_zimjDkp%odXr*{UF5;kaN;@IU)CIGG;h zzVBPsmgEegcCiep>xd(PtmgwDh($xAKRAUw@`+%*;!k26A{e%I2-t9FPYuLxNCTe% zt6X&aP+;u=2pJ^ssTn_^sWM-nmRd!`rlG+?l|`=G0%T;-TJsURF-?d8LrO;(aPt!& z2omOs@xvpxLiD&m9{;Cwt*Ki{eJA~csP3NqioGNAm_?Z9aVps{@S;=G7(=Z&P<^2Kv(t^f2sinp&OT6s z)~QL;&q#@PgZ9EnXKbr=K$__}30m`_7}{hY3(S_0hM^edg3_W_@Dvb7C`JhzdD8-z#T z+JZnIFl>LtL4sac0Q?Bi+NX2+a=r9HXECXk84nL5j`hu$K@S29lk*UqZx(H+PpGfs z?ySkLTYb2=jzw-LPaV)s9(g(U=y7`t8=laftG7>>X%l0YMBdnZqyU0 zQU9ejcc#|x>mU2=Es>>lDWyKWIzo`&I@t4;V5MGEqUwwY2$34I`i$H3dm?n`HG=P2+W{0Bu#{kVBF1;LP_9O!BCUrIZK zk+^2z$J;q}B|^0k@NE3oWKLpN>=_YP`~9W$)Y1O`Fmz-!e;0Fh14<`x@>3x2`^#=|+~2{Dz28dF5jBU6=V)YA^?!`f!qJ$Q z&ui;;!$48J{)qe`q^^koAI|cE74}7Zvv+F#!wJQR0XrM~X}g>6iht?pjG>L>d6;Q} zY;L9WKe_e%;&{N2I{3)AL-3J0WQeu9B<(nHuPNarp97^h z545IQTuM#w4`WX~h+kNLiS;Ys`W6pN^%i>?Z~tTr9g+JK-W3s5L4X&rsMzoZpN_Ti znF6kybiuh^u<%_NW7^$+O%MZLB91hF8WVau#vOV7SQ|wh{6g8*VRAkR>I_4 zdm(LdFhtN$o_@_I9zid==mCeVph4Hu)6*F`VlK5@jo65m{URA;aBh7@04Y5lUz9Bv z(C3(8dB${rK1$?js#}~${_<6nR;&daf0KrUKn>PoV=Hu zSv1*ZX`OK~RTE}CR*M9tCMbsDR7-U1qh11hXIiaUQ!(y5K=gAY;8Y~$KeUyP5Lp?O z%2sTqDD1u4<#ZU;2fX^Kb^pYR*6y>FyO0a(WHz>yO5|dy zyL86e6b4`sXJ)H$wnG!ep#F7wNw#7WMPcr_OE7Z6z{PYmR8j_Jw;v$u?Uk4RE9tt! z;cB0Df)qjYvIyCNsA2VmMli$arhn^J4X-ZQ|;SX4rfh&La{M5cm z9SJWr{qnK2#Hk$}+7vJ3`5<+GN5v0NB#eY9Y`r+W%#w3MUVEo0|L-+3CpUNP#v0s}`S!xOwv5vqZ&qh9DGTX@1blXuP_Z zNEdCm#CDw!qqds}vGu<^!62iZ5O|<;-$sg#H9dXdJLC8cMRK}!gA)A~l#Keu0>&F3 z>eTU3jRPZLvGzenYfH5gVYz;rJ(P^<-1YSd=kJ#%(XmbO{Qnx@jUxcm#4A5BZAN0*TY0$ zf;Q^aj-P?hI#`7HLR82TMHXPgzI%2Zae+oaWCkgTD>aPmeY~?Bc{06t_+w?|`5Ftv zOL&CU(IS`Kojwta>cU&uGYT;0b-ToG;cE$ZF{;nlEXtXwlH0|G=ffB~u<%F6>TW3B zLR~1QT$CFS4iG>_{N>mx$fQm{RD$MNOyf_ATA;Fd~Uh67uzn3$rt2Lv=(3}K^{ z`%(~wdf&)F6Wnq64Ci*!g#2*0A`W5SYt#N!;un9=-;w=%Uv)?=bYgPRn~o~^Qdq}O z7adpol}rahto`miF?I`PEp?O}phx8}SH|95-1rL_#7BL* z4xksRx#Y&9-rs{u@ft`cC^~&%l+oj=n!YbH!YVoxPm{1`Bs=eG<7+sF!m>TVi6&66 zx)82997TC{5ZK@IdFD~zh0IkSR?~AZnvS%DX1}FKes*Tj{jA`>Yb?lNQsj@pW#1pO(cMUt7>MXM$Y%U(U#dr18}KCt*qTcawfyf0T3g`v)0^V+}Wy zT<$>%DMa4!EQ29tFG6go6}gum3umMqVby9=J;Q;s7Rqld(4R=DGk53M$pC$2QYCr( zMN^VFCovX?O(Iy-h0Z}%(@j?bZx!wUy41@!zFjW(E1srjKX}Fg>=yceWrZz@Qv}Rj4K>z&>*gG?OyP#S#s`~!Y9#5 z#8e@3%)tvV$7u+u2@R`KdPsVMCVJ-GJS8VznH~2|HtF#hEU^(3O2`9bbwc&;UTWQtrUbPlbfRcaNNRZ;~{LnWEpCv7>P0GJ*bEC3ch% z8UB7YtXBm`jNiB9E+L(7-HRB_&Lt~rMnwOCCPbk$7d%LR=^-D{I0 z593<&E8?lJSy$yzeP_@j+<01+IsC);Z9d)=rRBB| z(or=95`}kf30h~8p|UB}tQnze2LddC^{@7wMBq}iWM?aIT-xcM<(Vh@GBKLL01xbx zPAI%zksMh!YF4J@d4@U=$Wz?Y@Qw(mXLR0HDk{*M(GpagP_?{1c-R4wd zu2_qccPglqUEg?hJ=(DXB_INeGqvW+|AxZ?;E?!rI__I0s#ARl)4P}ikb6@cLe7`g zFVbkq3emF2^#6zD$@}QIKkY!Vp!^46*XM)oHvyIKR>W*VdtsGL@flR>7P!j*eNoE8 zi^GI^Yw(2%M+SBB@kxF&>AaT~tmX4d?S(BGKD?a|6``_0k}XJM$Jo zmYSDZ-Xtj;^b+-07XEI6oD@fymkQAAO|g6!LA@+PP~-@W{Lw4W{|2jy+$;t=)(;4SU@v z4JW#-wC=yan9Sx8^l*|PiTDB`U2)qHoG7?>dn_KXI0Hnc+Eu*@dPUU_!xP?1z>$c? zkdbY1U^+gnFHsI6vE7o-?{syN(wP=MbgdVlwc?Bvivbeqg(y(^`?DX!_al{P+%n-9{GkQ;EUgb?o{a{JDC!LJ>+HlH+@%g=G)PeOEQ=i`z zRd2GNtQt?e3Fo;%r?b?1FU_d>xOj|+G=jV_is6qmN|Li^gG36v6S{bW2=!%lhoxo2 z+{BeCHf|j=qL3FI0=V*nIL%Dx(Ejp5#L)gER)al~*Dzn({YYy64lQv1P=y!$^gng9 zaYfsCih0afCok1HvYiR;ShzHU2z%E-b!{5(VO@&+gilV7wj1ZlpI@ zLO7TWDjj-HvqTE&H@C&hmK*CKa95r96tCkCl>5X%uYvI^94^WGnnlv>mO&gy(ILrZJ9#3 z#XJXaBf(}X@Gc77{?Y_1?Im~@lWsre`Is=bnByZ%F{g&~S4~{Atr&jy!?5v<=e&lf zF-@DZLK!)xDSwF*&H}=a*qi?1tX9d`qqHT3fo%n4D`?n$z4;!NRaqF2)U1>iIt`WM zx&L>QQDAnZ5<*D1y%l)P=7ditip zb{E?6p!zYcO@?4o#t>6ck7vVRWG;?AynhFu8^u6D0oci^~g_I=Cf7TKt>yCfU7SpsEelxuM9m zWW&v-vy3kJ?$#9}*A1@LXFGfcedK&G3Zf{!-Vg3N1oj5qtd_ZMclX9@iHir3xu`0M zB1PNJ8WUGGy(QOGBwb>3naa^#))pb`;T7xUsjNP-Wz#xU)+#2w75@H}NZGPo|34$k zXPb_e0Ux?HTOO7^y)M|$S8asMO2kwemCqY#?d98Y3$FaNKO6X7a}YX+oi%6;Kgcou zwB7t$KH*>TtKUbVgSN8<)2mUT>)TJZPLdaXx{RBJ&-#o7FdcH)Vb84wjd@ps6qd9k zcIm3lhtaO~=I#|5ylBBsCu|4ne#NzMEfb7?J zlPfj*mW4`Gn7J{f(AF%G=S8NI)ZYVYSAMc`9(6~@qQW&ik{0Y^XeQmhL}h^% zjxjW~ZeN_@eL0RX3{Cm6)t?it*aoI+BN&r6hT&h#wIi@%42|npv&1A@VcNO|qk*B~ z@7N`mhI3V`cr!?aK~m~drdRFLXr(F6SI8e2xd7Vl)y9gmt0!z$y27S+2<&NrrIxPt zoHxrbgqi14pDHnkj098qm0N9CS=m&g;W7VNg0Yy{8hKFslU41_ z0=N|HURD&o=U*7hpm@H?am(WnduJ$}ol~)YDwLg?_FrO3V2i%$(@*2mhwQQ=UA_vU z{B8xKP^TP*Atx*CEjTEg8K&g(fP$Ur%}l^M;aYh_sie-0Zi(Wx;VfPg5zdkL;)@Cw ztdUGPz50|1KRT)LpTy|G!mov}EI`U|cFiqWY5j>WQj^cg${_%rwS6}fYm-S!H7SSp zNs*p}W1TL#!5{ahVE;bs_!mkEP0GM5d^P! t913NaGNbZu;fnavgGOUTX4^8EJ06+;6%>V!Z delta 34 qcmdnx_{)Kpi-D6ZGbJapxP+^LX|f}u#N;#F+#3zp6egD`xBvjTv Date: Tue, 3 Dec 2024 23:17:00 +0800 Subject: [PATCH 479/897] More item changes, remove/deprecate more tooltier usages, change stored map colors --- .../item/GeyserNonVanillaCustomItemData.java | 2 + .../java/org/geysermc/geyser/item/Items.java | 78 +-- .../geyser/item/type/WolfArmorItem.java | 2 +- .../org/geysermc/geyser/level/MapColor.java | 509 +++++++++--------- .../populator/ItemRegistryPopulator.java | 8 +- .../registry/type/GeyserMappingItem.java | 1 - 6 files changed, 295 insertions(+), 305 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java b/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java index 9c9269df3..063a86a03 100644 --- a/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java +++ b/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java @@ -112,6 +112,7 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i return toolType; } + @SuppressWarnings("removal") @Override public String toolTier() { return toolTier; @@ -132,6 +133,7 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i return translationString; } + @SuppressWarnings("removal") @Override public Set repairMaterials() { return repairMaterials; 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 5cdb6c4ce..98450f476 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -43,7 +43,9 @@ 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.LightItem; import org.geysermc.geyser.item.type.MapItem; +import org.geysermc.geyser.item.type.OminousBottleItem; import org.geysermc.geyser.item.type.PlayerHeadItem; import org.geysermc.geyser.item.type.PotionItem; import org.geysermc.geyser.item.type.ShieldItem; @@ -295,8 +297,8 @@ public final class Items { public static final Item RED_WOOL = register(new BlockItem(builder(), Blocks.RED_WOOL)); public static final Item BLACK_WOOL = register(new BlockItem(builder(), Blocks.BLACK_WOOL)); public static final Item DANDELION = register(new BlockItem(builder(), Blocks.DANDELION)); -// TODO public static final Item OPEN_EYEBLOSSOM = register(new BlockItem(builder(), Blocks.OPEN_EYEBLOSSOM)); -// TODO public static final Item CLOSED_EYEBLOSSOM = register(new BlockItem(builder(), Blocks.CLOSED_EYEBLOSSOM)); + public static final Item OPEN_EYEBLOSSOM = register(new BlockItem(builder(), Blocks.OPEN_EYEBLOSSOM)); + public static final Item CLOSED_EYEBLOSSOM = register(new BlockItem(builder(), Blocks.CLOSED_EYEBLOSSOM)); public static final Item POPPY = register(new BlockItem(builder(), Blocks.POPPY)); public static final Item BLUE_ORCHID = register(new BlockItem(builder(), Blocks.BLUE_ORCHID)); public static final Item ALLIUM = register(new BlockItem(builder(), Blocks.ALLIUM)); @@ -445,13 +447,13 @@ public final class Items { public static final Item MELON = register(new BlockItem(builder(), Blocks.MELON)); public static final Item VINE = register(new BlockItem(builder(), Blocks.VINE)); public static final Item GLOW_LICHEN = register(new BlockItem(builder(), Blocks.GLOW_LICHEN)); - //TODO public static final Item RESIN_CLUMP = register(new BlockItem(builder(), Blocks.RESIN_CLUMP)); - //TODO public static final Item RESIN_BLOCK = register(new BlockItem(builder(), Blocks.RESIN_BLOCK)); - //TODO public static final Item RESIN_BRICKS = register(new BlockItem(builder(), Blocks.RESIN_BRICKS)); - //TODO public static final Item RESIN_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.RESIN_BRICK_STAIRS)); - //TODO public static final Item RESIN_BRICK_SLAB = register(new BlockItem(builder(), Blocks.RESIN_BRICK_SLAB)); - //TODO public static final Item RESIN_BRICK_WALL = register(new BlockItem(builder(), Blocks.RESIN_BRICK_WALL)); - //TODO public static final Item CHISELED_RESIN_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_RESIN_BRICKS)); + public static final Item RESIN_CLUMP = register(new BlockItem(builder(), Blocks.RESIN_CLUMP)); + public static final Item RESIN_BLOCK = register(new BlockItem(builder(), Blocks.RESIN_BLOCK)); + public static final Item RESIN_BRICKS = register(new BlockItem(builder(), Blocks.RESIN_BRICKS)); + public static final Item RESIN_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.RESIN_BRICK_STAIRS)); + public static final Item RESIN_BRICK_SLAB = register(new BlockItem(builder(), Blocks.RESIN_BRICK_SLAB)); + public static final Item RESIN_BRICK_WALL = register(new BlockItem(builder(), Blocks.RESIN_BRICK_WALL)); + public static final Item CHISELED_RESIN_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_RESIN_BRICKS)); public static final Item BRICK_STAIRS = register(new BlockItem(builder(), Blocks.BRICK_STAIRS)); public static final Item STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.STONE_BRICK_STAIRS)); public static final Item MUD_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MUD_BRICK_STAIRS)); @@ -536,7 +538,7 @@ public final class Items { 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(), Blocks.BARRIER)); - public static final Item LIGHT = register(new BlockItem(builder(), Blocks.LIGHT)); + public static final Item LIGHT = register(new LightItem(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)); @@ -894,10 +896,10 @@ public final class Items { public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder())); 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())); + public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", builder())); public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder())); public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder())); - public static final Item WOLF_ARMOR = register(new WolfArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder())); + public static final Item WOLF_ARMOR = register(new WolfArmorItem("wolf_armor", builder())); public static final Item FLINT_AND_STEEL = register(new Item("flint_and_steel", builder())); public static final Item BOWL = register(new Item("bowl", builder())); public static final Item APPLE = register(new Item("apple", builder())); @@ -956,30 +958,30 @@ public final class Items { public static final Item WHEAT_SEEDS = register(new BlockItem("wheat_seeds", builder(), Blocks.WHEAT)); public static final Item WHEAT = register(new Item("wheat", builder())); public static final Item BREAD = register(new Item("bread", builder())); - public static final Item LEATHER_HELMET = register(new DyeableArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder())); - public static final Item LEATHER_CHESTPLATE = register(new DyeableArmorItem("leather_chestplate", ArmorMaterial.LEATHER, builder())); - public static final Item LEATHER_LEGGINGS = register(new DyeableArmorItem("leather_leggings", ArmorMaterial.LEATHER, builder())); - public static final Item LEATHER_BOOTS = register(new DyeableArmorItem("leather_boots", ArmorMaterial.LEATHER, builder())); - public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", ArmorMaterial.CHAINMAIL, builder())); - public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", ArmorMaterial.CHAINMAIL, builder())); - public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", ArmorMaterial.CHAINMAIL, builder())); - public static final Item CHAINMAIL_BOOTS = register(new ArmorItem("chainmail_boots", ArmorMaterial.CHAINMAIL, builder())); - public static final Item IRON_HELMET = register(new ArmorItem("iron_helmet", ArmorMaterial.IRON, builder())); - public static final Item IRON_CHESTPLATE = register(new ArmorItem("iron_chestplate", ArmorMaterial.IRON, builder())); - public static final Item IRON_LEGGINGS = register(new ArmorItem("iron_leggings", ArmorMaterial.IRON, builder())); - public static final Item IRON_BOOTS = register(new ArmorItem("iron_boots", ArmorMaterial.IRON, builder())); - public static final Item DIAMOND_HELMET = register(new ArmorItem("diamond_helmet", ArmorMaterial.DIAMOND, builder())); - public static final Item DIAMOND_CHESTPLATE = register(new ArmorItem("diamond_chestplate", ArmorMaterial.DIAMOND, builder())); - public static final Item DIAMOND_LEGGINGS = register(new ArmorItem("diamond_leggings", ArmorMaterial.DIAMOND, builder())); - public static final Item DIAMOND_BOOTS = register(new ArmorItem("diamond_boots", ArmorMaterial.DIAMOND, builder())); - public static final Item GOLDEN_HELMET = register(new ArmorItem("golden_helmet", ArmorMaterial.GOLD, builder())); - public static final Item GOLDEN_CHESTPLATE = register(new ArmorItem("golden_chestplate", ArmorMaterial.GOLD, builder())); - public static final Item GOLDEN_LEGGINGS = register(new ArmorItem("golden_leggings", ArmorMaterial.GOLD, builder())); - public static final Item GOLDEN_BOOTS = register(new ArmorItem("golden_boots", ArmorMaterial.GOLD, builder())); - public static final Item NETHERITE_HELMET = register(new ArmorItem("netherite_helmet", ArmorMaterial.NETHERITE, builder())); - public static final Item NETHERITE_CHESTPLATE = register(new ArmorItem("netherite_chestplate", ArmorMaterial.NETHERITE, builder())); - public static final Item NETHERITE_LEGGINGS = register(new ArmorItem("netherite_leggings", ArmorMaterial.NETHERITE, builder())); - public static final Item NETHERITE_BOOTS = register(new ArmorItem("netherite_boots", ArmorMaterial.NETHERITE, builder())); + public static final Item LEATHER_HELMET = register(new DyeableArmorItem("leather_helmet", builder())); + public static final Item LEATHER_CHESTPLATE = register(new DyeableArmorItem("leather_chestplate", builder())); + public static final Item LEATHER_LEGGINGS = register(new DyeableArmorItem("leather_leggings", builder())); + public static final Item LEATHER_BOOTS = register(new DyeableArmorItem("leather_boots", builder())); + public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", builder())); + public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", builder())); + public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", builder())); + public static final Item CHAINMAIL_BOOTS = register(new ArmorItem("chainmail_boots", builder())); + public static final Item IRON_HELMET = register(new ArmorItem("iron_helmet", builder())); + public static final Item IRON_CHESTPLATE = register(new ArmorItem("iron_chestplate", builder())); + public static final Item IRON_LEGGINGS = register(new ArmorItem("iron_leggings", builder())); + public static final Item IRON_BOOTS = register(new ArmorItem("iron_boots", builder())); + public static final Item DIAMOND_HELMET = register(new ArmorItem("diamond_helmet", builder())); + public static final Item DIAMOND_CHESTPLATE = register(new ArmorItem("diamond_chestplate", builder())); + public static final Item DIAMOND_LEGGINGS = register(new ArmorItem("diamond_leggings", builder())); + public static final Item DIAMOND_BOOTS = register(new ArmorItem("diamond_boots", builder())); + public static final Item GOLDEN_HELMET = register(new ArmorItem("golden_helmet", builder())); + public static final Item GOLDEN_CHESTPLATE = register(new ArmorItem("golden_chestplate", builder())); + public static final Item GOLDEN_LEGGINGS = register(new ArmorItem("golden_leggings", builder())); + public static final Item GOLDEN_BOOTS = register(new ArmorItem("golden_boots", builder())); + public static final Item NETHERITE_HELMET = register(new ArmorItem("netherite_helmet", builder())); + public static final Item NETHERITE_CHESTPLATE = register(new ArmorItem("netherite_chestplate", builder())); + public static final Item NETHERITE_LEGGINGS = register(new ArmorItem("netherite_leggings", builder())); + public static final Item NETHERITE_BOOTS = register(new ArmorItem("netherite_boots", builder())); public static final Item FLINT = register(new Item("flint", builder())); public static final Item PORKCHOP = register(new Item("porkchop", builder())); public static final Item COOKED_PORKCHOP = register(new Item("cooked_porkchop", builder())); @@ -1248,7 +1250,7 @@ public final class Items { public static final Item IRON_HORSE_ARMOR = register(new Item("iron_horse_armor", builder())); public static final Item GOLDEN_HORSE_ARMOR = register(new Item("golden_horse_armor", builder())); public static final Item DIAMOND_HORSE_ARMOR = register(new Item("diamond_horse_armor", builder())); - public static final Item LEATHER_HORSE_ARMOR = register(new Item("leather_horse_armor", builder())); + public static final Item LEATHER_HORSE_ARMOR = register(new DyeableArmorItem("leather_horse_armor", builder())); 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())); @@ -1453,7 +1455,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 Item("ominous_bottle", builder())); + public static final Item OMINOUS_BOTTLE = register(new OminousBottleItem("ominous_bottle", builder())); public static final int AIR_ID = AIR.javaId(); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java index 52ded0407..41c72f532 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java @@ -30,7 +30,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -public class WolfArmorItem extends ArmorItem { +public class WolfArmorItem extends Item { public WolfArmorItem(String javaIdentifier, Builder builder) { super(javaIdentifier, builder); } diff --git a/core/src/main/java/org/geysermc/geyser/level/MapColor.java b/core/src/main/java/org/geysermc/geyser/level/MapColor.java index d84788db2..4b891e9b7 100644 --- a/core/src/main/java/org/geysermc/geyser/level/MapColor.java +++ b/core/src/main/java/org/geysermc/geyser/level/MapColor.java @@ -26,268 +26,261 @@ package org.geysermc.geyser.level; public enum MapColor { - COLOR_0(-1, -1, -1), - COLOR_1(-1, -1, -1), - COLOR_2(-1, -1, -1), - COLOR_3(-1, -1, -1), - COLOR_4(39, 125, 89), - COLOR_5(48, 153, 109), - COLOR_6(56, 178, 127), - COLOR_7(29, 94, 67), - COLOR_8(115, 164, 174), - COLOR_9(140, 201, 213), - COLOR_10(163, 233, 247), - COLOR_11(86, 123, 130), - COLOR_12(140, 140, 140), - COLOR_13(171, 171, 171), - COLOR_14(199, 199, 199), - COLOR_15(105, 105, 105), - COLOR_16(0, 0, 180), - COLOR_17(0, 0, 220), - COLOR_18(0, 0, 255), - COLOR_19(0, 0, 135), - COLOR_20(180, 112, 112), - COLOR_21(220, 138, 138), - COLOR_22(255, 160, 160), - COLOR_23(135, 84, 84), - COLOR_24(117, 117, 117), - COLOR_25(144, 144, 144), - COLOR_26(167, 167, 167), - COLOR_27(88, 88, 88), - COLOR_28(0, 87, 0), - COLOR_29(0, 106, 0), - COLOR_30(0, 124, 0), - COLOR_31(0, 65, 0), - COLOR_32(180, 180, 180), - COLOR_33(220, 220, 220), - COLOR_34(255, 255, 255), - COLOR_35(135, 135, 135), - COLOR_36(129, 118, 115), - COLOR_37(158, 144, 141), - COLOR_38(184, 168, 164), - COLOR_39(97, 88, 86), - COLOR_40(54, 76, 106), - COLOR_41(66, 94, 130), - COLOR_42(77, 109, 151), - COLOR_43(40, 57, 79), - COLOR_44(79, 79, 79), - COLOR_45(96, 96, 96), - COLOR_46(112, 112, 112), - COLOR_47(59, 59, 59), - COLOR_48(180, 45, 45), - COLOR_49(220, 55, 55), - COLOR_50(255, 64, 64), - COLOR_51(135, 33, 33), - COLOR_52(50, 84, 100), - COLOR_53(62, 102, 123), - COLOR_54(72, 119, 143), - COLOR_55(38, 63, 75), - COLOR_56(172, 177, 180), - COLOR_57(211, 217, 220), - COLOR_58(245, 252, 255), - COLOR_59(129, 133, 135), - COLOR_60(36, 89, 152), - COLOR_61(44, 109, 186), - COLOR_62(51, 127, 216), - COLOR_63(27, 67, 114), - COLOR_64(152, 53, 125), - COLOR_65(186, 65, 153), - COLOR_66(216, 76, 178), - COLOR_67(114, 40, 94), - COLOR_68(152, 108, 72), - COLOR_69(186, 132, 88), - COLOR_70(216, 153, 102), - COLOR_71(114, 81, 54), - COLOR_72(36, 161, 161), - COLOR_73(44, 197, 197), - COLOR_74(51, 229, 229), - COLOR_75(27, 121, 121), - COLOR_76(17, 144, 89), - COLOR_77(21, 176, 109), - COLOR_78(25, 204, 127), - COLOR_79(13, 108, 67), - COLOR_80(116, 89, 170), - COLOR_81(142, 109, 208), - COLOR_82(165, 127, 242), - COLOR_83(87, 67, 128), - COLOR_84(53, 53, 53), - COLOR_85(65, 65, 65), - COLOR_86(76, 76, 76), - COLOR_87(40, 40, 40), - COLOR_88(108, 108, 108), - COLOR_89(132, 132, 132), - COLOR_90(153, 153, 153), - COLOR_91(81, 81, 81), - COLOR_92(108, 89, 53), - COLOR_93(132, 109, 65), - COLOR_94(153, 127, 76), - COLOR_95(81, 67, 40), - COLOR_96(125, 44, 89), - COLOR_97(153, 54, 109), - COLOR_98(178, 63, 127), - COLOR_99(94, 33, 67), - COLOR_100(125, 53, 36), - COLOR_101(153, 65, 44), - COLOR_102(178, 76, 51), - COLOR_103(94, 40, 27), - COLOR_104(36, 53, 72), - COLOR_105(44, 65, 88), - COLOR_106(51, 76, 102), - COLOR_107(27, 40, 54), - COLOR_108(36, 89, 72), - COLOR_109(44, 109, 88), - COLOR_110(51, 127, 102), - COLOR_111(27, 67, 54), - COLOR_112(36, 36, 108), - COLOR_113(44, 44, 132), - COLOR_114(51, 51, 153), - COLOR_115(27, 27, 81), - COLOR_116(17, 17, 17), - COLOR_117(21, 21, 21), - COLOR_118(25, 25, 25), - COLOR_119(13, 13, 13), - COLOR_120(54, 168, 176), - COLOR_121(66, 205, 215), - COLOR_122(77, 238, 250), - COLOR_123(40, 126, 132), - COLOR_124(150, 154, 64), - COLOR_125(183, 188, 79), - COLOR_126(213, 219, 92), - COLOR_127(112, 115, 48), - COLOR_128(180, 90, 52), - COLOR_129(220, 110, 63), - COLOR_130(255, 128, 74), - COLOR_131(135, 67, 39), - COLOR_132(40, 153, 0), - COLOR_133(50, 187, 0), - COLOR_134(58, 217, 0), - COLOR_135(30, 114, 0), - COLOR_136(34, 60, 91), - COLOR_137(42, 74, 111), - COLOR_138(49, 86, 129), - COLOR_139(25, 45, 68), - COLOR_140(0, 1, 79), - COLOR_141(0, 1, 96), - COLOR_142(0, 2, 112), - COLOR_143(0, 1, 59), - COLOR_144(113, 124, 147), - COLOR_145(138, 152, 180), - COLOR_146(161, 177, 209), - COLOR_147(85, 93, 110), - COLOR_148(25, 57, 112), - COLOR_149(31, 70, 137), - COLOR_150(36, 82, 159), - COLOR_151(19, 43, 84), - COLOR_152(76, 61, 105), - COLOR_153(93, 75, 128), - COLOR_154(108, 87, 149), - COLOR_155(57, 46, 78), - COLOR_156(97, 76, 79), - COLOR_157(119, 93, 96), - COLOR_158(138, 108, 112), - COLOR_159(73, 57, 59), - COLOR_160(25, 93, 131), - COLOR_161(31, 114, 160), - COLOR_162(36, 133, 186), - COLOR_163(19, 70, 98), - COLOR_164(37, 82, 72), - COLOR_165(45, 100, 88), - COLOR_166(53, 117, 103), - COLOR_167(28, 61, 54), - COLOR_168(55, 54, 112), - COLOR_169(67, 66, 138), - COLOR_170(78, 77, 160), - COLOR_171(41, 40, 84), - COLOR_172(24, 28, 40), - COLOR_173(30, 35, 49), - COLOR_174(35, 41, 57), - COLOR_175(18, 21, 30), - COLOR_176(69, 75, 95), - COLOR_177(84, 92, 116), - COLOR_178(98, 107, 135), - COLOR_179(51, 56, 71), - COLOR_180(64, 64, 61), - COLOR_181(79, 79, 75), - COLOR_182(92, 92, 87), - COLOR_183(48, 48, 46), - COLOR_184(62, 51, 86), - COLOR_185(75, 62, 105), - COLOR_186(88, 73, 122), - COLOR_187(46, 38, 64), - COLOR_188(64, 43, 53), - COLOR_189(79, 53, 65), - COLOR_190(92, 62, 76), - COLOR_191(48, 32, 40), - COLOR_192(24, 35, 53), - COLOR_193(30, 43, 65), - COLOR_194(35, 50, 76), - COLOR_195(18, 26, 40), - COLOR_196(29, 57, 53), - COLOR_197(36, 70, 65), - COLOR_198(42, 82, 76), - COLOR_199(22, 43, 40), - COLOR_200(32, 42, 100), - COLOR_201(39, 51, 122), - COLOR_202(46, 60, 142), - COLOR_203(24, 31, 75), - COLOR_204(11, 15, 26), - COLOR_205(13, 18, 31), - COLOR_206(16, 22, 37), - COLOR_207(8, 11, 19), - COLOR_208(34, 33, 133), - COLOR_209(42, 41, 163), - COLOR_210(49, 48, 189), - COLOR_211(25, 25, 100), - COLOR_212(68, 44, 104), - COLOR_213(83, 54, 127), - COLOR_214(97, 63, 148), - COLOR_215(51, 33, 78), - COLOR_216(20, 17, 64), - COLOR_217(25, 21, 79), - COLOR_218(29, 25, 92), - COLOR_219(15, 13, 48), - COLOR_220(94, 88, 15), - COLOR_221(115, 108, 18), - COLOR_222(134, 126, 22), - COLOR_223(70, 66, 11), - COLOR_224(98, 100, 40), - COLOR_225(120, 122, 50), - COLOR_226(140, 142, 58), - COLOR_227(74, 75, 30), - COLOR_228(43, 31, 60), - COLOR_229(53, 37, 74), - COLOR_230(62, 44, 86), - COLOR_231(32, 23, 45), - COLOR_232(93, 127, 14), - COLOR_233(114, 155, 17), - COLOR_234(133, 180, 20), - COLOR_235(70, 95, 10), - COLOR_236(70, 70, 70), - COLOR_237(86, 86, 86), - COLOR_238(100, 100, 100), - COLOR_239(52, 52, 52), - COLOR_240(103, 123, 152), - COLOR_241(126, 150, 186), - COLOR_242(147, 175, 216), - COLOR_243(77, 92, 114), - COLOR_244(105, 117, 89), - COLOR_245(129, 144, 109), - COLOR_246(150, 167, 127), - COLOR_247(79, 88, 67); + COLOR_0(0), + COLOR_1(0), + COLOR_2(0), + COLOR_3(0), + COLOR_4(-10912473), + COLOR_5(-9594576), + COLOR_6(-8408520), + COLOR_7(-12362211), + COLOR_8(-5331853), + COLOR_9(-2766452), + COLOR_10(-530013), + COLOR_11(-8225962), + COLOR_12(-7566196), + COLOR_13(-5526613), + COLOR_14(-3684409), + COLOR_15(-9868951), + COLOR_16(-4980736), + COLOR_17(-2359296), + COLOR_18(-65536), + COLOR_19(-7929856), + COLOR_20(-9408332), + COLOR_21(-7697700), + COLOR_22(-6250241), + COLOR_23(-11250553), + COLOR_24(-9079435), + COLOR_25(-7303024), + COLOR_26(-5789785), + COLOR_27(-10987432), + COLOR_28(-16754944), + COLOR_29(-16750080), + COLOR_30(-16745472), + COLOR_31(-16760576), + COLOR_32(-4934476), + COLOR_33(-2302756), + COLOR_34(-1), + COLOR_35(-7895161), + COLOR_36(-9210239), + COLOR_37(-7499618), + COLOR_38(-5986120), + COLOR_39(-11118495), + COLOR_40(-9810890), + COLOR_41(-8233406), + COLOR_42(-6853299), + COLOR_43(-11585240), + COLOR_44(-11579569), + COLOR_45(-10461088), + COLOR_46(-9408400), + COLOR_47(-12895429), + COLOR_48(-13816396), + COLOR_49(-13158436), + COLOR_50(-12566273), + COLOR_51(-14605945), + COLOR_52(-10202062), + COLOR_53(-8690114), + COLOR_54(-7375032), + COLOR_55(-11845850), + COLOR_56(-4935252), + COLOR_57(-2303533), + COLOR_58(-779), + COLOR_59(-7895679), + COLOR_60(-6792924), + COLOR_61(-4559572), + COLOR_62(-2588877), + COLOR_63(-9288933), + COLOR_64(-8571496), + COLOR_65(-6733382), + COLOR_66(-5092136), + COLOR_67(-10606478), + COLOR_68(-12030824), + COLOR_69(-10976070), + COLOR_70(-10053160), + COLOR_71(-13217422), + COLOR_72(-6184668), + COLOR_73(-3816148), + COLOR_74(-1710797), + COLOR_75(-8816357), + COLOR_76(-10907631), + COLOR_77(-9588715), + COLOR_78(-8401895), + COLOR_79(-12358643), + COLOR_80(-5613196), + COLOR_81(-3117682), + COLOR_82(-884827), + COLOR_83(-8371369), + COLOR_84(-13290187), + COLOR_85(-12500671), + COLOR_86(-11776948), + COLOR_87(-14145496), + COLOR_88(-9671572), + COLOR_89(-8092540), + COLOR_90(-6710887), + COLOR_91(-11447983), + COLOR_92(-13280916), + COLOR_93(-12489340), + COLOR_94(-11763815), + COLOR_95(-14138543), + COLOR_96(-10933123), + COLOR_97(-9619815), + COLOR_98(-8437838), + COLOR_99(-12377762), + COLOR_100(-14404227), + COLOR_101(-13876839), + COLOR_102(-13415246), + COLOR_103(-14997410), + COLOR_104(-12045020), + COLOR_105(-10993364), + COLOR_106(-10073037), + COLOR_107(-13228005), + COLOR_108(-12035804), + COLOR_109(-10982100), + COLOR_110(-10059981), + COLOR_111(-13221093), + COLOR_112(-9690076), + COLOR_113(-8115156), + COLOR_114(-6737101), + COLOR_115(-11461861), + COLOR_116(-15658735), + COLOR_117(-15395563), + COLOR_118(-15132391), + COLOR_119(-15921907), + COLOR_120(-5199818), + COLOR_121(-2634430), + COLOR_122(-332211), + COLOR_123(-8094168), + COLOR_124(-12543338), + COLOR_125(-11551561), + COLOR_126(-10691627), + COLOR_127(-13601936), + COLOR_128(-13346124), + COLOR_129(-12620068), + COLOR_130(-11894529), + COLOR_131(-14204025), + COLOR_132(-16738008), + COLOR_133(-16729294), + COLOR_134(-16721606), + COLOR_135(-16748002), + COLOR_136(-10798046), + COLOR_137(-9483734), + COLOR_138(-8301007), + COLOR_139(-12309223), + COLOR_140(-11599616), + COLOR_141(-10485504), + COLOR_142(-9436672), + COLOR_143(-12910336), + COLOR_144(-7111567), + COLOR_145(-4941686), + COLOR_146(-3034719), + COLOR_147(-9544363), + COLOR_148(-9422567), + COLOR_149(-7780833), + COLOR_150(-6335964), + COLOR_151(-11261165), + COLOR_152(-9880244), + COLOR_153(-8369315), + COLOR_154(-6989972), + COLOR_155(-11653575), + COLOR_156(-11580319), + COLOR_157(-10461833), + COLOR_158(-9409398), + COLOR_159(-12895927), + COLOR_160(-8168167), + COLOR_161(-6262241), + COLOR_162(-4553436), + COLOR_163(-10336749), + COLOR_164(-12037595), + COLOR_165(-10984403), + COLOR_166(-9997003), + COLOR_167(-13222628), + COLOR_168(-9423305), + COLOR_169(-7716285), + COLOR_170(-6271666), + COLOR_171(-11261911), + COLOR_172(-14148584), + COLOR_173(-13556962), + COLOR_174(-13031133), + COLOR_175(-14805742), + COLOR_176(-10532027), + COLOR_177(-9151404), + COLOR_178(-7902366), + COLOR_179(-12109773), + COLOR_180(-12763072), + COLOR_181(-11841713), + COLOR_182(-11051940), + COLOR_183(-13750224), + COLOR_184(-11128002), + COLOR_185(-9879989), + COLOR_186(-8763048), + COLOR_187(-12573138), + COLOR_188(-13292736), + COLOR_189(-12503729), + COLOR_190(-11780516), + COLOR_191(-14147536), + COLOR_192(-13294824), + COLOR_193(-12506338), + COLOR_194(-11783645), + COLOR_195(-14149102), + COLOR_196(-13289187), + COLOR_197(-12499420), + COLOR_198(-11775446), + COLOR_199(-14144746), + COLOR_200(-10212832), + COLOR_201(-8768729), + COLOR_202(-7455698), + COLOR_203(-11854056), + COLOR_204(-15069429), + COLOR_205(-14740979), + COLOR_206(-14346736), + COLOR_207(-15529208), + COLOR_208(-8052446), + COLOR_209(-6084310), + COLOR_210(-4378575), + COLOR_211(-10217191), + COLOR_212(-9950140), + COLOR_213(-8440237), + COLOR_214(-7061663), + COLOR_215(-11656909), + COLOR_216(-12578540), + COLOR_217(-11594471), + COLOR_218(-10741475), + COLOR_219(-13628145), + COLOR_220(-15771554), + COLOR_221(-15569805), + COLOR_222(-15303034), + COLOR_223(-16039354), + COLOR_224(-14130078), + COLOR_225(-13469064), + COLOR_226(-12939636), + COLOR_227(-14791862), + COLOR_228(-12837077), + COLOR_229(-11918027), + COLOR_230(-11129794), + COLOR_231(-13822176), + COLOR_232(-15827107), + COLOR_233(-15623310), + COLOR_234(-15420283), + COLOR_235(-16097466), + COLOR_236(-12171706), + COLOR_237(-11119018), + COLOR_238(-10197916), + COLOR_239(-13355980), + COLOR_240(-6784153), + COLOR_241(-4548994), + COLOR_242(-2576493), + COLOR_243(-9282483), + COLOR_244(-10914455), + COLOR_245(-9596799), + COLOR_246(-8411242), + COLOR_247(-12363697); private static final MapColor[] VALUES = values(); private final int value; - MapColor(int red, int green, int blue) { - int alpha = 255; - if (red == -1 && green == -1 && blue == -1) - alpha = 0; // transparent - - this.value = ((alpha & 0xFF) << 24) | - ((red & 0xFF) << 16) | - ((green & 0xFF) << 8) | - (blue & 0xFF); + MapColor(int value) { + this.value = value; } public static MapColor fromId(int id) { @@ -297,4 +290,4 @@ public enum MapColor { public int getARGB() { return value; } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index c49ecad1d..a94cf132d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -425,13 +425,7 @@ public class ItemRegistryPopulator { .javaItem(javaItem); if (mappingItem.getToolType() != null) { - if (mappingItem.getToolTier() != null) { - mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType().intern()) - .toolTier(mappingItem.getToolTier().intern()); - } else { - mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType().intern()) - .toolTier(""); - } + mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType().intern()); } if (javaOnlyItems.contains(javaItem) || javaItem.defaultRarity() != Rarity.COMMON) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java b/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java index ab8c52bf6..ae682e8b5 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java @@ -48,7 +48,6 @@ public class GeyserMappingItem { Integer firstBlockRuntimeId; Integer lastBlockRuntimeId; @JsonProperty("tool_type") String toolType; - @JsonProperty("tool_tier") String toolTier; @JsonProperty("armor_type") String armorType; @JsonProperty("protection_value") int protectionValue; @JsonProperty("is_edible") boolean edible = false; From be77e6b2bfefd686f51a676030eb6d084452463f Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 4 Dec 2024 00:01:54 +0800 Subject: [PATCH 480/897] Load default item components --- .../java/org/geysermc/geyser/item/Items.java | 5 -- .../org/geysermc/geyser/item/type/Item.java | 12 +-- .../geysermc/geyser/registry/Registries.java | 5 ++ .../DataComponentRegistryPopulator.java | 89 +++++++++++++++++++ .../translator/item/ItemTranslator.java | 5 +- 5 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java 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 98450f476..664c956c3 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -66,11 +66,6 @@ import static org.geysermc.geyser.item.type.Item.builder; */ @SuppressWarnings("unused") public final class Items { - - static { - // Load data components here - } - public static final Item AIR = register(new Item("air", builder())); public static final Item STONE = register(new BlockItem(builder(), Blocks.STONE)); public static final Item GRANITE = register(new BlockItem(builder(), Blocks.GRANITE)); 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 fde742efa..9b2603284 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 @@ -40,6 +40,7 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.block.type.Block; +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; @@ -65,12 +66,9 @@ public class Item { private final int attackDamage; private final DataComponents baseComponents; // unmodifiable - private final List enchantmentGlintPresent = List.of(Items.ENCHANTED_GOLDEN_APPLE, Items.EXPERIENCE_BOTTLE, Items.WRITTEN_BOOK, - Items.NETHER_STAR, Items.ENCHANTED_BOOK, Items.END_CRYSTAL); - public Item(String javaIdentifier, Builder builder) { this.javaIdentifier = MinecraftKey.key(javaIdentifier); - this.baseComponents = builder.components; + this.baseComponents = builder.components == null ? Registries.DEFAULT_DATA_COMPONENTS.get(javaId) : builder.components; this.attackDamage = builder.attackDamage; } @@ -297,7 +295,7 @@ public class Item { } public static Builder builder() { - return new Builder().components(new DataComponents(ImmutableMap.of())); // TODO actually set components here + return new Builder(); } public static final class Builder { @@ -315,10 +313,6 @@ public class Item { return this; } - public DataComponents components() { - return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); - } - private Builder() { } } 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 61bb42454..fc41275ae 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -47,6 +47,7 @@ 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.DataComponentRegistryPopulator; import org.geysermc.geyser.registry.populator.ItemRegistryPopulator; import org.geysermc.geyser.registry.populator.PacketRegistryPopulator; import org.geysermc.geyser.registry.populator.TagRegistryPopulator; @@ -60,6 +61,7 @@ import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; import org.geysermc.mcprotocollib.network.packet.Packet; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; 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; @@ -139,6 +141,8 @@ public final class Registries { */ public static final SimpleMappedRegistry JAVA_ITEM_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); + public static final ListRegistry DEFAULT_DATA_COMPONENTS = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); + /** * A versioned registry which holds {@link ItemMappings} for each version. These item mappings contain * primarily Bedrock version-specific data. @@ -209,6 +213,7 @@ public final class Registries { public static void populate() { PacketRegistryPopulator.populate(); + DataComponentRegistryPopulator.populate(); ItemRegistryPopulator.populate(); TagRegistryPopulator.populate(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java new file mode 100644 index 000000000..0c89760b1 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java @@ -0,0 +1,89 @@ +/* + * 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.common.collect.ImmutableMap; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.geysermc.geyser.GeyserBootstrap; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; +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.ItemCodecHelper; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class DataComponentRegistryPopulator { + + public static void populate() { + GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); + List defaultComponents; + try (InputStream stream = bootstrap.getResourceOrThrow("mappings/item_data_components.json")) { + JsonElement rootElement = JsonParser.parseReader(new InputStreamReader(stream)); + JsonArray jsonArray = rootElement.getAsJsonArray(); + + defaultComponents = new ObjectArrayList<>(jsonArray.size()); + + for (JsonElement element : jsonArray) { + JsonObject entryObject = element.getAsJsonObject(); + JsonObject components = entryObject.getAsJsonObject("components"); + + Map, DataComponent> map = new HashMap<>(); + + for (Map.Entry componentEntry : components.entrySet()) { + String encodedValue = componentEntry.getValue().getAsString(); + byte[] bytes = Base64.getDecoder().decode(encodedValue); + ByteBuf buf = Unpooled.wrappedBuffer(bytes); + MinecraftCodecHelper helper = new MinecraftCodecHelper(); + int varInt = helper.readVarInt(buf); + DataComponentType dataComponentType = DataComponentType.from(varInt); + DataComponent dataComponent = dataComponentType.readDataComponent(ItemCodecHelper.INSTANCE, buf); + + map.put(dataComponentType, dataComponent); + } + + defaultComponents.add(new DataComponents(ImmutableMap.copyOf(map))); + } + } catch (Exception e) { + throw new AssertionError("Unable to load or parse components", e); + } + + Registries.DEFAULT_DATA_COMPONENTS.set(defaultComponents); + } +} 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 376957d67..54bbe086c 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 @@ -102,6 +102,9 @@ public final class ItemTranslator { SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.BODY, "body"); } + private final static List GLINT_PRESENT = List.of(Items.ENCHANTED_GOLDEN_APPLE, Items.EXPERIENCE_BOTTLE, Items.WRITTEN_BOOK, + Items.NETHER_STAR, Items.ENCHANTED_BOOK, Items.END_CRYSTAL); + private ItemTranslator() { } @@ -180,7 +183,7 @@ public final class ItemTranslator { } // Add enchantment override. We can't remove it - enchantments would stop showing - but we can add it. - if (components.getOrDefault(DataComponentType.ENCHANTMENT_GLINT_OVERRIDE, false)) { + if (components.getOrDefault(DataComponentType.ENCHANTMENT_GLINT_OVERRIDE, false) && !GLINT_PRESENT.contains(javaItem)) { NbtMapBuilder nbtMapBuilder = nbtBuilder.getOrCreateNbt(); nbtMapBuilder.putIfAbsent("ench", NbtList.EMPTY); } From d114ab9ad1e71098c7e9956e1f2ca475eff9d291 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 4 Dec 2024 00:43:06 +0800 Subject: [PATCH 481/897] send ServerboundPlayerLoadedPacket, update built-in-tags --- .../geyser/session/cache/tags/BlockTag.java | 6 ++-- .../geyser/session/cache/tags/ItemTag.java | 32 +++++++++++++++++-- ...SetLocalPlayerAsInitializedTranslator.java | 2 ++ 3 files changed, 35 insertions(+), 5 deletions(-) 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 6ad666780..59d301a89 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 @@ -56,6 +56,7 @@ public final class BlockTag { 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 PALE_OAK_LOGS = create("pale_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"); @@ -80,8 +81,8 @@ public final class BlockTag { 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 BEE_ATTRACTIVE = create("bee_attractive"); 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"); @@ -97,6 +98,7 @@ public final class BlockTag { 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 SHULKER_BOXES = create("shulker_boxes"); 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"); @@ -130,7 +132,6 @@ public final class BlockTag { 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"); @@ -198,6 +199,7 @@ public final class BlockTag { 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 BATS_SPAWNABLE_ON = create("bats_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"); 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 4f42f146a..e2f4f2db3 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 @@ -53,6 +53,7 @@ public final class ItemTag { 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 PALE_OAK_LOGS = create("pale_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"); @@ -77,11 +78,13 @@ public final class ItemTag { 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 PIGLIN_SAFE_ARMOR = create("piglin_safe_armor"); + public static final Tag DUPLICATES_ALLAYS = create("duplicates_allays"); + public static final Tag BREWING_FUEL = create("brewing_fuel"); + public static final Tag SHULKER_BOXES = create("shulker_boxes"); 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"); @@ -103,6 +106,7 @@ public final class ItemTag { 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 PANDA_EATS_FROM_GROUND = create("panda_eats_from_ground"); 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"); @@ -135,7 +139,20 @@ public final class ItemTag { 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 WOODEN_TOOL_MATERIALS = create("wooden_tool_materials"); public static final Tag STONE_TOOL_MATERIALS = create("stone_tool_materials"); + public static final Tag IRON_TOOL_MATERIALS = create("iron_tool_materials"); + public static final Tag GOLD_TOOL_MATERIALS = create("gold_tool_materials"); + public static final Tag DIAMOND_TOOL_MATERIALS = create("diamond_tool_materials"); + public static final Tag NETHERITE_TOOL_MATERIALS = create("netherite_tool_materials"); + public static final Tag REPAIRS_LEATHER_ARMOR = create("repairs_leather_armor"); + public static final Tag REPAIRS_CHAIN_ARMOR = create("repairs_chain_armor"); + public static final Tag REPAIRS_IRON_ARMOR = create("repairs_iron_armor"); + public static final Tag REPAIRS_GOLD_ARMOR = create("repairs_gold_armor"); + public static final Tag REPAIRS_DIAMOND_ARMOR = create("repairs_diamond_armor"); + public static final Tag REPAIRS_NETHERITE_ARMOR = create("repairs_netherite_armor"); + public static final Tag REPAIRS_TURTLE_HELMET = create("repairs_turtle_helmet"); + public static final Tag REPAIRS_WOLF_ARMOR = create("repairs_wolf_armor"); 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"); @@ -151,7 +168,6 @@ public final class ItemTag { 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"); @@ -161,7 +177,15 @@ public final class ItemTag { 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 VILLAGER_PICKS_UP = create("villager_picks_up"); public static final Tag DYEABLE = create("dyeable"); + public static final Tag FURNACE_MINECART_FUEL = create("furnace_minecart_fuel"); + public static final Tag BUNDLES = create("bundles"); + public static final Tag SKELETON_PREFERRED_WEAPONS = create("skeleton_preferred_weapons"); + public static final Tag DROWNED_PREFERRED_WEAPONS = create("drowned_preferred_weapons"); + public static final Tag PIGLIN_PREFERRED_WEAPONS = create("piglin_preferred_weapons"); + public static final Tag PILLAGER_PREFERRED_WEAPONS = create("pillager_preferred_weapons"); + public static final Tag WITHER_SKELETON_DISLIKED_WEAPONS = create("wither_skeleton_disliked_weapons"); 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"); @@ -181,6 +205,8 @@ public final class ItemTag { 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 Tag MAP_INVISIBILITY_EQUIPMENT = create("map_invisibility_equipment"); + public static final Tag GAZE_DISGUISE_EQUIPMENT = create("gaze_disguise_equipment"); private ItemTag() {} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java index 47c5bfd35..556d8cd8d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java @@ -34,6 +34,7 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.LoginEncryptionUtils; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundPlayerLoadedPacket; @Translator(packet = SetLocalPlayerAsInitializedPacket.class) public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator { @@ -72,6 +73,7 @@ public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslat session.getFormCache().resendAllForms(); GeyserImpl.getInstance().eventBus().fire(new SessionJoinEvent(session)); + session.sendDownstreamGamePacket(ServerboundPlayerLoadedPacket.INSTANCE); } } } From db246ffb3b98bf367fbc1c964f304bc75b404143 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 4 Dec 2024 01:28:29 +0800 Subject: [PATCH 482/897] Update Properties/Blocks, re-include neoforge, target 1.21.4 release --- .../GeyserSpigotNativeWorldManager.java | 1 - .../geysermc/geyser/level/block/Blocks.java | 73 +++++++++++++------ .../level/block/property/Properties.java | 13 ++-- .../inventory/AnvilInventoryTranslator.java | 2 +- .../inventory/BaseInventoryTranslator.java | 2 +- .../inventory/BeaconInventoryTranslator.java | 2 +- .../inventory/BrewingInventoryTranslator.java | 4 +- .../CartographyInventoryTranslator.java | 2 +- .../inventory/CrafterInventoryTranslator.java | 2 +- .../CraftingInventoryTranslator.java | 4 +- .../EnchantingInventoryTranslator.java | 4 +- .../GrindstoneInventoryTranslator.java | 2 +- .../inventory/LoomInventoryTranslator.java | 2 +- .../MerchantInventoryTranslator.java | 2 +- .../inventory/OldSmithingTableTranslator.java | 4 +- .../inventory/PlayerInventoryTranslator.java | 8 +- .../SmithingInventoryTranslator.java | 2 +- .../StonecutterInventoryTranslator.java | 2 +- .../ChestedHorseInventoryTranslator.java | 4 +- .../horse/HorseInventoryTranslator.java | 2 +- .../entity/JavaSetEquipmentTranslator.java | 4 +- .../org/geysermc/geyser/util/BlockUtils.java | 49 +------------ gradle/libs.versions.toml | 6 +- settings.gradle.kts | 4 +- 24 files changed, 94 insertions(+), 106 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java index c99ca4e78..96ae41933 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java @@ -33,7 +33,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.adapters.WorldAdapter; import org.geysermc.geyser.adapters.paper.PaperAdapters; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; 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 5db38c559..7dc526ee3 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 @@ -398,9 +398,10 @@ public final class Blocks { .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) + public static final Block CREAKING_HEART = register(new Block("creaking_heart", builder().setBlockEntity(BlockEntityType.CREAKING_HEART).destroyTime(10.0f) + .booleanState(ACTIVE) .enumState(AXIS, Axis.VALUES) - .enumState(CREAKING))); + .booleanState(NATURAL))); 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) @@ -592,9 +593,9 @@ public final class Blocks { .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) + public static final Block STONE_PRESSURE_PLATE = register(new Block("stone_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block IRON_DOOR = register(new DoorBlock("iron_door", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block IRON_DOOR = register(new DoorBlock("iron_door", builder().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF) .enumState(DOOR_HINGE) @@ -822,6 +823,14 @@ public final class Blocks { .booleanState(UP) .booleanState(WATERLOGGED) .booleanState(WEST))); + public static final Block RESIN_CLUMP = register(new Block("resin_clump", builder().pushReaction(PistonBehavior.DESTROY) + .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) @@ -845,6 +854,24 @@ public final class Blocks { public static final Block MYCELIUM = register(new Block("mycelium", builder().destroyTime(0.6f) .booleanState(SNOWY))); public static final Block LILY_PAD = register(new Block("lily_pad", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block RESIN_BLOCK = register(new Block("resin_block", builder())); + public static final Block RESIN_BRICKS = register(new Block("resin_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); + public static final Block RESIN_BRICK_STAIRS = register(new Block("resin_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))); + public static final Block RESIN_BRICK_SLAB = register(new Block("resin_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); + public static final Block RESIN_BRICK_WALL = register(new Block("resin_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); + public static final Block CHISELED_RESIN_BRICKS = register(new Block("chiseled_resin_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); 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) @@ -860,7 +887,7 @@ public final class Blocks { public static final Block NETHER_WART = register(new Block("nether_wart", builder().pushReaction(PistonBehavior.DESTROY) .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) + public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity(BlockEntityType.BREWING_STAND).destroyTime(0.5f) .booleanState(HAS_BOTTLE_0) .booleanState(HAS_BOTTLE_1) .booleanState(HAS_BOTTLE_2))); @@ -888,7 +915,7 @@ public final class Blocks { .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) + public static final Block ENDER_CHEST = register(new Block("ender_chest", builder().setBlockEntity(BlockEntityType.ENDER_CHEST).destroyTime(22.5f) .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) @@ -1062,9 +1089,9 @@ public final class Blocks { .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) + public static final Block LIGHT_WEIGHTED_PRESSURE_PLATE = register(new Block("light_weighted_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .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) + public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .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) @@ -2096,14 +2123,14 @@ public final class Blocks { 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))); - public static final Block BELL = register(new Block("bell", builder().setBlockEntity(BlockEntityType.BELL).requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block BELL = register(new Block("bell", builder().setBlockEntity(BlockEntityType.BELL).destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) .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) + public static final Block LANTERN = register(new Block("lantern", builder().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(HANGING) .booleanState(WATERLOGGED))); - public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(HANGING) .booleanState(WATERLOGGED))); public static final Block CAMPFIRE = register(new Block("campfire", builder().setBlockEntity(BlockEntityType.CAMPFIRE).destroyTime(2.0f) @@ -2307,7 +2334,7 @@ public final class Blocks { public static final Block POLISHED_BLACKSTONE_SLAB = register(new Block("polished_blackstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .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) + public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .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) @@ -2606,49 +2633,49 @@ public final class Blocks { 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))); - public static final Block COPPER_DOOR = register(new DoorBlock("copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block COPPER_DOOR = register(new DoorBlock("copper_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 EXPOSED_COPPER_DOOR = register(new DoorBlock("exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block EXPOSED_COPPER_DOOR = register(new DoorBlock("exposed_copper_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 OXIDIZED_COPPER_DOOR = register(new DoorBlock("oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block OXIDIZED_COPPER_DOOR = register(new DoorBlock("oxidized_copper_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 WEATHERED_COPPER_DOOR = register(new DoorBlock("weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block WEATHERED_COPPER_DOOR = register(new DoorBlock("weathered_copper_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 WAXED_COPPER_DOOR = register(new DoorBlock("waxed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block WAXED_COPPER_DOOR = register(new DoorBlock("waxed_copper_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 WAXED_EXPOSED_COPPER_DOOR = register(new DoorBlock("waxed_exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block WAXED_EXPOSED_COPPER_DOOR = register(new DoorBlock("waxed_exposed_copper_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 WAXED_OXIDIZED_COPPER_DOOR = register(new DoorBlock("waxed_oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block WAXED_OXIDIZED_COPPER_DOOR = register(new DoorBlock("waxed_oxidized_copper_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 WAXED_WEATHERED_COPPER_DOOR = register(new DoorBlock("waxed_weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + public static final Block WAXED_WEATHERED_COPPER_DOOR = register(new DoorBlock("waxed_weathered_copper_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) @@ -2888,8 +2915,12 @@ public final class Blocks { .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) + public static final Block PALE_HANGING_MOSS = register(new Block("pale_hanging_moss", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(TIP))); + public static final Block OPEN_EYEBLOSSOM = register(new Block("open_eyeblossom", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block CLOSED_EYEBLOSSOM = register(new Block("closed_eyeblossom", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_OPEN_EYEBLOSSOM = register(new FlowerPotBlock("potted_open_eyeblossom", OPEN_EYEBLOSSOM, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_CLOSED_EYEBLOSSOM = register(new FlowerPotBlock("potted_closed_eyeblossom", CLOSED_EYEBLOSSOM, builder().pushReaction(PistonBehavior.DESTROY))); 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 3e5f1b510..f295c4f51 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 @@ -29,8 +29,12 @@ import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Direction; public final class Properties { + public static final BooleanProperty ACTIVE = BooleanProperty.create("active"); public static final BooleanProperty ATTACHED = BooleanProperty.create("attached"); + public static final BooleanProperty BERRIES = BooleanProperty.create("berries"); + public static final BooleanProperty BLOOM = BooleanProperty.create("bloom"); public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom"); + public static final BooleanProperty CAN_SUMMON = BooleanProperty.create("can_summon"); public static final BooleanProperty CONDITIONAL = BooleanProperty.create("conditional"); public static final BooleanProperty DISARMED = BooleanProperty.create("disarmed"); public static final BooleanProperty DRAG = BooleanProperty.create("drag"); @@ -47,22 +51,20 @@ 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 NATURAL = BooleanProperty.create("natural"); public static final BooleanProperty OCCUPIED = BooleanProperty.create("occupied"); public static final BooleanProperty OPEN = BooleanProperty.create("open"); public static final BooleanProperty PERSISTENT = BooleanProperty.create("persistent"); public static final BooleanProperty POWERED = BooleanProperty.create("powered"); public static final BooleanProperty SHORT = BooleanProperty.create("short"); + public static final BooleanProperty SHRIEKING = BooleanProperty.create("shrieking"); public static final BooleanProperty SIGNAL_FIRE = BooleanProperty.create("signal_fire"); public static final BooleanProperty SNOWY = BooleanProperty.create("snowy"); + public static final BooleanProperty TIP = BooleanProperty.create("tip"); public static final BooleanProperty TRIGGERED = BooleanProperty.create("triggered"); public static final BooleanProperty UNSTABLE = BooleanProperty.create("unstable"); public static final BooleanProperty WATERLOGGED = BooleanProperty.create("waterlogged"); - public static final BooleanProperty BERRIES = BooleanProperty.create("berries"); - public static final BooleanProperty BLOOM = BooleanProperty.create("bloom"); - public static final BooleanProperty SHRIEKING = BooleanProperty.create("shrieking"); - public static final BooleanProperty CAN_SUMMON = BooleanProperty.create("can_summon"); public static final EnumProperty HORIZONTAL_AXIS = EnumProperty.create("axis", Axis.X, Axis.Z); public static final EnumProperty AXIS = EnumProperty.create("axis", Axis.VALUES); public static final BooleanProperty UP = BooleanProperty.create("up"); @@ -143,6 +145,5 @@ 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/translator/inventory/AnvilInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java index 40ee28362..cbc8ce7bd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java @@ -73,7 +73,7 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - return switch (slotInfoData.getContainer()) { + return switch (slotInfoData.getContainerName().getContainer()) { case ANVIL_INPUT -> 0; case ANVIL_MATERIAL -> 1; case ANVIL_RESULT, CREATED_OUTPUT -> 2; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java index f70bad9ea..fd6d9a930 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java @@ -44,7 +44,7 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator { @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { int slotnum = slotInfoData.getSlot(); - switch (slotInfoData.getContainer()) { + switch (slotInfoData.getContainerName().getContainer()) { case HOTBAR_AND_INVENTORY: case HOTBAR: case INVENTORY: diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java index ceae1b640..6edbd925e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java @@ -121,7 +121,7 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.BEACON_PAYMENT) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.BEACON_PAYMENT) { return 0; } return super.bedrockSlotToJava(slotInfoData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java index e425342f3..5147fb75d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java @@ -74,11 +74,11 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.BREWING_INPUT) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.BREWING_INPUT) { // Ingredient return 3; } - if (slotInfoData.getContainer() == ContainerSlotType.BREWING_RESULT) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.BREWING_RESULT) { // Potions return slotInfoData.getSlot() - 1; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java index b0914e5dd..65fc7b35c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java @@ -56,7 +56,7 @@ public class CartographyInventoryTranslator extends AbstractBlockInventoryTransl @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - return switch (slotInfoData.getContainer()) { + return switch (slotInfoData.getContainerName().getContainer()) { case CARTOGRAPHY_INPUT -> 0; case CARTOGRAPHY_ADDITIONAL -> 1; case CARTOGRAPHY_RESULT, CREATED_OUTPUT -> 2; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java index 8b0a0ac44..83076640a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java @@ -77,7 +77,7 @@ public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { int slot = slotInfoData.getSlot(); - switch (slotInfoData.getContainer()) { + switch (slotInfoData.getContainerName().getContainer()) { case HOTBAR_AND_INVENTORY, HOTBAR, INVENTORY -> { //hotbar if (slot >= 9) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java index 4a0f1d7d9..577d87fe5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java @@ -64,12 +64,12 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.CRAFTING_INPUT) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.CRAFTING_INPUT) { // Java goes from 1 - 9, left to right then up to down // Bedrock is the same, but it starts from 32. return slotInfoData.getSlot() - 31; } - if (slotInfoData.getContainer() == ContainerSlotType.CRAFTING_OUTPUT || slotInfoData.getContainer() == ContainerSlotType.CREATED_OUTPUT) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.CRAFTING_OUTPUT || slotInfoData.getContainerName().getContainer() == ContainerSlotType.CREATED_OUTPUT) { return 0; } return super.bedrockSlotToJava(slotInfoData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java index b51d86d13..eb0e351e1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java @@ -135,10 +135,10 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.ENCHANTING_INPUT) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.ENCHANTING_INPUT) { return 0; } - if (slotInfoData.getContainer() == ContainerSlotType.ENCHANTING_MATERIAL) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.ENCHANTING_MATERIAL) { return 1; } return super.bedrockSlotToJava(slotInfoData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java index 5344d27cb..d3283de40 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java @@ -39,7 +39,7 @@ public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTransla @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - return switch (slotInfoData.getContainer()) { + return switch (slotInfoData.getContainerName().getContainer()) { case GRINDSTONE_INPUT -> 0; case GRINDSTONE_ADDITIONAL -> 1; case GRINDSTONE_RESULT, CREATED_OUTPUT -> 2; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 7cdcbe8a9..e294442f9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -169,7 +169,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - return switch (slotInfoData.getContainer()) { + return switch (slotInfoData.getContainerName().getContainer()) { case LOOM_INPUT -> 0; case LOOM_DYE -> 1; case LOOM_MATERIAL -> 2; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java index 7a7646503..c67b3b190 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java @@ -77,7 +77,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - return switch (slotInfoData.getContainer()) { + return switch (slotInfoData.getContainerName().getContainer()) { case TRADE2_INGREDIENT_1 -> 0; case TRADE2_INGREDIENT_2 -> 1; case TRADE2_RESULT, CREATED_OUTPUT -> 2; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java index 38bb6ddcd..fc9c4f587 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java @@ -63,7 +63,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - return switch (slotInfoData.getContainer()) { + return switch (slotInfoData.getContainerName().getContainer()) { case SMITHING_TABLE_INPUT -> 0; case SMITHING_TABLE_MATERIAL -> 1; case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> 2; @@ -130,7 +130,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator } private boolean isInvalidAction(ItemStackRequestSlotData slotData) { - return slotData.getContainer().equals(ContainerSlotType.SMITHING_TABLE_TEMPLATE); + return slotData.getContainerName().getContainer().equals(ContainerSlotType.SMITHING_TABLE_TEMPLATE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index f08b90765..445b4715b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -184,7 +184,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { int slotnum = slotInfoData.getSlot(); - switch (slotInfoData.getContainer()) { + switch (slotInfoData.getContainerName().getContainer()) { case HOTBAR_AND_INVENTORY: case HOTBAR: case INVENTORY: @@ -462,7 +462,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } craftState = CraftState.TRANSFER; - if (transferAction.getSource().getContainer() != ContainerSlotType.CREATED_OUTPUT) { + if (transferAction.getSource().getContainerName().getContainer() != ContainerSlotType.CREATED_OUTPUT) { return rejectRequest(request); } @@ -495,7 +495,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } DropAction dropAction = (DropAction) action; - if (dropAction.getSource().getContainer() != ContainerSlotType.CREATED_OUTPUT || dropAction.getSource().getSlot() != 50) { + if (dropAction.getSource().getContainerName().getContainer() != ContainerSlotType.CREATED_OUTPUT || dropAction.getSource().getSlot() != 50) { return rejectRequest(request); } @@ -532,7 +532,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } private static boolean isCraftingGrid(ItemStackRequestSlotData slotInfoData) { - return slotInfoData.getContainer() == ContainerSlotType.CRAFTING_INPUT; + return slotInfoData.getContainerName().getContainer() == ContainerSlotType.CRAFTING_INPUT; } @Override 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 dbe24230a..2a9e974f3 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 @@ -44,7 +44,7 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - return switch (slotInfoData.getContainer()) { + return switch (slotInfoData.getContainerName().getContainer()) { case SMITHING_TABLE_TEMPLATE -> TEMPLATE; case SMITHING_TABLE_INPUT -> INPUT; case SMITHING_TABLE_MATERIAL -> MATERIAL; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java index b977ee1a1..df7e15fef 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java @@ -84,7 +84,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - return switch (slotInfoData.getContainer()) { + return switch (slotInfoData.getContainerName().getContainer()) { case STONECUTTER_INPUT -> 0; case STONECUTTER_RESULT, CREATED_OUTPUT -> 1; default -> super.bedrockSlotToJava(slotInfoData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java index f1a5723c8..1a65ad982 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java @@ -53,10 +53,10 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.HORSE_EQUIP) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.HORSE_EQUIP) { return this.equipSlot; } - if (slotInfoData.getContainer() == ContainerSlotType.LEVEL_ENTITY) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.LEVEL_ENTITY) { return slotInfoData.getSlot() + 1; } return super.bedrockSlotToJava(slotInfoData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/HorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/HorseInventoryTranslator.java index 84d7744d1..af09d5f61 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/HorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/HorseInventoryTranslator.java @@ -36,7 +36,7 @@ public class HorseInventoryTranslator extends AbstractHorseInventoryTranslator { @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { - if (slotInfoData.getContainer() == ContainerSlotType.HORSE_EQUIP) { + if (slotInfoData.getContainerName().getContainer() == ContainerSlotType.HORSE_EQUIP) { return slotInfoData.getSlot(); } return super.bedrockSlotToJava(slotInfoData); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index e1ff7a5fc..cdadb1bb9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.protocol.java.entity; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.FakeHeadProvider; @@ -35,6 +36,7 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Equipment; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEquipmentPacket; @Translator(packet = ClientboundSetEquipmentPacket.class) @@ -64,7 +66,7 @@ public class JavaSetEquipmentTranslator extends PacketTranslator Date: Wed, 4 Dec 2024 20:46:38 +0800 Subject: [PATCH 483/897] Start on block remapping, send ServerboundPlayerLoadedPacket on respawn/new logins --- core/build.gradle.kts | 4 + .../geyser/entity/EntityDefinitions.java | 10 ++ .../type/living/monster/CreakingEntity.java | 54 +++++++++ .../populator/BlockRegistryPopulator.java | 28 +---- .../registry/populator/Conversion748_729.java | 48 -------- .../registry/populator/Conversion766_748.java | 104 ++++++++++++++++++ .../populator/ItemRegistryPopulator.java | 40 ++++++- ...SetLocalPlayerAsInitializedTranslator.java | 1 + .../protocol/java/JavaLoginTranslator.java | 5 + .../protocol/java/JavaRespawnTranslator.java | 3 + 10 files changed, 222 insertions(+), 75 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index b0ea5fdf6..29cb49dc2 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -71,6 +71,10 @@ dependencies { api(libs.events) } +tasks.test { + enabled = false +} + tasks.processResources { // This is solely for backwards compatibility for other programs that used this file before the switch to gradle. // It used to be generated by the maven Git-Commit-Id-Plugin 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 47b97c934..f48cf4053 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -116,6 +116,7 @@ import org.geysermc.geyser.entity.type.living.monster.BasePiglinEntity; import org.geysermc.geyser.entity.type.living.monster.BlazeEntity; import org.geysermc.geyser.entity.type.living.monster.BoggedEntity; import org.geysermc.geyser.entity.type.living.monster.BreezeEntity; +import org.geysermc.geyser.entity.type.living.monster.CreakingEntity; import org.geysermc.geyser.entity.type.living.monster.CreeperEntity; import org.geysermc.geyser.entity.type.living.monster.ElderGuardianEntity; import org.geysermc.geyser.entity.type.living.monster.EnderDragonEntity; @@ -179,6 +180,7 @@ public final class EntityDefinitions { public static final EntityDefinition COD; public static final EntityDefinition COMMAND_BLOCK_MINECART; public static final EntityDefinition COW; + public static final EntityDefinition CREAKING; public static final EntityDefinition CREEPER; public static final EntityDefinition DARK_OAK_BOAT; public static final EntityDefinition DARK_OAK_CHEST_BOAT; @@ -671,6 +673,14 @@ public final class EntityDefinitions { .type(EntityType.BREEZE) .height(1.77f).width(0.6f) .build(); + CREAKING = EntityDefinition.inherited(CreakingEntity::new, mobEntityBase) + .type(EntityType.CREAKING) + .height(2.7f).width(0.9f) + .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setCanMove) + .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setActive) + .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setIsTearingDown) + .addTranslator(MetadataType.OPTIONAL_POSITION, CreakingEntity::setHomePos) + .build(); CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase) .type(EntityType.CREEPER) .height(1.7f).width(0.6f) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java new file mode 100644 index 000000000..8cfaf7428 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java @@ -0,0 +1,54 @@ +/* + * 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.monster; + +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; + +import java.util.Optional; +import java.util.UUID; + +public class CreakingEntity extends MonsterEntity { + public CreakingEntity(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 void setCanMove(EntityMetadata> booleanEntityMetadata) { + } + + public void setActive(EntityMetadata> booleanEntityMetadata) { + } + + public void setIsTearingDown(EntityMetadata> booleanEntityMetadata) { + } + + public void setHomePos(EntityMetadata,? extends MetadataType>> optionalEntityMetadata) { + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 1723b22ed..46a820c16 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -58,7 +58,6 @@ 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.level.block.type.FlowerPotBlock; -import org.geysermc.geyser.level.block.type.SkullBlock; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -66,7 +65,6 @@ import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.GeyserBedrockBlock; import org.geysermc.geyser.util.BlockUtils; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.jetbrains.annotations.NotNull; import java.io.DataInputStream; import java.io.InputStream; @@ -125,8 +123,8 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { var blockMappers = ImmutableMap., Remapper>builder() - .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) - .put(ObjectIntPair.of("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) + .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), Conversion766_748::remapBlock) + .put(ObjectIntPair.of("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()), tag -> tag) .build(); // We can keep this strong as nothing should be garbage collected @@ -259,15 +257,6 @@ public final class BlockRegistryPopulator { NbtMap originalBedrockTag = buildBedrockState(blockState, entry); NbtMap bedrockTag = stateMapper.remap(originalBedrockTag); - // FIXME TEMPORARY - if (blockState.block() instanceof SkullBlock && palette.valueInt() >= Bedrock_v748.CODEC.getProtocolVersion()) { - // The flattening must be a very interesting process. - String skullName = blockState.block().javaIdentifier().asString().replace("_wall", ""); - bedrockTag = bedrockTag.toBuilder() - .putString("name", skullName) - .build(); - } - GeyserBedrockBlock vanillaBedrockDefinition = blockStateOrderedMap.get(bedrockTag); GeyserBedrockBlock bedrockDefinition; @@ -413,19 +402,6 @@ public final class BlockRegistryPopulator { } } - private static @NotNull Remapper faultyStrippedWoodRemapper() { - return tag -> { - final String name = tag.getString("name"); - if (name.endsWith("_wood") && tag.getCompound("states").containsKey("stripped_bit")) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("stripped_bit"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - return tag; - }; - } - private static void registerJavaBlocks() { List blocksNbt; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/blocks.nbt")) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java deleted file mode 100644 index 7a2d1a0cb..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.type.GeyserMappingItem; - -import java.util.Map; - -public class Conversion748_729 { - - private static final Map NEW_PLAYER_HEADS = Map.of("minecraft:skeleton_skull", 0, "minecraft:wither_skeleton_skull", 1, "minecraft:zombie_head", 2, "minecraft:player_head", 3, "minecraft:creeper_head", 4, "minecraft:dragon_head", 5, "minecraft:piglin_head", 6); - - static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { - String identifier = mapping.getBedrockIdentifier(); - - if (NEW_PLAYER_HEADS.containsKey(identifier)) { - return mapping.withBedrockIdentifier("minecraft:skull") - .withBedrockData(NEW_PLAYER_HEADS.get(identifier)); - } - - return mapping; - } - -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java new file mode 100644 index 000000000..79265552f --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java @@ -0,0 +1,104 @@ +/* + * 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 io.jsonwebtoken.lang.Collections; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.level.block.Blocks; + +import java.util.ArrayList; +import java.util.List; + +public class Conversion766_748 { + static List newBlockIds = new ArrayList<>(); + static List bedrockIds = new ArrayList<>(); // TODO temp remove + static { + var blocks = Collections.of( + Blocks.PALE_OAK_WOOD, + Blocks.PALE_OAK_PLANKS, + Blocks.PALE_OAK_SAPLING, + Blocks.PALE_OAK_LOG, + Blocks.STRIPPED_PALE_OAK_LOG, + Blocks.STRIPPED_PALE_OAK_WOOD, + Blocks.PALE_OAK_LEAVES, + Blocks.PALE_OAK_SIGN, + Blocks.PALE_OAK_WALL_SIGN, + Blocks.PALE_OAK_HANGING_SIGN, + Blocks.PALE_OAK_WALL_HANGING_SIGN, + Blocks.PALE_OAK_PRESSURE_PLATE, + Blocks.PALE_OAK_TRAPDOOR, + Blocks.POTTED_PALE_OAK_SAPLING, + Blocks.PALE_OAK_BUTTON, + Blocks.PALE_OAK_STAIRS, + Blocks.PALE_OAK_SLAB, + Blocks.PALE_OAK_FENCE_GATE, + Blocks.PALE_OAK_FENCE, + Blocks.PALE_OAK_DOOR, + Blocks.PALE_MOSS_BLOCK, + Blocks.PALE_MOSS_CARPET, + Blocks.PALE_HANGING_MOSS, + + Blocks.OPEN_EYEBLOSSOM, + Blocks.CLOSED_EYEBLOSSOM, + Blocks.POTTED_OPEN_EYEBLOSSOM, + Blocks.POTTED_CLOSED_EYEBLOSSOM, + + Blocks.RESIN_CLUMP, + Blocks.RESIN_BLOCK, + Blocks.RESIN_BRICKS, + Blocks.RESIN_BRICK_STAIRS, + Blocks.RESIN_BRICK_SLAB, + Blocks.RESIN_BRICK_WALL, + Blocks.CHISELED_RESIN_BRICKS, + + Blocks.CREAKING_HEART + ); + + blocks.forEach(block -> newBlockIds.add(block.javaIdentifier().value())); + } + + static NbtMap remapBlock(NbtMap tag) { + + GeyserImpl.getInstance().getLogger().info(tag.toString()); + + String name = tag.getString("name"); + if (newBlockIds.contains(name)) { + bedrockIds.add(name); + // TODO + return tag.toBuilder() + .putCompound("states", NbtMap.builder().build()) + .putString("name", "minecraft:unknown") + .build(); + } + + if (name.contains("resin") || name.contains("creaking") || name.contains("pale")) { + throw new RuntimeException("ya missed " + name); + } + + return tag; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index a94cf132d..7c636cd24 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -82,6 +82,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -107,8 +108,45 @@ public class ItemRegistryPopulator { } public static void populate() { + + Map itemFallbacks = new HashMap<>(); + itemFallbacks.put(Items.PALE_OAK_PLANKS, Items.BIRCH_PLANKS); + itemFallbacks.put(Items.PALE_OAK_FENCE, Items.BIRCH_FENCE); + itemFallbacks.put(Items.PALE_OAK_FENCE_GATE, Items.BIRCH_FENCE_GATE); + itemFallbacks.put(Items.PALE_OAK_STAIRS, Items.BIRCH_STAIRS); + itemFallbacks.put(Items.PALE_OAK_DOOR, Items.BIRCH_DOOR); + itemFallbacks.put(Items.PALE_OAK_TRAPDOOR, Items.BIRCH_TRAPDOOR); + itemFallbacks.put(Items.PALE_OAK_SLAB, Items.BIRCH_SLAB); + itemFallbacks.put(Items.PALE_OAK_LOG, Items.BIRCH_LOG); + itemFallbacks.put(Items.STRIPPED_PALE_OAK_LOG, Items.STRIPPED_BIRCH_LOG); + itemFallbacks.put(Items.PALE_OAK_WOOD, Items.BIRCH_WOOD); + itemFallbacks.put(Items.PALE_OAK_LEAVES, Items.BIRCH_LEAVES); + itemFallbacks.put(Items.PALE_OAK_SAPLING, Items.BIRCH_SAPLING); + itemFallbacks.put(Items.STRIPPED_PALE_OAK_WOOD, Items.STRIPPED_BIRCH_WOOD); + itemFallbacks.put(Items.PALE_OAK_SIGN, Items.BIRCH_SIGN); + itemFallbacks.put(Items.PALE_OAK_HANGING_SIGN, Items.BIRCH_HANGING_SIGN); + itemFallbacks.put(Items.PALE_OAK_BOAT, Items.BIRCH_BOAT); + itemFallbacks.put(Items.PALE_OAK_CHEST_BOAT, Items.BIRCH_CHEST_BOAT); + itemFallbacks.put(Items.PALE_OAK_BUTTON, Items.BIRCH_BUTTON); + itemFallbacks.put(Items.PALE_OAK_PRESSURE_PLATE, Items.BIRCH_PRESSURE_PLATE); + itemFallbacks.put(Items.RESIN_CLUMP, Items.RAW_COPPER); + itemFallbacks.put(Items.RESIN_BRICK_WALL, Items.RED_SANDSTONE_WALL); + itemFallbacks.put(Items.RESIN_BRICK_STAIRS, Items.RED_SANDSTONE_STAIRS); + itemFallbacks.put(Items.RESIN_BRICK_SLAB, Items.RED_SANDSTONE_SLAB); + itemFallbacks.put(Items.RESIN_BLOCK, Items.RED_SANDSTONE); + itemFallbacks.put(Items.RESIN_BRICK, Items.BRICK); + itemFallbacks.put(Items.RESIN_BRICKS, Items.CUT_RED_SANDSTONE); + itemFallbacks.put(Items.CHISELED_RESIN_BRICKS, Items.CHISELED_RED_SANDSTONE); + itemFallbacks.put(Items.CLOSED_EYEBLOSSOM, Items.WHITE_TULIP); + itemFallbacks.put(Items.OPEN_EYEBLOSSOM, Items.OXEYE_DAISY); + itemFallbacks.put(Items.PALE_MOSS_BLOCK, Items.MOSS_BLOCK); + itemFallbacks.put(Items.PALE_MOSS_CARPET, Items.MOSS_CARPET); + itemFallbacks.put(Items.PALE_HANGING_MOSS, Items.HANGING_ROOTS); + itemFallbacks.put(Items.CREAKING_HEART, Items.CHISELED_POLISHED_BLACKSTONE); + itemFallbacks.put(Items.CREAKING_SPAWN_EGG, Items.HOGLIN_SPAWN_EGG); + List paletteVersions = new ArrayList<>(2); - paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping)); paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v765.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java index 556d8cd8d..fcbd3bb8c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java @@ -40,6 +40,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.Serverbound public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, SetLocalPlayerAsInitializedPacket packet) { + GeyserImpl.getInstance().getLogger().info(packet.toString()); if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) { if (!session.getUpstream().isInitialized()) { session.getUpstream().setInitialized(true); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 93a7d9a14..7a33c53d6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -45,6 +45,7 @@ import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundPlayerLoadedPacket; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -128,5 +129,9 @@ public class JavaLoginTranslator extends PacketTranslator { @@ -93,5 +94,7 @@ public class JavaRespawnTranslator extends PacketTranslator Date: Thu, 5 Dec 2024 01:11:03 +0800 Subject: [PATCH 484/897] Various small fixes - update cloudburst/protocol dependency, remove "temporary" log info spamming (#5186) --- .../geyser/platform/spigot/GeyserSpigotInjector.java | 1 - .../main/java/org/geysermc/geyser/network/GameProtocol.java | 5 ++--- .../geyser/registry/populator/BlockRegistryPopulator.java | 4 ++-- .../geyser/registry/populator/ItemRegistryPopulator.java | 4 ++-- .../geyser/registry/populator/TagRegistryPopulator.java | 4 ++-- .../protocol/java/entity/JavaTeleportEntityTranslator.java | 2 +- gradle/libs.versions.toml | 6 +++--- 7 files changed, 12 insertions(+), 14 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index 5dcfbd0f8..a3402a752 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -180,7 +180,6 @@ public class GeyserSpigotInjector extends GeyserInjector { bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress, InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper()); session.connect(); - session.disconnect(""); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 378dc5078..c762cf5d3 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.network; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; -import org.cloudburstmc.protocol.bedrock.codec.v765.Bedrock_v765; +import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; import org.geysermc.mcprotocollib.protocol.codec.PacketCodec; @@ -46,9 +46,8 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v765.CODEC.toBuilder() + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v766.CODEC.toBuilder() .minecraftVersion("1.21.50") - .protocolVersion(766) .build()); /** diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 1723b22ed..e1f1b2c8b 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -45,7 +45,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; -import org.cloudburstmc.protocol.bedrock.codec.v765.Bedrock_v765; +import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -126,7 +126,7 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { var blockMappers = ImmutableMap., Remapper>builder() .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) - .put(ObjectIntPair.of("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) + .put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) .build(); // We can keep this strong as nothing should be garbage collected diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index e9901c620..cda81cf5b 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -46,7 +46,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; -import org.cloudburstmc.protocol.bedrock.codec.v765.Bedrock_v765; +import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; @@ -109,7 +109,7 @@ public class ItemRegistryPopulator { public static void populate() { List paletteVersions = new ArrayList<>(2); paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); - paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v765.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v766.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); 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 index dd654531a..bf1ed6194 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java @@ -34,7 +34,7 @@ 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.v748.Bedrock_v748; -import org.cloudburstmc.protocol.bedrock.codec.v765.Bedrock_v765; +import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.item.type.Item; @@ -68,7 +68,7 @@ public final class TagRegistryPopulator { List> paletteVersions = List.of( ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), - ObjectIntPair.of("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()) + ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()) ); Type type = new TypeToken>>() {}.getType(); 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 eda195a8f..40379eac3 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 @@ -35,6 +35,6 @@ public class JavaTeleportEntityTranslator extends PacketTranslator Date: Thu, 5 Dec 2024 17:54:00 +0800 Subject: [PATCH 485/897] Finish mappings - let it build --- core/build.gradle.kts | 4 - .../entity/type/player/PlayerEntity.java | 2 +- .../org/geysermc/geyser/item/type/Item.java | 9 ++- .../registry/populator/Conversion766_748.java | 78 ++++++++++++------- .../MerchantInventoryTranslator.java | 2 +- .../player/BedrockInteractTranslator.java | 2 +- .../entity/JavaSetPassengersTranslator.java | 4 +- 7 files changed, 63 insertions(+), 38 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 29cb49dc2..b0ea5fdf6 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -71,10 +71,6 @@ dependencies { api(libs.events) } -tasks.test { - enabled = false -} - tasks.processResources { // This is solely for backwards compatibility for other programs that used this file before the switch to gradle. // It used to be generated by the maven Git-Commit-Id-Plugin 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 7a443d6e8..2bdbb56df 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 @@ -335,7 +335,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { parrot.updateBedrockMetadata(); SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); EntityLinkData.Type type = isLeft ? EntityLinkData.Type.RIDER : EntityLinkData.Type.PASSENGER; - linkPacket.setEntityLink(new EntityLinkData(geyserId, parrot.getGeyserId(), type, false, false)); + linkPacket.setEntityLink(new EntityLinkData(geyserId, parrot.getGeyserId(), type, false, false, 0f)); // Delay, or else spawned-in players won't get the link // TODO: Find a better solution. session.scheduleInEventLoop(() -> session.sendUpstreamPacket(linkPacket), 500, TimeUnit.MILLISECONDS); 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 9b2603284..b12ab4d67 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 @@ -64,11 +64,13 @@ public class Item { protected final Key javaIdentifier; private int javaId = -1; private final int attackDamage; - private final DataComponents baseComponents; // unmodifiable + private DataComponents baseComponents; // unmodifiable public Item(String javaIdentifier, Builder builder) { this.javaIdentifier = MinecraftKey.key(javaIdentifier); - this.baseComponents = builder.components == null ? Registries.DEFAULT_DATA_COMPONENTS.get(javaId) : builder.components; + if (builder.components != null) { + this.baseComponents = builder.components; + } this.attackDamage = builder.attackDamage; } @@ -272,6 +274,9 @@ public class Item { throw new RuntimeException("Item ID has already been set!"); } this.javaId = javaId; + if (this.baseComponents == null) { + this.baseComponents = Registries.DEFAULT_DATA_COMPONENTS.get(javaId); + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java index 79265552f..4568d0154 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java @@ -25,19 +25,20 @@ package org.geysermc.geyser.registry.populator; -import io.jsonwebtoken.lang.Collections; import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.geyser.GeyserImpl; +import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.Blocks; import java.util.ArrayList; import java.util.List; +import java.util.Set; public class Conversion766_748 { - static List newBlockIds = new ArrayList<>(); - static List bedrockIds = new ArrayList<>(); // TODO temp remove + static List PALE_WOODEN_BLOCKS = new ArrayList<>(); + static List OTHER_NEW_BLOCKS = new ArrayList<>(); + static { - var blocks = Collections.of( + Set.of( Blocks.PALE_OAK_WOOD, Blocks.PALE_OAK_PLANKS, Blocks.PALE_OAK_SAPLING, @@ -45,27 +46,29 @@ public class Conversion766_748 { Blocks.STRIPPED_PALE_OAK_LOG, Blocks.STRIPPED_PALE_OAK_WOOD, Blocks.PALE_OAK_LEAVES, - Blocks.PALE_OAK_SIGN, - Blocks.PALE_OAK_WALL_SIGN, Blocks.PALE_OAK_HANGING_SIGN, - Blocks.PALE_OAK_WALL_HANGING_SIGN, Blocks.PALE_OAK_PRESSURE_PLATE, Blocks.PALE_OAK_TRAPDOOR, - Blocks.POTTED_PALE_OAK_SAPLING, Blocks.PALE_OAK_BUTTON, Blocks.PALE_OAK_STAIRS, Blocks.PALE_OAK_SLAB, Blocks.PALE_OAK_FENCE_GATE, Blocks.PALE_OAK_FENCE, - Blocks.PALE_OAK_DOOR, + Blocks.PALE_OAK_DOOR + ).forEach(block -> PALE_WOODEN_BLOCKS.add(block.javaIdentifier().value())); + + // Some things are of course stupid + PALE_WOODEN_BLOCKS.add("pale_oak_standing_sign"); + PALE_WOODEN_BLOCKS.add("pale_oak_wall_sign"); + PALE_WOODEN_BLOCKS.add("pale_oak_double_slab"); + + Set.of( Blocks.PALE_MOSS_BLOCK, Blocks.PALE_MOSS_CARPET, Blocks.PALE_HANGING_MOSS, Blocks.OPEN_EYEBLOSSOM, Blocks.CLOSED_EYEBLOSSOM, - Blocks.POTTED_OPEN_EYEBLOSSOM, - Blocks.POTTED_CLOSED_EYEBLOSSOM, Blocks.RESIN_CLUMP, Blocks.RESIN_BLOCK, @@ -76,29 +79,50 @@ public class Conversion766_748 { Blocks.CHISELED_RESIN_BRICKS, Blocks.CREAKING_HEART - ); + ).forEach(block -> OTHER_NEW_BLOCKS.add(block.javaIdentifier().value())); - blocks.forEach(block -> newBlockIds.add(block.javaIdentifier().value())); + OTHER_NEW_BLOCKS.add("resin_brick_double_slab"); } static NbtMap remapBlock(NbtMap tag) { - - GeyserImpl.getInstance().getLogger().info(tag.toString()); - - String name = tag.getString("name"); - if (newBlockIds.contains(name)) { - bedrockIds.add(name); - // TODO - return tag.toBuilder() - .putCompound("states", NbtMap.builder().build()) - .putString("name", "minecraft:unknown") - .build(); + String name = tag.getString("name").replace("minecraft:", ""); + if (PALE_WOODEN_BLOCKS.contains(name)) { + return withName(tag, name.replace("pale_oak", "birch")); } - if (name.contains("resin") || name.contains("creaking") || name.contains("pale")) { - throw new RuntimeException("ya missed " + name); + if (OTHER_NEW_BLOCKS.contains(name)) { + return switch (name) { + case "resin_brick_double_slab" -> withName(tag,"red_sandstone_double_slab"); + case "pale_moss_block" -> withName(tag, "moss_block"); + case "pale_moss_carpet" -> withoutStates("moss_carpet"); + case "pale_hanging_moss" -> withoutStates("hanging_roots"); + case "open_eyeblossom" -> withoutStates("oxeye_daisy"); + case "closed_eyeblossom" -> withoutStates("white_tulip"); + case "resin_clump" -> withoutStates("unknown"); + case "resin_block" -> withoutStates("red_sandstone"); + case "resin_bricks" -> withoutStates("cut_red_sandstone"); + case "resin_brick_stairs" -> withName(tag, "red_sandstone_stairs"); + case "resin_brick_slab" -> withName(tag, "red_sandstone_slab"); + case "resin_brick_wall" -> withName(tag, "red_sandstone_wall"); + case "chiseled_resin_bricks" -> withName(tag, "chiseled_red_sandstone"); + case "creaking_heart" -> withoutStates("chiseled_polished_blackstone"); + default -> throw new IllegalStateException("missing replacement for new block! " + name); + }; } return tag; } + + static NbtMap withName(NbtMap tag, String name) { + NbtMapBuilder builder = tag.toBuilder(); + builder.replace("name", "minecraft:" + name); + return builder.build(); + } + + static NbtMap withoutStates(String name) { + NbtMapBuilder tagBuilder = NbtMap.builder(); + tagBuilder.putString("name", "minecraft:" + name); + tagBuilder.putCompound("states", NbtMap.builder().build()); + return tagBuilder.build(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java index c67b3b190..4ac159981 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java @@ -112,7 +112,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); EntityLinkData.Type type = EntityLinkData.Type.PASSENGER; - linkPacket.setEntityLink(new EntityLinkData(session.getPlayerEntity().getGeyserId(), geyserId, type, true, false)); + linkPacket.setEntityLink(new EntityLinkData(session.getPlayerEntity().getGeyserId(), geyserId, type, true, false, 0f)); session.sendUpstreamPacket(linkPacket); merchantInventory.setVillager(villager); 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 2df77ad16..62487b20d 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 @@ -91,7 +91,7 @@ public class BedrockInteractTranslator extends PacketTranslator // If the server doesn't agree with our dismount (sends a packet saying we dismounted), // then remount the player. SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); - linkPacket.setEntityLink(new EntityLinkData(vehicleBedrockId, session.getPlayerEntity().getGeyserId(), EntityLinkData.Type.PASSENGER, true, false)); + linkPacket.setEntityLink(new EntityLinkData(vehicleBedrockId, session.getPlayerEntity().getGeyserId(), EntityLinkData.Type.PASSENGER, true, false, 0f)); session.sendUpstreamPacket(linkPacket); } }, 1, TimeUnit.SECONDS)); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java index 865ca0464..fe4a13748 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetPassengersTranslator.java @@ -70,7 +70,7 @@ public class JavaSetPassengersTranslator extends PacketTranslator Date: Thu, 5 Dec 2024 18:16:09 +0800 Subject: [PATCH 486/897] Include item_data_components.json, target new mappings --- .../DataComponentRegistryPopulator.java | 2 +- .../resources/java/item_data_components.json | 19962 ++++++++++++++++ core/src/main/resources/mappings | 2 +- 3 files changed, 19964 insertions(+), 2 deletions(-) create mode 100644 core/src/main/resources/java/item_data_components.json diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java index 0c89760b1..386c795d2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java @@ -54,7 +54,7 @@ public final class DataComponentRegistryPopulator { public static void populate() { GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); List defaultComponents; - try (InputStream stream = bootstrap.getResourceOrThrow("mappings/item_data_components.json")) { + try (InputStream stream = bootstrap.getResourceOrThrow("java/item_data_components.json")) { JsonElement rootElement = JsonParser.parseReader(new InputStreamReader(stream)); JsonArray jsonArray = rootElement.getAsJsonArray(); diff --git a/core/src/main/resources/java/item_data_components.json b/core/src/main/resources/java/item_data_components.json new file mode 100644 index 000000000..141666fc9 --- /dev/null +++ b/core/src/main/resources/java/item_data_components.json @@ -0,0 +1,19962 @@ +[ + { + "id": 0, + "key": "minecraft:air", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw1taW5lY3JhZnQ6YWly", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2Jsb2NrLm1pbmVjcmFmdC5haXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1, + "key": "minecraft:stone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6c3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5zdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 2, + "key": "minecraft:granite", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6Z3Jhbml0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5ncmFuaXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 3, + "key": "minecraft:polished_granite", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cG9saXNoZWRfZ3Jhbml0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ncmFuaXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 4, + "key": "minecraft:diorite", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6ZGlvcml0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5kaW9yaXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 5, + "key": "minecraft:polished_diorite", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cG9saXNoZWRfZGlvcml0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9kaW9yaXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 6, + "key": "minecraft:andesite", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6YW5kZXNpdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5hbmRlc2l0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 7, + "key": "minecraft:polished_andesite", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cG9saXNoZWRfYW5kZXNpdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9hbmRlc2l0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 8, + "key": "minecraft:deepslate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6ZGVlcHNsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 9, + "key": "minecraft:cobbled_deepslate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y29iYmxlZF9kZWVwc2xhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5jb2JibGVkX2RlZXBzbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 10, + "key": "minecraft:polished_deepslate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cG9saXNoZWRfZGVlcHNsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9kZWVwc2xhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 11, + "key": "minecraft:calcite", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6Y2FsY2l0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5jYWxjaXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 12, + "key": "minecraft:tuff", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6dHVmZg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC50dWZmAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 13, + "key": "minecraft:tuff_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6dHVmZl9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC50dWZmX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 14, + "key": "minecraft:tuff_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6dHVmZl9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC50dWZmX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 15, + "key": "minecraft:tuff_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6dHVmZl93YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC50dWZmX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 16, + "key": "minecraft:chiseled_tuff", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y2hpc2VsZWRfdHVmZg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF90dWZmAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 17, + "key": "minecraft:polished_tuff", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cG9saXNoZWRfdHVmZg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF90dWZmAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 18, + "key": "minecraft:polished_tuff_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cG9saXNoZWRfdHVmZl9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF90dWZmX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 19, + "key": "minecraft:polished_tuff_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6cG9saXNoZWRfdHVmZl9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF90dWZmX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 20, + "key": "minecraft:polished_tuff_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cG9saXNoZWRfdHVmZl93YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF90dWZmX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 21, + "key": "minecraft:tuff_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6dHVmZl9icmlja3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC50dWZmX2JyaWNrcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 22, + "key": "minecraft:tuff_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6dHVmZl9icmlja19zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC50dWZmX2JyaWNrX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 23, + "key": "minecraft:tuff_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6dHVmZl9icmlja19zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC50dWZmX2JyaWNrX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 24, + "key": "minecraft:tuff_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6dHVmZl9icmlja193YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC50dWZmX2JyaWNrX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 25, + "key": "minecraft:chiseled_tuff_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Y2hpc2VsZWRfdHVmZl9icmlja3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF90dWZmX2JyaWNrcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 26, + "key": "minecraft:dripstone_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZHJpcHN0b25lX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kcmlwc3RvbmVfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 27, + "key": "minecraft:grass_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Z3Jhc3NfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ncmFzc19ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 28, + "key": "minecraft:dirt", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6ZGlydA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5kaXJ0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 29, + "key": "minecraft:coarse_dirt", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y29hcnNlX2RpcnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jb2Fyc2VfZGlydAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 30, + "key": "minecraft:podzol", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6cG9kem9s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5wb2R6b2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 31, + "key": "minecraft:rooted_dirt", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cm9vdGVkX2RpcnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5yb290ZWRfZGlydAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 32, + "key": "minecraft:mud", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw1taW5lY3JhZnQ6bXVk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2Jsb2NrLm1pbmVjcmFmdC5tdWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 33, + "key": "minecraft:crimson_nylium", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y3JpbXNvbl9ueWxpdW0=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jcmltc29uX255bGl1bQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 34, + "key": "minecraft:warped_nylium", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d2FycGVkX255bGl1bQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfbnlsaXVtAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 35, + "key": "minecraft:cobblestone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y29iYmxlc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jb2JibGVzdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 36, + "key": "minecraft:oak_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6b2FrX3BsYW5rcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5vYWtfcGxhbmtzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 37, + "key": "minecraft:spruce_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3BydWNlX3BsYW5rcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfcGxhbmtzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 38, + "key": "minecraft:birch_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmlyY2hfcGxhbmtz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5iaXJjaF9wbGFua3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 39, + "key": "minecraft:jungle_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6anVuZ2xlX3BsYW5rcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfcGxhbmtzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 40, + "key": "minecraft:acacia_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YWNhY2lhX3BsYW5rcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfcGxhbmtzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 41, + "key": "minecraft:cherry_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y2hlcnJ5X3BsYW5rcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jaGVycnlfcGxhbmtzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 42, + "key": "minecraft:dark_oak_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGFya19vYWtfcGxhbmtz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19wbGFua3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 43, + "key": "minecraft:pale_oak_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cGFsZV9vYWtfcGxhbmtz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19wbGFua3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 44, + "key": "minecraft:mangrove_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bWFuZ3JvdmVfcGxhbmtz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9wbGFua3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 45, + "key": "minecraft:bamboo_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YmFtYm9vX3BsYW5rcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5iYW1ib29fcGxhbmtzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 46, + "key": "minecraft:crimson_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y3JpbXNvbl9wbGFua3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jcmltc29uX3BsYW5rcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 47, + "key": "minecraft:warped_planks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d2FycGVkX3BsYW5rcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfcGxhbmtzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 48, + "key": "minecraft:bamboo_mosaic", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YmFtYm9vX21vc2FpYw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5iYW1ib29fbW9zYWljAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 49, + "key": "minecraft:oak_sapling", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6b2FrX3NhcGxpbmc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5vYWtfc2FwbGluZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 50, + "key": "minecraft:spruce_sapling", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c3BydWNlX3NhcGxpbmc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2Vfc2FwbGluZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 51, + "key": "minecraft:birch_sapling", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YmlyY2hfc2FwbGluZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5iaXJjaF9zYXBsaW5nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 52, + "key": "minecraft:jungle_sapling", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6anVuZ2xlX3NhcGxpbmc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfc2FwbGluZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 53, + "key": "minecraft:acacia_sapling", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YWNhY2lhX3NhcGxpbmc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfc2FwbGluZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 54, + "key": "minecraft:cherry_sapling", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y2hlcnJ5X3NhcGxpbmc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jaGVycnlfc2FwbGluZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 55, + "key": "minecraft:dark_oak_sapling", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZGFya19vYWtfc2FwbGluZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19zYXBsaW5nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 56, + "key": "minecraft:pale_oak_sapling", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cGFsZV9vYWtfc2FwbGluZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19zYXBsaW5nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 57, + "key": "minecraft:mangrove_propagule", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bWFuZ3JvdmVfcHJvcGFndWxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9wcm9wYWd1bGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 58, + "key": "minecraft:bedrock", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6YmVkcm9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5iZWRyb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 59, + "key": "minecraft:sand", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6c2FuZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5zYW5kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 60, + "key": "minecraft:suspicious_sand", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6c3VzcGljaW91c19zYW5k", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5zdXNwaWNpb3VzX3NhbmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 61, + "key": "minecraft:suspicious_gravel", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6c3VzcGljaW91c19ncmF2ZWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5zdXNwaWNpb3VzX2dyYXZlbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 62, + "key": "minecraft:red_sand", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cmVkX3NhbmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5yZWRfc2FuZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 63, + "key": "minecraft:gravel", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6Z3JhdmVs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5ncmF2ZWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 64, + "key": "minecraft:coal_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Y29hbF9vcmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5jb2FsX29yZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 65, + "key": "minecraft:deepslate_coal_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6ZGVlcHNsYXRlX2NvYWxfb3Jl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfY29hbF9vcmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 66, + "key": "minecraft:iron_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6aXJvbl9vcmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5pcm9uX29yZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 67, + "key": "minecraft:deepslate_iron_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6ZGVlcHNsYXRlX2lyb25fb3Jl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfaXJvbl9vcmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 68, + "key": "minecraft:copper_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Y29wcGVyX29yZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5jb3BwZXJfb3JlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 69, + "key": "minecraft:deepslate_copper_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZGVlcHNsYXRlX2NvcHBlcl9vcmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfY29wcGVyX29yZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 70, + "key": "minecraft:gold_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Z29sZF9vcmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5nb2xkX29yZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 71, + "key": "minecraft:deepslate_gold_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6ZGVlcHNsYXRlX2dvbGRfb3Jl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfZ29sZF9vcmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 72, + "key": "minecraft:redstone_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cmVkc3RvbmVfb3Jl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5yZWRzdG9uZV9vcmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 73, + "key": "minecraft:deepslate_redstone_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6ZGVlcHNsYXRlX3JlZHN0b25lX29yZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfcmVkc3RvbmVfb3JlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 74, + "key": "minecraft:emerald_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZW1lcmFsZF9vcmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5lbWVyYWxkX29yZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 75, + "key": "minecraft:deepslate_emerald_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6ZGVlcHNsYXRlX2VtZXJhbGRfb3Jl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfZW1lcmFsZF9vcmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 76, + "key": "minecraft:lapis_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6bGFwaXNfb3Jl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5sYXBpc19vcmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 77, + "key": "minecraft:deepslate_lapis_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGVlcHNsYXRlX2xhcGlzX29yZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfbGFwaXNfb3JlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 78, + "key": "minecraft:diamond_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZGlhbW9uZF9vcmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5kaWFtb25kX29yZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 79, + "key": "minecraft:deepslate_diamond_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6ZGVlcHNsYXRlX2RpYW1vbmRfb3Jl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfZGlhbW9uZF9vcmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 80, + "key": "minecraft:nether_gold_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bmV0aGVyX2dvbGRfb3Jl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5uZXRoZXJfZ29sZF9vcmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 81, + "key": "minecraft:nether_quartz_ore", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bmV0aGVyX3F1YXJ0el9vcmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5uZXRoZXJfcXVhcnR6X29yZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 82, + "key": "minecraft:ancient_debris", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YW5jaWVudF9kZWJyaXM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5hbmNpZW50X2RlYnJpcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 83, + "key": "minecraft:coal_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Y29hbF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5jb2FsX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 84, + "key": "minecraft:raw_iron_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6cmF3X2lyb25fYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5yYXdfaXJvbl9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 85, + "key": "minecraft:raw_copper_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cmF3X2NvcHBlcl9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5yYXdfY29wcGVyX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 86, + "key": "minecraft:raw_gold_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6cmF3X2dvbGRfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5yYXdfZ29sZF9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 87, + "key": "minecraft:heavy_core", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6aGVhdnlfY29yZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5oZWF2eV9jb3JlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 88, + "key": "minecraft:amethyst_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YW1ldGh5c3RfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5hbWV0aHlzdF9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 89, + "key": "minecraft:budding_amethyst", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6YnVkZGluZ19hbWV0aHlzdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5idWRkaW5nX2FtZXRoeXN0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 90, + "key": "minecraft:iron_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6aXJvbl9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5pcm9uX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 91, + "key": "minecraft:copper_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y29wcGVyX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jb3BwZXJfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 92, + "key": "minecraft:gold_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Z29sZF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5nb2xkX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 93, + "key": "minecraft:diamond_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGlhbW9uZF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5kaWFtb25kX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 94, + "key": "minecraft:netherite_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bmV0aGVyaXRlX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5uZXRoZXJpdGVfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 95, + "key": "minecraft:exposed_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6ZXhwb3NlZF9jb3BwZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2NvcHBlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 96, + "key": "minecraft:weathered_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6d2VhdGhlcmVkX2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY29wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 97, + "key": "minecraft:oxidized_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6b3hpZGl6ZWRfY29wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 98, + "key": "minecraft:chiseled_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y2hpc2VsZWRfY29wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 99, + "key": "minecraft:exposed_chiseled_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6ZXhwb3NlZF9jaGlzZWxlZF9jb3BwZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2NoaXNlbGVkX2NvcHBlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 100, + "key": "minecraft:weathered_chiseled_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6d2VhdGhlcmVkX2NoaXNlbGVkX2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY2hpc2VsZWRfY29wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 101, + "key": "minecraft:oxidized_chiseled_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6b3hpZGl6ZWRfY2hpc2VsZWRfY29wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jaGlzZWxlZF9jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 102, + "key": "minecraft:cut_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Y3V0X2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5jdXRfY29wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 103, + "key": "minecraft:exposed_cut_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6ZXhwb3NlZF9jdXRfY29wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2N1dF9jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 104, + "key": "minecraft:weathered_cut_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6d2VhdGhlcmVkX2N1dF9jb3BwZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY3V0X2NvcHBlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 105, + "key": "minecraft:oxidized_cut_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6b3hpZGl6ZWRfY3V0X2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jdXRfY29wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 106, + "key": "minecraft:cut_copper_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y3V0X2NvcHBlcl9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5jdXRfY29wcGVyX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 107, + "key": "minecraft:exposed_cut_copper_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6ZXhwb3NlZF9jdXRfY29wcGVyX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2N1dF9jb3BwZXJfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 108, + "key": "minecraft:weathered_cut_copper_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByVtaW5lY3JhZnQ6d2VhdGhlcmVkX2N1dF9jb3BwZXJfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAK2Jsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY3V0X2NvcHBlcl9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 109, + "key": "minecraft:oxidized_cut_copper_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6b3hpZGl6ZWRfY3V0X2NvcHBlcl9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jdXRfY29wcGVyX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 110, + "key": "minecraft:cut_copper_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y3V0X2NvcHBlcl9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5jdXRfY29wcGVyX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 111, + "key": "minecraft:exposed_cut_copper_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6ZXhwb3NlZF9jdXRfY29wcGVyX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2N1dF9jb3BwZXJfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 112, + "key": "minecraft:weathered_cut_copper_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6d2VhdGhlcmVkX2N1dF9jb3BwZXJfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY3V0X2NvcHBlcl9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 113, + "key": "minecraft:oxidized_cut_copper_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6b3hpZGl6ZWRfY3V0X2NvcHBlcl9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jdXRfY29wcGVyX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 114, + "key": "minecraft:waxed_copper_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6d2F4ZWRfY29wcGVyX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC53YXhlZF9jb3BwZXJfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 115, + "key": "minecraft:waxed_exposed_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jb3BwZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2NvcHBlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 116, + "key": "minecraft:waxed_weathered_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY29wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 117, + "key": "minecraft:waxed_oxidized_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY29wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 118, + "key": "minecraft:waxed_chiseled_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2F4ZWRfY2hpc2VsZWRfY29wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53YXhlZF9jaGlzZWxlZF9jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 119, + "key": "minecraft:waxed_exposed_chiseled_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BydtaW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jaGlzZWxlZF9jb3BwZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALWJsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2NoaXNlbGVkX2NvcHBlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 120, + "key": "minecraft:waxed_weathered_chiseled_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByltaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2NoaXNlbGVkX2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAL2Jsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY2hpc2VsZWRfY29wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 121, + "key": "minecraft:waxed_oxidized_chiseled_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByhtaW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY2hpc2VsZWRfY29wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALmJsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jaGlzZWxlZF9jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 122, + "key": "minecraft:waxed_cut_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6d2F4ZWRfY3V0X2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC53YXhlZF9jdXRfY29wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 123, + "key": "minecraft:waxed_exposed_cut_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jdXRfY29wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2N1dF9jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 124, + "key": "minecraft:waxed_weathered_cut_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2N1dF9jb3BwZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY3V0X2NvcHBlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 125, + "key": "minecraft:waxed_oxidized_cut_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY3V0X2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jdXRfY29wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 126, + "key": "minecraft:waxed_cut_copper_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6d2F4ZWRfY3V0X2NvcHBlcl9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC53YXhlZF9jdXRfY29wcGVyX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 127, + "key": "minecraft:waxed_exposed_cut_copper_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByltaW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jdXRfY29wcGVyX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAL2Jsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2N1dF9jb3BwZXJfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 128, + "key": "minecraft:waxed_weathered_cut_copper_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByttaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2N1dF9jb3BwZXJfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMWJsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY3V0X2NvcHBlcl9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 129, + "key": "minecraft:waxed_oxidized_cut_copper_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByptaW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY3V0X2NvcHBlcl9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGJsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jdXRfY29wcGVyX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 130, + "key": "minecraft:waxed_cut_copper_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2F4ZWRfY3V0X2NvcHBlcl9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53YXhlZF9jdXRfY29wcGVyX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 131, + "key": "minecraft:waxed_exposed_cut_copper_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BydtaW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jdXRfY29wcGVyX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALWJsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2N1dF9jb3BwZXJfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 132, + "key": "minecraft:waxed_weathered_cut_copper_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByltaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2N1dF9jb3BwZXJfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAL2Jsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY3V0X2NvcHBlcl9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 133, + "key": "minecraft:waxed_oxidized_cut_copper_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByhtaW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY3V0X2NvcHBlcl9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALmJsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jdXRfY29wcGVyX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 134, + "key": "minecraft:oak_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6b2FrX2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5vYWtfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 135, + "key": "minecraft:spruce_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c3BydWNlX2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 136, + "key": "minecraft:birch_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6YmlyY2hfbG9n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5iaXJjaF9sb2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 137, + "key": "minecraft:jungle_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6anVuZ2xlX2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 138, + "key": "minecraft:acacia_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YWNhY2lhX2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 139, + "key": "minecraft:cherry_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Y2hlcnJ5X2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5jaGVycnlfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 140, + "key": "minecraft:pale_oak_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cGFsZV9vYWtfbG9n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19sb2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 141, + "key": "minecraft:dark_oak_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6ZGFya19vYWtfbG9n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19sb2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 142, + "key": "minecraft:mangrove_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6bWFuZ3JvdmVfbG9n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9sb2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 143, + "key": "minecraft:mangrove_roots", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bWFuZ3JvdmVfcm9vdHM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9yb290cwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 144, + "key": "minecraft:muddy_mangrove_roots", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6bXVkZHlfbWFuZ3JvdmVfcm9vdHM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5tdWRkeV9tYW5ncm92ZV9yb290cwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 145, + "key": "minecraft:crimson_stem", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y3JpbXNvbl9zdGVt", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jcmltc29uX3N0ZW0A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 146, + "key": "minecraft:warped_stem", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6d2FycGVkX3N0ZW0=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC53YXJwZWRfc3RlbQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 147, + "key": "minecraft:bamboo_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmFtYm9vX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5iYW1ib29fYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 148, + "key": "minecraft:stripped_oak_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6c3RyaXBwZWRfb2FrX2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9vYWtfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 149, + "key": "minecraft:stripped_spruce_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c3RyaXBwZWRfc3BydWNlX2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9zcHJ1Y2VfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 150, + "key": "minecraft:stripped_birch_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6c3RyaXBwZWRfYmlyY2hfbG9n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9iaXJjaF9sb2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 151, + "key": "minecraft:stripped_jungle_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c3RyaXBwZWRfanVuZ2xlX2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9qdW5nbGVfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 152, + "key": "minecraft:stripped_acacia_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c3RyaXBwZWRfYWNhY2lhX2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9hY2FjaWFfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 153, + "key": "minecraft:stripped_cherry_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c3RyaXBwZWRfY2hlcnJ5X2xvZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9jaGVycnlfbG9nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 154, + "key": "minecraft:stripped_dark_oak_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6c3RyaXBwZWRfZGFya19vYWtfbG9n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9kYXJrX29ha19sb2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 155, + "key": "minecraft:stripped_pale_oak_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6c3RyaXBwZWRfcGFsZV9vYWtfbG9n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9wYWxlX29ha19sb2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 156, + "key": "minecraft:stripped_mangrove_log", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6c3RyaXBwZWRfbWFuZ3JvdmVfbG9n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9tYW5ncm92ZV9sb2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 157, + "key": "minecraft:stripped_crimson_stem", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6c3RyaXBwZWRfY3JpbXNvbl9zdGVt", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9jcmltc29uX3N0ZW0A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 158, + "key": "minecraft:stripped_warped_stem", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c3RyaXBwZWRfd2FycGVkX3N0ZW0=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF93YXJwZWRfc3RlbQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 159, + "key": "minecraft:stripped_oak_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6c3RyaXBwZWRfb2FrX3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9vYWtfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 160, + "key": "minecraft:stripped_spruce_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c3RyaXBwZWRfc3BydWNlX3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9zcHJ1Y2Vfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 161, + "key": "minecraft:stripped_birch_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c3RyaXBwZWRfYmlyY2hfd29vZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9iaXJjaF93b29kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 162, + "key": "minecraft:stripped_jungle_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c3RyaXBwZWRfanVuZ2xlX3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9qdW5nbGVfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 163, + "key": "minecraft:stripped_acacia_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c3RyaXBwZWRfYWNhY2lhX3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9hY2FjaWFfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 164, + "key": "minecraft:stripped_cherry_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c3RyaXBwZWRfY2hlcnJ5X3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9jaGVycnlfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 165, + "key": "minecraft:stripped_dark_oak_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6c3RyaXBwZWRfZGFya19vYWtfd29vZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9kYXJrX29ha193b29kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 166, + "key": "minecraft:stripped_pale_oak_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6c3RyaXBwZWRfcGFsZV9vYWtfd29vZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9wYWxlX29ha193b29kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 167, + "key": "minecraft:stripped_mangrove_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6c3RyaXBwZWRfbWFuZ3JvdmVfd29vZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9tYW5ncm92ZV93b29kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 168, + "key": "minecraft:stripped_crimson_hyphae", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6c3RyaXBwZWRfY3JpbXNvbl9oeXBoYWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9jcmltc29uX2h5cGhhZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 169, + "key": "minecraft:stripped_warped_hyphae", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6c3RyaXBwZWRfd2FycGVkX2h5cGhhZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF93YXJwZWRfaHlwaGFlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 170, + "key": "minecraft:stripped_bamboo_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6c3RyaXBwZWRfYmFtYm9vX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5zdHJpcHBlZF9iYW1ib29fYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 171, + "key": "minecraft:oak_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6b2FrX3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5vYWtfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 172, + "key": "minecraft:spruce_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c3BydWNlX3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zcHJ1Y2Vfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 173, + "key": "minecraft:birch_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YmlyY2hfd29vZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5iaXJjaF93b29kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 174, + "key": "minecraft:jungle_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6anVuZ2xlX3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5qdW5nbGVfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 175, + "key": "minecraft:acacia_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YWNhY2lhX3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5hY2FjaWFfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 176, + "key": "minecraft:cherry_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y2hlcnJ5X3dvb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jaGVycnlfd29vZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 177, + "key": "minecraft:pale_oak_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cGFsZV9vYWtfd29vZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha193b29kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 178, + "key": "minecraft:dark_oak_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGFya19vYWtfd29vZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha193b29kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 179, + "key": "minecraft:mangrove_wood", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bWFuZ3JvdmVfd29vZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV93b29kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 180, + "key": "minecraft:crimson_hyphae", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y3JpbXNvbl9oeXBoYWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jcmltc29uX2h5cGhhZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 181, + "key": "minecraft:warped_hyphae", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d2FycGVkX2h5cGhhZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfaHlwaGFlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 182, + "key": "minecraft:oak_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6b2FrX2xlYXZlcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5vYWtfbGVhdmVzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 183, + "key": "minecraft:spruce_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3BydWNlX2xlYXZlcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfbGVhdmVzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 184, + "key": "minecraft:birch_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmlyY2hfbGVhdmVz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5iaXJjaF9sZWF2ZXMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 185, + "key": "minecraft:jungle_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6anVuZ2xlX2xlYXZlcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfbGVhdmVzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 186, + "key": "minecraft:acacia_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YWNhY2lhX2xlYXZlcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfbGVhdmVzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 187, + "key": "minecraft:cherry_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y2hlcnJ5X2xlYXZlcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jaGVycnlfbGVhdmVzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 188, + "key": "minecraft:dark_oak_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGFya19vYWtfbGVhdmVz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19sZWF2ZXMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 189, + "key": "minecraft:pale_oak_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cGFsZV9vYWtfbGVhdmVz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19sZWF2ZXMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 190, + "key": "minecraft:mangrove_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bWFuZ3JvdmVfbGVhdmVz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9sZWF2ZXMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 191, + "key": "minecraft:azalea_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YXphbGVhX2xlYXZlcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5hemFsZWFfbGVhdmVzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 192, + "key": "minecraft:flowering_azalea_leaves", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6Zmxvd2VyaW5nX2F6YWxlYV9sZWF2ZXM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5mbG93ZXJpbmdfYXphbGVhX2xlYXZlcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 193, + "key": "minecraft:sponge", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6c3Bvbmdl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5zcG9uZ2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 194, + "key": "minecraft:wet_sponge", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6d2V0X3Nwb25nZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC53ZXRfc3BvbmdlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 195, + "key": "minecraft:glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6Z2xhc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5nbGFzcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 196, + "key": "minecraft:tinted_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6dGludGVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC50aW50ZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 197, + "key": "minecraft:lapis_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bGFwaXNfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5sYXBpc19ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 198, + "key": "minecraft:sandstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6c2FuZHN0b25l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5zYW5kc3RvbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 199, + "key": "minecraft:chiseled_sandstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y2hpc2VsZWRfc2FuZHN0b25l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9zYW5kc3RvbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 200, + "key": "minecraft:cut_sandstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y3V0X3NhbmRzdG9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jdXRfc2FuZHN0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 201, + "key": "minecraft:cobweb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6Y29id2Vi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5jb2J3ZWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 202, + "key": "minecraft:short_grass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c2hvcnRfZ3Jhc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zaG9ydF9ncmFzcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 203, + "key": "minecraft:fern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6ZmVybg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5mZXJuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 204, + "key": "minecraft:azalea", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YXphbGVh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5hemFsZWEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 205, + "key": "minecraft:flowering_azalea", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Zmxvd2VyaW5nX2F6YWxlYQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5mbG93ZXJpbmdfYXphbGVhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 206, + "key": "minecraft:dead_bush", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6ZGVhZF9idXNo", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5kZWFkX2J1c2gA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 207, + "key": "minecraft:seagrass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6c2VhZ3Jhc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5zZWFncmFzcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 208, + "key": "minecraft:sea_pickle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c2VhX3BpY2tsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5zZWFfcGlja2xlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 209, + "key": "minecraft:white_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6d2hpdGVfd29vbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC53aGl0ZV93b29sAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 210, + "key": "minecraft:orange_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6b3JhbmdlX3dvb2w=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5vcmFuZ2Vfd29vbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 211, + "key": "minecraft:magenta_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6bWFnZW50YV93b29s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX3dvb2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 212, + "key": "minecraft:light_blue_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bGlnaHRfYmx1ZV93b29s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX3dvb2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 213, + "key": "minecraft:yellow_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6eWVsbG93X3dvb2w=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC55ZWxsb3dfd29vbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 214, + "key": "minecraft:lime_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6bGltZV93b29s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5saW1lX3dvb2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 215, + "key": "minecraft:pink_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6cGlua193b29s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5waW5rX3dvb2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 216, + "key": "minecraft:gray_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Z3JheV93b29s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5ncmF5X3dvb2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 217, + "key": "minecraft:light_gray_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bGlnaHRfZ3JheV93b29s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X3dvb2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 218, + "key": "minecraft:cyan_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Y3lhbl93b29s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5jeWFuX3dvb2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 219, + "key": "minecraft:purple_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cHVycGxlX3dvb2w=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5wdXJwbGVfd29vbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 220, + "key": "minecraft:blue_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Ymx1ZV93b29s", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5ibHVlX3dvb2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 221, + "key": "minecraft:brown_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YnJvd25fd29vbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5icm93bl93b29sAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 222, + "key": "minecraft:green_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Z3JlZW5fd29vbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5ncmVlbl93b29sAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 223, + "key": "minecraft:red_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cmVkX3dvb2w=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5yZWRfd29vbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 224, + "key": "minecraft:black_wool", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YmxhY2tfd29vbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5ibGFja193b29sAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 225, + "key": "minecraft:dandelion", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6ZGFuZGVsaW9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5kYW5kZWxpb24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 226, + "key": "minecraft:open_eyeblossom", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6b3Blbl9leWVibG9zc29t", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5vcGVuX2V5ZWJsb3Nzb20A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 227, + "key": "minecraft:closed_eyeblossom", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y2xvc2VkX2V5ZWJsb3Nzb20=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5jbG9zZWRfZXllYmxvc3NvbQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 228, + "key": "minecraft:poppy", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6cG9wcHk=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5wb3BweQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 229, + "key": "minecraft:blue_orchid", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Ymx1ZV9vcmNoaWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ibHVlX29yY2hpZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 230, + "key": "minecraft:allium", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YWxsaXVt", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5hbGxpdW0A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 231, + "key": "minecraft:azure_bluet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YXp1cmVfYmx1ZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5henVyZV9ibHVldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 232, + "key": "minecraft:red_tulip", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6cmVkX3R1bGlw", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5yZWRfdHVsaXAA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 233, + "key": "minecraft:orange_tulip", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6b3JhbmdlX3R1bGlw", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfdHVsaXAA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 234, + "key": "minecraft:white_tulip", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6d2hpdGVfdHVsaXA=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC53aGl0ZV90dWxpcAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 235, + "key": "minecraft:pink_tulip", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cGlua190dWxpcA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5waW5rX3R1bGlwAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 236, + "key": "minecraft:oxeye_daisy", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6b3hleWVfZGFpc3k=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5veGV5ZV9kYWlzeQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 237, + "key": "minecraft:cornflower", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Y29ybmZsb3dlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5jb3JuZmxvd2VyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 238, + "key": "minecraft:lily_of_the_valley", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bGlseV9vZl90aGVfdmFsbGV5", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5saWx5X29mX3RoZV92YWxsZXkA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 239, + "key": "minecraft:wither_rose", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6d2l0aGVyX3Jvc2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC53aXRoZXJfcm9zZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 240, + "key": "minecraft:torchflower", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6dG9yY2hmbG93ZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC50b3JjaGZsb3dlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 241, + "key": "minecraft:pitcher_plant", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cGl0Y2hlcl9wbGFudA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5waXRjaGVyX3BsYW50AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 242, + "key": "minecraft:spore_blossom", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3BvcmVfYmxvc3NvbQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zcG9yZV9ibG9zc29tAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 243, + "key": "minecraft:brown_mushroom", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YnJvd25fbXVzaHJvb20=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5icm93bl9tdXNocm9vbQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 244, + "key": "minecraft:red_mushroom", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cmVkX211c2hyb29t", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5yZWRfbXVzaHJvb20A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 245, + "key": "minecraft:crimson_fungus", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y3JpbXNvbl9mdW5ndXM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jcmltc29uX2Z1bmd1cwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 246, + "key": "minecraft:warped_fungus", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d2FycGVkX2Z1bmd1cw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfZnVuZ3VzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 247, + "key": "minecraft:crimson_roots", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y3JpbXNvbl9yb290cw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jcmltc29uX3Jvb3RzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 248, + "key": "minecraft:warped_roots", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d2FycGVkX3Jvb3Rz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC53YXJwZWRfcm9vdHMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 249, + "key": "minecraft:nether_sprouts", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bmV0aGVyX3Nwcm91dHM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5uZXRoZXJfc3Byb3V0cwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 250, + "key": "minecraft:weeping_vines", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d2VlcGluZ192aW5lcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC53ZWVwaW5nX3ZpbmVzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 251, + "key": "minecraft:twisting_vines", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6dHdpc3RpbmdfdmluZXM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC50d2lzdGluZ192aW5lcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 252, + "key": "minecraft:sugar_cane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c3VnYXJfY2FuZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5zdWdhcl9jYW5lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 253, + "key": "minecraft:kelp", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6a2VscA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5rZWxwAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 254, + "key": "minecraft:pink_petals", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cGlua19wZXRhbHM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5waW5rX3BldGFscwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 255, + "key": "minecraft:moss_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bW9zc19jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5tb3NzX2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 256, + "key": "minecraft:moss_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6bW9zc19ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5tb3NzX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 257, + "key": "minecraft:pale_moss_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cGFsZV9tb3NzX2NhcnBldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5wYWxlX21vc3NfY2FycGV0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 258, + "key": "minecraft:pale_hanging_moss", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cGFsZV9oYW5naW5nX21vc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5wYWxlX2hhbmdpbmdfbW9zcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 259, + "key": "minecraft:pale_moss_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cGFsZV9tb3NzX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wYWxlX21vc3NfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 260, + "key": "minecraft:hanging_roots", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6aGFuZ2luZ19yb290cw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5oYW5naW5nX3Jvb3RzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 261, + "key": "minecraft:big_dripleaf", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmlnX2RyaXBsZWFm", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5iaWdfZHJpcGxlYWYA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 262, + "key": "minecraft:small_dripleaf", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c21hbGxfZHJpcGxlYWY=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5zbWFsbF9kcmlwbGVhZgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 263, + "key": "minecraft:bamboo", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YmFtYm9v", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5iYW1ib28A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 264, + "key": "minecraft:oak_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6b2FrX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5vYWtfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 265, + "key": "minecraft:spruce_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c3BydWNlX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zcHJ1Y2Vfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 266, + "key": "minecraft:birch_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YmlyY2hfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5iaXJjaF9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 267, + "key": "minecraft:jungle_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6anVuZ2xlX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5qdW5nbGVfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 268, + "key": "minecraft:acacia_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YWNhY2lhX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5hY2FjaWFfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 269, + "key": "minecraft:cherry_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y2hlcnJ5X3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jaGVycnlfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 270, + "key": "minecraft:dark_oak_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGFya19vYWtfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 271, + "key": "minecraft:pale_oak_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cGFsZV9vYWtfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 272, + "key": "minecraft:mangrove_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bWFuZ3JvdmVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 273, + "key": "minecraft:bamboo_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YmFtYm9vX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5iYW1ib29fc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 274, + "key": "minecraft:bamboo_mosaic_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6YmFtYm9vX21vc2FpY19zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5iYW1ib29fbW9zYWljX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 275, + "key": "minecraft:crimson_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y3JpbXNvbl9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jcmltc29uX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 276, + "key": "minecraft:warped_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6d2FycGVkX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC53YXJwZWRfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 277, + "key": "minecraft:stone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c3RvbmVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5zdG9uZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 278, + "key": "minecraft:smooth_stone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6c21vb3RoX3N0b25lX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfc3RvbmVfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 279, + "key": "minecraft:sandstone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c2FuZHN0b25lX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5zYW5kc3RvbmVfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 280, + "key": "minecraft:cut_sandstone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y3V0X3NhbmRzdG9uZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5jdXRfc2FuZHN0b25lX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 281, + "key": "minecraft:petrified_oak_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cGV0cmlmaWVkX29ha19zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5wZXRyaWZpZWRfb2FrX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 282, + "key": "minecraft:cobblestone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Y29iYmxlc3RvbmVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5jb2JibGVzdG9uZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 283, + "key": "minecraft:brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YnJpY2tfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5icmlja19zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 284, + "key": "minecraft:stone_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6c3RvbmVfYnJpY2tfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5zdG9uZV9icmlja19zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 285, + "key": "minecraft:mud_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bXVkX2JyaWNrX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5tdWRfYnJpY2tfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 286, + "key": "minecraft:nether_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bmV0aGVyX2JyaWNrX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5uZXRoZXJfYnJpY2tfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 287, + "key": "minecraft:quartz_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cXVhcnR6X3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5xdWFydHpfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 288, + "key": "minecraft:red_sandstone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cmVkX3NhbmRzdG9uZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5yZWRfc2FuZHN0b25lX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 289, + "key": "minecraft:cut_red_sandstone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y3V0X3JlZF9zYW5kc3RvbmVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5jdXRfcmVkX3NhbmRzdG9uZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 290, + "key": "minecraft:purpur_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cHVycHVyX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5wdXJwdXJfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 291, + "key": "minecraft:prismarine_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cHJpc21hcmluZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wcmlzbWFyaW5lX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 292, + "key": "minecraft:prismarine_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cHJpc21hcmluZV9icmlja19zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5wcmlzbWFyaW5lX2JyaWNrX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 293, + "key": "minecraft:dark_prismarine_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZGFya19wcmlzbWFyaW5lX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5kYXJrX3ByaXNtYXJpbmVfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 294, + "key": "minecraft:smooth_quartz", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c21vb3RoX3F1YXJ0eg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfcXVhcnR6AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 295, + "key": "minecraft:smooth_red_sandstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c21vb3RoX3JlZF9zYW5kc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfcmVkX3NhbmRzdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 296, + "key": "minecraft:smooth_sandstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6c21vb3RoX3NhbmRzdG9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfc2FuZHN0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 297, + "key": "minecraft:smooth_stone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6c21vb3RoX3N0b25l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfc3RvbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 298, + "key": "minecraft:bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 299, + "key": "minecraft:bookshelf", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Ym9va3NoZWxm", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5ib29rc2hlbGYA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 300, + "key": "minecraft:chiseled_bookshelf", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y2hpc2VsZWRfYm9va3NoZWxm", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9ib29rc2hlbGYA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 301, + "key": "minecraft:decorated_pot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGVjb3JhdGVkX3BvdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5kZWNvcmF0ZWRfcG90AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:pot_decorations": "PQS6B7oHuge6Bw==", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 302, + "key": "minecraft:mossy_cobblestone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bW9zc3lfY29iYmxlc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5tb3NzeV9jb2JibGVzdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 303, + "key": "minecraft:obsidian", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6b2JzaWRpYW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5vYnNpZGlhbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 304, + "key": "minecraft:torch", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6dG9yY2g=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC50b3JjaAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 305, + "key": "minecraft:end_rod", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6ZW5kX3JvZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5lbmRfcm9kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 306, + "key": "minecraft:chorus_plant", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y2hvcnVzX3BsYW50", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jaG9ydXNfcGxhbnQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 307, + "key": "minecraft:chorus_flower", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y2hvcnVzX2Zsb3dlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jaG9ydXNfZmxvd2VyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 308, + "key": "minecraft:purpur_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cHVycHVyX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5wdXJwdXJfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 309, + "key": "minecraft:purpur_pillar", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cHVycHVyX3BpbGxhcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wdXJwdXJfcGlsbGFyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 310, + "key": "minecraft:purpur_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cHVycHVyX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wdXJwdXJfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 311, + "key": "minecraft:spawner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6c3Bhd25lcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5zcGF3bmVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 312, + "key": "minecraft:creaking_heart", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y3JlYWtpbmdfaGVhcnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jcmVha2luZ19oZWFydAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 313, + "key": "minecraft:chest", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6Y2hlc3Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5jaGVzdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 314, + "key": "minecraft:crafting_table", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y3JhZnRpbmdfdGFibGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jcmFmdGluZ190YWJsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 315, + "key": "minecraft:farmland", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6ZmFybWxhbmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5mYXJtbGFuZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 316, + "key": "minecraft:furnace", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6ZnVybmFjZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5mdXJuYWNlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 317, + "key": "minecraft:ladder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6bGFkZGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5sYWRkZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 318, + "key": "minecraft:cobblestone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y29iYmxlc3RvbmVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5jb2JibGVzdG9uZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 319, + "key": "minecraft:snow", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6c25vdw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5zbm93AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 320, + "key": "minecraft:ice", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw1taW5lY3JhZnQ6aWNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2Jsb2NrLm1pbmVjcmFmdC5pY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 321, + "key": "minecraft:snow_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c25vd19ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5zbm93X2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 322, + "key": "minecraft:cactus", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6Y2FjdHVz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5jYWN0dXMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 323, + "key": "minecraft:clay", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6Y2xheQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5jbGF5AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 324, + "key": "minecraft:jukebox", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6anVrZWJveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5qdWtlYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 325, + "key": "minecraft:oak_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6b2FrX2ZlbmNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5vYWtfZmVuY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 326, + "key": "minecraft:spruce_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6c3BydWNlX2ZlbmNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfZmVuY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 327, + "key": "minecraft:birch_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YmlyY2hfZmVuY2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5iaXJjaF9mZW5jZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 328, + "key": "minecraft:jungle_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6anVuZ2xlX2ZlbmNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfZmVuY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 329, + "key": "minecraft:acacia_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YWNhY2lhX2ZlbmNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfZmVuY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 330, + "key": "minecraft:cherry_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y2hlcnJ5X2ZlbmNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jaGVycnlfZmVuY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 331, + "key": "minecraft:dark_oak_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6ZGFya19vYWtfZmVuY2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19mZW5jZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 332, + "key": "minecraft:pale_oak_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6cGFsZV9vYWtfZmVuY2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19mZW5jZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 333, + "key": "minecraft:mangrove_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bWFuZ3JvdmVfZmVuY2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9mZW5jZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 334, + "key": "minecraft:bamboo_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmFtYm9vX2ZlbmNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5iYW1ib29fZmVuY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 335, + "key": "minecraft:crimson_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y3JpbXNvbl9mZW5jZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jcmltc29uX2ZlbmNlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 336, + "key": "minecraft:warped_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d2FycGVkX2ZlbmNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC53YXJwZWRfZmVuY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 337, + "key": "minecraft:pumpkin", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6cHVtcGtpbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5wdW1wa2luAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 338, + "key": "minecraft:carved_pumpkin", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARHAAEabWluZWNyYWZ0Om1pc2MvcHVtcGtpbmJsdXIAAQAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y2FydmVkX3B1bXBraW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jYXJ2ZWRfcHVtcGtpbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 339, + "key": "minecraft:jack_o_lantern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6amFja19vX2xhbnRlcm4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5qYWNrX29fbGFudGVybgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 340, + "key": "minecraft:netherrack", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6bmV0aGVycmFjaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5uZXRoZXJyYWNrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 341, + "key": "minecraft:soul_sand", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6c291bF9zYW5k", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5zb3VsX3NhbmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 342, + "key": "minecraft:soul_soil", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6c291bF9zb2ls", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5zb3VsX3NvaWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 343, + "key": "minecraft:basalt", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YmFzYWx0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5iYXNhbHQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 344, + "key": "minecraft:polished_basalt", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cG9saXNoZWRfYmFzYWx0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9iYXNhbHQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 345, + "key": "minecraft:smooth_basalt", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c21vb3RoX2Jhc2FsdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfYmFzYWx0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 346, + "key": "minecraft:soul_torch", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c291bF90b3JjaA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5zb3VsX3RvcmNoAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 347, + "key": "minecraft:glowstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Z2xvd3N0b25l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5nbG93c3RvbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 348, + "key": "minecraft:infested_stone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6aW5mZXN0ZWRfc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5pbmZlc3RlZF9zdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 349, + "key": "minecraft:infested_cobblestone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6aW5mZXN0ZWRfY29iYmxlc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5pbmZlc3RlZF9jb2JibGVzdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 350, + "key": "minecraft:infested_stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6aW5mZXN0ZWRfc3RvbmVfYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5pbmZlc3RlZF9zdG9uZV9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 351, + "key": "minecraft:infested_mossy_stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByVtaW5lY3JhZnQ6aW5mZXN0ZWRfbW9zc3lfc3RvbmVfYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAK2Jsb2NrLm1pbmVjcmFmdC5pbmZlc3RlZF9tb3NzeV9zdG9uZV9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 352, + "key": "minecraft:infested_cracked_stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BydtaW5lY3JhZnQ6aW5mZXN0ZWRfY3JhY2tlZF9zdG9uZV9icmlja3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALWJsb2NrLm1pbmVjcmFmdC5pbmZlc3RlZF9jcmFja2VkX3N0b25lX2JyaWNrcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 353, + "key": "minecraft:infested_chiseled_stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByhtaW5lY3JhZnQ6aW5mZXN0ZWRfY2hpc2VsZWRfc3RvbmVfYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALmJsb2NrLm1pbmVjcmFmdC5pbmZlc3RlZF9jaGlzZWxlZF9zdG9uZV9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 354, + "key": "minecraft:infested_deepslate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6aW5mZXN0ZWRfZGVlcHNsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5pbmZlc3RlZF9kZWVwc2xhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 355, + "key": "minecraft:stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6c3RvbmVfYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5zdG9uZV9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 356, + "key": "minecraft:mossy_stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bW9zc3lfc3RvbmVfYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5tb3NzeV9zdG9uZV9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 357, + "key": "minecraft:cracked_stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Y3JhY2tlZF9zdG9uZV9icmlja3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5jcmFja2VkX3N0b25lX2JyaWNrcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 358, + "key": "minecraft:chiseled_stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Y2hpc2VsZWRfc3RvbmVfYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9zdG9uZV9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 359, + "key": "minecraft:packed_mud", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cGFja2VkX211ZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5wYWNrZWRfbXVkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 360, + "key": "minecraft:mud_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6bXVkX2JyaWNrcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5tdWRfYnJpY2tzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 361, + "key": "minecraft:deepslate_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZGVlcHNsYXRlX2JyaWNrcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfYnJpY2tzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 362, + "key": "minecraft:cracked_deepslate_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6Y3JhY2tlZF9kZWVwc2xhdGVfYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5jcmFja2VkX2RlZXBzbGF0ZV9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 363, + "key": "minecraft:deepslate_tiles", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGVlcHNsYXRlX3RpbGVz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfdGlsZXMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 364, + "key": "minecraft:cracked_deepslate_tiles", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6Y3JhY2tlZF9kZWVwc2xhdGVfdGlsZXM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5jcmFja2VkX2RlZXBzbGF0ZV90aWxlcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 365, + "key": "minecraft:chiseled_deepslate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y2hpc2VsZWRfZGVlcHNsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9kZWVwc2xhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 366, + "key": "minecraft:reinforced_deepslate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6cmVpbmZvcmNlZF9kZWVwc2xhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5yZWluZm9yY2VkX2RlZXBzbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 367, + "key": "minecraft:brown_mushroom_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6YnJvd25fbXVzaHJvb21fYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5icm93bl9tdXNocm9vbV9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 368, + "key": "minecraft:red_mushroom_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cmVkX211c2hyb29tX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5yZWRfbXVzaHJvb21fYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 369, + "key": "minecraft:mushroom_stem", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bXVzaHJvb21fc3RlbQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5tdXNocm9vbV9zdGVtAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 370, + "key": "minecraft:iron_bars", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6aXJvbl9iYXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5pcm9uX2JhcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 371, + "key": "minecraft:chain", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6Y2hhaW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5jaGFpbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 372, + "key": "minecraft:glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Z2xhc3NfcGFuZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5nbGFzc19wYW5lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 373, + "key": "minecraft:melon", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6bWVsb24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5tZWxvbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 374, + "key": "minecraft:vine", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6dmluZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC52aW5lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 375, + "key": "minecraft:glow_lichen", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Z2xvd19saWNoZW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5nbG93X2xpY2hlbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 376, + "key": "minecraft:resin_clump", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cmVzaW5fY2x1bXA=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnJlc2luX2NsdW1wAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 377, + "key": "minecraft:resin_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cmVzaW5fYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5yZXNpbl9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 378, + "key": "minecraft:resin_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cmVzaW5fYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5yZXNpbl9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 379, + "key": "minecraft:resin_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cmVzaW5fYnJpY2tfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5yZXNpbl9icmlja19zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 380, + "key": "minecraft:resin_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cmVzaW5fYnJpY2tfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5yZXNpbl9icmlja19zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 381, + "key": "minecraft:resin_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cmVzaW5fYnJpY2tfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5yZXNpbl9icmlja193YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 382, + "key": "minecraft:chiseled_resin_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Y2hpc2VsZWRfcmVzaW5fYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9yZXNpbl9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 383, + "key": "minecraft:brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YnJpY2tfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5icmlja19zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 384, + "key": "minecraft:stone_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6c3RvbmVfYnJpY2tfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5zdG9uZV9icmlja19zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 385, + "key": "minecraft:mud_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bXVkX2JyaWNrX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5tdWRfYnJpY2tfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 386, + "key": "minecraft:mycelium", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6bXljZWxpdW0=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5teWNlbGl1bQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 387, + "key": "minecraft:lily_pad", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6bGlseV9wYWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5saWx5X3BhZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 388, + "key": "minecraft:nether_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bmV0aGVyX2JyaWNrcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5uZXRoZXJfYnJpY2tzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 389, + "key": "minecraft:cracked_nether_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Y3JhY2tlZF9uZXRoZXJfYnJpY2tz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5jcmFja2VkX25ldGhlcl9icmlja3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 390, + "key": "minecraft:chiseled_nether_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y2hpc2VsZWRfbmV0aGVyX2JyaWNrcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9uZXRoZXJfYnJpY2tzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 391, + "key": "minecraft:nether_brick_fence", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bmV0aGVyX2JyaWNrX2ZlbmNl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5uZXRoZXJfYnJpY2tfZmVuY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 392, + "key": "minecraft:nether_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bmV0aGVyX2JyaWNrX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5uZXRoZXJfYnJpY2tfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 393, + "key": "minecraft:sculk", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6c2N1bGs=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5zY3VsawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 394, + "key": "minecraft:sculk_vein", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c2N1bGtfdmVpbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5zY3Vsa192ZWluAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 395, + "key": "minecraft:sculk_catalyst", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c2N1bGtfY2F0YWx5c3Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5zY3Vsa19jYXRhbHlzdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 396, + "key": "minecraft:sculk_shrieker", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c2N1bGtfc2hyaWVrZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5zY3Vsa19zaHJpZWtlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 397, + "key": "minecraft:enchanting_table", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZW5jaGFudGluZ190YWJsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5lbmNoYW50aW5nX3RhYmxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 398, + "key": "minecraft:end_portal_frame", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZW5kX3BvcnRhbF9mcmFtZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5lbmRfcG9ydGFsX2ZyYW1lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 399, + "key": "minecraft:end_stone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6ZW5kX3N0b25l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5lbmRfc3RvbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 400, + "key": "minecraft:end_stone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZW5kX3N0b25lX2JyaWNrcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5lbmRfc3RvbmVfYnJpY2tzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 401, + "key": "minecraft:dragon_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6ZHJhZ29uX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5kcmFnb25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 402, + "key": "minecraft:sandstone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6c2FuZHN0b25lX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5zYW5kc3RvbmVfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 403, + "key": "minecraft:ender_chest", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZW5kZXJfY2hlc3Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5lbmRlcl9jaGVzdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 404, + "key": "minecraft:emerald_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZW1lcmFsZF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5lbWVyYWxkX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 405, + "key": "minecraft:oak_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6b2FrX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5vYWtfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 406, + "key": "minecraft:spruce_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3BydWNlX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2Vfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 407, + "key": "minecraft:birch_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmlyY2hfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5iaXJjaF9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 408, + "key": "minecraft:jungle_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6anVuZ2xlX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 409, + "key": "minecraft:acacia_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YWNhY2lhX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 410, + "key": "minecraft:cherry_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y2hlcnJ5X3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jaGVycnlfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 411, + "key": "minecraft:dark_oak_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGFya19vYWtfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 412, + "key": "minecraft:pale_oak_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cGFsZV9vYWtfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 413, + "key": "minecraft:mangrove_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bWFuZ3JvdmVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 414, + "key": "minecraft:bamboo_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YmFtYm9vX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5iYW1ib29fc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 415, + "key": "minecraft:bamboo_mosaic_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6YmFtYm9vX21vc2FpY19zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5iYW1ib29fbW9zYWljX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 416, + "key": "minecraft:crimson_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y3JpbXNvbl9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jcmltc29uX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 417, + "key": "minecraft:warped_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d2FycGVkX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 418, + "key": "minecraft:command_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y29tbWFuZF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jb21tYW5kX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 419, + "key": "minecraft:beacon", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YmVhY29u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5iZWFjb24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 420, + "key": "minecraft:cobblestone_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Y29iYmxlc3RvbmVfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5jb2JibGVzdG9uZV93YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 421, + "key": "minecraft:mossy_cobblestone_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6bW9zc3lfY29iYmxlc3RvbmVfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5tb3NzeV9jb2JibGVzdG9uZV93YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 422, + "key": "minecraft:brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YnJpY2tfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5icmlja193YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 423, + "key": "minecraft:prismarine_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cHJpc21hcmluZV93YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wcmlzbWFyaW5lX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 424, + "key": "minecraft:red_sandstone_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cmVkX3NhbmRzdG9uZV93YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5yZWRfc2FuZHN0b25lX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 425, + "key": "minecraft:mossy_stone_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6bW9zc3lfc3RvbmVfYnJpY2tfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5tb3NzeV9zdG9uZV9icmlja193YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 426, + "key": "minecraft:granite_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z3Jhbml0ZV93YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5ncmFuaXRlX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 427, + "key": "minecraft:stone_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6c3RvbmVfYnJpY2tfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5zdG9uZV9icmlja193YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 428, + "key": "minecraft:mud_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bXVkX2JyaWNrX3dhbGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5tdWRfYnJpY2tfd2FsbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 429, + "key": "minecraft:nether_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bmV0aGVyX2JyaWNrX3dhbGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5uZXRoZXJfYnJpY2tfd2FsbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 430, + "key": "minecraft:andesite_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YW5kZXNpdGVfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5hbmRlc2l0ZV93YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 431, + "key": "minecraft:red_nether_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cmVkX25ldGhlcl9icmlja193YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5yZWRfbmV0aGVyX2JyaWNrX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 432, + "key": "minecraft:sandstone_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c2FuZHN0b25lX3dhbGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5zYW5kc3RvbmVfd2FsbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 433, + "key": "minecraft:end_stone_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZW5kX3N0b25lX2JyaWNrX3dhbGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5lbmRfc3RvbmVfYnJpY2tfd2FsbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 434, + "key": "minecraft:diorite_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6ZGlvcml0ZV93YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5kaW9yaXRlX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 435, + "key": "minecraft:blackstone_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YmxhY2tzdG9uZV93YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5ibGFja3N0b25lX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 436, + "key": "minecraft:polished_blackstone_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV93YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 437, + "key": "minecraft:polished_blackstone_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByhtaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV9icmlja193YWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALmJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX2JyaWNrX3dhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 438, + "key": "minecraft:cobbled_deepslate_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y29iYmxlZF9kZWVwc2xhdGVfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5jb2JibGVkX2RlZXBzbGF0ZV93YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 439, + "key": "minecraft:polished_deepslate_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cG9saXNoZWRfZGVlcHNsYXRlX3dhbGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9kZWVwc2xhdGVfd2FsbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 440, + "key": "minecraft:deepslate_brick_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZGVlcHNsYXRlX2JyaWNrX3dhbGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfYnJpY2tfd2FsbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 441, + "key": "minecraft:deepslate_tile_wall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGVlcHNsYXRlX3RpbGVfd2FsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfdGlsZV93YWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 442, + "key": "minecraft:anvil", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6YW52aWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5hbnZpbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 443, + "key": "minecraft:chipped_anvil", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y2hpcHBlZF9hbnZpbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jaGlwcGVkX2FudmlsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 444, + "key": "minecraft:damaged_anvil", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGFtYWdlZF9hbnZpbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5kYW1hZ2VkX2FudmlsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 445, + "key": "minecraft:chiseled_quartz_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Y2hpc2VsZWRfcXVhcnR6X2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9xdWFydHpfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 446, + "key": "minecraft:quartz_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cXVhcnR6X2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5xdWFydHpfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 447, + "key": "minecraft:quartz_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cXVhcnR6X2JyaWNrcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5xdWFydHpfYnJpY2tzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 448, + "key": "minecraft:quartz_pillar", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cXVhcnR6X3BpbGxhcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5xdWFydHpfcGlsbGFyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 449, + "key": "minecraft:quartz_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cXVhcnR6X3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5xdWFydHpfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 450, + "key": "minecraft:white_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6d2hpdGVfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC53aGl0ZV90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 451, + "key": "minecraft:orange_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6b3JhbmdlX3RlcnJhY290dGE=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfdGVycmFjb3R0YQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 452, + "key": "minecraft:magenta_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bWFnZW50YV90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 453, + "key": "minecraft:light_blue_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6bGlnaHRfYmx1ZV90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 454, + "key": "minecraft:yellow_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6eWVsbG93X3RlcnJhY290dGE=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfdGVycmFjb3R0YQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 455, + "key": "minecraft:lime_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bGltZV90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5saW1lX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 456, + "key": "minecraft:pink_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cGlua190ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5waW5rX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 457, + "key": "minecraft:gray_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Z3JheV90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5ncmF5X3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 458, + "key": "minecraft:light_gray_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6bGlnaHRfZ3JheV90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 459, + "key": "minecraft:cyan_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y3lhbl90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5jeWFuX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 460, + "key": "minecraft:purple_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cHVycGxlX3RlcnJhY290dGE=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfdGVycmFjb3R0YQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 461, + "key": "minecraft:blue_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Ymx1ZV90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5ibHVlX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 462, + "key": "minecraft:brown_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6YnJvd25fdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5icm93bl90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 463, + "key": "minecraft:green_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Z3JlZW5fdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5ncmVlbl90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 464, + "key": "minecraft:red_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6cmVkX3RlcnJhY290dGE=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5yZWRfdGVycmFjb3R0YQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 465, + "key": "minecraft:black_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6YmxhY2tfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5ibGFja190ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 466, + "key": "minecraft:barrier", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6YmFycmllcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5iYXJyaWVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 467, + "key": "minecraft:light", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:block_state": "PwEFbGV2ZWwCMTU=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6bGlnaHQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5saWdodAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 468, + "key": "minecraft:hay_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6aGF5X2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5oYXlfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 469, + "key": "minecraft:white_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEWbWluZWNyYWZ0OndoaXRlX2NhcnBldAABA0t/AQEB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d2hpdGVfY2FycGV0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC53aGl0ZV9jYXJwZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 470, + "key": "minecraft:orange_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEXbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQAAQNLfwEBAQ==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6b3JhbmdlX2NhcnBldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfY2FycGV0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 471, + "key": "minecraft:magenta_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEYbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0AAEDS38BAQE=", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bWFnZW50YV9jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 472, + "key": "minecraft:light_blue_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEbbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0AAEDS38BAQE=", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bGlnaHRfYmx1ZV9jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 473, + "key": "minecraft:yellow_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEXbWluZWNyYWZ0OnllbGxvd19jYXJwZXQAAQNLfwEBAQ==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6eWVsbG93X2NhcnBldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfY2FycGV0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 474, + "key": "minecraft:lime_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEVbWluZWNyYWZ0OmxpbWVfY2FycGV0AAEDS38BAQE=", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bGltZV9jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5saW1lX2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 475, + "key": "minecraft:pink_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEVbWluZWNyYWZ0OnBpbmtfY2FycGV0AAEDS38BAQE=", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cGlua19jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5waW5rX2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 476, + "key": "minecraft:gray_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEVbWluZWNyYWZ0OmdyYXlfY2FycGV0AAEDS38BAQE=", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Z3JheV9jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ncmF5X2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 477, + "key": "minecraft:light_gray_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEbbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0AAEDS38BAQE=", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bGlnaHRfZ3JheV9jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 478, + "key": "minecraft:cyan_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEVbWluZWNyYWZ0OmN5YW5fY2FycGV0AAEDS38BAQE=", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y3lhbl9jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jeWFuX2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 479, + "key": "minecraft:purple_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEXbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQAAQNLfwEBAQ==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cHVycGxlX2NhcnBldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfY2FycGV0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 480, + "key": "minecraft:blue_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEVbWluZWNyYWZ0OmJsdWVfY2FycGV0AAEDS38BAQE=", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Ymx1ZV9jYXJwZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ibHVlX2NhcnBldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 481, + "key": "minecraft:brown_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEWbWluZWNyYWZ0OmJyb3duX2NhcnBldAABA0t/AQEB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YnJvd25fY2FycGV0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5icm93bl9jYXJwZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 482, + "key": "minecraft:green_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEWbWluZWNyYWZ0OmdyZWVuX2NhcnBldAABA0t/AQEB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z3JlZW5fY2FycGV0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5ncmVlbl9jYXJwZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 483, + "key": "minecraft:red_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEUbWluZWNyYWZ0OnJlZF9jYXJwZXQAAQNLfwEBAQ==", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cmVkX2NhcnBldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5yZWRfY2FycGV0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 484, + "key": "minecraft:black_carpet", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAaxBgEWbWluZWNyYWZ0OmJsYWNrX2NhcnBldAABA0t/AQEB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmxhY2tfY2FycGV0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5ibGFja19jYXJwZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 485, + "key": "minecraft:terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6dGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC50ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 486, + "key": "minecraft:packed_ice", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cGFja2VkX2ljZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5wYWNrZWRfaWNlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 487, + "key": "minecraft:dirt_path", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6ZGlydF9wYXRo", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5kaXJ0X3BhdGgA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 488, + "key": "minecraft:sunflower", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6c3VuZmxvd2Vy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5zdW5mbG93ZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 489, + "key": "minecraft:lilac", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6bGlsYWM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5saWxhYwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 490, + "key": "minecraft:rose_bush", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6cm9zZV9idXNo", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5yb3NlX2J1c2gA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 491, + "key": "minecraft:peony", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6cGVvbnk=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5wZW9ueQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 492, + "key": "minecraft:tall_grass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6dGFsbF9ncmFzcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC50YWxsX2dyYXNzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 493, + "key": "minecraft:large_fern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6bGFyZ2VfZmVybg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5sYXJnZV9mZXJuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 494, + "key": "minecraft:white_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6d2hpdGVfc3RhaW5lZF9nbGFzcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC53aGl0ZV9zdGFpbmVkX2dsYXNzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 495, + "key": "minecraft:orange_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6b3JhbmdlX3N0YWluZWRfZ2xhc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5vcmFuZ2Vfc3RhaW5lZF9nbGFzcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 496, + "key": "minecraft:magenta_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6bWFnZW50YV9zdGFpbmVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX3N0YWluZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 497, + "key": "minecraft:light_blue_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6bGlnaHRfYmx1ZV9zdGFpbmVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX3N0YWluZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 498, + "key": "minecraft:yellow_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6eWVsbG93X3N0YWluZWRfZ2xhc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfc3RhaW5lZF9nbGFzcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 499, + "key": "minecraft:lime_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bGltZV9zdGFpbmVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5saW1lX3N0YWluZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 500, + "key": "minecraft:pink_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cGlua19zdGFpbmVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5waW5rX3N0YWluZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 501, + "key": "minecraft:gray_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Z3JheV9zdGFpbmVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5ncmF5X3N0YWluZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 502, + "key": "minecraft:light_gray_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6bGlnaHRfZ3JheV9zdGFpbmVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X3N0YWluZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 503, + "key": "minecraft:cyan_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y3lhbl9zdGFpbmVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5jeWFuX3N0YWluZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 504, + "key": "minecraft:purple_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6cHVycGxlX3N0YWluZWRfZ2xhc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfc3RhaW5lZF9nbGFzcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 505, + "key": "minecraft:blue_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Ymx1ZV9zdGFpbmVkX2dsYXNz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5ibHVlX3N0YWluZWRfZ2xhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 506, + "key": "minecraft:brown_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6YnJvd25fc3RhaW5lZF9nbGFzcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5icm93bl9zdGFpbmVkX2dsYXNzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 507, + "key": "minecraft:green_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6Z3JlZW5fc3RhaW5lZF9nbGFzcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5ncmVlbl9zdGFpbmVkX2dsYXNzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 508, + "key": "minecraft:red_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cmVkX3N0YWluZWRfZ2xhc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5yZWRfc3RhaW5lZF9nbGFzcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 509, + "key": "minecraft:black_stained_glass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6YmxhY2tfc3RhaW5lZF9nbGFzcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5ibGFja19zdGFpbmVkX2dsYXNzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 510, + "key": "minecraft:white_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6d2hpdGVfc3RhaW5lZF9nbGFzc19wYW5l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC53aGl0ZV9zdGFpbmVkX2dsYXNzX3BhbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 511, + "key": "minecraft:orange_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6b3JhbmdlX3N0YWluZWRfZ2xhc3NfcGFuZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC5vcmFuZ2Vfc3RhaW5lZF9nbGFzc19wYW5lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 512, + "key": "minecraft:magenta_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6bWFnZW50YV9zdGFpbmVkX2dsYXNzX3BhbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX3N0YWluZWRfZ2xhc3NfcGFuZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 513, + "key": "minecraft:light_blue_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BydtaW5lY3JhZnQ6bGlnaHRfYmx1ZV9zdGFpbmVkX2dsYXNzX3BhbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALWJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX3N0YWluZWRfZ2xhc3NfcGFuZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 514, + "key": "minecraft:yellow_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6eWVsbG93X3N0YWluZWRfZ2xhc3NfcGFuZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfc3RhaW5lZF9nbGFzc19wYW5lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 515, + "key": "minecraft:lime_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6bGltZV9zdGFpbmVkX2dsYXNzX3BhbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5saW1lX3N0YWluZWRfZ2xhc3NfcGFuZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 516, + "key": "minecraft:pink_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cGlua19zdGFpbmVkX2dsYXNzX3BhbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5waW5rX3N0YWluZWRfZ2xhc3NfcGFuZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 517, + "key": "minecraft:gray_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6Z3JheV9zdGFpbmVkX2dsYXNzX3BhbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5ncmF5X3N0YWluZWRfZ2xhc3NfcGFuZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 518, + "key": "minecraft:light_gray_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BydtaW5lY3JhZnQ6bGlnaHRfZ3JheV9zdGFpbmVkX2dsYXNzX3BhbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALWJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X3N0YWluZWRfZ2xhc3NfcGFuZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 519, + "key": "minecraft:cyan_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6Y3lhbl9zdGFpbmVkX2dsYXNzX3BhbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5jeWFuX3N0YWluZWRfZ2xhc3NfcGFuZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 520, + "key": "minecraft:purple_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6cHVycGxlX3N0YWluZWRfZ2xhc3NfcGFuZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfc3RhaW5lZF9nbGFzc19wYW5lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 521, + "key": "minecraft:blue_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6Ymx1ZV9zdGFpbmVkX2dsYXNzX3BhbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5ibHVlX3N0YWluZWRfZ2xhc3NfcGFuZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 522, + "key": "minecraft:brown_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6YnJvd25fc3RhaW5lZF9nbGFzc19wYW5l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5icm93bl9zdGFpbmVkX2dsYXNzX3BhbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 523, + "key": "minecraft:green_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6Z3JlZW5fc3RhaW5lZF9nbGFzc19wYW5l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5ncmVlbl9zdGFpbmVkX2dsYXNzX3BhbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 524, + "key": "minecraft:red_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6cmVkX3N0YWluZWRfZ2xhc3NfcGFuZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5yZWRfc3RhaW5lZF9nbGFzc19wYW5lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 525, + "key": "minecraft:black_stained_glass_pane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6YmxhY2tfc3RhaW5lZF9nbGFzc19wYW5l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5ibGFja19zdGFpbmVkX2dsYXNzX3BhbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 526, + "key": "minecraft:prismarine", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cHJpc21hcmluZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5wcmlzbWFyaW5lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 527, + "key": "minecraft:prismarine_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cHJpc21hcmluZV9icmlja3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5wcmlzbWFyaW5lX2JyaWNrcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 528, + "key": "minecraft:dark_prismarine", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGFya19wcmlzbWFyaW5l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kYXJrX3ByaXNtYXJpbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 529, + "key": "minecraft:prismarine_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cHJpc21hcmluZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5wcmlzbWFyaW5lX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 530, + "key": "minecraft:prismarine_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cHJpc21hcmluZV9icmlja19zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5wcmlzbWFyaW5lX2JyaWNrX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 531, + "key": "minecraft:dark_prismarine_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6ZGFya19wcmlzbWFyaW5lX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5kYXJrX3ByaXNtYXJpbmVfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 532, + "key": "minecraft:sea_lantern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c2VhX2xhbnRlcm4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zZWFfbGFudGVybgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 533, + "key": "minecraft:red_sandstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cmVkX3NhbmRzdG9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5yZWRfc2FuZHN0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 534, + "key": "minecraft:chiseled_red_sandstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y2hpc2VsZWRfcmVkX3NhbmRzdG9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9yZWRfc2FuZHN0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 535, + "key": "minecraft:cut_red_sandstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y3V0X3JlZF9zYW5kc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5jdXRfcmVkX3NhbmRzdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 536, + "key": "minecraft:red_sandstone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6cmVkX3NhbmRzdG9uZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5yZWRfc2FuZHN0b25lX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 537, + "key": "minecraft:repeating_command_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cmVwZWF0aW5nX2NvbW1hbmRfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5yZXBlYXRpbmdfY29tbWFuZF9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 538, + "key": "minecraft:chain_command_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6Y2hhaW5fY29tbWFuZF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5jaGFpbl9jb21tYW5kX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 539, + "key": "minecraft:magma_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bWFnbWFfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5tYWdtYV9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 540, + "key": "minecraft:nether_wart_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bmV0aGVyX3dhcnRfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5uZXRoZXJfd2FydF9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 541, + "key": "minecraft:warped_wart_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6d2FycGVkX3dhcnRfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfd2FydF9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 542, + "key": "minecraft:red_nether_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cmVkX25ldGhlcl9icmlja3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5yZWRfbmV0aGVyX2JyaWNrcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 543, + "key": "minecraft:bone_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Ym9uZV9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5ib25lX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 544, + "key": "minecraft:structure_void", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c3RydWN0dXJlX3ZvaWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5zdHJ1Y3R1cmVfdm9pZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 545, + "key": "minecraft:shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c2h1bGtlcl9ib3g=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zaHVsa2VyX2JveAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 546, + "key": "minecraft:white_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6d2hpdGVfc2h1bGtlcl9ib3g=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC53aGl0ZV9zaHVsa2VyX2JveAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 547, + "key": "minecraft:orange_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6b3JhbmdlX3NodWxrZXJfYm94", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5vcmFuZ2Vfc2h1bGtlcl9ib3gA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 548, + "key": "minecraft:magenta_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bWFnZW50YV9zaHVsa2VyX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX3NodWxrZXJfYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 549, + "key": "minecraft:light_blue_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6bGlnaHRfYmx1ZV9zaHVsa2VyX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX3NodWxrZXJfYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 550, + "key": "minecraft:yellow_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6eWVsbG93X3NodWxrZXJfYm94", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfc2h1bGtlcl9ib3gA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 551, + "key": "minecraft:lime_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bGltZV9zaHVsa2VyX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5saW1lX3NodWxrZXJfYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 552, + "key": "minecraft:pink_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cGlua19zaHVsa2VyX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5waW5rX3NodWxrZXJfYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 553, + "key": "minecraft:gray_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Z3JheV9zaHVsa2VyX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5ncmF5X3NodWxrZXJfYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 554, + "key": "minecraft:light_gray_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6bGlnaHRfZ3JheV9zaHVsa2VyX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X3NodWxrZXJfYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 555, + "key": "minecraft:cyan_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Y3lhbl9zaHVsa2VyX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5jeWFuX3NodWxrZXJfYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 556, + "key": "minecraft:purple_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cHVycGxlX3NodWxrZXJfYm94", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfc2h1bGtlcl9ib3gA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 557, + "key": "minecraft:blue_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Ymx1ZV9zaHVsa2VyX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5ibHVlX3NodWxrZXJfYm94AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 558, + "key": "minecraft:brown_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YnJvd25fc2h1bGtlcl9ib3g=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5icm93bl9zaHVsa2VyX2JveAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 559, + "key": "minecraft:green_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Z3JlZW5fc2h1bGtlcl9ib3g=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5ncmVlbl9zaHVsa2VyX2JveAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 560, + "key": "minecraft:red_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cmVkX3NodWxrZXJfYm94", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5yZWRfc2h1bGtlcl9ib3gA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 561, + "key": "minecraft:black_shulker_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YmxhY2tfc2h1bGtlcl9ib3g=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5ibGFja19zaHVsa2VyX2JveAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 562, + "key": "minecraft:white_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6d2hpdGVfZ2xhemVkX3RlcnJhY290dGE=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC53aGl0ZV9nbGF6ZWRfdGVycmFjb3R0YQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 563, + "key": "minecraft:orange_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6b3JhbmdlX2dsYXplZF90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfZ2xhemVkX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 564, + "key": "minecraft:magenta_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6bWFnZW50YV9nbGF6ZWRfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX2dsYXplZF90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 565, + "key": "minecraft:light_blue_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByZtaW5lY3JhZnQ6bGlnaHRfYmx1ZV9nbGF6ZWRfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALGJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX2dsYXplZF90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 566, + "key": "minecraft:yellow_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6eWVsbG93X2dsYXplZF90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfZ2xhemVkX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 567, + "key": "minecraft:lime_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6bGltZV9nbGF6ZWRfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5saW1lX2dsYXplZF90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 568, + "key": "minecraft:pink_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6cGlua19nbGF6ZWRfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5waW5rX2dsYXplZF90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 569, + "key": "minecraft:gray_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Z3JheV9nbGF6ZWRfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5ncmF5X2dsYXplZF90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 570, + "key": "minecraft:light_gray_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByZtaW5lY3JhZnQ6bGlnaHRfZ3JheV9nbGF6ZWRfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALGJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X2dsYXplZF90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 571, + "key": "minecraft:cyan_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y3lhbl9nbGF6ZWRfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5jeWFuX2dsYXplZF90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 572, + "key": "minecraft:purple_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6cHVycGxlX2dsYXplZF90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfZ2xhemVkX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 573, + "key": "minecraft:blue_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Ymx1ZV9nbGF6ZWRfdGVycmFjb3R0YQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5ibHVlX2dsYXplZF90ZXJyYWNvdHRhAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 574, + "key": "minecraft:brown_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6YnJvd25fZ2xhemVkX3RlcnJhY290dGE=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5icm93bl9nbGF6ZWRfdGVycmFjb3R0YQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 575, + "key": "minecraft:green_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6Z3JlZW5fZ2xhemVkX3RlcnJhY290dGE=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5ncmVlbl9nbGF6ZWRfdGVycmFjb3R0YQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 576, + "key": "minecraft:red_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cmVkX2dsYXplZF90ZXJyYWNvdHRh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5yZWRfZ2xhemVkX3RlcnJhY290dGEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 577, + "key": "minecraft:black_glazed_terracotta", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6YmxhY2tfZ2xhemVkX3RlcnJhY290dGE=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5ibGFja19nbGF6ZWRfdGVycmFjb3R0YQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 578, + "key": "minecraft:white_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6d2hpdGVfY29uY3JldGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC53aGl0ZV9jb25jcmV0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 579, + "key": "minecraft:orange_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6b3JhbmdlX2NvbmNyZXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfY29uY3JldGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 580, + "key": "minecraft:magenta_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bWFnZW50YV9jb25jcmV0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX2NvbmNyZXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 581, + "key": "minecraft:light_blue_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bGlnaHRfYmx1ZV9jb25jcmV0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX2NvbmNyZXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 582, + "key": "minecraft:yellow_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6eWVsbG93X2NvbmNyZXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC55ZWxsb3dfY29uY3JldGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 583, + "key": "minecraft:lime_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bGltZV9jb25jcmV0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5saW1lX2NvbmNyZXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 584, + "key": "minecraft:pink_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cGlua19jb25jcmV0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5waW5rX2NvbmNyZXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 585, + "key": "minecraft:gray_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Z3JheV9jb25jcmV0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5ncmF5X2NvbmNyZXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 586, + "key": "minecraft:light_gray_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bGlnaHRfZ3JheV9jb25jcmV0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X2NvbmNyZXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 587, + "key": "minecraft:cyan_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y3lhbl9jb25jcmV0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jeWFuX2NvbmNyZXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 588, + "key": "minecraft:purple_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cHVycGxlX2NvbmNyZXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wdXJwbGVfY29uY3JldGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 589, + "key": "minecraft:blue_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Ymx1ZV9jb25jcmV0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5ibHVlX2NvbmNyZXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 590, + "key": "minecraft:brown_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YnJvd25fY29uY3JldGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5icm93bl9jb25jcmV0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 591, + "key": "minecraft:green_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Z3JlZW5fY29uY3JldGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5ncmVlbl9jb25jcmV0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 592, + "key": "minecraft:red_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cmVkX2NvbmNyZXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5yZWRfY29uY3JldGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 593, + "key": "minecraft:black_concrete", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YmxhY2tfY29uY3JldGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5ibGFja19jb25jcmV0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 594, + "key": "minecraft:white_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2hpdGVfY29uY3JldGVfcG93ZGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53aGl0ZV9jb25jcmV0ZV9wb3dkZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 595, + "key": "minecraft:orange_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6b3JhbmdlX2NvbmNyZXRlX3Bvd2Rlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfY29uY3JldGVfcG93ZGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 596, + "key": "minecraft:magenta_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6bWFnZW50YV9jb25jcmV0ZV9wb3dkZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX2NvbmNyZXRlX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 597, + "key": "minecraft:light_blue_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6bGlnaHRfYmx1ZV9jb25jcmV0ZV9wb3dkZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX2NvbmNyZXRlX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 598, + "key": "minecraft:yellow_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6eWVsbG93X2NvbmNyZXRlX3Bvd2Rlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfY29uY3JldGVfcG93ZGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 599, + "key": "minecraft:lime_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6bGltZV9jb25jcmV0ZV9wb3dkZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5saW1lX2NvbmNyZXRlX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 600, + "key": "minecraft:pink_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6cGlua19jb25jcmV0ZV9wb3dkZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5waW5rX2NvbmNyZXRlX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 601, + "key": "minecraft:gray_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Z3JheV9jb25jcmV0ZV9wb3dkZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5ncmF5X2NvbmNyZXRlX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 602, + "key": "minecraft:light_gray_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6bGlnaHRfZ3JheV9jb25jcmV0ZV9wb3dkZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X2NvbmNyZXRlX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 603, + "key": "minecraft:cyan_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Y3lhbl9jb25jcmV0ZV9wb3dkZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5jeWFuX2NvbmNyZXRlX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 604, + "key": "minecraft:purple_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6cHVycGxlX2NvbmNyZXRlX3Bvd2Rlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfY29uY3JldGVfcG93ZGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 605, + "key": "minecraft:blue_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Ymx1ZV9jb25jcmV0ZV9wb3dkZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5ibHVlX2NvbmNyZXRlX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 606, + "key": "minecraft:brown_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6YnJvd25fY29uY3JldGVfcG93ZGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5icm93bl9jb25jcmV0ZV9wb3dkZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 607, + "key": "minecraft:green_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Z3JlZW5fY29uY3JldGVfcG93ZGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5ncmVlbl9jb25jcmV0ZV9wb3dkZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 608, + "key": "minecraft:red_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6cmVkX2NvbmNyZXRlX3Bvd2Rlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5yZWRfY29uY3JldGVfcG93ZGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 609, + "key": "minecraft:black_concrete_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6YmxhY2tfY29uY3JldGVfcG93ZGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5ibGFja19jb25jcmV0ZV9wb3dkZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 610, + "key": "minecraft:turtle_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6dHVydGxlX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC50dXJ0bGVfZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 611, + "key": "minecraft:sniffer_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c25pZmZlcl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zbmlmZmVyX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 612, + "key": "minecraft:dead_tube_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6ZGVhZF90dWJlX2NvcmFsX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5kZWFkX3R1YmVfY29yYWxfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 613, + "key": "minecraft:dead_brain_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6ZGVhZF9icmFpbl9jb3JhbF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5kZWFkX2JyYWluX2NvcmFsX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 614, + "key": "minecraft:dead_bubble_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6ZGVhZF9idWJibGVfY29yYWxfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5kZWFkX2J1YmJsZV9jb3JhbF9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 615, + "key": "minecraft:dead_fire_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6ZGVhZF9maXJlX2NvcmFsX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5kZWFkX2ZpcmVfY29yYWxfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 616, + "key": "minecraft:dead_horn_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6ZGVhZF9ob3JuX2NvcmFsX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5kZWFkX2hvcm5fY29yYWxfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 617, + "key": "minecraft:tube_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6dHViZV9jb3JhbF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC50dWJlX2NvcmFsX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 618, + "key": "minecraft:brain_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YnJhaW5fY29yYWxfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5icmFpbl9jb3JhbF9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 619, + "key": "minecraft:bubble_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6YnViYmxlX2NvcmFsX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5idWJibGVfY29yYWxfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 620, + "key": "minecraft:fire_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZmlyZV9jb3JhbF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5maXJlX2NvcmFsX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 621, + "key": "minecraft:horn_coral_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6aG9ybl9jb3JhbF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5ob3JuX2NvcmFsX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 622, + "key": "minecraft:tube_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6dHViZV9jb3JhbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC50dWJlX2NvcmFsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 623, + "key": "minecraft:brain_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YnJhaW5fY29yYWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5icmFpbl9jb3JhbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 624, + "key": "minecraft:bubble_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YnViYmxlX2NvcmFs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5idWJibGVfY29yYWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 625, + "key": "minecraft:fire_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6ZmlyZV9jb3JhbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5maXJlX2NvcmFsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 626, + "key": "minecraft:horn_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6aG9ybl9jb3JhbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5ob3JuX2NvcmFsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 627, + "key": "minecraft:dead_brain_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZGVhZF9icmFpbl9jb3JhbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5kZWFkX2JyYWluX2NvcmFsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 628, + "key": "minecraft:dead_bubble_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6ZGVhZF9idWJibGVfY29yYWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5kZWFkX2J1YmJsZV9jb3JhbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 629, + "key": "minecraft:dead_fire_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGVhZF9maXJlX2NvcmFs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kZWFkX2ZpcmVfY29yYWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 630, + "key": "minecraft:dead_horn_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGVhZF9ob3JuX2NvcmFs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kZWFkX2hvcm5fY29yYWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 631, + "key": "minecraft:dead_tube_coral", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGVhZF90dWJlX2NvcmFs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kZWFkX3R1YmVfY29yYWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 632, + "key": "minecraft:tube_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6dHViZV9jb3JhbF9mYW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC50dWJlX2NvcmFsX2ZhbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 633, + "key": "minecraft:brain_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YnJhaW5fY29yYWxfZmFu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5icmFpbl9jb3JhbF9mYW4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 634, + "key": "minecraft:bubble_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6YnViYmxlX2NvcmFsX2Zhbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5idWJibGVfY29yYWxfZmFuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 635, + "key": "minecraft:fire_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6ZmlyZV9jb3JhbF9mYW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5maXJlX2NvcmFsX2ZhbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 636, + "key": "minecraft:horn_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6aG9ybl9jb3JhbF9mYW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5ob3JuX2NvcmFsX2ZhbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 637, + "key": "minecraft:dead_tube_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGVhZF90dWJlX2NvcmFsX2Zhbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5kZWFkX3R1YmVfY29yYWxfZmFuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 638, + "key": "minecraft:dead_brain_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZGVhZF9icmFpbl9jb3JhbF9mYW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5kZWFkX2JyYWluX2NvcmFsX2ZhbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 639, + "key": "minecraft:dead_bubble_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6ZGVhZF9idWJibGVfY29yYWxfZmFu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5kZWFkX2J1YmJsZV9jb3JhbF9mYW4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 640, + "key": "minecraft:dead_fire_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGVhZF9maXJlX2NvcmFsX2Zhbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5kZWFkX2ZpcmVfY29yYWxfZmFuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 641, + "key": "minecraft:dead_horn_coral_fan", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGVhZF9ob3JuX2NvcmFsX2Zhbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5kZWFkX2hvcm5fY29yYWxfZmFuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 642, + "key": "minecraft:blue_ice", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Ymx1ZV9pY2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5ibHVlX2ljZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 643, + "key": "minecraft:conduit", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6Y29uZHVpdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5jb25kdWl0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 644, + "key": "minecraft:polished_granite_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cG9saXNoZWRfZ3Jhbml0ZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ncmFuaXRlX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 645, + "key": "minecraft:smooth_red_sandstone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByVtaW5lY3JhZnQ6c21vb3RoX3JlZF9zYW5kc3RvbmVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAK2Jsb2NrLm1pbmVjcmFmdC5zbW9vdGhfcmVkX3NhbmRzdG9uZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 646, + "key": "minecraft:mossy_stone_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6bW9zc3lfc3RvbmVfYnJpY2tfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5tb3NzeV9zdG9uZV9icmlja19zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 647, + "key": "minecraft:polished_diorite_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cG9saXNoZWRfZGlvcml0ZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9kaW9yaXRlX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 648, + "key": "minecraft:mossy_cobblestone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6bW9zc3lfY29iYmxlc3RvbmVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5tb3NzeV9jb2JibGVzdG9uZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 649, + "key": "minecraft:end_stone_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6ZW5kX3N0b25lX2JyaWNrX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5lbmRfc3RvbmVfYnJpY2tfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 650, + "key": "minecraft:stone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6c3RvbmVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5zdG9uZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 651, + "key": "minecraft:smooth_sandstone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6c21vb3RoX3NhbmRzdG9uZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5zbW9vdGhfc2FuZHN0b25lX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 652, + "key": "minecraft:smooth_quartz_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c21vb3RoX3F1YXJ0el9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfcXVhcnR6X3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 653, + "key": "minecraft:granite_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Z3Jhbml0ZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5ncmFuaXRlX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 654, + "key": "minecraft:andesite_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YW5kZXNpdGVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5hbmRlc2l0ZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 655, + "key": "minecraft:red_nether_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cmVkX25ldGhlcl9icmlja19zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5yZWRfbmV0aGVyX2JyaWNrX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 656, + "key": "minecraft:polished_andesite_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6cG9saXNoZWRfYW5kZXNpdGVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9hbmRlc2l0ZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 657, + "key": "minecraft:diorite_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6ZGlvcml0ZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5kaW9yaXRlX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 658, + "key": "minecraft:cobbled_deepslate_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6Y29iYmxlZF9kZWVwc2xhdGVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5jb2JibGVkX2RlZXBzbGF0ZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 659, + "key": "minecraft:polished_deepslate_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6cG9saXNoZWRfZGVlcHNsYXRlX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9kZWVwc2xhdGVfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 660, + "key": "minecraft:deepslate_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6ZGVlcHNsYXRlX2JyaWNrX3N0YWlycw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfYnJpY2tfc3RhaXJzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 661, + "key": "minecraft:deepslate_tile_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6ZGVlcHNsYXRlX3RpbGVfc3RhaXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfdGlsZV9zdGFpcnMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 662, + "key": "minecraft:polished_granite_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cG9saXNoZWRfZ3Jhbml0ZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ncmFuaXRlX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 663, + "key": "minecraft:smooth_red_sandstone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6c21vb3RoX3JlZF9zYW5kc3RvbmVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfcmVkX3NhbmRzdG9uZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 664, + "key": "minecraft:mossy_stone_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6bW9zc3lfc3RvbmVfYnJpY2tfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5tb3NzeV9zdG9uZV9icmlja19zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 665, + "key": "minecraft:polished_diorite_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cG9saXNoZWRfZGlvcml0ZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9kaW9yaXRlX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 666, + "key": "minecraft:mossy_cobblestone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6bW9zc3lfY29iYmxlc3RvbmVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5tb3NzeV9jb2JibGVzdG9uZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 667, + "key": "minecraft:end_stone_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZW5kX3N0b25lX2JyaWNrX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5lbmRfc3RvbmVfYnJpY2tfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 668, + "key": "minecraft:smooth_sandstone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6c21vb3RoX3NhbmRzdG9uZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfc2FuZHN0b25lX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 669, + "key": "minecraft:smooth_quartz_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6c21vb3RoX3F1YXJ0el9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5zbW9vdGhfcXVhcnR6X3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 670, + "key": "minecraft:granite_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z3Jhbml0ZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5ncmFuaXRlX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 671, + "key": "minecraft:andesite_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YW5kZXNpdGVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5hbmRlc2l0ZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 672, + "key": "minecraft:red_nether_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cmVkX25ldGhlcl9icmlja19zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5yZWRfbmV0aGVyX2JyaWNrX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 673, + "key": "minecraft:polished_andesite_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6cG9saXNoZWRfYW5kZXNpdGVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9hbmRlc2l0ZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 674, + "key": "minecraft:diorite_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6ZGlvcml0ZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5kaW9yaXRlX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 675, + "key": "minecraft:cobbled_deepslate_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y29iYmxlZF9kZWVwc2xhdGVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5jb2JibGVkX2RlZXBzbGF0ZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 676, + "key": "minecraft:polished_deepslate_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cG9saXNoZWRfZGVlcHNsYXRlX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9kZWVwc2xhdGVfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 677, + "key": "minecraft:deepslate_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZGVlcHNsYXRlX2JyaWNrX3NsYWI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfYnJpY2tfc2xhYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 678, + "key": "minecraft:deepslate_tile_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGVlcHNsYXRlX3RpbGVfc2xhYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5kZWVwc2xhdGVfdGlsZV9zbGFiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 679, + "key": "minecraft:scaffolding", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c2NhZmZvbGRpbmc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zY2FmZm9sZGluZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 680, + "key": "minecraft:redstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cmVkc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LnJlZHN0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 681, + "key": "minecraft:redstone_torch", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6cmVkc3RvbmVfdG9yY2g=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5yZWRzdG9uZV90b3JjaAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 682, + "key": "minecraft:redstone_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6cmVkc3RvbmVfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5yZWRzdG9uZV9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 683, + "key": "minecraft:repeater", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cmVwZWF0ZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5yZXBlYXRlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 684, + "key": "minecraft:comparator", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Y29tcGFyYXRvcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5jb21wYXJhdG9yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 685, + "key": "minecraft:piston", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6cGlzdG9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5waXN0b24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 686, + "key": "minecraft:sticky_piston", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3RpY2t5X3Bpc3Rvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zdGlja3lfcGlzdG9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 687, + "key": "minecraft:slime_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c2xpbWVfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zbGltZV9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 688, + "key": "minecraft:honey_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6aG9uZXlfYmxvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ob25leV9ibG9jawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 689, + "key": "minecraft:observer", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6b2JzZXJ2ZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5vYnNlcnZlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 690, + "key": "minecraft:hopper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6aG9wcGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5ob3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 691, + "key": "minecraft:dispenser", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6ZGlzcGVuc2Vy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5kaXNwZW5zZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 692, + "key": "minecraft:dropper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6ZHJvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5kcm9wcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 693, + "key": "minecraft:lectern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6bGVjdGVybg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5sZWN0ZXJuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 694, + "key": "minecraft:target", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6dGFyZ2V0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC50YXJnZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 695, + "key": "minecraft:lever", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6bGV2ZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC5sZXZlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 696, + "key": "minecraft:lightning_rod", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bGlnaHRuaW5nX3JvZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5saWdodG5pbmdfcm9kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 697, + "key": "minecraft:daylight_detector", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6ZGF5bGlnaHRfZGV0ZWN0b3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5kYXlsaWdodF9kZXRlY3RvcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 698, + "key": "minecraft:sculk_sensor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6c2N1bGtfc2Vuc29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5zY3Vsa19zZW5zb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 699, + "key": "minecraft:calibrated_sculk_sensor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6Y2FsaWJyYXRlZF9zY3Vsa19zZW5zb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5jYWxpYnJhdGVkX3NjdWxrX3NlbnNvcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 700, + "key": "minecraft:tripwire_hook", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6dHJpcHdpcmVfaG9vaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC50cmlwd2lyZV9ob29rAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 701, + "key": "minecraft:trapped_chest", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6dHJhcHBlZF9jaGVzdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC50cmFwcGVkX2NoZXN0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 702, + "key": "minecraft:tnt", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw1taW5lY3JhZnQ6dG50", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2Jsb2NrLm1pbmVjcmFmdC50bnQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 703, + "key": "minecraft:redstone_lamp", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cmVkc3RvbmVfbGFtcA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5yZWRzdG9uZV9sYW1wAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 704, + "key": "minecraft:note_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6bm90ZV9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5ub3RlX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 705, + "key": "minecraft:stone_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6c3RvbmVfYnV0dG9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5zdG9uZV9idXR0b24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 706, + "key": "minecraft:polished_blackstone_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV9idXR0b24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX2J1dHRvbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 707, + "key": "minecraft:oak_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6b2FrX2J1dHRvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5vYWtfYnV0dG9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 708, + "key": "minecraft:spruce_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3BydWNlX2J1dHRvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfYnV0dG9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 709, + "key": "minecraft:birch_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmlyY2hfYnV0dG9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5iaXJjaF9idXR0b24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 710, + "key": "minecraft:jungle_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6anVuZ2xlX2J1dHRvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfYnV0dG9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 711, + "key": "minecraft:acacia_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YWNhY2lhX2J1dHRvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfYnV0dG9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 712, + "key": "minecraft:cherry_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y2hlcnJ5X2J1dHRvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5jaGVycnlfYnV0dG9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 713, + "key": "minecraft:dark_oak_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGFya19vYWtfYnV0dG9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19idXR0b24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 714, + "key": "minecraft:pale_oak_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cGFsZV9vYWtfYnV0dG9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19idXR0b24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 715, + "key": "minecraft:mangrove_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bWFuZ3JvdmVfYnV0dG9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9idXR0b24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 716, + "key": "minecraft:bamboo_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YmFtYm9vX2J1dHRvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5iYW1ib29fYnV0dG9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 717, + "key": "minecraft:crimson_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y3JpbXNvbl9idXR0b24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5jcmltc29uX2J1dHRvbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 718, + "key": "minecraft:warped_button", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d2FycGVkX2J1dHRvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfYnV0dG9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 719, + "key": "minecraft:stone_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c3RvbmVfcHJlc3N1cmVfcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5zdG9uZV9wcmVzc3VyZV9wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 720, + "key": "minecraft:polished_blackstone_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByxtaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV9wcmVzc3VyZV9wbGF0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMmJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX3ByZXNzdXJlX3BsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 721, + "key": "minecraft:light_weighted_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BydtaW5lY3JhZnQ6bGlnaHRfd2VpZ2h0ZWRfcHJlc3N1cmVfcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALWJsb2NrLm1pbmVjcmFmdC5saWdodF93ZWlnaHRlZF9wcmVzc3VyZV9wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 722, + "key": "minecraft:heavy_weighted_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BydtaW5lY3JhZnQ6aGVhdnlfd2VpZ2h0ZWRfcHJlc3N1cmVfcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALWJsb2NrLm1pbmVjcmFmdC5oZWF2eV93ZWlnaHRlZF9wcmVzc3VyZV9wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 723, + "key": "minecraft:oak_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6b2FrX3ByZXNzdXJlX3BsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5vYWtfcHJlc3N1cmVfcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 724, + "key": "minecraft:spruce_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6c3BydWNlX3ByZXNzdXJlX3BsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfcHJlc3N1cmVfcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 725, + "key": "minecraft:birch_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6YmlyY2hfcHJlc3N1cmVfcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5iaXJjaF9wcmVzc3VyZV9wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 726, + "key": "minecraft:jungle_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6anVuZ2xlX3ByZXNzdXJlX3BsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfcHJlc3N1cmVfcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 727, + "key": "minecraft:acacia_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6YWNhY2lhX3ByZXNzdXJlX3BsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfcHJlc3N1cmVfcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 728, + "key": "minecraft:cherry_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Y2hlcnJ5X3ByZXNzdXJlX3BsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5jaGVycnlfcHJlc3N1cmVfcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 729, + "key": "minecraft:dark_oak_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6ZGFya19vYWtfcHJlc3N1cmVfcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19wcmVzc3VyZV9wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 730, + "key": "minecraft:pale_oak_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6cGFsZV9vYWtfcHJlc3N1cmVfcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19wcmVzc3VyZV9wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 731, + "key": "minecraft:mangrove_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6bWFuZ3JvdmVfcHJlc3N1cmVfcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9wcmVzc3VyZV9wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 732, + "key": "minecraft:bamboo_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6YmFtYm9vX3ByZXNzdXJlX3BsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5iYW1ib29fcHJlc3N1cmVfcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 733, + "key": "minecraft:crimson_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y3JpbXNvbl9wcmVzc3VyZV9wbGF0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC5jcmltc29uX3ByZXNzdXJlX3BsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 734, + "key": "minecraft:warped_pressure_plate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2FycGVkX3ByZXNzdXJlX3BsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfcHJlc3N1cmVfcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 735, + "key": "minecraft:iron_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6aXJvbl9kb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5pcm9uX2Rvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 736, + "key": "minecraft:oak_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6b2FrX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5vYWtfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 737, + "key": "minecraft:spruce_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c3BydWNlX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 738, + "key": "minecraft:birch_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YmlyY2hfZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5iaXJjaF9kb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 739, + "key": "minecraft:jungle_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6anVuZ2xlX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5qdW5nbGVfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 740, + "key": "minecraft:acacia_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YWNhY2lhX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5hY2FjaWFfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 741, + "key": "minecraft:cherry_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y2hlcnJ5X2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jaGVycnlfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 742, + "key": "minecraft:dark_oak_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGFya19vYWtfZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19kb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 743, + "key": "minecraft:pale_oak_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cGFsZV9vYWtfZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19kb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 744, + "key": "minecraft:mangrove_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bWFuZ3JvdmVfZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9kb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 745, + "key": "minecraft:bamboo_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YmFtYm9vX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5iYW1ib29fZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 746, + "key": "minecraft:crimson_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y3JpbXNvbl9kb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jcmltc29uX2Rvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 747, + "key": "minecraft:warped_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6d2FycGVkX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC53YXJwZWRfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 748, + "key": "minecraft:copper_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y29wcGVyX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jb3BwZXJfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 749, + "key": "minecraft:exposed_copper_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZXhwb3NlZF9jb3BwZXJfZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2NvcHBlcl9kb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 750, + "key": "minecraft:weathered_copper_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2VhdGhlcmVkX2NvcHBlcl9kb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY29wcGVyX2Rvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 751, + "key": "minecraft:oxidized_copper_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6b3hpZGl6ZWRfY29wcGVyX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jb3BwZXJfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 752, + "key": "minecraft:waxed_copper_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6d2F4ZWRfY29wcGVyX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC53YXhlZF9jb3BwZXJfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 753, + "key": "minecraft:waxed_exposed_copper_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jb3BwZXJfZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2NvcHBlcl9kb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 754, + "key": "minecraft:waxed_weathered_copper_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByVtaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2NvcHBlcl9kb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAK2Jsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY29wcGVyX2Rvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 755, + "key": "minecraft:waxed_oxidized_copper_door", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY29wcGVyX2Rvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jb3BwZXJfZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 756, + "key": "minecraft:iron_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6aXJvbl90cmFwZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5pcm9uX3RyYXBkb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 757, + "key": "minecraft:oak_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6b2FrX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5vYWtfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 758, + "key": "minecraft:spruce_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6c3BydWNlX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 759, + "key": "minecraft:birch_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YmlyY2hfdHJhcGRvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5iaXJjaF90cmFwZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 760, + "key": "minecraft:jungle_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6anVuZ2xlX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5qdW5nbGVfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 761, + "key": "minecraft:acacia_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YWNhY2lhX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5hY2FjaWFfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 762, + "key": "minecraft:cherry_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y2hlcnJ5X3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5jaGVycnlfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 763, + "key": "minecraft:dark_oak_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6ZGFya19vYWtfdHJhcGRvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha190cmFwZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 764, + "key": "minecraft:pale_oak_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cGFsZV9vYWtfdHJhcGRvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha190cmFwZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 765, + "key": "minecraft:mangrove_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bWFuZ3JvdmVfdHJhcGRvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV90cmFwZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 766, + "key": "minecraft:bamboo_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YmFtYm9vX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5iYW1ib29fdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 767, + "key": "minecraft:crimson_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Y3JpbXNvbl90cmFwZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5jcmltc29uX3RyYXBkb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 768, + "key": "minecraft:warped_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6d2FycGVkX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC53YXJwZWRfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 769, + "key": "minecraft:copper_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y29wcGVyX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5jb3BwZXJfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 770, + "key": "minecraft:exposed_copper_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6ZXhwb3NlZF9jb3BwZXJfdHJhcGRvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2Jsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2NvcHBlcl90cmFwZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 771, + "key": "minecraft:weathered_copper_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6d2VhdGhlcmVkX2NvcHBlcl90cmFwZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY29wcGVyX3RyYXBkb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 772, + "key": "minecraft:oxidized_copper_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6b3hpZGl6ZWRfY29wcGVyX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jb3BwZXJfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 773, + "key": "minecraft:waxed_copper_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2F4ZWRfY29wcGVyX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53YXhlZF9jb3BwZXJfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 774, + "key": "minecraft:waxed_exposed_copper_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BydtaW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jb3BwZXJfdHJhcGRvb3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALWJsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2NvcHBlcl90cmFwZG9vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 775, + "key": "minecraft:waxed_weathered_copper_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByltaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2NvcHBlcl90cmFwZG9vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAL2Jsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY29wcGVyX3RyYXBkb29yAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 776, + "key": "minecraft:waxed_oxidized_copper_trapdoor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByhtaW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY29wcGVyX3RyYXBkb29y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALmJsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jb3BwZXJfdHJhcGRvb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 777, + "key": "minecraft:oak_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6b2FrX2ZlbmNlX2dhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5vYWtfZmVuY2VfZ2F0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 778, + "key": "minecraft:spruce_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6c3BydWNlX2ZlbmNlX2dhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfZmVuY2VfZ2F0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 779, + "key": "minecraft:birch_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6YmlyY2hfZmVuY2VfZ2F0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5iaXJjaF9mZW5jZV9nYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 780, + "key": "minecraft:jungle_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6anVuZ2xlX2ZlbmNlX2dhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5qdW5nbGVfZmVuY2VfZ2F0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 781, + "key": "minecraft:acacia_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YWNhY2lhX2ZlbmNlX2dhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5hY2FjaWFfZmVuY2VfZ2F0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 782, + "key": "minecraft:cherry_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y2hlcnJ5X2ZlbmNlX2dhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5jaGVycnlfZmVuY2VfZ2F0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 783, + "key": "minecraft:dark_oak_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGFya19vYWtfZmVuY2VfZ2F0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19mZW5jZV9nYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 784, + "key": "minecraft:pale_oak_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6cGFsZV9vYWtfZmVuY2VfZ2F0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19mZW5jZV9nYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 785, + "key": "minecraft:mangrove_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bWFuZ3JvdmVfZmVuY2VfZ2F0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9mZW5jZV9nYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 786, + "key": "minecraft:bamboo_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YmFtYm9vX2ZlbmNlX2dhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5iYW1ib29fZmVuY2VfZ2F0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 787, + "key": "minecraft:crimson_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y3JpbXNvbl9mZW5jZV9nYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5jcmltc29uX2ZlbmNlX2dhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 788, + "key": "minecraft:warped_fence_gate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6d2FycGVkX2ZlbmNlX2dhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC53YXJwZWRfZmVuY2VfZ2F0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 789, + "key": "minecraft:powered_rail", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cG93ZXJlZF9yYWls", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5wb3dlcmVkX3JhaWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 790, + "key": "minecraft:detector_rail", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGV0ZWN0b3JfcmFpbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5kZXRlY3Rvcl9yYWlsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 791, + "key": "minecraft:rail", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6cmFpbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5yYWlsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 792, + "key": "minecraft:activator_rail", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YWN0aXZhdG9yX3JhaWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5hY3RpdmF0b3JfcmFpbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 793, + "key": "minecraft:saddle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6c2FkZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnNhZGRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 794, + "key": "minecraft:minecart", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6bWluZWNhcnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0Lm1pbmVjYXJ0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 795, + "key": "minecraft:chest_minecart", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y2hlc3RfbWluZWNhcnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmNoZXN0X21pbmVjYXJ0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 796, + "key": "minecraft:furnace_minecart", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZnVybmFjZV9taW5lY2FydA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmZ1cm5hY2VfbWluZWNhcnQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 797, + "key": "minecraft:tnt_minecart", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6dG50X21pbmVjYXJ0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LnRudF9taW5lY2FydAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 798, + "key": "minecraft:hopper_minecart", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6aG9wcGVyX21pbmVjYXJ0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmhvcHBlcl9taW5lY2FydAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 799, + "key": "minecraft:carrot_on_a_stick", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage": "AwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y2Fycm90X29uX2Ffc3RpY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmNhcnJvdF9vbl9hX3N0aWNrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Ahk=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 800, + "key": "minecraft:warped_fungus_on_a_stick", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage": "AwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6d2FycGVkX2Z1bmd1c19vbl9hX3N0aWNr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2l0ZW0ubWluZWNyYWZ0LndhcnBlZF9mdW5ndXNfb25fYV9zdGljawA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AmQ=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 801, + "key": "minecraft:phantom_membrane", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cGhhbnRvbV9tZW1icmFuZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnBoYW50b21fbWVtYnJhbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 802, + "key": "minecraft:elytra", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage": "AwA=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HANGARBtaW5lY3JhZnQ6ZWx5dHJhAAABAQA=", + "minecraft:glider": "Hg==", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6ZWx5dHJh", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LmVseXRyYQA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ArAD", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQKhBg==" + } + }, + { + "id": 803, + "key": "minecraft:oak_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6b2FrX2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0Lm9ha19ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 804, + "key": "minecraft:oak_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6b2FrX2NoZXN0X2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lm9ha19jaGVzdF9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 805, + "key": "minecraft:spruce_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c3BydWNlX2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnNwcnVjZV9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 806, + "key": "minecraft:spruce_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6c3BydWNlX2NoZXN0X2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnNwcnVjZV9jaGVzdF9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 807, + "key": "minecraft:birch_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YmlyY2hfYm9hdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmJpcmNoX2JvYXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 808, + "key": "minecraft:birch_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6YmlyY2hfY2hlc3RfYm9hdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmJpcmNoX2NoZXN0X2JvYXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 809, + "key": "minecraft:jungle_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6anVuZ2xlX2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lmp1bmdsZV9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 810, + "key": "minecraft:jungle_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6anVuZ2xlX2NoZXN0X2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0Lmp1bmdsZV9jaGVzdF9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 811, + "key": "minecraft:acacia_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YWNhY2lhX2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmFjYWNpYV9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 812, + "key": "minecraft:acacia_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YWNhY2lhX2NoZXN0X2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmFjYWNpYV9jaGVzdF9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 813, + "key": "minecraft:cherry_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y2hlcnJ5X2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmNoZXJyeV9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 814, + "key": "minecraft:cherry_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y2hlcnJ5X2NoZXN0X2JvYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmNoZXJyeV9jaGVzdF9ib2F0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 815, + "key": "minecraft:dark_oak_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGFya19vYWtfYm9hdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmRhcmtfb2FrX2JvYXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 816, + "key": "minecraft:dark_oak_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGFya19vYWtfY2hlc3RfYm9hdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LmRhcmtfb2FrX2NoZXN0X2JvYXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 817, + "key": "minecraft:pale_oak_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cGFsZV9vYWtfYm9hdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnBhbGVfb2FrX2JvYXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 818, + "key": "minecraft:pale_oak_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6cGFsZV9vYWtfY2hlc3RfYm9hdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LnBhbGVfb2FrX2NoZXN0X2JvYXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 819, + "key": "minecraft:mangrove_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bWFuZ3JvdmVfYm9hdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lm1hbmdyb3ZlX2JvYXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 820, + "key": "minecraft:mangrove_chest_boat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bWFuZ3JvdmVfY2hlc3RfYm9hdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0Lm1hbmdyb3ZlX2NoZXN0X2JvYXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 821, + "key": "minecraft:bamboo_raft", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YmFtYm9vX3JhZnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmJhbWJvb19yYWZ0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 822, + "key": "minecraft:bamboo_chest_raft", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YmFtYm9vX2NoZXN0X3JhZnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmJhbWJvb19jaGVzdF9yYWZ0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 823, + "key": "minecraft:structure_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6c3RydWN0dXJlX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5zdHJ1Y3R1cmVfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 824, + "key": "minecraft:jigsaw", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6amlnc2F3", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5qaWdzYXcA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 825, + "key": "minecraft:turtle_helmet", + "components": { + "minecraft:attribute_modifiers": "DQIAFm1pbmVjcmFmdDphcm1vci5oZWxtZXRAAAAAAAAAAAAHARZtaW5lY3JhZnQ6YXJtb3IuaGVsbWV0AAAAAAAAAAAABwE=", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARMARZtaW5lY3JhZnQ6dHVydGxlX3NjdXRlAAABAQE=", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6dHVydGxlX2hlbG1ldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnR1cnRsZV9oZWxtZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ApMC", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfdHVydGxlX2hlbG1ldA==" + } + }, + { + "id": 826, + "key": "minecraft:turtle_scute", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6dHVydGxlX3NjdXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LnR1cnRsZV9zY3V0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 827, + "key": "minecraft:armadillo_scute", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YXJtYWRpbGxvX3NjdXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmFybWFkaWxsb19zY3V0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 828, + "key": "minecraft:wolf_armor", + "components": { + "minecraft:attribute_modifiers": "DQIAFG1pbmVjcmFmdDphcm1vci5ib2R5QCYAAAAAAAAACQEUbWluZWNyYWZ0OmFybW9yLmJvZHkAAAAAAAAAAAAJAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAZNARltaW5lY3JhZnQ6YXJtYWRpbGxvX3NjdXRlAAECjQEBAQE=", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6d29sZl9hcm1vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LndvbGZfYXJtb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AkA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfd29sZl9hcm1vcg==" + } + }, + { + "id": 829, + "key": "minecraft:flint_and_steel", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage": "AwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZmxpbnRfYW5kX3N0ZWVs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmZsaW50X2FuZF9zdGVlbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AkA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 830, + "key": "minecraft:bowl", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6Ym93bA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2l0ZW0ubWluZWNyYWZ0LmJvd2wA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 831, + "key": "minecraft:apple", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQRAGZmaAA==", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6YXBwbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LmFwcGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 832, + "key": "minecraft:bow", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw1taW5lY3JhZnQ6Ym93", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAEml0ZW0ubWluZWNyYWZ0LmJvdwA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AoAD", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 833, + "key": "minecraft:arrow", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6YXJyb3c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LmFycm93AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 834, + "key": "minecraft:coal", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6Y29hbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2l0ZW0ubWluZWNyYWZ0LmNvYWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 835, + "key": "minecraft:charcoal", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Y2hhcmNvYWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LmNoYXJjb2FsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 836, + "key": "minecraft:diamond", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6ZGlhbW9uZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0LmRpYW1vbmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 837, + "key": "minecraft:emerald", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6ZW1lcmFsZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0LmVtZXJhbGQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 838, + "key": "minecraft:lapis_lazuli", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6bGFwaXNfbGF6dWxp", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmxhcGlzX2xhenVsaQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 839, + "key": "minecraft:quartz", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6cXVhcnR6", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnF1YXJ0egA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 840, + "key": "minecraft:amethyst_shard", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YW1ldGh5c3Rfc2hhcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmFtZXRoeXN0X3NoYXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 841, + "key": "minecraft:raw_iron", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cmF3X2lyb24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LnJhd19pcm9uAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 842, + "key": "minecraft:iron_ingot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6aXJvbl9pbmdvdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0Lmlyb25faW5nb3QA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 843, + "key": "minecraft:raw_copper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cmF3X2NvcHBlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LnJhd19jb3BwZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 844, + "key": "minecraft:copper_ingot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y29wcGVyX2luZ290", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmNvcHBlcl9pbmdvdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 845, + "key": "minecraft:raw_gold", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cmF3X2dvbGQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LnJhd19nb2xkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 846, + "key": "minecraft:gold_ingot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Z29sZF9pbmdvdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmdvbGRfaW5nb3QA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 847, + "key": "minecraft:netherite_ingot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bmV0aGVyaXRlX2luZ290", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9pbmdvdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 848, + "key": "minecraft:netherite_scrap", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bmV0aGVyaXRlX3NjcmFw", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9zY3JhcAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 849, + "key": "minecraft:wooden_sword", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VACAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTAAzMzQAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d29vZGVuX3N3b3Jk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0Lndvb2Rlbl9zd29yZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Ajs=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0Ondvb2Rlbl90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgICgQEBQXAAAAEBABltaW5lY3JhZnQ6c3dvcmRfZWZmaWNpZW50AT/AAAAAP4AAAAI=" + } + }, + { + "id": 850, + "key": "minecraft:wooden_shovel", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2U/+AAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d29vZGVuX3Nob3ZlbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lndvb2Rlbl9zaG92ZWwA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Ajs=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0Ondvb2Rlbl90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgIAI21pbmVjcmFmdDppbmNvcnJlY3RfZm9yX3dvb2Rlbl90b29sAAEAABltaW5lY3JhZnQ6bWluZWFibGUvc2hvdmVsAUAAAAABAT+AAAAB" + } + }, + { + "id": 851, + "key": "minecraft:wooden_pickaxe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2U/8AAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTABmZmYAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6d29vZGVuX3BpY2theGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lndvb2Rlbl9waWNrYXhlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Ajs=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0Ondvb2Rlbl90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgIAI21pbmVjcmFmdDppbmNvcnJlY3RfZm9yX3dvb2Rlbl90b29sAAEAABptaW5lY3JhZnQ6bWluZWFibGUvcGlja2F4ZQFAAAAAAQE/gAAAAQ==" + } + }, + { + "id": 852, + "key": "minecraft:wooden_axe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAGAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACZmZoAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6d29vZGVuX2F4ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0Lndvb2Rlbl9heGUA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Ajs=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0Ondvb2Rlbl90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgIAI21pbmVjcmFmdDppbmNvcnJlY3RfZm9yX3dvb2Rlbl90b29sAAEAABZtaW5lY3JhZnQ6bWluZWFibGUvYXhlAUAAAAABAT+AAAAB" + } + }, + { + "id": 853, + "key": "minecraft:wooden_hoe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2UAAAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6d29vZGVuX2hvZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0Lndvb2Rlbl9ob2UA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Ajs=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0Ondvb2Rlbl90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgIAI21pbmVjcmFmdDppbmNvcnJlY3RfZm9yX3dvb2Rlbl90b29sAAEAABZtaW5lY3JhZnQ6bWluZWFibGUvaG9lAUAAAAABAT+AAAAB" + } + }, + { + "id": 854, + "key": "minecraft:stone_sword", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAEAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTAAzMzQAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwU=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c3RvbmVfc3dvcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnN0b25lX3N3b3JkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AoMB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAebWluZWNyYWZ0OnN0b25lX3Rvb2xfbWF0ZXJpYWxz", + "minecraft:tool": "GgICgQEBQXAAAAEBABltaW5lY3JhZnQ6c3dvcmRfZWZmaWNpZW50AT/AAAAAP4AAAAI=" + } + }, + { + "id": 855, + "key": "minecraft:stone_shovel", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VABAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwU=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6c3RvbmVfc2hvdmVs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LnN0b25lX3Nob3ZlbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AoMB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAebWluZWNyYWZ0OnN0b25lX3Rvb2xfbWF0ZXJpYWxz", + "minecraft:tool": "GgIAIm1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX3N0b25lX3Rvb2wAAQAAGW1pbmVjcmFmdDptaW5lYWJsZS9zaG92ZWwBQIAAAAEBP4AAAAE=" + } + }, + { + "id": 856, + "key": "minecraft:stone_pickaxe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAAAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTABmZmYAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwU=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3RvbmVfcGlja2F4ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnN0b25lX3BpY2theGUA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AoMB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAebWluZWNyYWZ0OnN0b25lX3Rvb2xfbWF0ZXJpYWxz", + "minecraft:tool": "GgIAIm1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX3N0b25lX3Rvb2wAAQAAGm1pbmVjcmFmdDptaW5lYWJsZS9waWNrYXhlAUCAAAABAT+AAAAB" + } + }, + { + "id": 857, + "key": "minecraft:stone_axe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAIAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACZmZoAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwU=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6c3RvbmVfYXhl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LnN0b25lX2F4ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AoMB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAebWluZWNyYWZ0OnN0b25lX3Rvb2xfbWF0ZXJpYWxz", + "minecraft:tool": "GgIAIm1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX3N0b25lX3Rvb2wAAQAAFm1pbmVjcmFmdDptaW5lYWJsZS9heGUBQIAAAAEBP4AAAAE=" + } + }, + { + "id": 858, + "key": "minecraft:stone_hoe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2UAAAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTAAAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwU=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6c3RvbmVfaG9l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LnN0b25lX2hvZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AoMB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAebWluZWNyYWZ0OnN0b25lX3Rvb2xfbWF0ZXJpYWxz", + "minecraft:tool": "GgIAIm1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX3N0b25lX3Rvb2wAAQAAFm1pbmVjcmFmdDptaW5lYWJsZS9ob2UBQIAAAAEBP4AAAAE=" + } + }, + { + "id": 859, + "key": "minecraft:golden_sword", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VACAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTAAzMzQAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GxY=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z29sZGVuX3N3b3Jk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmdvbGRlbl9zd29yZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AiA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OmdvbGRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgICgQEBQXAAAAEBABltaW5lY3JhZnQ6c3dvcmRfZWZmaWNpZW50AT/AAAAAP4AAAAI=" + } + }, + { + "id": 860, + "key": "minecraft:golden_shovel", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2U/+AAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GxY=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Z29sZGVuX3Nob3ZlbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmdvbGRlbl9zaG92ZWwA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AiA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OmdvbGRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAIW1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2dvbGRfdG9vbAABAAAZbWluZWNyYWZ0Om1pbmVhYmxlL3Nob3ZlbAFBQAAAAQE/gAAAAQ==" + } + }, + { + "id": 861, + "key": "minecraft:golden_pickaxe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2U/8AAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTABmZmYAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GxY=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Z29sZGVuX3BpY2theGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmdvbGRlbl9waWNrYXhlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AiA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OmdvbGRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAIW1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2dvbGRfdG9vbAABAAAabWluZWNyYWZ0Om1pbmVhYmxlL3BpY2theGUBQUAAAAEBP4AAAAE=" + } + }, + { + "id": 862, + "key": "minecraft:golden_axe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAGAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GxY=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Z29sZGVuX2F4ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmdvbGRlbl9heGUA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AiA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OmdvbGRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAIW1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2dvbGRfdG9vbAABAAAWbWluZWNyYWZ0Om1pbmVhYmxlL2F4ZQFBQAAAAQE/gAAAAQ==" + } + }, + { + "id": 863, + "key": "minecraft:golden_hoe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2UAAAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GxY=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Z29sZGVuX2hvZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmdvbGRlbl9ob2UA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AiA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OmdvbGRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAIW1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2dvbGRfdG9vbAABAAAWbWluZWNyYWZ0Om1pbmVhYmxlL2hvZQFBQAAAAQE/gAAAAQ==" + } + }, + { + "id": 864, + "key": "minecraft:iron_sword", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAFAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTAAzMzQAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw4=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6aXJvbl9zd29yZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0Lmlyb25fc3dvcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvoB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0Omlyb25fdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgICgQEBQXAAAAEBABltaW5lY3JhZnQ6c3dvcmRfZWZmaWNpZW50AT/AAAAAP4AAAAI=" + } + }, + { + "id": 865, + "key": "minecraft:iron_shovel", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VADAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw4=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6aXJvbl9zaG92ZWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lmlyb25fc2hvdmVsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvoB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0Omlyb25fdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAIW1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2lyb25fdG9vbAABAAAZbWluZWNyYWZ0Om1pbmVhYmxlL3Nob3ZlbAFAwAAAAQE/gAAAAQ==" + } + }, + { + "id": 866, + "key": "minecraft:iron_pickaxe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VACAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTABmZmYAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw4=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6aXJvbl9waWNrYXhl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0Lmlyb25fcGlja2F4ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvoB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0Omlyb25fdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAIW1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2lyb25fdG9vbAABAAAabWluZWNyYWZ0Om1pbmVhYmxlL3BpY2theGUBQMAAAAEBP4AAAAE=" + } + }, + { + "id": 867, + "key": "minecraft:iron_axe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAIAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACMzMwAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw4=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6aXJvbl9heGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0Lmlyb25fYXhlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvoB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0Omlyb25fdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAIW1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2lyb25fdG9vbAABAAAWbWluZWNyYWZ0Om1pbmVhYmxlL2F4ZQFAwAAAAQE/gAAAAQ==" + } + }, + { + "id": 868, + "key": "minecraft:iron_hoe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2UAAAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWS/8AAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw4=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6aXJvbl9ob2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0Lmlyb25faG9lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvoB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0Omlyb25fdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAIW1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2lyb25fdG9vbAABAAAWbWluZWNyYWZ0Om1pbmVhYmxlL2hvZQFAwAAAAQE/gAAAAQ==" + } + }, + { + "id": 869, + "key": "minecraft:diamond_sword", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAGAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTAAzMzQAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGlhbW9uZF9zd29yZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfc3dvcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ApkM", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAgbWluZWNyYWZ0OmRpYW1vbmRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgICgQEBQXAAAAEBABltaW5lY3JhZnQ6c3dvcmRfZWZmaWNpZW50AT/AAAAAP4AAAAI=" + } + }, + { + "id": 870, + "key": "minecraft:diamond_shovel", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAEgAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6ZGlhbW9uZF9zaG92ZWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfc2hvdmVsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ApkM", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAgbWluZWNyYWZ0OmRpYW1vbmRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAJG1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2RpYW1vbmRfdG9vbAABAAAZbWluZWNyYWZ0Om1pbmVhYmxlL3Nob3ZlbAFBAAAAAQE/gAAAAQ==" + } + }, + { + "id": 871, + "key": "minecraft:diamond_pickaxe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAEAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTABmZmYAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGlhbW9uZF9waWNrYXhl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfcGlja2F4ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ApkM", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAgbWluZWNyYWZ0OmRpYW1vbmRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAJG1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2RpYW1vbmRfdG9vbAABAAAabWluZWNyYWZ0Om1pbmVhYmxlL3BpY2theGUBQQAAAAEBP4AAAAE=" + } + }, + { + "id": 872, + "key": "minecraft:diamond_axe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAIAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZGlhbW9uZF9heGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfYXhlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ApkM", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAgbWluZWNyYWZ0OmRpYW1vbmRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAJG1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2RpYW1vbmRfdG9vbAABAAAWbWluZWNyYWZ0Om1pbmVhYmxlL2F4ZQFBAAAAAQE/gAAAAQ==" + } + }, + { + "id": 873, + "key": "minecraft:diamond_hoe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2UAAAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWQAAAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZGlhbW9uZF9ob2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfaG9lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ApkM", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAgbWluZWNyYWZ0OmRpYW1vbmRfdG9vbF9tYXRlcmlhbHM=", + "minecraft:tool": "GgIAJG1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX2RpYW1vbmRfdG9vbAABAAAWbWluZWNyYWZ0Om1pbmVhYmxlL2hvZQFBAAAAAQE/gAAAAQ==" + } + }, + { + "id": 874, + "key": "minecraft:netherite_sword", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAHAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTAAzMzQAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bmV0aGVyaXRlX3N3b3Jk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9zd29yZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Au8P", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAibWluZWNyYWZ0Om5ldGhlcml0ZV90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgICgQEBQXAAAAEBABltaW5lY3JhZnQ6c3dvcmRfZWZmaWNpZW50AT/AAAAAP4AAAAI=" + } + }, + { + "id": 875, + "key": "minecraft:netherite_shovel", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAFgAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bmV0aGVyaXRlX3Nob3ZlbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9zaG92ZWwA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Au8P", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAibWluZWNyYWZ0Om5ldGhlcml0ZV90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgIAJm1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX25ldGhlcml0ZV90b29sAAEAABltaW5lY3JhZnQ6bWluZWFibGUvc2hvdmVsAUEQAAABAT+AAAAB" + } + }, + { + "id": 876, + "key": "minecraft:netherite_pickaxe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAFAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTABmZmYAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bmV0aGVyaXRlX3BpY2theGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9waWNrYXhlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Au8P", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAibWluZWNyYWZ0Om5ldGhlcml0ZV90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgIAJm1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX25ldGhlcml0ZV90b29sAAEAABptaW5lY3JhZnQ6bWluZWFibGUvcGlja2F4ZQFBEAAAAQE/gAAAAQ==" + } + }, + { + "id": 877, + "key": "minecraft:netherite_axe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAIgAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bmV0aGVyaXRlX2F4ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9heGUA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Au8P", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAibWluZWNyYWZ0Om5ldGhlcml0ZV90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgIAJm1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX25ldGhlcml0ZV90b29sAAEAABZtaW5lY3JhZnQ6bWluZWFibGUvYXhlAUEQAAABAT+AAAAB" + } + }, + { + "id": 878, + "key": "minecraft:netherite_hoe", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2UAAAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWQAAAAAAAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bmV0aGVyaXRlX2hvZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9ob2UA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Au8P", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAibWluZWNyYWZ0Om5ldGhlcml0ZV90b29sX21hdGVyaWFscw==", + "minecraft:tool": "GgIAJm1pbmVjcmFmdDppbmNvcnJlY3RfZm9yX25ldGhlcml0ZV90b29sAAEAABZtaW5lY3JhZnQ6bWluZWFibGUvaG9lAUEQAAABAT+AAAAB" + } + }, + { + "id": 879, + "key": "minecraft:stick", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6c3RpY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LnN0aWNrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 880, + "key": "minecraft:mushroom_stew", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQZA5mZnAA==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bXVzaHJvb21fc3Rldw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lm11c2hyb29tX3N0ZXcA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_remainder": "FwG+BgAA" + } + }, + { + "id": 881, + "key": "minecraft:string", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6c3RyaW5n", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnN0cmluZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 882, + "key": "minecraft:feather", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6ZmVhdGhlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0LmZlYXRoZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 883, + "key": "minecraft:gunpowder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Z3VucG93ZGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0Lmd1bnBvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 884, + "key": "minecraft:wheat_seeds", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6d2hlYXRfc2VlZHM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LndoZWF0X3NlZWRzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 885, + "key": "minecraft:wheat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6d2hlYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LndoZWF0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 886, + "key": "minecraft:bread", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQVAwAAAAA==", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6YnJlYWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LmJyZWFkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 887, + "key": "minecraft:leather_helmet", + "components": { + "minecraft:attribute_modifiers": "DQIAFm1pbmVjcmFmdDphcm1vci5oZWxtZXQ/8AAAAAAAAAAHARZtaW5lY3JhZnQ6YXJtb3IuaGVsbWV0AAAAAAAAAAAABwE=", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARKARFtaW5lY3JhZnQ6bGVhdGhlcgAAAQEB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bGVhdGhlcl9oZWxtZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmxlYXRoZXJfaGVsbWV0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Ajc=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfbGVhdGhlcl9hcm1vcg==" + } + }, + { + "id": 888, + "key": "minecraft:leather_chestplate", + "components": { + "minecraft:attribute_modifiers": "DQIAGm1pbmVjcmFmdDphcm1vci5jaGVzdHBsYXRlQAgAAAAAAAAABgEabWluZWNyYWZ0OmFybW9yLmNoZXN0cGxhdGUAAAAAAAAAAAAGAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HANKARFtaW5lY3JhZnQ6bGVhdGhlcgAAAQEB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bGVhdGhlcl9jaGVzdHBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LmxlYXRoZXJfY2hlc3RwbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AlA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfbGVhdGhlcl9hcm1vcg==" + } + }, + { + "id": 889, + "key": "minecraft:leather_leggings", + "components": { + "minecraft:attribute_modifiers": "DQIAGG1pbmVjcmFmdDphcm1vci5sZWdnaW5nc0AAAAAAAAAAAAUBGG1pbmVjcmFmdDphcm1vci5sZWdnaW5ncwAAAAAAAAAAAAUB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAJKARFtaW5lY3JhZnQ6bGVhdGhlcgAAAQEB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bGVhdGhlcl9sZWdnaW5ncw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmxlYXRoZXJfbGVnZ2luZ3MA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Aks=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfbGVhdGhlcl9hcm1vcg==" + } + }, + { + "id": 890, + "key": "minecraft:leather_boots", + "components": { + "minecraft:attribute_modifiers": "DQIAFW1pbmVjcmFmdDphcm1vci5ib290cz/wAAAAAAAAAAQBFW1pbmVjcmFmdDphcm1vci5ib290cwAAAAAAAAAAAAQB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAFKARFtaW5lY3JhZnQ6bGVhdGhlcgAAAQEB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bGVhdGhlcl9ib290cw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmxlYXRoZXJfYm9vdHMA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AkE=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfbGVhdGhlcl9hcm1vcg==" + } + }, + { + "id": 891, + "key": "minecraft:chainmail_helmet", + "components": { + "minecraft:attribute_modifiers": "DQIAFm1pbmVjcmFmdDphcm1vci5oZWxtZXRAAAAAAAAAAAAHARZtaW5lY3JhZnQ6YXJtb3IuaGVsbWV0AAAAAAAAAAAABwE=", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gww=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAREARNtaW5lY3JhZnQ6Y2hhaW5tYWlsAAABAQE=", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Y2hhaW5tYWlsX2hlbG1ldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmNoYWlubWFpbF9oZWxtZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AqUB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OnJlcGFpcnNfY2hhaW5fYXJtb3I=" + } + }, + { + "id": 892, + "key": "minecraft:chainmail_chestplate", + "components": { + "minecraft:attribute_modifiers": "DQIAGm1pbmVjcmFmdDphcm1vci5jaGVzdHBsYXRlQBQAAAAAAAAABgEabWluZWNyYWZ0OmFybW9yLmNoZXN0cGxhdGUAAAAAAAAAAAAGAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gww=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HANEARNtaW5lY3JhZnQ6Y2hhaW5tYWlsAAABAQE=", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Y2hhaW5tYWlsX2NoZXN0cGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LmNoYWlubWFpbF9jaGVzdHBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvAB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OnJlcGFpcnNfY2hhaW5fYXJtb3I=" + } + }, + { + "id": 893, + "key": "minecraft:chainmail_leggings", + "components": { + "minecraft:attribute_modifiers": "DQIAGG1pbmVjcmFmdDphcm1vci5sZWdnaW5nc0AQAAAAAAAAAAUBGG1pbmVjcmFmdDphcm1vci5sZWdnaW5ncwAAAAAAAAAAAAUB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gww=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAJEARNtaW5lY3JhZnQ6Y2hhaW5tYWlsAAABAQE=", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y2hhaW5tYWlsX2xlZ2dpbmdz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LmNoYWlubWFpbF9sZWdnaW5ncwA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AuEB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OnJlcGFpcnNfY2hhaW5fYXJtb3I=" + } + }, + { + "id": 894, + "key": "minecraft:chainmail_boots", + "components": { + "minecraft:attribute_modifiers": "DQIAFW1pbmVjcmFmdDphcm1vci5ib290cz/wAAAAAAAAAAQBFW1pbmVjcmFmdDphcm1vci5ib290cwAAAAAAAAAAAAQB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gww=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAFEARNtaW5lY3JhZnQ6Y2hhaW5tYWlsAAABAQE=", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y2hhaW5tYWlsX2Jvb3Rz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmNoYWlubWFpbF9ib290cwA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AsMB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAdbWluZWNyYWZ0OnJlcGFpcnNfY2hhaW5fYXJtb3I=" + } + }, + { + "id": 895, + "key": "minecraft:iron_helmet", + "components": { + "minecraft:attribute_modifiers": "DQIAFm1pbmVjcmFmdDphcm1vci5oZWxtZXRAAAAAAAAAAAAHARZtaW5lY3JhZnQ6YXJtb3IuaGVsbWV0AAAAAAAAAAAABwE=", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARJAQ5taW5lY3JhZnQ6aXJvbgAAAQEB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6aXJvbl9oZWxtZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lmlyb25faGVsbWV0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AqUB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfaXJvbl9hcm1vcg==" + } + }, + { + "id": 896, + "key": "minecraft:iron_chestplate", + "components": { + "minecraft:attribute_modifiers": "DQIAGm1pbmVjcmFmdDphcm1vci5jaGVzdHBsYXRlQBgAAAAAAAAABgEabWluZWNyYWZ0OmFybW9yLmNoZXN0cGxhdGUAAAAAAAAAAAAGAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HANJAQ5taW5lY3JhZnQ6aXJvbgAAAQEB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6aXJvbl9jaGVzdHBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lmlyb25fY2hlc3RwbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvAB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfaXJvbl9hcm1vcg==" + } + }, + { + "id": 897, + "key": "minecraft:iron_leggings", + "components": { + "minecraft:attribute_modifiers": "DQIAGG1pbmVjcmFmdDphcm1vci5sZWdnaW5nc0AUAAAAAAAAAAUBGG1pbmVjcmFmdDphcm1vci5sZWdnaW5ncwAAAAAAAAAAAAUB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAJJAQ5taW5lY3JhZnQ6aXJvbgAAAQEB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6aXJvbl9sZWdnaW5ncw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lmlyb25fbGVnZ2luZ3MA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AuEB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfaXJvbl9hcm1vcg==" + } + }, + { + "id": 898, + "key": "minecraft:iron_boots", + "components": { + "minecraft:attribute_modifiers": "DQIAFW1pbmVjcmFmdDphcm1vci5ib290c0AAAAAAAAAAAAQBFW1pbmVjcmFmdDphcm1vci5ib290cwAAAAAAAAAAAAQB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAFJAQ5taW5lY3JhZnQ6aXJvbgAAAQEB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6aXJvbl9ib290cw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0Lmlyb25fYm9vdHMA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AsMB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfaXJvbl9hcm1vcg==" + } + }, + { + "id": 899, + "key": "minecraft:diamond_helmet", + "components": { + "minecraft:attribute_modifiers": "DQIAFm1pbmVjcmFmdDphcm1vci5oZWxtZXRACAAAAAAAAAAHARZtaW5lY3JhZnQ6YXJtb3IuaGVsbWV0QAAAAAAAAAAABwE=", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARFARFtaW5lY3JhZnQ6ZGlhbW9uZAAAAQEB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6ZGlhbW9uZF9oZWxtZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfaGVsbWV0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AusC", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfZGlhbW9uZF9hcm1vcg==" + } + }, + { + "id": 900, + "key": "minecraft:diamond_chestplate", + "components": { + "minecraft:attribute_modifiers": "DQIAGm1pbmVjcmFmdDphcm1vci5jaGVzdHBsYXRlQCAAAAAAAAAABgEabWluZWNyYWZ0OmFybW9yLmNoZXN0cGxhdGVAAAAAAAAAAAAGAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HANFARFtaW5lY3JhZnQ6ZGlhbW9uZAAAAQEB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6ZGlhbW9uZF9jaGVzdHBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfY2hlc3RwbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ApAE", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfZGlhbW9uZF9hcm1vcg==" + } + }, + { + "id": 901, + "key": "minecraft:diamond_leggings", + "components": { + "minecraft:attribute_modifiers": "DQIAGG1pbmVjcmFmdDphcm1vci5sZWdnaW5nc0AYAAAAAAAAAAUBGG1pbmVjcmFmdDphcm1vci5sZWdnaW5nc0AAAAAAAAAAAAUB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAJFARFtaW5lY3JhZnQ6ZGlhbW9uZAAAAQEB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZGlhbW9uZF9sZWdnaW5ncw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfbGVnZ2luZ3MA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Au8D", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfZGlhbW9uZF9hcm1vcg==" + } + }, + { + "id": 902, + "key": "minecraft:diamond_boots", + "components": { + "minecraft:attribute_modifiers": "DQIAFW1pbmVjcmFmdDphcm1vci5ib290c0AIAAAAAAAAAAQBFW1pbmVjcmFmdDphcm1vci5ib290c0AAAAAAAAAAAAQB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gwo=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAFFARFtaW5lY3JhZnQ6ZGlhbW9uZAAAAQEB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGlhbW9uZF9ib290cw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfYm9vdHMA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Aq0D", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0OnJlcGFpcnNfZGlhbW9uZF9hcm1vcg==" + } + }, + { + "id": 903, + "key": "minecraft:golden_helmet", + "components": { + "minecraft:attribute_modifiers": "DQIAFm1pbmVjcmFmdDphcm1vci5oZWxtZXRAAAAAAAAAAAAHARZtaW5lY3JhZnQ6YXJtb3IuaGVsbWV0AAAAAAAAAAAABwE=", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gxk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARIAQ5taW5lY3JhZnQ6Z29sZAAAAQEB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Z29sZGVuX2hlbG1ldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmdvbGRlbl9oZWxtZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Ak0=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfZ29sZF9hcm1vcg==" + } + }, + { + "id": 904, + "key": "minecraft:golden_chestplate", + "components": { + "minecraft:attribute_modifiers": "DQIAGm1pbmVjcmFmdDphcm1vci5jaGVzdHBsYXRlQBQAAAAAAAAABgEabWluZWNyYWZ0OmFybW9yLmNoZXN0cGxhdGUAAAAAAAAAAAAGAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gxk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HANIAQ5taW5lY3JhZnQ6Z29sZAAAAQEB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Z29sZGVuX2NoZXN0cGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmdvbGRlbl9jaGVzdHBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AnA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfZ29sZF9hcm1vcg==" + } + }, + { + "id": 905, + "key": "minecraft:golden_leggings", + "components": { + "minecraft:attribute_modifiers": "DQIAGG1pbmVjcmFmdDphcm1vci5sZWdnaW5nc0AIAAAAAAAAAAUBGG1pbmVjcmFmdDphcm1vci5sZWdnaW5ncwAAAAAAAAAAAAUB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gxk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAJIAQ5taW5lY3JhZnQ6Z29sZAAAAQEB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Z29sZGVuX2xlZ2dpbmdz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmdvbGRlbl9sZWdnaW5ncwA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Amk=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfZ29sZF9hcm1vcg==" + } + }, + { + "id": 906, + "key": "minecraft:golden_boots", + "components": { + "minecraft:attribute_modifiers": "DQIAFW1pbmVjcmFmdDphcm1vci5ib290cz/wAAAAAAAAAAQBFW1pbmVjcmFmdDphcm1vci5ib290cwAAAAAAAAAAAAQB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gxk=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAFIAQ5taW5lY3JhZnQ6Z29sZAAAAQEB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z29sZGVuX2Jvb3Rz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmdvbGRlbl9ib290cwA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Als=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAcbWluZWNyYWZ0OnJlcGFpcnNfZ29sZF9hcm1vcg==" + } + }, + { + "id": 907, + "key": "minecraft:netherite_helmet", + "components": { + "minecraft:attribute_modifiers": "DQMAFm1pbmVjcmFmdDphcm1vci5oZWxtZXRACAAAAAAAAAAHARZtaW5lY3JhZnQ6YXJtb3IuaGVsbWV0QAgAAAAAAAAABw8WbWluZWNyYWZ0OmFybW9yLmhlbG1ldD+5mZmgAAAAAAcB", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARLARNtaW5lY3JhZnQ6bmV0aGVyaXRlAAABAQE=", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bmV0aGVyaXRlX2hlbG1ldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9oZWxtZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "ApcD", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAhbWluZWNyYWZ0OnJlcGFpcnNfbmV0aGVyaXRlX2FybW9y" + } + }, + { + "id": 908, + "key": "minecraft:netherite_chestplate", + "components": { + "minecraft:attribute_modifiers": "DQMAGm1pbmVjcmFmdDphcm1vci5jaGVzdHBsYXRlQCAAAAAAAAAABgEabWluZWNyYWZ0OmFybW9yLmNoZXN0cGxhdGVACAAAAAAAAAAGDxptaW5lY3JhZnQ6YXJtb3IuY2hlc3RwbGF0ZT+5mZmgAAAAAAYB", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HANLARNtaW5lY3JhZnQ6bmV0aGVyaXRlAAABAQE=", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6bmV0aGVyaXRlX2NoZXN0cGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9jaGVzdHBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AtAE", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAhbWluZWNyYWZ0OnJlcGFpcnNfbmV0aGVyaXRlX2FybW9y" + } + }, + { + "id": 909, + "key": "minecraft:netherite_leggings", + "components": { + "minecraft:attribute_modifiers": "DQMAGG1pbmVjcmFmdDphcm1vci5sZWdnaW5nc0AYAAAAAAAAAAUBGG1pbmVjcmFmdDphcm1vci5sZWdnaW5nc0AIAAAAAAAAAAUPGG1pbmVjcmFmdDphcm1vci5sZWdnaW5ncz+5mZmgAAAAAAUB", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAJLARNtaW5lY3JhZnQ6bmV0aGVyaXRlAAABAQE=", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bmV0aGVyaXRlX2xlZ2dpbmdz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9sZWdnaW5ncwA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AqsE", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAhbWluZWNyYWZ0OnJlcGFpcnNfbmV0aGVyaXRlX2FybW9y" + } + }, + { + "id": 910, + "key": "minecraft:netherite_boots", + "components": { + "minecraft:attribute_modifiers": "DQMAFW1pbmVjcmFmdDphcm1vci5ib290c0AIAAAAAAAAAAQBFW1pbmVjcmFmdDphcm1vci5ib290c0AIAAAAAAAAAAQPFW1pbmVjcmFmdDphcm1vci5ib290cz+5mZmgAAAAAAQB", + "minecraft:damage": "AwA=", + "minecraft:damage_resistant": "GRFtaW5lY3JhZnQ6aXNfZmlyZQ==", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAFLARNtaW5lY3JhZnQ6bmV0aGVyaXRlAAABAQE=", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bmV0aGVyaXRlX2Jvb3Rz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV9ib290cwA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AuED", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAhbWluZWNyYWZ0OnJlcGFpcnNfbmV0aGVyaXRlX2FybW9y" + } + }, + { + "id": 911, + "key": "minecraft:flint", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6ZmxpbnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LmZsaW50AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 912, + "key": "minecraft:porkchop", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQM/5mZnAA==", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cG9ya2Nob3A=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LnBvcmtjaG9wAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 913, + "key": "minecraft:cooked_porkchop", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQhBTMzNAA==", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y29va2VkX3BvcmtjaG9w", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmNvb2tlZF9wb3JrY2hvcAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 914, + "key": "minecraft:painting", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cGFpbnRpbmc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LnBhaW50aW5nAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 915, + "key": "minecraft:golden_apple", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAQACCQFkAAEBABUA4BIAAQEAP4AAAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQRBGZmaAQ==", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z29sZGVuX2FwcGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmdvbGRlbl9hcHBsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 916, + "key": "minecraft:enchanted_golden_apple", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAQAECQGQAwABAQAKAPAuAAEBAAsA8C4AAQEAFQPgEgABAQA/gAAA", + "minecraft:enchantment_glint_override": "EwE=", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQRBGZmaAQ==", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6ZW5jaGFudGVkX2dvbGRlbl9hcHBsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LmVuY2hhbnRlZF9nb2xkZW5fYXBwbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 917, + "key": "minecraft:oak_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6b2FrX3NpZ24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5vYWtfc2lnbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 918, + "key": "minecraft:spruce_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c3BydWNlX3NpZ24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zcHJ1Y2Vfc2lnbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 919, + "key": "minecraft:birch_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YmlyY2hfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5iaXJjaF9zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 920, + "key": "minecraft:jungle_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6anVuZ2xlX3NpZ24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5qdW5nbGVfc2lnbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 921, + "key": "minecraft:acacia_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YWNhY2lhX3NpZ24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5hY2FjaWFfc2lnbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 922, + "key": "minecraft:cherry_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y2hlcnJ5X3NpZ24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jaGVycnlfc2lnbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 923, + "key": "minecraft:dark_oak_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZGFya19vYWtfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 924, + "key": "minecraft:pale_oak_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cGFsZV9vYWtfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 925, + "key": "minecraft:mangrove_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bWFuZ3JvdmVfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 926, + "key": "minecraft:bamboo_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YmFtYm9vX3NpZ24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5iYW1ib29fc2lnbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 927, + "key": "minecraft:crimson_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y3JpbXNvbl9zaWdu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jcmltc29uX3NpZ24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 928, + "key": "minecraft:warped_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6d2FycGVkX3NpZ24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC53YXJwZWRfc2lnbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 929, + "key": "minecraft:oak_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6b2FrX2hhbmdpbmdfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5vYWtfaGFuZ2luZ19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 930, + "key": "minecraft:spruce_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c3BydWNlX2hhbmdpbmdfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5zcHJ1Y2VfaGFuZ2luZ19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 931, + "key": "minecraft:birch_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6YmlyY2hfaGFuZ2luZ19zaWdu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5iaXJjaF9oYW5naW5nX3NpZ24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 932, + "key": "minecraft:jungle_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6anVuZ2xlX2hhbmdpbmdfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5qdW5nbGVfaGFuZ2luZ19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 933, + "key": "minecraft:acacia_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6YWNhY2lhX2hhbmdpbmdfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5hY2FjaWFfaGFuZ2luZ19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 934, + "key": "minecraft:cherry_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6Y2hlcnJ5X2hhbmdpbmdfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5jaGVycnlfaGFuZ2luZ19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 935, + "key": "minecraft:dark_oak_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6ZGFya19vYWtfaGFuZ2luZ19zaWdu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5kYXJrX29ha19oYW5naW5nX3NpZ24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 936, + "key": "minecraft:pale_oak_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cGFsZV9vYWtfaGFuZ2luZ19zaWdu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5wYWxlX29ha19oYW5naW5nX3NpZ24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 937, + "key": "minecraft:mangrove_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6bWFuZ3JvdmVfaGFuZ2luZ19zaWdu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5tYW5ncm92ZV9oYW5naW5nX3NpZ24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 938, + "key": "minecraft:bamboo_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6YmFtYm9vX2hhbmdpbmdfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5iYW1ib29faGFuZ2luZ19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 939, + "key": "minecraft:crimson_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Y3JpbXNvbl9oYW5naW5nX3NpZ24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5jcmltc29uX2hhbmdpbmdfc2lnbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 940, + "key": "minecraft:warped_hanging_sign", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6d2FycGVkX2hhbmdpbmdfc2lnbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC53YXJwZWRfaGFuZ2luZ19zaWduAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 941, + "key": "minecraft:bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YnVja2V0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LmJ1Y2tldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 942, + "key": "minecraft:water_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d2F0ZXJfYnVja2V0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LndhdGVyX2J1Y2tldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 943, + "key": "minecraft:lava_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bGF2YV9idWNrZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmxhdmFfYnVja2V0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 944, + "key": "minecraft:powder_snow_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cG93ZGVyX3Nub3dfYnVja2V0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LnBvd2Rlcl9zbm93X2J1Y2tldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 945, + "key": "minecraft:snowball", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6c25vd2JhbGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LnNub3diYWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 946, + "key": "minecraft:leather", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6bGVhdGhlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0LmxlYXRoZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 947, + "key": "minecraft:milk_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0C2QQAAQI=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bWlsa19idWNrZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lm1pbGtfYnVja2V0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_remainder": "FwGtBwAA" + } + }, + { + "id": 948, + "key": "minecraft:pufferfish_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bucket_entity_data": "MAoA", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cHVmZmVyZmlzaF9idWNrZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnB1ZmZlcmZpc2hfYnVja2V0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 949, + "key": "minecraft:salmon_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bucket_entity_data": "MAoA", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c2FsbW9uX2J1Y2tldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnNhbG1vbl9idWNrZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 950, + "key": "minecraft:cod_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bucket_entity_data": "MAoA", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Y29kX2J1Y2tldA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmNvZF9idWNrZXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 951, + "key": "minecraft:tropical_fish_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bucket_entity_data": "MAoA", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6dHJvcGljYWxfZmlzaF9idWNrZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnRyb3BpY2FsX2Zpc2hfYnVja2V0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 952, + "key": "minecraft:axolotl_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bucket_entity_data": "MAoA", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YXhvbG90bF9idWNrZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmF4b2xvdGxfYnVja2V0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 953, + "key": "minecraft:tadpole_bucket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bucket_entity_data": "MAoA", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6dGFkcG9sZV9idWNrZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LnRhZHBvbGVfYnVja2V0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 954, + "key": "minecraft:brick", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6YnJpY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LmJyaWNrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 955, + "key": "minecraft:clay_ball", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Y2xheV9iYWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmNsYXlfYmFsbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 956, + "key": "minecraft:dried_kelp_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZHJpZWRfa2VscF9ibG9jaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5kcmllZF9rZWxwX2Jsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 957, + "key": "minecraft:paper", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6cGFwZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LnBhcGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 958, + "key": "minecraft:book", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantable": "GwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6Ym9vaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2l0ZW0ubWluZWNyYWZ0LmJvb2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 959, + "key": "minecraft:slime_ball", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c2xpbWVfYmFsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LnNsaW1lX2JhbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 960, + "key": "minecraft:egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw1taW5lY3JhZnQ6ZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAEml0ZW0ubWluZWNyYWZ0LmVnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 961, + "key": "minecraft:compass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6Y29tcGFzcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0LmNvbXBhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 962, + "key": "minecraft:recovery_compass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cmVjb3ZlcnlfY29tcGFzcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnJlY292ZXJ5X2NvbXBhc3MA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 963, + "key": "minecraft:bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YnVuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LmJ1bmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 964, + "key": "minecraft:white_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d2hpdGVfYnVuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LndoaXRlX2J1bmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 965, + "key": "minecraft:orange_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6b3JhbmdlX2J1bmRsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lm9yYW5nZV9idW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 966, + "key": "minecraft:magenta_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bWFnZW50YV9idW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lm1hZ2VudGFfYnVuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 967, + "key": "minecraft:light_blue_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bGlnaHRfYmx1ZV9idW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmxpZ2h0X2JsdWVfYnVuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 968, + "key": "minecraft:yellow_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6eWVsbG93X2J1bmRsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnllbGxvd19idW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 969, + "key": "minecraft:lime_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bGltZV9idW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmxpbWVfYnVuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 970, + "key": "minecraft:pink_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cGlua19idW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnBpbmtfYnVuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 971, + "key": "minecraft:gray_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Z3JheV9idW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmdyYXlfYnVuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 972, + "key": "minecraft:light_gray_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bGlnaHRfZ3JheV9idW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmxpZ2h0X2dyYXlfYnVuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 973, + "key": "minecraft:cyan_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y3lhbl9idW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmN5YW5fYnVuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 974, + "key": "minecraft:purple_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cHVycGxlX2J1bmRsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnB1cnBsZV9idW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 975, + "key": "minecraft:blue_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Ymx1ZV9idW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmJsdWVfYnVuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 976, + "key": "minecraft:brown_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YnJvd25fYnVuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmJyb3duX2J1bmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 977, + "key": "minecraft:green_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z3JlZW5fYnVuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmdyZWVuX2J1bmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 978, + "key": "minecraft:red_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cmVkX2J1bmRsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LnJlZF9idW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 979, + "key": "minecraft:black_bundle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bundle_contents": "KAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmxhY2tfYnVuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmJsYWNrX2J1bmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 980, + "key": "minecraft:fishing_rod", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZmlzaGluZ19yb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmZpc2hpbmdfcm9kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AkA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 981, + "key": "minecraft:clock", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6Y2xvY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LmNsb2NrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 982, + "key": "minecraft:spyglass", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6c3B5Z2xhc3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LnNweWdsYXNzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 983, + "key": "minecraft:glowstone_dust", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Z2xvd3N0b25lX2R1c3Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lmdsb3dzdG9uZV9kdXN0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 984, + "key": "minecraft:cod", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI+zMzNAA==", + "minecraft:item_model": "Bw1taW5lY3JhZnQ6Y29k", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAEml0ZW0ubWluZWNyYWZ0LmNvZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 985, + "key": "minecraft:salmon", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI+zMzNAA==", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6c2FsbW9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnNhbG1vbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 986, + "key": "minecraft:tropical_fish", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQE+TMzNAA==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6dHJvcGljYWxfZmlzaA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnRyb3BpY2FsX2Zpc2gA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 987, + "key": "minecraft:pufferfish", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAQADEgGwCQABAQAQAqwCAAEBAAgArAIAAQEAP4AAAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQE+TMzNAA==", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cHVmZmVyZmlzaA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LnB1ZmZlcmZpc2gA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 988, + "key": "minecraft:cooked_cod", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQVAwAAAAA==", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Y29va2VkX2NvZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmNvb2tlZF9jb2QA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 989, + "key": "minecraft:cooked_salmon", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQZBGZmaAA==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y29va2VkX3NhbG1vbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmNvb2tlZF9zYWxtb24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 990, + "key": "minecraft:ink_sac", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6aW5rX3NhYw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0Lmlua19zYWMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 991, + "key": "minecraft:glow_ink_sac", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z2xvd19pbmtfc2Fj", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0Lmdsb3dfaW5rX3NhYwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 992, + "key": "minecraft:cocoa_beans", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y29jb2FfYmVhbnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmNvY29hX2JlYW5zAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 993, + "key": "minecraft:white_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6d2hpdGVfZHll", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LndoaXRlX2R5ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 994, + "key": "minecraft:orange_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6b3JhbmdlX2R5ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0Lm9yYW5nZV9keWUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 995, + "key": "minecraft:magenta_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bWFnZW50YV9keWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lm1hZ2VudGFfZHllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 996, + "key": "minecraft:light_blue_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bGlnaHRfYmx1ZV9keWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmxpZ2h0X2JsdWVfZHllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 997, + "key": "minecraft:yellow_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6eWVsbG93X2R5ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LnllbGxvd19keWUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 998, + "key": "minecraft:lime_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6bGltZV9keWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LmxpbWVfZHllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 999, + "key": "minecraft:pink_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cGlua19keWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LnBpbmtfZHllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1000, + "key": "minecraft:gray_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Z3JheV9keWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LmdyYXlfZHllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1001, + "key": "minecraft:light_gray_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bGlnaHRfZ3JheV9keWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmxpZ2h0X2dyYXlfZHllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1002, + "key": "minecraft:cyan_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Y3lhbl9keWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LmN5YW5fZHllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1003, + "key": "minecraft:purple_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cHVycGxlX2R5ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LnB1cnBsZV9keWUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1004, + "key": "minecraft:blue_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Ymx1ZV9keWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LmJsdWVfZHllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1005, + "key": "minecraft:brown_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6YnJvd25fZHll", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmJyb3duX2R5ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1006, + "key": "minecraft:green_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Z3JlZW5fZHll", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmdyZWVuX2R5ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1007, + "key": "minecraft:red_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6cmVkX2R5ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0LnJlZF9keWUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1008, + "key": "minecraft:black_dye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6YmxhY2tfZHll", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmJsYWNrX2R5ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1009, + "key": "minecraft:bone_meal", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Ym9uZV9tZWFs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmJvbmVfbWVhbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1010, + "key": "minecraft:bone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6Ym9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2l0ZW0ubWluZWNyYWZ0LmJvbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1011, + "key": "minecraft:sugar", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6c3VnYXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LnN1Z2FyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1012, + "key": "minecraft:cake", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6Y2FrZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5jYWtlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1013, + "key": "minecraft:white_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6d2hpdGVfYmVk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC53aGl0ZV9iZWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1014, + "key": "minecraft:orange_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6b3JhbmdlX2JlZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfYmVkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1015, + "key": "minecraft:magenta_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bWFnZW50YV9iZWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX2JlZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1016, + "key": "minecraft:light_blue_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bGlnaHRfYmx1ZV9iZWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX2JlZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1017, + "key": "minecraft:yellow_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6eWVsbG93X2JlZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfYmVkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1018, + "key": "minecraft:lime_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6bGltZV9iZWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5saW1lX2JlZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1019, + "key": "minecraft:pink_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6cGlua19iZWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5waW5rX2JlZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1020, + "key": "minecraft:gray_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Z3JheV9iZWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5ncmF5X2JlZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1021, + "key": "minecraft:light_gray_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bGlnaHRfZ3JheV9iZWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X2JlZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1022, + "key": "minecraft:cyan_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Y3lhbl9iZWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5jeWFuX2JlZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1023, + "key": "minecraft:purple_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cHVycGxlX2JlZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfYmVkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1024, + "key": "minecraft:blue_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Ymx1ZV9iZWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5ibHVlX2JlZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1025, + "key": "minecraft:brown_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6YnJvd25fYmVk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5icm93bl9iZWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1026, + "key": "minecraft:green_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Z3JlZW5fYmVk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5ncmVlbl9iZWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1027, + "key": "minecraft:red_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6cmVkX2JlZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5yZWRfYmVkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1028, + "key": "minecraft:black_bed", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6YmxhY2tfYmVk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5ibGFja19iZWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1029, + "key": "minecraft:cookie", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI+zMzNAA==", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6Y29va2ll", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LmNvb2tpZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1030, + "key": "minecraft:crafter", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6Y3JhZnRlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5jcmFmdGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1031, + "key": "minecraft:filled_map", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6ZmlsbGVkX21hcA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmZpbGxlZF9tYXAA", + "minecraft:lore": "CAA=", + "minecraft:map_color": "IwBGQC4=", + "minecraft:map_decorations": "JQoA", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1032, + "key": "minecraft:shears", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage": "AwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6c2hlYXJz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnNoZWFycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "Au4B", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:tool": "GgQCgQEBQXAAAAEBABBtaW5lY3JhZnQ6bGVhdmVzAUFwAAAAAA5taW5lY3JhZnQ6d29vbAFAoAAAAAPLAswCAUAAAAAAP4AAAAE=" + } + }, + { + "id": 1033, + "key": "minecraft:melon_slice", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI/mZmaAA==", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bWVsb25fc2xpY2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lm1lbG9uX3NsaWNlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1034, + "key": "minecraft:dried_kelp", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj9MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQE/GZmaAA==", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6ZHJpZWRfa2VscA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmRyaWVkX2tlbHAA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1035, + "key": "minecraft:pumpkin_seeds", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cHVtcGtpbl9zZWVkcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnB1bXBraW5fc2VlZHMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1036, + "key": "minecraft:melon_seeds", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bWVsb25fc2VlZHM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lm1lbG9uX3NlZWRzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1037, + "key": "minecraft:beef", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQM/5mZnAA==", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6YmVlZg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2l0ZW0ubWluZWNyYWZ0LmJlZWYA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1038, + "key": "minecraft:cooked_beef", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQhBTMzNAA==", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y29va2VkX2JlZWY=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmNvb2tlZF9iZWVmAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1039, + "key": "minecraft:chicken", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAQABEADYBAABAQA+mZma", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI/mZmaAA==", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6Y2hpY2tlbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0LmNoaWNrZW4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1040, + "key": "minecraft:cooked_chicken", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQZA5mZnAA==", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Y29va2VkX2NoaWNrZW4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmNvb2tlZF9jaGlja2VuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1041, + "key": "minecraft:rotten_flesh", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAQABEADYBAABAQA/TMzN", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQQ/TMzNAA==", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6cm90dGVuX2ZsZXNo", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LnJvdHRlbl9mbGVzaAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1042, + "key": "minecraft:ender_pearl", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZW5kZXJfcGVhcmw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmVuZGVyX3BlYXJsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_cooldown": "GD+AAAAA" + } + }, + { + "id": 1043, + "key": "minecraft:blaze_rod", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6YmxhemVfcm9k", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmJsYXplX3JvZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1044, + "key": "minecraft:ghast_tear", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Z2hhc3RfdGVhcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmdoYXN0X3RlYXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1045, + "key": "minecraft:gold_nugget", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Z29sZF9udWdnZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmdvbGRfbnVnZ2V0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1046, + "key": "minecraft:nether_wart", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bmV0aGVyX3dhcnQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lm5ldGhlcl93YXJ0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1047, + "key": "minecraft:glass_bottle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z2xhc3NfYm90dGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmdsYXNzX2JvdHRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1048, + "key": "minecraft:potion", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0C2QQAAA==", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6cG90aW9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnBvdGlvbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:potion_contents": "KQAAAAA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_remainder": "FwGXCAAA" + } + }, + { + "id": 1049, + "key": "minecraft:spider_eye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAQABEgBkAAEBAD+AAAA=", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQJATMzNAA==", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6c3BpZGVyX2V5ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LnNwaWRlcl9leWUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1050, + "key": "minecraft:fermented_spider_eye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZmVybWVudGVkX3NwaWRlcl9leWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LmZlcm1lbnRlZF9zcGlkZXJfZXllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1051, + "key": "minecraft:blaze_powder", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmxhemVfcG93ZGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmJsYXplX3Bvd2RlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1052, + "key": "minecraft:magma_cream", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bWFnbWFfY3JlYW0=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lm1hZ21hX2NyZWFtAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1053, + "key": "minecraft:brewing_stand", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YnJld2luZ19zdGFuZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5icmV3aW5nX3N0YW5kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1054, + "key": "minecraft:cauldron", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Y2F1bGRyb24=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5jYXVsZHJvbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1055, + "key": "minecraft:ender_eye", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6ZW5kZXJfZXll", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmVuZGVyX2V5ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1056, + "key": "minecraft:glistering_melon_slice", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Z2xpc3RlcmluZ19tZWxvbl9zbGljZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LmdsaXN0ZXJpbmdfbWVsb25fc2xpY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1057, + "key": "minecraft:armadillo_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6YXJtYWRpbGxvX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LmFybWFkaWxsb19zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1058, + "key": "minecraft:allay_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YWxsYXlfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmFsbGF5X3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1059, + "key": "minecraft:axolotl_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YXhvbG90bF9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmF4b2xvdGxfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1060, + "key": "minecraft:bat_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YmF0X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmJhdF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1061, + "key": "minecraft:bee_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YmVlX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmJlZV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1062, + "key": "minecraft:blaze_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YmxhemVfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmJsYXplX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1063, + "key": "minecraft:bogged_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6Ym9nZ2VkX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmJvZ2dlZF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1064, + "key": "minecraft:breeze_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6YnJlZXplX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmJyZWV6ZV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1065, + "key": "minecraft:cat_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y2F0X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmNhdF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1066, + "key": "minecraft:camel_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y2FtZWxfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmNhbWVsX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1067, + "key": "minecraft:cave_spider_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Y2F2ZV9zcGlkZXJfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGl0ZW0ubWluZWNyYWZ0LmNhdmVfc3BpZGVyX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1068, + "key": "minecraft:chicken_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y2hpY2tlbl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmNoaWNrZW5fc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1069, + "key": "minecraft:cod_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y29kX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmNvZF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1070, + "key": "minecraft:cow_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y293X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmNvd19zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1071, + "key": "minecraft:creeper_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y3JlZXBlcl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmNyZWVwZXJfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1072, + "key": "minecraft:dolphin_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6ZG9scGhpbl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmRvbHBoaW5fc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1073, + "key": "minecraft:donkey_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZG9ua2V5X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmRvbmtleV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1074, + "key": "minecraft:drowned_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6ZHJvd25lZF9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmRyb3duZWRfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1075, + "key": "minecraft:elder_guardian_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6ZWxkZXJfZ3VhcmRpYW5fc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2l0ZW0ubWluZWNyYWZ0LmVsZGVyX2d1YXJkaWFuX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1076, + "key": "minecraft:ender_dragon_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6ZW5kZXJfZHJhZ29uX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LmVuZGVyX2RyYWdvbl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1077, + "key": "minecraft:enderman_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6ZW5kZXJtYW5fc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LmVuZGVybWFuX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1078, + "key": "minecraft:endermite_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZW5kZXJtaXRlX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LmVuZGVybWl0ZV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1079, + "key": "minecraft:evoker_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6ZXZva2VyX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmV2b2tlcl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1080, + "key": "minecraft:fox_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Zm94X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmZveF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1081, + "key": "minecraft:frog_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6ZnJvZ19zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmZyb2dfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1082, + "key": "minecraft:ghast_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Z2hhc3Rfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmdoYXN0X3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1083, + "key": "minecraft:glow_squid_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Z2xvd19zcXVpZF9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0Lmdsb3dfc3F1aWRfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1084, + "key": "minecraft:goat_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6Z29hdF9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmdvYXRfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1085, + "key": "minecraft:guardian_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Z3VhcmRpYW5fc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0Lmd1YXJkaWFuX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1086, + "key": "minecraft:hoglin_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6aG9nbGluX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmhvZ2xpbl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1087, + "key": "minecraft:horse_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6aG9yc2Vfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmhvcnNlX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1088, + "key": "minecraft:husk_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6aHVza19zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lmh1c2tfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1089, + "key": "minecraft:iron_golem_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6aXJvbl9nb2xlbV9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0Lmlyb25fZ29sZW1fc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1090, + "key": "minecraft:llama_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bGxhbWFfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmxsYW1hX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1091, + "key": "minecraft:magma_cube_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6bWFnbWFfY3ViZV9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0Lm1hZ21hX2N1YmVfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1092, + "key": "minecraft:mooshroom_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bW9vc2hyb29tX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0Lm1vb3Nocm9vbV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1093, + "key": "minecraft:mule_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bXVsZV9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lm11bGVfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1094, + "key": "minecraft:ocelot_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6b2NlbG90X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0Lm9jZWxvdF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1095, + "key": "minecraft:panda_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6cGFuZGFfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LnBhbmRhX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1096, + "key": "minecraft:parrot_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cGFycm90X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnBhcnJvdF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1097, + "key": "minecraft:phantom_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cGhhbnRvbV9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnBoYW50b21fc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1098, + "key": "minecraft:pig_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cGlnX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnBpZ19zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1099, + "key": "minecraft:piglin_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cGlnbGluX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnBpZ2xpbl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1100, + "key": "minecraft:piglin_brute_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6cGlnbGluX2JydXRlX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LnBpZ2xpbl9icnV0ZV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1101, + "key": "minecraft:pillager_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6cGlsbGFnZXJfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LnBpbGxhZ2VyX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1102, + "key": "minecraft:polar_bear_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6cG9sYXJfYmVhcl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnBvbGFyX2JlYXJfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1103, + "key": "minecraft:pufferfish_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6cHVmZmVyZmlzaF9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnB1ZmZlcmZpc2hfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1104, + "key": "minecraft:rabbit_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cmFiYml0X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnJhYmJpdF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1105, + "key": "minecraft:ravager_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cmF2YWdlcl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnJhdmFnZXJfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1106, + "key": "minecraft:salmon_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6c2FsbW9uX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnNhbG1vbl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1107, + "key": "minecraft:sheep_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6c2hlZXBfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LnNoZWVwX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1108, + "key": "minecraft:shulker_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6c2h1bGtlcl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnNodWxrZXJfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1109, + "key": "minecraft:silverfish_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c2lsdmVyZmlzaF9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnNpbHZlcmZpc2hfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1110, + "key": "minecraft:skeleton_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6c2tlbGV0b25fc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LnNrZWxldG9uX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1111, + "key": "minecraft:skeleton_horse_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6c2tlbGV0b25faG9yc2Vfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2l0ZW0ubWluZWNyYWZ0LnNrZWxldG9uX2hvcnNlX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1112, + "key": "minecraft:slime_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6c2xpbWVfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LnNsaW1lX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1113, + "key": "minecraft:sniffer_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6c25pZmZlcl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnNuaWZmZXJfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1114, + "key": "minecraft:snow_golem_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c25vd19nb2xlbV9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnNub3dfZ29sZW1fc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1115, + "key": "minecraft:spider_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6c3BpZGVyX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnNwaWRlcl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1116, + "key": "minecraft:squid_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6c3F1aWRfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LnNxdWlkX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1117, + "key": "minecraft:stray_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6c3RyYXlfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LnN0cmF5X3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1118, + "key": "minecraft:strider_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6c3RyaWRlcl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnN0cmlkZXJfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1119, + "key": "minecraft:tadpole_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6dGFkcG9sZV9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnRhZHBvbGVfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1120, + "key": "minecraft:trader_llama_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6dHJhZGVyX2xsYW1hX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LnRyYWRlcl9sbGFtYV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1121, + "key": "minecraft:tropical_fish_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByFtaW5lY3JhZnQ6dHJvcGljYWxfZmlzaF9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJml0ZW0ubWluZWNyYWZ0LnRyb3BpY2FsX2Zpc2hfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1122, + "key": "minecraft:turtle_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6dHVydGxlX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnR1cnRsZV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1123, + "key": "minecraft:vex_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6dmV4X3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnZleF9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1124, + "key": "minecraft:villager_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6dmlsbGFnZXJfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LnZpbGxhZ2VyX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1125, + "key": "minecraft:vindicator_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6dmluZGljYXRvcl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnZpbmRpY2F0b3Jfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1126, + "key": "minecraft:wandering_trader_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6d2FuZGVyaW5nX3RyYWRlcl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWl0ZW0ubWluZWNyYWZ0LndhbmRlcmluZ190cmFkZXJfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1127, + "key": "minecraft:warden_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6d2FyZGVuX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LndhcmRlbl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1128, + "key": "minecraft:witch_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6d2l0Y2hfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LndpdGNoX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1129, + "key": "minecraft:wither_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6d2l0aGVyX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LndpdGhlcl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1130, + "key": "minecraft:wither_skeleton_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6d2l0aGVyX3NrZWxldG9uX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGl0ZW0ubWluZWNyYWZ0LndpdGhlcl9za2VsZXRvbl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1131, + "key": "minecraft:wolf_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6d29sZl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LndvbGZfc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1132, + "key": "minecraft:zoglin_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6em9nbGluX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnpvZ2xpbl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1133, + "key": "minecraft:creaking_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Y3JlYWtpbmdfc3Bhd25fZWdn", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LmNyZWFraW5nX3NwYXduX2VnZwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1134, + "key": "minecraft:zombie_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6em9tYmllX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnpvbWJpZV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1135, + "key": "minecraft:zombie_horse_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6em9tYmllX2hvcnNlX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LnpvbWJpZV9ob3JzZV9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1136, + "key": "minecraft:zombie_villager_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6em9tYmllX3ZpbGxhZ2VyX3NwYXduX2VnZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGl0ZW0ubWluZWNyYWZ0LnpvbWJpZV92aWxsYWdlcl9zcGF3bl9lZ2cA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1137, + "key": "minecraft:zombified_piglin_spawn_egg", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6em9tYmlmaWVkX3BpZ2xpbl9zcGF3bl9lZ2c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWl0ZW0ubWluZWNyYWZ0LnpvbWJpZmllZF9waWdsaW5fc3Bhd25fZWdnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1138, + "key": "minecraft:experience_bottle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantment_glint_override": "EwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6ZXhwZXJpZW5jZV9ib3R0bGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LmV4cGVyaWVuY2VfYm90dGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1139, + "key": "minecraft:fire_charge", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZmlyZV9jaGFyZ2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmZpcmVfY2hhcmdlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1140, + "key": "minecraft:wind_charge", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6d2luZF9jaGFyZ2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LndpbmRfY2hhcmdlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_cooldown": "GD8AAAAA" + } + }, + { + "id": 1141, + "key": "minecraft:writable_book", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6d3JpdGFibGVfYm9vaw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LndyaXRhYmxlX2Jvb2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:writable_book_content": "KwA=" + } + }, + { + "id": 1142, + "key": "minecraft:written_book", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantment_glint_override": "EwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d3JpdHRlbl9ib29r", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LndyaXR0ZW5fYm9vawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1143, + "key": "minecraft:breeze_rod", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YnJlZXplX3JvZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmJyZWV6ZV9yb2QA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1144, + "key": "minecraft:mace", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAFAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTACzMzQAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "Gw8=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6bWFjZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2l0ZW0ubWluZWNyYWZ0Lm1hY2UA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvQD", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQL3CA==", + "minecraft:tool": "GgA/gAAAAg==" + } + }, + { + "id": 1145, + "key": "minecraft:item_frame", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6aXRlbV9mcmFtZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0Lml0ZW1fZnJhbWUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1146, + "key": "minecraft:glow_item_frame", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Z2xvd19pdGVtX2ZyYW1l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lmdsb3dfaXRlbV9mcmFtZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1147, + "key": "minecraft:flower_pot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Zmxvd2VyX3BvdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5mbG93ZXJfcG90AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1148, + "key": "minecraft:carrot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQNAZmZnAA==", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6Y2Fycm90", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LmNhcnJvdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1149, + "key": "minecraft:potato", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQE/GZmaAA==", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6cG90YXRv", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnBvdGF0bwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1150, + "key": "minecraft:baked_potato", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQVAwAAAAA==", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmFrZWRfcG90YXRv", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmJha2VkX3BvdGF0bwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1151, + "key": "minecraft:poisonous_potato", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAQABEgBkAAEBAD8ZmZo=", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI/mZmaAA==", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cG9pc29ub3VzX3BvdGF0bw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnBvaXNvbm91c19wb3RhdG8A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1152, + "key": "minecraft:map", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw1taW5lY3JhZnQ6bWFw", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAEml0ZW0ubWluZWNyYWZ0Lm1hcAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1153, + "key": "minecraft:golden_carrot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQZBZmZnAA==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Z29sZGVuX2NhcnJvdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmdvbGRlbl9jYXJyb3QA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1154, + "key": "minecraft:skeleton_skull", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARHAAAAAQAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c2tlbGV0b25fc2t1bGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5za2VsZXRvbl9za3VsbAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1155, + "key": "minecraft:wither_skeleton_skull", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARHAAAAAQAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2l0aGVyX3NrZWxldG9uX3NrdWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53aXRoZXJfc2tlbGV0b25fc2t1bGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1156, + "key": "minecraft:player_head", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARHAAAAAQAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cGxheWVyX2hlYWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5wbGF5ZXJfaGVhZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1157, + "key": "minecraft:zombie_head", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARHAAAAAQAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6em9tYmllX2hlYWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC56b21iaWVfaGVhZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1158, + "key": "minecraft:creeper_head", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARHAAAAAQAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y3JlZXBlcl9oZWFk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jcmVlcGVyX2hlYWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1159, + "key": "minecraft:dragon_head", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARHAAAAAQAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZHJhZ29uX2hlYWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5kcmFnb25faGVhZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1160, + "key": "minecraft:piglin_head", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HARHAAAAAQAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cGlnbGluX2hlYWQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5waWdsaW5faGVhZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1161, + "key": "minecraft:nether_star", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage_resistant": "GRZtaW5lY3JhZnQ6aXNfZXhwbG9zaW9u", + "minecraft:enchantment_glint_override": "EwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bmV0aGVyX3N0YXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lm5ldGhlcl9zdGFyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1162, + "key": "minecraft:pumpkin_pie", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQhAmZmaAA==", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cHVtcGtpbl9waWU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnB1bXBraW5fcGllAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1163, + "key": "minecraft:firework_rocket", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:fireworks": "OAEA", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZmlyZXdvcmtfcm9ja2V0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmZpcmV3b3JrX3JvY2tldAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1164, + "key": "minecraft:firework_star", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZmlyZXdvcmtfc3Rhcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmZpcmV3b3JrX3N0YXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1165, + "key": "minecraft:enchanted_book", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantment_glint_override": "EwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6ZW5jaGFudGVkX2Jvb2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmVuY2hhbnRlZF9ib29rAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=", + "minecraft:stored_enchantments": "IQAB" + } + }, + { + "id": 1166, + "key": "minecraft:nether_brick", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6bmV0aGVyX2JyaWNr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0Lm5ldGhlcl9icmljawA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1167, + "key": "minecraft:resin_brick", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cmVzaW5fYnJpY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnJlc2luX2JyaWNrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1168, + "key": "minecraft:prismarine_shard", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6cHJpc21hcmluZV9zaGFyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnByaXNtYXJpbmVfc2hhcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1169, + "key": "minecraft:prismarine_crystals", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6cHJpc21hcmluZV9jcnlzdGFscw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LnByaXNtYXJpbmVfY3J5c3RhbHMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1170, + "key": "minecraft:rabbit", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQM/5mZnAA==", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6cmFiYml0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnJhYmJpdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1171, + "key": "minecraft:cooked_rabbit", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQVAwAAAAA==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y29va2VkX3JhYmJpdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmNvb2tlZF9yYWJiaXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1172, + "key": "minecraft:rabbit_stew", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQpBQAAAAA==", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cmFiYml0X3N0ZXc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnJhYmJpdF9zdGV3AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_remainder": "FwG+BgAA" + } + }, + { + "id": 1173, + "key": "minecraft:rabbit_foot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cmFiYml0X2Zvb3Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnJhYmJpdF9mb290AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1174, + "key": "minecraft:rabbit_hide", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cmFiYml0X2hpZGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnJhYmJpdF9oaWRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1175, + "key": "minecraft:armor_stand", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6YXJtb3Jfc3RhbmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmFybW9yX3N0YW5kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1176, + "key": "minecraft:iron_horse_armor", + "components": { + "minecraft:attribute_modifiers": "DQIAFG1pbmVjcmFmdDphcm1vci5ib2R5QBQAAAAAAAAACQEUbWluZWNyYWZ0OmFybW9yLmJvZHkAAAAAAAAAAAAJAQ==", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAblBQEObWluZWNyYWZ0Omlyb24AAQI/AQEA", + "minecraft:item_model": "BxptaW5lY3JhZnQ6aXJvbl9ob3JzZV9hcm1vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0Lmlyb25faG9yc2VfYXJtb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1177, + "key": "minecraft:golden_horse_armor", + "components": { + "minecraft:attribute_modifiers": "DQIAFG1pbmVjcmFmdDphcm1vci5ib2R5QBwAAAAAAAAACQEUbWluZWNyYWZ0OmFybW9yLmJvZHkAAAAAAAAAAAAJAQ==", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAblBQEObWluZWNyYWZ0OmdvbGQAAQI/AQEA", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Z29sZGVuX2hvcnNlX2FybW9y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LmdvbGRlbl9ob3JzZV9hcm1vcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1178, + "key": "minecraft:diamond_horse_armor", + "components": { + "minecraft:attribute_modifiers": "DQIAFG1pbmVjcmFmdDphcm1vci5ib2R5QCYAAAAAAAAACQEUbWluZWNyYWZ0OmFybW9yLmJvZHlAAAAAAAAAAAAJAQ==", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAblBQERbWluZWNyYWZ0OmRpYW1vbmQAAQI/AQEA", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZGlhbW9uZF9ob3JzZV9hcm1vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LmRpYW1vbmRfaG9yc2VfYXJtb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1179, + "key": "minecraft:leather_horse_armor", + "components": { + "minecraft:attribute_modifiers": "DQIAFG1pbmVjcmFmdDphcm1vci5ib2R5QAgAAAAAAAAACQEUbWluZWNyYWZ0OmFybW9yLmJvZHkAAAAAAAAAAAAJAQ==", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAblBQERbWluZWNyYWZ0OmxlYXRoZXIAAQI/AQEA", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bGVhdGhlcl9ob3JzZV9hcm1vcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LmxlYXRoZXJfaG9yc2VfYXJtb3IA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1180, + "key": "minecraft:lead", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6bGVhZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAE2l0ZW0ubWluZWNyYWZ0LmxlYWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1181, + "key": "minecraft:name_tag", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6bmFtZV90YWc=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0Lm5hbWVfdGFnAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1182, + "key": "minecraft:command_block_minecart", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y29tbWFuZF9ibG9ja19taW5lY2FydA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LmNvbW1hbmRfYmxvY2tfbWluZWNhcnQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1183, + "key": "minecraft:mutton", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI/mZmaAA==", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6bXV0dG9u", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0Lm11dHRvbgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1184, + "key": "minecraft:cooked_mutton", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQZBGZmaAA==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Y29va2VkX211dHRvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmNvb2tlZF9tdXR0b24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1185, + "key": "minecraft:white_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d2hpdGVfYmFubmVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC53aGl0ZV9iYW5uZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1186, + "key": "minecraft:orange_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6b3JhbmdlX2Jhbm5lcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfYmFubmVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1187, + "key": "minecraft:magenta_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bWFnZW50YV9iYW5uZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX2Jhbm5lcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1188, + "key": "minecraft:light_blue_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bGlnaHRfYmx1ZV9iYW5uZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX2Jhbm5lcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1189, + "key": "minecraft:yellow_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6eWVsbG93X2Jhbm5lcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfYmFubmVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1190, + "key": "minecraft:lime_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bGltZV9iYW5uZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5saW1lX2Jhbm5lcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1191, + "key": "minecraft:pink_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cGlua19iYW5uZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5waW5rX2Jhbm5lcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1192, + "key": "minecraft:gray_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Z3JheV9iYW5uZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ncmF5X2Jhbm5lcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1193, + "key": "minecraft:light_gray_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bGlnaHRfZ3JheV9iYW5uZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X2Jhbm5lcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1194, + "key": "minecraft:cyan_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y3lhbl9iYW5uZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jeWFuX2Jhbm5lcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1195, + "key": "minecraft:purple_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cHVycGxlX2Jhbm5lcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfYmFubmVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1196, + "key": "minecraft:blue_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Ymx1ZV9iYW5uZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ibHVlX2Jhbm5lcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1197, + "key": "minecraft:brown_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YnJvd25fYmFubmVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5icm93bl9iYW5uZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1198, + "key": "minecraft:green_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z3JlZW5fYmFubmVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5ncmVlbl9iYW5uZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1199, + "key": "minecraft:red_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cmVkX2Jhbm5lcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5yZWRfYmFubmVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1200, + "key": "minecraft:black_banner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmxhY2tfYmFubmVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5ibGFja19iYW5uZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1201, + "key": "minecraft:end_crystal", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantment_glint_override": "EwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZW5kX2NyeXN0YWw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmVuZF9jcnlzdGFsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1202, + "key": "minecraft:chorus_fruit", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAQNBgAAA", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQRAGZmaAQ==", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y2hvcnVzX2ZydWl0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmNob3J1c19mcnVpdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_cooldown": "GD+AAAAA" + } + }, + { + "id": 1203, + "key": "minecraft:popped_chorus_fruit", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6cG9wcGVkX2Nob3J1c19mcnVpdA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LnBvcHBlZF9jaG9ydXNfZnJ1aXQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1204, + "key": "minecraft:torchflower_seeds", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6dG9yY2hmbG93ZXJfc2VlZHM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0LnRvcmNoZmxvd2VyX3NlZWRzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1205, + "key": "minecraft:pitcher_pod", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cGl0Y2hlcl9wb2Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LnBpdGNoZXJfcG9kAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1206, + "key": "minecraft:beetroot", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQE/mZmaAA==", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6YmVldHJvb3Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LmJlZXRyb290AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1207, + "key": "minecraft:beetroot_seeds", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6YmVldHJvb3Rfc2VlZHM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LmJlZXRyb290X3NlZWRzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1208, + "key": "minecraft:beetroot_soup", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQZA5mZnAA==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6YmVldHJvb3Rfc291cA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmJlZXRyb290X3NvdXAA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_remainder": "FwG+BgAA" + } + }, + { + "id": 1209, + "key": "minecraft:dragon_breath", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6ZHJhZ29uX2JyZWF0aA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LmRyYWdvbl9icmVhdGgA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1210, + "key": "minecraft:splash_potion", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3BsYXNoX3BvdGlvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnNwbGFzaF9wb3Rpb24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:potion_contents": "KQAAAAA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1211, + "key": "minecraft:spectral_arrow", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c3BlY3RyYWxfYXJyb3c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0LnNwZWN0cmFsX2Fycm93AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1212, + "key": "minecraft:tipped_arrow", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6dGlwcGVkX2Fycm93", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LnRpcHBlZF9hcnJvdwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:potion_contents": "KQAAAAA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1213, + "key": "minecraft:lingering_potion", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bGluZ2VyaW5nX3BvdGlvbg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmxpbmdlcmluZ19wb3Rpb24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:potion_contents": "KQAAAAA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1214, + "key": "minecraft:shield", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:banner_patterns": "OwA=", + "minecraft:damage": "AwA=", + "minecraft:enchantments": "CgAB", + "minecraft:equippable": "HAVHAAAAAQAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6c2hpZWxk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWl0ZW0ubWluZWNyYWZ0LnNoaWVsZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AtAC", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:repairable": "HQAfbWluZWNyYWZ0Ondvb2Rlbl90b29sX21hdGVyaWFscw==" + } + }, + { + "id": 1215, + "key": "minecraft:totem_of_undying", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:death_protection": "IAICAAMJAYQHAAEBABUBZAABAQALAKAGAAEBAD+AAAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6dG90ZW1fb2ZfdW5keWluZw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LnRvdGVtX29mX3VuZHlpbmcA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1216, + "key": "minecraft:shulker_shell", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c2h1bGtlcl9zaGVsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnNodWxrZXJfc2hlbGwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1217, + "key": "minecraft:iron_nugget", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6aXJvbl9udWdnZXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0Lmlyb25fbnVnZ2V0AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1218, + "key": "minecraft:knowledge_book", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6a25vd2xlZGdlX2Jvb2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lmtub3dsZWRnZV9ib29rAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQM=", + "minecraft:recipes": "NQkAAAAAAA==", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1219, + "key": "minecraft:debug_stick", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:debug_stick_state": "LgoA", + "minecraft:enchantment_glint_override": "EwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6ZGVidWdfc3RpY2s=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGml0ZW0ubWluZWNyYWZ0LmRlYnVnX3N0aWNrAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1220, + "key": "minecraft:music_disc_13", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bXVzaWNfZGlzY18xMw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfMTMA", + "minecraft:jukebox_playable": "NAAMbWluZWNyYWZ0OjEzAQ==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1221, + "key": "minecraft:music_disc_cat", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bXVzaWNfZGlzY19jYXQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfY2F0AA==", + "minecraft:jukebox_playable": "NAANbWluZWNyYWZ0OmNhdAE=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1222, + "key": "minecraft:music_disc_blocks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bXVzaWNfZGlzY19ibG9ja3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfYmxvY2tzAA==", + "minecraft:jukebox_playable": "NAAQbWluZWNyYWZ0OmJsb2NrcwE=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1223, + "key": "minecraft:music_disc_chirp", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bXVzaWNfZGlzY19jaGlycA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfY2hpcnAA", + "minecraft:jukebox_playable": "NAAPbWluZWNyYWZ0OmNoaXJwAQ==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1224, + "key": "minecraft:music_disc_creator", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bXVzaWNfZGlzY19jcmVhdG9y", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfY3JlYXRvcgA=", + "minecraft:jukebox_playable": "NAARbWluZWNyYWZ0OmNyZWF0b3IB", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1225, + "key": "minecraft:music_disc_creator_music_box", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByZtaW5lY3JhZnQ6bXVzaWNfZGlzY19jcmVhdG9yX211c2ljX2JveA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAK2l0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfY3JlYXRvcl9tdXNpY19ib3gA", + "minecraft:jukebox_playable": "NAAbbWluZWNyYWZ0OmNyZWF0b3JfbXVzaWNfYm94AQ==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1226, + "key": "minecraft:music_disc_far", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bXVzaWNfZGlzY19mYXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfZmFyAA==", + "minecraft:jukebox_playable": "NAANbWluZWNyYWZ0OmZhcgE=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1227, + "key": "minecraft:music_disc_mall", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bXVzaWNfZGlzY19tYWxs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfbWFsbAA=", + "minecraft:jukebox_playable": "NAAObWluZWNyYWZ0Om1hbGwB", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1228, + "key": "minecraft:music_disc_mellohi", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bXVzaWNfZGlzY19tZWxsb2hp", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfbWVsbG9oaQA=", + "minecraft:jukebox_playable": "NAARbWluZWNyYWZ0Om1lbGxvaGkB", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1229, + "key": "minecraft:music_disc_stal", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bXVzaWNfZGlzY19zdGFs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2Nfc3RhbAA=", + "minecraft:jukebox_playable": "NAAObWluZWNyYWZ0OnN0YWwB", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1230, + "key": "minecraft:music_disc_strad", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bXVzaWNfZGlzY19zdHJhZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2Nfc3RyYWQA", + "minecraft:jukebox_playable": "NAAPbWluZWNyYWZ0OnN0cmFkAQ==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1231, + "key": "minecraft:music_disc_ward", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bXVzaWNfZGlzY193YXJk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2Nfd2FyZAA=", + "minecraft:jukebox_playable": "NAAObWluZWNyYWZ0OndhcmQB", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1232, + "key": "minecraft:music_disc_11", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6bXVzaWNfZGlzY18xMQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfMTEA", + "minecraft:jukebox_playable": "NAAMbWluZWNyYWZ0OjExAQ==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1233, + "key": "minecraft:music_disc_wait", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6bXVzaWNfZGlzY193YWl0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2Nfd2FpdAA=", + "minecraft:jukebox_playable": "NAAObWluZWNyYWZ0OndhaXQB", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1234, + "key": "minecraft:music_disc_otherside", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6bXVzaWNfZGlzY19vdGhlcnNpZGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2Nfb3RoZXJzaWRlAA==", + "minecraft:jukebox_playable": "NAATbWluZWNyYWZ0Om90aGVyc2lkZQE=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1235, + "key": "minecraft:music_disc_relic", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6bXVzaWNfZGlzY19yZWxpYw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfcmVsaWMA", + "minecraft:jukebox_playable": "NAAPbWluZWNyYWZ0OnJlbGljAQ==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1236, + "key": "minecraft:music_disc_5", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6bXVzaWNfZGlzY181", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfNQA=", + "minecraft:jukebox_playable": "NAALbWluZWNyYWZ0OjUB", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1237, + "key": "minecraft:music_disc_pigstep", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bXVzaWNfZGlzY19waWdzdGVw", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfcGlnc3RlcAA=", + "minecraft:jukebox_playable": "NAARbWluZWNyYWZ0OnBpZ3N0ZXAB", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1238, + "key": "minecraft:music_disc_precipice", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6bXVzaWNfZGlzY19wcmVjaXBpY2U=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0Lm11c2ljX2Rpc2NfcHJlY2lwaWNlAA==", + "minecraft:jukebox_playable": "NAATbWluZWNyYWZ0OnByZWNpcGljZQE=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1239, + "key": "minecraft:disc_fragment_5", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZGlzY19mcmFnbWVudF81", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LmRpc2NfZnJhZ21lbnRfNQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1240, + "key": "minecraft:trident", + "components": { + "minecraft:attribute_modifiers": "DQICHG1pbmVjcmFmdDpiYXNlX2F0dGFja19kYW1hZ2VAIAAAAAAAAAABBBttaW5lY3JhZnQ6YmFzZV9hdHRhY2tfc3BlZWTABzMzQAAAAAABAQ==", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6dHJpZGVudA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFml0ZW0ubWluZWNyYWZ0LnRyaWRlbnQA", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AvoB", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=", + "minecraft:tool": "GgA/gAAAAg==" + } + }, + { + "id": 1241, + "key": "minecraft:nautilus_shell", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bmF1dGlsdXNfc2hlbGw=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lm5hdXRpbHVzX3NoZWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1242, + "key": "minecraft:heart_of_the_sea", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6aGVhcnRfb2ZfdGhlX3NlYQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2l0ZW0ubWluZWNyYWZ0LmhlYXJ0X29mX3RoZV9zZWEA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1243, + "key": "minecraft:crossbow", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:charged_projectiles": "JwA=", + "minecraft:damage": "AwA=", + "minecraft:enchantable": "GwE=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Y3Jvc3Nib3c=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2l0ZW0ubWluZWNyYWZ0LmNyb3NzYm93AA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AtED", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1244, + "key": "minecraft:suspicious_stew", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQZA5mZnAQ==", + "minecraft:item_model": "BxltaW5lY3JhZnQ6c3VzcGljaW91c19zdGV3", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHml0ZW0ubWluZWNyYWZ0LnN1c3BpY2lvdXNfc3RldwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:suspicious_stew_effects": "KgA=", + "minecraft:use_remainder": "FwG+BgAA" + } + }, + { + "id": 1245, + "key": "minecraft:loom", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6bG9vbQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5sb29tAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1246, + "key": "minecraft:flower_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Zmxvd2VyX2Jhbm5lcl9wYXR0ZXJu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGl0ZW0ubWluZWNyYWZ0LmZsb3dlcl9iYW5uZXJfcGF0dGVybgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1247, + "key": "minecraft:creeper_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6Y3JlZXBlcl9iYW5uZXJfcGF0dGVybg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LmNyZWVwZXJfYmFubmVyX3BhdHRlcm4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1248, + "key": "minecraft:skull_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c2t1bGxfYmFubmVyX3BhdHRlcm4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnNrdWxsX2Jhbm5lcl9wYXR0ZXJuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1249, + "key": "minecraft:mojang_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6bW9qYW5nX2Jhbm5lcl9wYXR0ZXJu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGl0ZW0ubWluZWNyYWZ0Lm1vamFuZ19iYW5uZXJfcGF0dGVybgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1250, + "key": "minecraft:globe_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Z2xvYmVfYmFubmVyX3BhdHRlcm4=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0Lmdsb2JlX2Jhbm5lcl9wYXR0ZXJuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1251, + "key": "minecraft:piglin_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cGlnbGluX2Jhbm5lcl9wYXR0ZXJu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGl0ZW0ubWluZWNyYWZ0LnBpZ2xpbl9iYW5uZXJfcGF0dGVybgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1252, + "key": "minecraft:flow_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6Zmxvd19iYW5uZXJfcGF0dGVybg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LmZsb3dfYmFubmVyX3BhdHRlcm4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1253, + "key": "minecraft:guster_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6Z3VzdGVyX2Jhbm5lcl9wYXR0ZXJu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGl0ZW0ubWluZWNyYWZ0Lmd1c3Rlcl9iYW5uZXJfcGF0dGVybgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1254, + "key": "minecraft:field_masoned_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByZtaW5lY3JhZnQ6ZmllbGRfbWFzb25lZF9iYW5uZXJfcGF0dGVybg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAK2l0ZW0ubWluZWNyYWZ0LmZpZWxkX21hc29uZWRfYmFubmVyX3BhdHRlcm4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1255, + "key": "minecraft:bordure_indented_banner_pattern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByltaW5lY3JhZnQ6Ym9yZHVyZV9pbmRlbnRlZF9iYW5uZXJfcGF0dGVybg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALml0ZW0ubWluZWNyYWZ0LmJvcmR1cmVfaW5kZW50ZWRfYmFubmVyX3BhdHRlcm4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1256, + "key": "minecraft:goat_horn", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Z29hdF9ob3Ju", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmdvYXRfaG9ybgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1257, + "key": "minecraft:composter", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6Y29tcG9zdGVy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5jb21wb3N0ZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1258, + "key": "minecraft:barrel", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6YmFycmVs", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5iYXJyZWwA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1259, + "key": "minecraft:smoker", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6c21va2Vy", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5zbW9rZXIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1260, + "key": "minecraft:blast_furnace", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6Ymxhc3RfZnVybmFjZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5ibGFzdF9mdXJuYWNlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1261, + "key": "minecraft:cartography_table", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Y2FydG9ncmFwaHlfdGFibGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5jYXJ0b2dyYXBoeV90YWJsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1262, + "key": "minecraft:fletching_table", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6ZmxldGNoaW5nX3RhYmxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5mbGV0Y2hpbmdfdGFibGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1263, + "key": "minecraft:grindstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6Z3JpbmRzdG9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5ncmluZHN0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1264, + "key": "minecraft:smithing_table", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6c21pdGhpbmdfdGFibGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5zbWl0aGluZ190YWJsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1265, + "key": "minecraft:stonecutter", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c3RvbmVjdXR0ZXI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zdG9uZWN1dHRlcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1266, + "key": "minecraft:bell", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw5taW5lY3JhZnQ6YmVsbA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGJsb2NrLm1pbmVjcmFmdC5iZWxsAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1267, + "key": "minecraft:lantern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6bGFudGVybg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5sYW50ZXJuAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1268, + "key": "minecraft:soul_lantern", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6c291bF9sYW50ZXJu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5zb3VsX2xhbnRlcm4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1269, + "key": "minecraft:sweet_berries", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI+zMzNAA==", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c3dlZXRfYmVycmllcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGl0ZW0ubWluZWNyYWZ0LnN3ZWV0X2JlcnJpZXMA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1270, + "key": "minecraft:glow_berries", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0B2gQBAA==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQI+zMzNAA==", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z2xvd19iZXJyaWVz", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0Lmdsb3dfYmVycmllcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1271, + "key": "minecraft:campfire", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6Y2FtcGZpcmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5jYW1wZmlyZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1272, + "key": "minecraft:soul_campfire", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:container": "PgA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6c291bF9jYW1wZmlyZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5zb3VsX2NhbXBmaXJlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1273, + "key": "minecraft:shroomlight", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6c2hyb29tbGlnaHQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5zaHJvb21saWdodAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1274, + "key": "minecraft:honeycomb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6aG9uZXljb21i", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LmhvbmV5Y29tYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1275, + "key": "minecraft:bee_nest", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bees": "QAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxJtaW5lY3JhZnQ6YmVlX25lc3Q=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGJsb2NrLm1pbmVjcmFmdC5iZWVfbmVzdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1276, + "key": "minecraft:beehive", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:bees": "QAA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxFtaW5lY3JhZnQ6YmVlaGl2ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAF2Jsb2NrLm1pbmVjcmFmdC5iZWVoaXZlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1277, + "key": "minecraft:honey_bottle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "FkAAAAAC2gUAAQECEg==", + "minecraft:enchantments": "CgAB", + "minecraft:food": "FQY/mZmaAQ==", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6aG9uZXlfYm90dGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2l0ZW0ubWluZWNyYWZ0LmhvbmV5X2JvdHRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "ARA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=", + "minecraft:use_remainder": "FwGXCAAA" + } + }, + { + "id": 1278, + "key": "minecraft:honeycomb_block", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6aG9uZXljb21iX2Jsb2Nr", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5ob25leWNvbWJfYmxvY2sA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1279, + "key": "minecraft:lodestone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6bG9kZXN0b25l", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5sb2Rlc3RvbmUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1280, + "key": "minecraft:crying_obsidian", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6Y3J5aW5nX29ic2lkaWFu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5jcnlpbmdfb2JzaWRpYW4A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1281, + "key": "minecraft:blackstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6YmxhY2tzdG9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5ibGFja3N0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1282, + "key": "minecraft:blackstone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6YmxhY2tzdG9uZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5ibGFja3N0b25lX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1283, + "key": "minecraft:blackstone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6YmxhY2tzdG9uZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5ibGFja3N0b25lX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1284, + "key": "minecraft:gilded_blackstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6Z2lsZGVkX2JsYWNrc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5naWxkZWRfYmxhY2tzdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1285, + "key": "minecraft:polished_blackstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1286, + "key": "minecraft:polished_blackstone_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV9zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKGJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1287, + "key": "minecraft:polished_blackstone_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV9zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1288, + "key": "minecraft:chiseled_polished_blackstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByZtaW5lY3JhZnQ6Y2hpc2VsZWRfcG9saXNoZWRfYmxhY2tzdG9uZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALGJsb2NrLm1pbmVjcmFmdC5jaGlzZWxlZF9wb2xpc2hlZF9ibGFja3N0b25lAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1289, + "key": "minecraft:polished_blackstone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3M=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX2JyaWNrcwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1290, + "key": "minecraft:polished_blackstone_brick_slab", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByhtaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV9icmlja19zbGFi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALmJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX2JyaWNrX3NsYWIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1291, + "key": "minecraft:polished_blackstone_brick_stairs", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByptaW5lY3JhZnQ6cG9saXNoZWRfYmxhY2tzdG9uZV9icmlja19zdGFpcnM=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGJsb2NrLm1pbmVjcmFmdC5wb2xpc2hlZF9ibGFja3N0b25lX2JyaWNrX3N0YWlycwA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1292, + "key": "minecraft:cracked_polished_blackstone_bricks", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByxtaW5lY3JhZnQ6Y3JhY2tlZF9wb2xpc2hlZF9ibGFja3N0b25lX2JyaWNrcw==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMmJsb2NrLm1pbmVjcmFmdC5jcmFja2VkX3BvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1293, + "key": "minecraft:respawn_anchor", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6cmVzcGF3bl9hbmNob3I=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5yZXNwYXduX2FuY2hvcgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1294, + "key": "minecraft:candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxBtaW5lY3JhZnQ6Y2FuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFmJsb2NrLm1pbmVjcmFmdC5jYW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1295, + "key": "minecraft:white_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6d2hpdGVfY2FuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC53aGl0ZV9jYW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1296, + "key": "minecraft:orange_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6b3JhbmdlX2NhbmRsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5vcmFuZ2VfY2FuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1297, + "key": "minecraft:magenta_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6bWFnZW50YV9jYW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHmJsb2NrLm1pbmVjcmFmdC5tYWdlbnRhX2NhbmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1298, + "key": "minecraft:light_blue_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bGlnaHRfYmx1ZV9jYW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5saWdodF9ibHVlX2NhbmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1299, + "key": "minecraft:yellow_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6eWVsbG93X2NhbmRsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC55ZWxsb3dfY2FuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1300, + "key": "minecraft:lime_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6bGltZV9jYW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5saW1lX2NhbmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1301, + "key": "minecraft:pink_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6cGlua19jYW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5waW5rX2NhbmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1302, + "key": "minecraft:gray_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Z3JheV9jYW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ncmF5X2NhbmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1303, + "key": "minecraft:light_gray_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6bGlnaHRfZ3JheV9jYW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5saWdodF9ncmF5X2NhbmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1304, + "key": "minecraft:cyan_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y3lhbl9jYW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jeWFuX2NhbmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1305, + "key": "minecraft:purple_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6cHVycGxlX2NhbmRsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC5wdXJwbGVfY2FuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1306, + "key": "minecraft:blue_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Ymx1ZV9jYW5kbGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5ibHVlX2NhbmRsZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1307, + "key": "minecraft:brown_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YnJvd25fY2FuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5icm93bl9jYW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1308, + "key": "minecraft:green_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Z3JlZW5fY2FuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5ncmVlbl9jYW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1309, + "key": "minecraft:red_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6cmVkX2NhbmRsZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGmJsb2NrLm1pbmVjcmFmdC5yZWRfY2FuZGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1310, + "key": "minecraft:black_candle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6YmxhY2tfY2FuZGxl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5ibGFja19jYW5kbGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1311, + "key": "minecraft:small_amethyst_bud", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6c21hbGxfYW1ldGh5c3RfYnVk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5zbWFsbF9hbWV0aHlzdF9idWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1312, + "key": "minecraft:medium_amethyst_bud", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bWVkaXVtX2FtZXRoeXN0X2J1ZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5tZWRpdW1fYW1ldGh5c3RfYnVkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1313, + "key": "minecraft:large_amethyst_bud", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6bGFyZ2VfYW1ldGh5c3RfYnVk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC5sYXJnZV9hbWV0aHlzdF9idWQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1314, + "key": "minecraft:amethyst_cluster", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxptaW5lY3JhZnQ6YW1ldGh5c3RfY2x1c3Rlcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGJsb2NrLm1pbmVjcmFmdC5hbWV0aHlzdF9jbHVzdGVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1315, + "key": "minecraft:pointed_dripstone", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6cG9pbnRlZF9kcmlwc3RvbmU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC5wb2ludGVkX2RyaXBzdG9uZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1316, + "key": "minecraft:ochre_froglight", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxltaW5lY3JhZnQ6b2NocmVfZnJvZ2xpZ2h0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAH2Jsb2NrLm1pbmVjcmFmdC5vY2hyZV9mcm9nbGlnaHQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1317, + "key": "minecraft:verdant_froglight", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6dmVyZGFudF9mcm9nbGlnaHQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC52ZXJkYW50X2Zyb2dsaWdodAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1318, + "key": "minecraft:pearlescent_froglight", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6cGVhcmxlc2NlbnRfZnJvZ2xpZ2h0", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5wZWFybGVzY2VudF9mcm9nbGlnaHQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1319, + "key": "minecraft:frogspawn", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6ZnJvZ3NwYXdu", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWJsb2NrLm1pbmVjcmFmdC5mcm9nc3Bhd24A", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1320, + "key": "minecraft:echo_shard", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxRtaW5lY3JhZnQ6ZWNob19zaGFyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGWl0ZW0ubWluZWNyYWZ0LmVjaG9fc2hhcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1321, + "key": "minecraft:brush", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:damage": "AwA=", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6YnJ1c2g=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFGl0ZW0ubWluZWNyYWZ0LmJydXNoAA==", + "minecraft:lore": "CAA=", + "minecraft:max_damage": "AkA=", + "minecraft:max_stack_size": "AQE=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1322, + "key": "minecraft:netherite_upgrade_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "By1taW5lY3JhZnQ6bmV0aGVyaXRlX3VwZ3JhZGVfc21pdGhpbmdfdGVtcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMml0ZW0ubWluZWNyYWZ0Lm5ldGhlcml0ZV91cGdyYWRlX3NtaXRoaW5nX3RlbXBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1323, + "key": "minecraft:sentry_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "By1taW5lY3JhZnQ6c2VudHJ5X2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMml0ZW0ubWluZWNyYWZ0LnNlbnRyeV9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1324, + "key": "minecraft:dune_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByttaW5lY3JhZnQ6ZHVuZV9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGl0ZW0ubWluZWNyYWZ0LmR1bmVfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1325, + "key": "minecraft:coast_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByxtaW5lY3JhZnQ6Y29hc3RfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMWl0ZW0ubWluZWNyYWZ0LmNvYXN0X2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1326, + "key": "minecraft:wild_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByttaW5lY3JhZnQ6d2lsZF9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGl0ZW0ubWluZWNyYWZ0LndpbGRfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1327, + "key": "minecraft:ward_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByttaW5lY3JhZnQ6d2FyZF9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGl0ZW0ubWluZWNyYWZ0LndhcmRfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1328, + "key": "minecraft:eye_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByptaW5lY3JhZnQ6ZXllX2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAL2l0ZW0ubWluZWNyYWZ0LmV5ZV9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1329, + "key": "minecraft:vex_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByptaW5lY3JhZnQ6dmV4X2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAL2l0ZW0ubWluZWNyYWZ0LnZleF9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1330, + "key": "minecraft:tide_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByttaW5lY3JhZnQ6dGlkZV9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGl0ZW0ubWluZWNyYWZ0LnRpZGVfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1331, + "key": "minecraft:snout_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByxtaW5lY3JhZnQ6c25vdXRfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMWl0ZW0ubWluZWNyYWZ0LnNub3V0X2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1332, + "key": "minecraft:rib_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByptaW5lY3JhZnQ6cmliX2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAL2l0ZW0ubWluZWNyYWZ0LnJpYl9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1333, + "key": "minecraft:spire_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByxtaW5lY3JhZnQ6c3BpcmVfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMWl0ZW0ubWluZWNyYWZ0LnNwaXJlX2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQI=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1334, + "key": "minecraft:wayfinder_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BzBtaW5lY3JhZnQ6d2F5ZmluZGVyX2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUANWl0ZW0ubWluZWNyYWZ0LndheWZpbmRlcl9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1335, + "key": "minecraft:shaper_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "By1taW5lY3JhZnQ6c2hhcGVyX2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMml0ZW0ubWluZWNyYWZ0LnNoYXBlcl9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1336, + "key": "minecraft:silence_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "By5taW5lY3JhZnQ6c2lsZW5jZV9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAM2l0ZW0ubWluZWNyYWZ0LnNpbGVuY2VfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQM=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1337, + "key": "minecraft:raiser_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "By1taW5lY3JhZnQ6cmFpc2VyX2FybW9yX3RyaW1fc21pdGhpbmdfdGVtcGxhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMml0ZW0ubWluZWNyYWZ0LnJhaXNlcl9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1338, + "key": "minecraft:host_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByttaW5lY3JhZnQ6aG9zdF9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGl0ZW0ubWluZWNyYWZ0Lmhvc3RfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1339, + "key": "minecraft:flow_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByttaW5lY3JhZnQ6Zmxvd19hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGl0ZW0ubWluZWNyYWZ0LmZsb3dfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1340, + "key": "minecraft:bolt_armor_trim_smithing_template", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByttaW5lY3JhZnQ6Ym9sdF9hcm1vcl90cmltX3NtaXRoaW5nX3RlbXBsYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAMGl0ZW0ubWluZWNyYWZ0LmJvbHRfYXJtb3JfdHJpbV9zbWl0aGluZ190ZW1wbGF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1341, + "key": "minecraft:angler_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6YW5nbGVyX3BvdHRlcnlfc2hlcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LmFuZ2xlcl9wb3R0ZXJ5X3NoZXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1342, + "key": "minecraft:archer_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6YXJjaGVyX3BvdHRlcnlfc2hlcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LmFyY2hlcl9wb3R0ZXJ5X3NoZXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1343, + "key": "minecraft:arms_up_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6YXJtc191cF9wb3R0ZXJ5X3NoZXJk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGl0ZW0ubWluZWNyYWZ0LmFybXNfdXBfcG90dGVyeV9zaGVyZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1344, + "key": "minecraft:blade_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6YmxhZGVfcG90dGVyeV9zaGVyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LmJsYWRlX3BvdHRlcnlfc2hlcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1345, + "key": "minecraft:brewer_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6YnJld2VyX3BvdHRlcnlfc2hlcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LmJyZXdlcl9wb3R0ZXJ5X3NoZXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1346, + "key": "minecraft:burn_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6YnVybl9wb3R0ZXJ5X3NoZXJk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LmJ1cm5fcG90dGVyeV9zaGVyZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1347, + "key": "minecraft:danger_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZGFuZ2VyX3BvdHRlcnlfc2hlcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LmRhbmdlcl9wb3R0ZXJ5X3NoZXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1348, + "key": "minecraft:explorer_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6ZXhwbG9yZXJfcG90dGVyeV9zaGVyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWl0ZW0ubWluZWNyYWZ0LmV4cGxvcmVyX3BvdHRlcnlfc2hlcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1349, + "key": "minecraft:flow_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6Zmxvd19wb3R0ZXJ5X3NoZXJk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0LmZsb3dfcG90dGVyeV9zaGVyZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1350, + "key": "minecraft:friend_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZnJpZW5kX3BvdHRlcnlfc2hlcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LmZyaWVuZF9wb3R0ZXJ5X3NoZXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1351, + "key": "minecraft:guster_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6Z3VzdGVyX3BvdHRlcnlfc2hlcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0Lmd1c3Rlcl9wb3R0ZXJ5X3NoZXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1352, + "key": "minecraft:heart_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6aGVhcnRfcG90dGVyeV9zaGVyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LmhlYXJ0X3BvdHRlcnlfc2hlcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1353, + "key": "minecraft:heartbreak_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByJtaW5lY3JhZnQ6aGVhcnRicmVha19wb3R0ZXJ5X3NoZXJk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJ2l0ZW0ubWluZWNyYWZ0LmhlYXJ0YnJlYWtfcG90dGVyeV9zaGVyZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1354, + "key": "minecraft:howl_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6aG93bF9wb3R0ZXJ5X3NoZXJk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWl0ZW0ubWluZWNyYWZ0Lmhvd2xfcG90dGVyeV9zaGVyZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1355, + "key": "minecraft:miner_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6bWluZXJfcG90dGVyeV9zaGVyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0Lm1pbmVyX3BvdHRlcnlfc2hlcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1356, + "key": "minecraft:mourner_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6bW91cm5lcl9wb3R0ZXJ5X3NoZXJk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGl0ZW0ubWluZWNyYWZ0Lm1vdXJuZXJfcG90dGVyeV9zaGVyZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1357, + "key": "minecraft:plenty_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6cGxlbnR5X3BvdHRlcnlfc2hlcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnBsZW50eV9wb3R0ZXJ5X3NoZXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1358, + "key": "minecraft:prize_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6cHJpemVfcG90dGVyeV9zaGVyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LnByaXplX3BvdHRlcnlfc2hlcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1359, + "key": "minecraft:scrape_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6c2NyYXBlX3BvdHRlcnlfc2hlcmQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2l0ZW0ubWluZWNyYWZ0LnNjcmFwZV9wb3R0ZXJ5X3NoZXJkAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1360, + "key": "minecraft:sheaf_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c2hlYWZfcG90dGVyeV9zaGVyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LnNoZWFmX3BvdHRlcnlfc2hlcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1361, + "key": "minecraft:shelter_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6c2hlbHRlcl9wb3R0ZXJ5X3NoZXJk", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGl0ZW0ubWluZWNyYWZ0LnNoZWx0ZXJfcG90dGVyeV9zaGVyZAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1362, + "key": "minecraft:skull_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c2t1bGxfcG90dGVyeV9zaGVyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LnNrdWxsX3BvdHRlcnlfc2hlcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1363, + "key": "minecraft:snort_pottery_sherd", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6c25vcnRfcG90dGVyeV9zaGVyZA==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIml0ZW0ubWluZWNyYWZ0LnNub3J0X3BvdHRlcnlfc2hlcmQA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1364, + "key": "minecraft:copper_grate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxZtaW5lY3JhZnQ6Y29wcGVyX2dyYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHGJsb2NrLm1pbmVjcmFmdC5jb3BwZXJfZ3JhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1365, + "key": "minecraft:exposed_copper_grate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6ZXhwb3NlZF9jb3BwZXJfZ3JhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2NvcHBlcl9ncmF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1366, + "key": "minecraft:weathered_copper_grate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByBtaW5lY3JhZnQ6d2VhdGhlcmVkX2NvcHBlcl9ncmF0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJmJsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY29wcGVyX2dyYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1367, + "key": "minecraft:oxidized_copper_grate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6b3hpZGl6ZWRfY29wcGVyX2dyYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jb3BwZXJfZ3JhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1368, + "key": "minecraft:waxed_copper_grate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxxtaW5lY3JhZnQ6d2F4ZWRfY29wcGVyX2dyYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAImJsb2NrLm1pbmVjcmFmdC53YXhlZF9jb3BwZXJfZ3JhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1369, + "key": "minecraft:waxed_exposed_copper_grate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jb3BwZXJfZ3JhdGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2NvcHBlcl9ncmF0ZQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1370, + "key": "minecraft:waxed_weathered_copper_grate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByZtaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2NvcHBlcl9ncmF0ZQ==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUALGJsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY29wcGVyX2dyYXRlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1371, + "key": "minecraft:waxed_oxidized_copper_grate", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByVtaW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY29wcGVyX2dyYXRl", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAK2Jsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jb3BwZXJfZ3JhdGUA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1372, + "key": "minecraft:copper_bulb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxVtaW5lY3JhZnQ6Y29wcGVyX2J1bGI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAG2Jsb2NrLm1pbmVjcmFmdC5jb3BwZXJfYnVsYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1373, + "key": "minecraft:exposed_copper_bulb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx1taW5lY3JhZnQ6ZXhwb3NlZF9jb3BwZXJfYnVsYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAI2Jsb2NrLm1pbmVjcmFmdC5leHBvc2VkX2NvcHBlcl9idWxiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1374, + "key": "minecraft:weathered_copper_bulb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx9taW5lY3JhZnQ6d2VhdGhlcmVkX2NvcHBlcl9idWxi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJWJsb2NrLm1pbmVjcmFmdC53ZWF0aGVyZWRfY29wcGVyX2J1bGIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1375, + "key": "minecraft:oxidized_copper_bulb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bx5taW5lY3JhZnQ6b3hpZGl6ZWRfY29wcGVyX2J1bGI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAJGJsb2NrLm1pbmVjcmFmdC5veGlkaXplZF9jb3BwZXJfYnVsYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1376, + "key": "minecraft:waxed_copper_bulb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6d2F4ZWRfY29wcGVyX2J1bGI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIWJsb2NrLm1pbmVjcmFmdC53YXhlZF9jb3BwZXJfYnVsYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1377, + "key": "minecraft:waxed_exposed_copper_bulb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByNtaW5lY3JhZnQ6d2F4ZWRfZXhwb3NlZF9jb3BwZXJfYnVsYg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKWJsb2NrLm1pbmVjcmFmdC53YXhlZF9leHBvc2VkX2NvcHBlcl9idWxiAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1378, + "key": "minecraft:waxed_weathered_copper_bulb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByVtaW5lY3JhZnQ6d2F4ZWRfd2VhdGhlcmVkX2NvcHBlcl9idWxi", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAK2Jsb2NrLm1pbmVjcmFmdC53YXhlZF93ZWF0aGVyZWRfY29wcGVyX2J1bGIA", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1379, + "key": "minecraft:waxed_oxidized_copper_bulb", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "ByRtaW5lY3JhZnQ6d2F4ZWRfb3hpZGl6ZWRfY29wcGVyX2J1bGI=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAKmJsb2NrLm1pbmVjcmFmdC53YXhlZF9veGlkaXplZF9jb3BwZXJfYnVsYgA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1380, + "key": "minecraft:trial_spawner", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxdtaW5lY3JhZnQ6dHJpYWxfc3Bhd25lcg==", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWJsb2NrLm1pbmVjcmFmdC50cmlhbF9zcGF3bmVyAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1381, + "key": "minecraft:trial_key", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxNtaW5lY3JhZnQ6dHJpYWxfa2V5", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAGGl0ZW0ubWluZWNyYWZ0LnRyaWFsX2tleQA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1382, + "key": "minecraft:ominous_trial_key", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxttaW5lY3JhZnQ6b21pbm91c190cmlhbF9rZXk=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAIGl0ZW0ubWluZWNyYWZ0Lm9taW5vdXNfdHJpYWxfa2V5AA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1383, + "key": "minecraft:vault", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "Bw9taW5lY3JhZnQ6dmF1bHQ=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAFWJsb2NrLm1pbmVjcmFmdC52YXVsdAA=", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:rarity": "CQA=", + "minecraft:repair_cost": "EQA=" + } + }, + { + "id": 1384, + "key": "minecraft:ominous_bottle", + "components": { + "minecraft:attribute_modifiers": "DQAB", + "minecraft:consumable": "Fj/MzM0C2QQAAQSMCA==", + "minecraft:enchantments": "CgAB", + "minecraft:item_model": "BxhtaW5lY3JhZnQ6b21pbm91c19ib3R0bGU=", + "minecraft:item_name": "BgoIAAl0cmFuc2xhdGUAHWl0ZW0ubWluZWNyYWZ0Lm9taW5vdXNfYm90dGxlAA==", + "minecraft:lore": "CAA=", + "minecraft:max_stack_size": "AUA=", + "minecraft:ominous_bottle_amplifier": "MwA=", + "minecraft:rarity": "CQE=", + "minecraft:repair_cost": "EQA=" + } + } +] diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index e1eafe2c5..452312f88 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit e1eafe2c5304012d23acba80659459f7868fe2b1 +Subproject commit 452312f88317cce019b8f336f485ffa7b2c19557 From 2019e53bad109d79077b544cd9d9ec15e8f69472 Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:35:03 +0100 Subject: [PATCH 487/897] Feature: Accurate Java packet ticking (#5121) * Use proposed mcpl ticking PR * Remove more not needed overrides * Bump mcpl * Fix missing import * Bump mcpl * Switch to official version --------- Co-authored-by: chris --- .../platform/spigot/GeyserSpigotInjector.java | 2 +- .../java/org/geysermc/geyser/GeyserImpl.java | 3 -- .../geyser/network/UpstreamPacketHandler.java | 2 +- .../geyser/network/netty/LocalSession.java | 7 +-- .../registry/PacketTranslatorRegistry.java | 6 +-- .../geyser/session/GeyserSession.java | 49 +++++++++---------- .../entity/SkullBlockEntityTranslator.java | 7 +-- .../translator/protocol/PacketTranslator.java | 1 + .../entity/player/BedrockEmoteTranslator.java | 7 +-- .../java/JavaCustomPayloadTranslator.java | 6 --- .../java/JavaDisconnectTranslator.java | 5 -- .../java/JavaKeepAliveTranslator.java | 5 -- .../java/JavaLoginDisconnectTranslator.java | 5 -- .../java/JavaSelectKnownPacksTranslator.java | 6 --- .../JavaStartConfigurationTranslator.java | 6 --- .../player/JavaCookieRequestTranslator.java | 4 +- gradle/libs.versions.toml | 2 +- 17 files changed, 41 insertions(+), 82 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index a3402a752..9f7e21579 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -178,7 +178,7 @@ public class GeyserSpigotInjector extends GeyserInjector { MinecraftProtocol protocol = new MinecraftProtocol(); LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().address(), bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress, - InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper()); + InetAddress.getLoopbackAddress().getHostAddress(), protocol, Runnable::run); session.connect(); } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 0a8222f8d..065c1f0cc 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -414,9 +414,6 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { } } - // Ensure that PacketLib does not create an event loop for handling packets; we'll do that ourselves - TcpSession.USE_EVENT_LOOP_FOR_PACKETS = false; - pendingMicrosoftAuthentication = new PendingMicrosoftAuthentication(config.getPendingAuthenticationTimeout()); this.newsHandler = new NewsHandler(BRANCH, this.buildNumber()); 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 0cf161c6a..dfebb93dc 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -96,7 +96,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } private PacketSignal translateAndDefault(BedrockPacket packet) { - Registries.BEDROCK_PACKET_TRANSLATORS.translate(packet.getClass(), packet, session); + Registries.BEDROCK_PACKET_TRANSLATORS.translate(packet.getClass(), packet, session, false); return PacketSignal.HANDLED; // PacketSignal.UNHANDLED will log a WARN publicly } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 739c1c25e..3b86a0bf9 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -59,6 +59,7 @@ import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; /** @@ -72,11 +73,11 @@ public final class LocalSession extends TcpSession { private final String clientIp; private final PacketCodecHelper codecHelper; - public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, MinecraftCodecHelper codecHelper) { - super(host, port, protocol); + public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, Executor packetHandlerExecutor) { + super(host, port, protocol, packetHandlerExecutor); this.targetAddress = targetAddress; this.clientIp = clientIp; - this.codecHelper = codecHelper; + this.codecHelper = protocol.createHelper(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java index b31f2b4f0..e81935edf 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java @@ -56,15 +56,15 @@ public class PacketTranslatorRegistry extends AbstractMappedRegistry boolean translate(Class clazz, P packet, GeyserSession session) { + public

    boolean translate(Class clazz, P packet, GeyserSession session, boolean canRunImmediately) { if (session.getUpstream().isClosed() || session.isClosed()) { return false; } PacketTranslator

    translator = (PacketTranslator

    ) this.mappings.get(clazz); if (translator != null) { - EventLoop eventLoop = session.getEventLoop(); - if (!translator.shouldExecuteInEventLoop() || eventLoop.inEventLoop()) { + EventLoop eventLoop = session.getTickEventLoop(); + if (canRunImmediately || !translator.shouldExecuteInEventLoop() || eventLoop.inEventLoop()) { translate0(session, translator, packet); } else { eventLoop.execute(() -> translate0(session, translator, packet)); 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 cfb981b7d..b4a8e6203 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -253,7 +253,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * The loop where all packets and ticking is processed to prevent concurrency issues. * If this is manually called, ensure that any exceptions are properly handled. */ - private final EventLoop eventLoop; + private final EventLoop tickEventLoop; @Setter private AuthData authData; private BedrockClientData clientData; @@ -653,10 +653,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private MinecraftProtocol protocol; - public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop eventLoop) { + public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop tickEventLoop) { this.geyser = geyser; this.upstream = new UpstreamSession(bedrockServerSession); - this.eventLoop = eventLoop; + this.tickEventLoop = tickEventLoop; this.erosionHandler = new GeyserboundHandshakePacketHandler(this); @@ -947,17 +947,17 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { boolean floodgate = this.remoteServer.authType() == AuthType.FLOODGATE; // Start ticking - tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); + tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); TcpSession downstream; if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP downstream = new LocalSession(this.remoteServer.address(), this.remoteServer.port(), geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), - this.protocol, this.protocol.createHelper()); + this.protocol, tickEventLoop); this.downstream = new DownstreamSession(downstream); } else { - downstream = new TcpClientSession(this.remoteServer.address(), this.remoteServer.port(), this.protocol); + downstream = new TcpClientSession(this.remoteServer.address(), this.remoteServer.port(), "0.0.0.0", 0, this.protocol, null, tickEventLoop); this.downstream = new DownstreamSession(downstream); boolean resolveSrv = false; @@ -1143,7 +1143,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public void packetReceived(Session session, Packet packet) { - Registries.JAVA_PACKET_TRANSLATORS.translate(packet.getClass(), packet, GeyserSession.this); + Registries.JAVA_PACKET_TRANSLATORS.translate(packet.getClass(), packet, GeyserSession.this, true); } @Override @@ -1213,10 +1213,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Moves task to the session event loop if already not in it. Otherwise, the task is automatically ran. */ public void ensureInEventLoop(Runnable runnable) { - if (eventLoop.inEventLoop()) { - runnable.run(); + if (tickEventLoop.inEventLoop()) { + executeRunnable(runnable); return; } + executeInEventLoop(runnable); } @@ -1224,15 +1225,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Executes a task and prints a stack trace if an error occurs. */ public void executeInEventLoop(Runnable runnable) { - eventLoop.execute(() -> { - try { - runnable.run(); - } catch (ErosionCancellationException e) { - geyser.getLogger().debug("Caught ErosionCancellationException"); - } catch (Throwable e) { - geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); - } - }); + tickEventLoop.execute(() -> executeRunnable(runnable)); } /** @@ -1241,19 +1234,25 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * The task will not run if the session is closed. */ public ScheduledFuture scheduleInEventLoop(Runnable runnable, long duration, TimeUnit timeUnit) { - return eventLoop.schedule(() -> { - try { + return tickEventLoop.schedule(() -> { + executeRunnable(() -> { if (!closed) { runnable.run(); } - } catch (ErosionCancellationException e) { - geyser.getLogger().debug("Caught ErosionCancellationException"); - } catch (Throwable e) { - geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); - } + }); }, duration, timeUnit); } + private void executeRunnable(Runnable runnable) { + try { + runnable.run(); + } catch (ErosionCancellationException e) { + geyser.getLogger().debug("Caught ErosionCancellationException"); + } catch (Throwable e) { + geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); + } + } + /** * Called every 50 milliseconds - one Minecraft tick. */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index be0f8560f..10d45658e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -131,11 +131,8 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements session.getGeyser().getLogger().debug("Custom skull with invalid profile tag: " + blockPosition + " " + javaNbt); return; } - if (session.getEventLoop().inEventLoop()) { - putSkull(session, blockPosition, uuid, texturesProperty, blockState); - } else { - session.executeInEventLoop(() -> putSkull(session, blockPosition, uuid, texturesProperty, blockState)); - } + + session.ensureInEventLoop(() -> putSkull(session, blockPosition, uuid, texturesProperty, blockState)); }); // We don't have the textures yet, so we can't determine if a custom block was defined for this skull diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/PacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/PacketTranslator.java index d49cdd6d0..da5cd5cb0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/PacketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/PacketTranslator.java @@ -34,6 +34,7 @@ public abstract class PacketTranslator { /** * Determines if this packet should be handled in the session's event loop. This should generally be true - * only when the packet has to be executed immediately should it be false. + * This method is only used for bedrock packets, java packets have a more sophisticated system through MCProtocolLib. */ public boolean shouldExecuteInEventLoop() { return true; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockEmoteTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockEmoteTranslator.java index 7a37aa72e..07af4ddc4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockEmoteTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockEmoteTranslator.java @@ -61,11 +61,8 @@ public class BedrockEmoteTranslator extends PacketTranslator { for (GeyserSession otherSession : session.getGeyser().getSessionManager().getSessions().values()) { if (otherSession != session) { if (otherSession.isClosed()) continue; - if (otherSession.getEventLoop().inEventLoop()) { - playEmote(otherSession, javaId, xuid, emote); - } else { - otherSession.executeInEventLoop(() -> playEmote(otherSession, javaId, xuid, emote)); - } + + otherSession.ensureInEventLoop(() -> playEmote(otherSession, javaId, xuid, emote)); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java index 811449a99..c3108167b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java @@ -140,10 +140,4 @@ public class JavaCustomPayloadTranslator extends PacketTranslator { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 029e444a5..ebd378d57 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20241203.200249-19" protocol-codec = "3.0.0.Beta5-20241203.200249-19" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21.2-20241107.110329-3" +mcprotocollib = "1.21.2-20241127.160724-5" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 92c7f9895b7fb0055d93433e04727c90ce9d37f6 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 5 Dec 2024 20:45:56 +0800 Subject: [PATCH 488/897] Implement new boat types --- .../org/geysermc/geyser/entity/EntityDefinitions.java | 4 ++++ .../java/org/geysermc/geyser/entity/type/BoatEntity.java | 9 ++++++++- .../java/org/geysermc/geyser/network/GameProtocol.java | 5 +++++ .../protocol/java/level/JavaBlockEventTranslator.java | 5 +++++ gradle/libs.versions.toml | 2 +- 5 files changed, 23 insertions(+), 2 deletions(-) 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 f48cf4053..8e485e14b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -238,6 +238,8 @@ public final class EntityDefinitions { public static final EntityDefinition OAK_CHEST_BOAT; public static final EntityDefinition OCELOT; public static final EntityDefinition PAINTING; + public static final EntityDefinition PALE_OAK_BOAT; + public static final EntityDefinition PALE_OAK_CHEST_BOAT; public static final EntityDefinition PANDA; public static final EntityDefinition PARROT; public static final EntityDefinition PHANTOM; @@ -593,6 +595,7 @@ public final class EntityDefinitions { 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); + PALE_OAK_BOAT = buildBoat(boatBase, EntityType.PALE_OAK_BOAT, BoatEntity.BoatVariant.PALE_OAK); EntityDefinition chestBoatBase = EntityDefinition.inherited(null, boatBase) .build(); @@ -606,6 +609,7 @@ public final class EntityDefinitions { 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); + PALE_OAK_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.PALE_OAK_CHEST_BOAT, BoatEntity.BoatVariant.PALE_OAK); } EntityDefinition livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase) 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 86accea17..6c7b6e122 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 @@ -34,6 +34,7 @@ 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.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -77,6 +78,11 @@ public class BoatEntity extends Entity implements Leashable, Tickable { super(session, entityId, geyserId, uuid, definition, position.add(0d, definition.offset(), 0d), motion, yaw + 90, 0, yaw + 90); this.variant = variant; + // TODO remove once 1.21.40 is dropped + if (variant == BoatVariant.PALE_OAK && GameProtocol.isPreWinterDrop(session)) { + variant = BoatVariant.BIRCH; + } + 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+ @@ -238,7 +244,8 @@ public class BoatEntity extends Entity implements Leashable, Tickable { 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); + CHERRY(Items.CHERRY_BOAT, Items.CHERRY_CHEST_BOAT), + PALE_OAK(Items.PALE_OAK_BOAT, Items.PALE_OAK_CHEST_BOAT); private final Item pickItem; final Item chestPickItem; diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index c762cf5d3..bb7032d25 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -30,6 +30,7 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; import org.geysermc.mcprotocollib.protocol.codec.PacketCodec; @@ -84,6 +85,10 @@ public final class GameProtocol { /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ + public static boolean isPreWinterDrop(GeyserSession session) { + return session.getUpstream().getProtocolVersion() == Bedrock_v748.CODEC.getProtocolVersion(); + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java index c94468c17..917075976 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java @@ -62,6 +62,11 @@ public class JavaBlockEventTranslator extends PacketTranslator Date: Fri, 6 Dec 2024 21:18:42 +0800 Subject: [PATCH 489/897] start on implementing creaking --- README.md | 2 +- .../fabric/src/main/resources/fabric.mod.json | 2 +- ....modrinth-uploading-conventions.gradle.kts | 2 +- .../geyser/entity/EntityDefinitions.java | 9 ++ .../type/living/monster/CreakingEntity.java | 87 +++++++++++++++++++ .../geyser/session/GeyserSession.java | 5 +- .../entity/JavaEntityEventTranslator.java | 6 ++ gradle/libs.versions.toml | 2 +- 8 files changed, 110 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 83a1d5c0b..9f5c9d8d5 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.21.40 - 1.21.50 and Minecraft Java 1.21.2/1.21.3. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.21.40 - 1.21.50 and Minecraft Java 1.21.4. 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/src/main/resources/fabric.mod.json b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json index a801eb207..4f50768f4 100644 --- a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json @@ -25,6 +25,6 @@ "depends": { "fabricloader": ">=0.16.7", "fabric": "*", - "minecraft": ">=1.21.2" + "minecraft": ">=1.21.4" } } 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 59f85d182..4f445f455 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 @@ -13,7 +13,7 @@ modrinth { versionNumber.set(projectVersion(project)) versionType.set("beta") changelog.set(System.getenv("CHANGELOG") ?: "") - gameVersions.addAll("1.21.2", libs.minecraft.get().version as String) + gameVersions.add(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/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index 8e485e14b..d284cba3f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -684,6 +684,15 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setActive) .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setIsTearingDown) .addTranslator(MetadataType.OPTIONAL_POSITION, CreakingEntity::setHomePos) + .properties(new GeyserEntityProperties.Builder() + .addEnum("minecraft:creaking_state", + "neutral", + "hostile_observed", + "hostile_unobserved", + "twitching", + "crumbling") + .addInt("minecraft:creaking_swaying_ticks", 0, 6) + .build()) .build(); CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase) .type(EntityType.CREEPER) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java index 8cfaf7428..a1861ca69 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java @@ -27,6 +27,12 @@ package org.geysermc.geyser.entity.type.living.monster; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.protocol.bedrock.data.LevelEvent; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; @@ -36,19 +42,100 @@ import java.util.Optional; import java.util.UUID; public class CreakingEntity extends MonsterEntity { + + private Vector3i homePosition; + public CreakingEntity(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 + protected void initializeMetadata() { + super.initializeMetadata(); + setFlag(EntityFlag.HIDDEN_WHEN_INVISIBLE, true); + setFlag(EntityFlag.FIRE_IMMUNE, true); + } + + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add("minecraft:creaking_state", "neutral"); + propertyManager.add("minecraft:creaking_swaying_ticks", 0); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + public void setCanMove(EntityMetadata> booleanEntityMetadata) { + if (booleanEntityMetadata.getValue()) { + setFlag(EntityFlag.BODY_ROTATION_BLOCKED, false); + + // unfreeze sound? SoundEvent.UNFREEZE + propertyManager.add("minecraft:creaking_state", "hostile_unobserved"); + updateBedrockEntityProperties(); + } else { + setFlag(EntityFlag.BODY_ROTATION_BLOCKED, true); + propertyManager.add("minecraft:creaking_state", "hostile_observed"); + updateBedrockEntityProperties(); + } + + GeyserImpl.getInstance().getLogger().warning("set can move; " + booleanEntityMetadata.toString()); } public void setActive(EntityMetadata> booleanEntityMetadata) { + if (booleanEntityMetadata.getValue()) { +// LevelSoundEvent2Packet addEntityPacket = new LevelSoundEvent2Packet(); +// addEntityPacket.setIdentifier("minecraft:creaking"); +// addEntityPacket.setPosition(position); +// addEntityPacket.setBabySound(false); +// addEntityPacket.setSound(SoundEvent.ACTIVATE); +// addEntityPacket.setExtraData(-1); +// session.sendUpstreamPacket(addEntityPacket); + +// setFlag(EntityFlag.HIDDEN_WHEN_INVISIBLE, true); +// setFlag(EntityFlag.BODY_ROTATION_BLOCKED, true); + } else { + propertyManager.add("minecraft:creaking_state", "neutral"); + } + GeyserImpl.getInstance().getLogger().warning("set active; " + booleanEntityMetadata.toString()); } public void setIsTearingDown(EntityMetadata> booleanEntityMetadata) { + GeyserImpl.getInstance().getLogger().warning("set isTearingDown; " + booleanEntityMetadata.toString()); + if (booleanEntityMetadata.getValue()) { + propertyManager.add("minecraft:creaking_state", "crumbling"); + updateBedrockEntityProperties(); +// LevelEventPacket levelEventPacket = new LevelEventPacket(); +// levelEventPacket.setType(ParticleType.CREAKING_CRUMBLE); +// levelEventPacket.setPosition(position); +// levelEventPacket.setData(0); + } } public void setHomePos(EntityMetadata,? extends MetadataType>> optionalEntityMetadata) { + if (optionalEntityMetadata.getValue().isPresent()) { + this.homePosition = optionalEntityMetadata.getValue().get(); + } else { + this.homePosition = null; + } + } + + public void createParticleBeam() { + if (this.homePosition != null) { + LevelEventGenericPacket levelEventGenericPacket = new LevelEventGenericPacket(); + levelEventGenericPacket.setType(LevelEvent.PARTICLE_CREAKING_HEART_TRIAL); + levelEventGenericPacket.setTag( + NbtMap.builder() + .putInt("CreakingAmount", 0) + .putFloat("CreakingX", position.getX()) + .putFloat("CreakingY", position.getY()) + .putFloat("CreakingZ", position.getZ()) + .putInt("HeartAmount", 20) + .putFloat("HeartX", homePosition.getX()) + .putFloat("HeartY", homePosition.getY()) + .putFloat("HeartZ", homePosition.getZ()) + .build() + ); + + GeyserImpl.getInstance().getLogger().warning(levelEventGenericPacket.toString()); + session.sendUpstreamPacket(levelEventGenericPacket); + } } } 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 d6fe6739b..cedf9ab66 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1153,7 +1153,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public void packetError(PacketErrorEvent event) { - geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.downstream_error", event.getCause().getMessage())); + geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.downstream_error", + (event.getPacketClass() != null ? "(" + event.getPacketClass().getSimpleName() + ")" : "") + + event.getCause().getMessage()) + ); if (geyser.getConfig().isDebugMode()) event.getCause().printStackTrace(); event.setSuppress(true); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index 6c2e02cd3..d52a2b501 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -43,6 +43,7 @@ import org.geysermc.geyser.entity.type.EvokerFangsEntity; import org.geysermc.geyser.entity.type.FishingHookEntity; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.living.animal.ArmadilloEntity; +import org.geysermc.geyser.entity.type.living.monster.CreakingEntity; import org.geysermc.geyser.entity.type.living.monster.WardenEntity; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; @@ -288,6 +289,11 @@ public class JavaEntityEventTranslator extends PacketTranslator Date: Sun, 8 Dec 2024 04:18:07 +0800 Subject: [PATCH 490/897] Some minor fixes, fix own block breaking progress not showing on the player's end --- .../geyser/entity/EntityDefinitions.java | 4 +- .../living/animal/tameable/WolfEntity.java | 9 ++-- .../type/living/monster/CreakingEntity.java | 21 +++++++--- .../updater/AnvilInventoryUpdater.java | 6 +-- .../geyser/session/cache/TagCache.java | 31 ++++++++++++++ .../session/cache/tags/GeyserHolderSet.java | 22 ---------- .../player/input/BedrockBlockActions.java | 4 +- .../java/JavaSelectKnownPacksTranslator.java | 2 +- .../entity/JavaEntityEventTranslator.java | 3 ++ .../level/JavaBlockDestructionTranslator.java | 7 +++- .../org/geysermc/geyser/util/BlockUtils.java | 41 +++++++------------ 11 files changed, 79 insertions(+), 71 deletions(-) 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 d284cba3f..dab8cb6e7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -685,13 +685,13 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setIsTearingDown) .addTranslator(MetadataType.OPTIONAL_POSITION, CreakingEntity::setHomePos) .properties(new GeyserEntityProperties.Builder() - .addEnum("minecraft:creaking_state", + .addEnum(CreakingEntity.CREAKING_STATE, "neutral", "hostile_observed", "hostile_unobserved", "twitching", "crumbling") - .addInt("minecraft:creaking_swaying_ticks", 0, 6) + .addInt(CreakingEntity.CREAKING_SWAYING_TICKS, 0, 6) .build()) .build(); CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase) 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 67e5788c6..1b06f3860 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 @@ -38,8 +38,6 @@ 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.registry.JavaRegistries; -import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; @@ -62,7 +60,7 @@ import java.util.UUID; public class WolfEntity extends TameableEntity { private byte collarColor = 14; // Red - default - private GeyserHolderSet repairableItems = null; + private HolderSet repairableItems = null; private boolean isCurseOfBinding = false; public WolfEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -130,8 +128,7 @@ public class WolfEntity extends TameableEntity { public void setBody(ItemStack stack) { super.setBody(stack); isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); - HolderSet set = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE); - repairableItems = GeyserHolderSet.convertHolderSet(JavaRegistries.ITEM, set); + repairableItems = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE); } @Override @@ -166,7 +163,7 @@ public class WolfEntity extends TameableEntity { return InteractiveTag.REMOVE_WOLF_ARMOR; } if (getFlag(EntityFlag.SITTING) && - session.getTagCache().is(repairableItems, itemInHand.asItem()) && + session.getTagCache().isItem(repairableItems, itemInHand.asItem()) && this.body.isValid() && this.body.getTag() != null && this.body.getTag().getInt("Damage") > 0) { return InteractiveTag.REPAIR_WOLF_ARMOR; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java index a1861ca69..1f2ddc37c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java @@ -41,10 +41,21 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataTyp import java.util.Optional; import java.util.UUID; +/* + * Relevant bits: + * - LevelSoundEvent2Packet(sound=SPAWN, position=(233.5, 112.295, 4717.5), extraData=-1, identifier=minecraft:creaking, babySound=false, relativeVolumeDisabled=false) + * - [11:29:34:768] [CLIENT BOUND] - LevelSoundEvent2Packet(sound=CREAKING_HEART_SPAWN, position=(233.0, 110.0, 4717.0), extraData=-1, identifier=minecraft:creaking, babySound=false, relativeVolumeDisabled=false) + * - [11:29:34:768] [CLIENT BOUND] - LevelSoundEvent2Packet(sound=CREAKING_HEART_SPAWN, position=(235.0, 113.0, 4722.0), extraData=13734, identifier=, babySound=false, relativeVolumeDisabled=false) + * - [11:29:34:768] [CLIENT BOUND] - LevelEventPacket(type=PARTICLE_MOB_BLOCK_SPAWN, position=(233.0, 110.0, 4717.0), data=769) + * + */ public class CreakingEntity extends MonsterEntity { private Vector3i homePosition; + public static final String CREAKING_STATE = "minecraft:creaking_state"; + public static final String CREAKING_SWAYING_TICKS = "minecraft:creaking_swaying_ticks"; + public CreakingEntity(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); } @@ -58,7 +69,7 @@ public class CreakingEntity extends MonsterEntity { @Override public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { - propertyManager.add("minecraft:creaking_state", "neutral"); + propertyManager.add(CREAKING_STATE, "neutral"); propertyManager.add("minecraft:creaking_swaying_ticks", 0); propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); } @@ -68,11 +79,11 @@ public class CreakingEntity extends MonsterEntity { setFlag(EntityFlag.BODY_ROTATION_BLOCKED, false); // unfreeze sound? SoundEvent.UNFREEZE - propertyManager.add("minecraft:creaking_state", "hostile_unobserved"); + propertyManager.add(CREAKING_STATE, "hostile_unobserved"); updateBedrockEntityProperties(); } else { setFlag(EntityFlag.BODY_ROTATION_BLOCKED, true); - propertyManager.add("minecraft:creaking_state", "hostile_observed"); + propertyManager.add(CREAKING_STATE, "hostile_observed"); updateBedrockEntityProperties(); } @@ -92,7 +103,7 @@ public class CreakingEntity extends MonsterEntity { // setFlag(EntityFlag.HIDDEN_WHEN_INVISIBLE, true); // setFlag(EntityFlag.BODY_ROTATION_BLOCKED, true); } else { - propertyManager.add("minecraft:creaking_state", "neutral"); + propertyManager.add(CREAKING_STATE, "neutral"); } GeyserImpl.getInstance().getLogger().warning("set active; " + booleanEntityMetadata.toString()); } @@ -100,7 +111,7 @@ public class CreakingEntity extends MonsterEntity { public void setIsTearingDown(EntityMetadata> booleanEntityMetadata) { GeyserImpl.getInstance().getLogger().warning("set isTearingDown; " + booleanEntityMetadata.toString()); if (booleanEntityMetadata.getValue()) { - propertyManager.add("minecraft:creaking_state", "crumbling"); + propertyManager.add(CREAKING_STATE, "crumbling"); updateBedrockEntityProperties(); // LevelEventPacket levelEventPacket = new LevelEventPacket(); // levelEventPacket.setType(ParticleType.CREAKING_CRUMBLE); 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 459d8adf8..3ea78a942 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 @@ -40,10 +40,7 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.enchantment.Enchantment; -import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.registry.JavaRegistries; -import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; @@ -403,8 +400,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { return false; } - GeyserHolderSet set = GeyserHolderSet.convertHolderSet(JavaRegistries.ITEM, repairable); - return session.getTagCache().is(set, material.asItem()); + return session.getTagCache().isItem(repairable, material.asItem()); } private boolean isRenaming(GeyserSession session, AnvilContainer anvilContainer, boolean bedrock) { 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 26b6aad96..c77081eb0 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 @@ -28,16 +28,19 @@ 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.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; 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.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.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import javax.annotation.ParametersAreNonnullByDefault; @@ -127,6 +130,34 @@ public final class TagCache { return contains(holderSet.resolveRaw(this), holderSet.getRegistry().toNetworkId(session, object)); } + /** + * Accessible via the {@link #isItem(HolderSet, Item)} method. + * @return true if the specified network ID is in the given {@link HolderSet} set. + */ + private boolean is(@Nullable HolderSet holderSet, @NonNull JavaRegistryKey registry, int id) { + if (holderSet == null) { + return false; + } + + int[] entries = holderSet.resolve(key -> { + if (key.value().startsWith("#")) { + key = Key.key(key.namespace(), key.value().substring(1)); + } + return getRaw(new Tag<>(registry, key)); + }); + + return contains(entries, id); + } + + public boolean isItem(@Nullable HolderSet holderSet, @NonNull Item item) { + return is(holderSet, JavaRegistries.ITEM, item.javaId()); + } + + public boolean isBlock(@Nullable HolderSet holderSet, @NonNull Block block) { + return is(holderSet, JavaRegistries.BLOCK, block.javaId()); + } + + public List get(Tag tag) { return mapRawArray(session, getRaw(tag), tag.registry()); } 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 index 0e0d117a4..c77f0a642 100644 --- 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 @@ -33,7 +33,6 @@ 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; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.List; import java.util.Objects; @@ -88,27 +87,6 @@ public final class GeyserHolderSet { return tagCache.getRaw(Objects.requireNonNull(tag, "HolderSet must have a tag if it doesn't have a list of IDs")); } - /** - * Reads a MCPL {@link HolderSet} and turns it into a GeyserHolderSet. - * @param registry the registry the HolderSet contains IDs from. - * @param holderSet the HolderSet as the MCPL HolderSet object - */ - public static GeyserHolderSet convertHolderSet(@NonNull JavaRegistryKey registry, @Nullable HolderSet holderSet) { - if (holderSet == null) { - return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY); - } - - if (holderSet.getHolders() != null) { - return new GeyserHolderSet<>(registry, holderSet.getHolders()); - } - - if (holderSet.getLocation() != null) { - return new GeyserHolderSet<>(registry, new Tag<>(registry, holderSet.getLocation())); - } - - throw new IllegalStateException("HolderSet must have a tag or a list of IDs! " + holderSet); - } - /** * Reads a HolderSet from an object from NBT. * 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 index ea386ebcf..b8facaa10 100644 --- 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 @@ -89,7 +89,7 @@ final class BedrockBlockActions { LevelEventPacket startBreak = new LevelEventPacket(); startBreak.setType(LevelEvent.BLOCK_START_BREAK); startBreak.setPosition(vector.toFloat()); - double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20; // TODO afdaöwelfunöwoaenf + double breakTime = BlockUtils.getSessionBreakTimeTicks(session, BlockState.of(blockState).block()); // If the block is custom or the breaking item is custom, we must keep track of break time ourselves GeyserItemStack item = session.getPlayerInventory().getItemInHand(); @@ -137,7 +137,7 @@ final class BedrockBlockActions { Direction direction = Direction.VALUES[blockFace]; spawnBlockBreakParticles(session, direction, vector, breakingBlockState); - double breakTime = BlockUtils.getSessionBreakTime(session, breakingBlockState.block()) * 20; + double breakTime = BlockUtils.getSessionBreakTimeTicks(session, breakingBlockState.block()); // If the block is custom, we must keep track of when it should break ourselves long blockBreakStartTime = session.getBlockBreakStartTime(); if (blockBreakStartTime != 0) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java index 67717febb..f2ab22e60 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectKnownPacksTranslator.java @@ -40,7 +40,7 @@ import java.util.Set; @Translator(packet = ClientboundSelectKnownPacks.class) public class JavaSelectKnownPacksTranslator extends PacketTranslator { // todo: dump from client? - private static final Set KNOWN_PACK_IDS = Set.of("core", "winter_drop", "trade_rebalance", "redstone_experiments", "minecart_improvements"); + private static final Set KNOWN_PACK_IDS = Set.of("core", "trade_rebalance", "redstone_experiments", "minecart_improvements"); @Override public void translate(GeyserSession session, ClientboundSelectKnownPacks packet) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index d52a2b501..504348b5b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -37,6 +37,7 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.EvokerFangsEntity; @@ -294,6 +295,8 @@ public class JavaEntityEventTranslator extends PacketTranslator set = GeyserHolderSet.convertHolderSet(JavaRegistries.BLOCK, rule.getBlocks()); - if (session.getTagCache().is(set, block)) { + if (session.getTagCache().isBlock(rule.getBlocks(), block)) { return rule.getCorrectForDrops(); } } @@ -84,8 +81,7 @@ public final class BlockUtils { for (ToolData.Rule rule : tool.getRules()) { if (rule.getSpeed() != null) { - GeyserHolderSet set = GeyserHolderSet.convertHolderSet(JavaRegistries.BLOCK, rule.getBlocks()); - if (session.getTagCache().is(set, block)) { + if (session.getTagCache().isBlock(rule.getBlocks(), block)) { return rule.getSpeed(); } } @@ -94,8 +90,8 @@ public final class BlockUtils { return tool.getDefaultMiningSpeed(); } - private static float getPlayerDestroySpeed(GeyserSession session, BlockState blockState, GeyserItemStack itemInHand) { - float destroySpeed = getItemDestroySpeed(session, blockState.block(), itemInHand); + private static float getPlayerDestroySpeed(GeyserSession session, Block block, GeyserItemStack itemInHand) { + float destroySpeed = getItemDestroySpeed(session, block, itemInHand); EntityEffectCache effectCache = session.getEffectCache(); if (destroySpeed > 1.0F) { @@ -133,17 +129,8 @@ public final class BlockUtils { return Math.max(cache.getHaste(), cache.getConduitPower()); } - public int getDestroyStage(GeyserSession session) { - return session.getDestroyProgress() > 0F ? (int) session.getDestroyProgress() * 10 : -1; - } - - // TODO 1.21.4 this changed probably; no more tiers - public static double getBreakTime(GeyserSession session, Block block, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { - return 0.0; // TODO 1.21.4 - } - - public static double getSessionBreakTime(GeyserSession session, Block block) { - return 0.0; // TODO 1.21.4 + public static double getSessionBreakTimeTicks(GeyserSession session, Block block) { + return Math.ceil(1 / getBlockMiningProgressPerTick(session, block, session.getPlayerInventory().getItemInHand())); } /** From f610a0d12ba590deb7f4d793814cf3db461804bb Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 8 Dec 2024 05:34:10 +0800 Subject: [PATCH 491/897] Tidy up creaking entity code, remove debugging --- .../type/living/monster/CreakingEntity.java | 50 +++---------------- .../geyser/network/UpstreamPacketHandler.java | 9 ---- .../geyser/session/GeyserSession.java | 3 -- ...SetLocalPlayerAsInitializedTranslator.java | 1 - .../player/input/BedrockBlockActions.java | 1 - core/src/main/resources/mappings | 2 +- 6 files changed, 8 insertions(+), 58 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java index 1f2ddc37c..1a26eb43b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java @@ -32,7 +32,6 @@ import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; @@ -41,14 +40,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataTyp import java.util.Optional; import java.util.UUID; -/* - * Relevant bits: - * - LevelSoundEvent2Packet(sound=SPAWN, position=(233.5, 112.295, 4717.5), extraData=-1, identifier=minecraft:creaking, babySound=false, relativeVolumeDisabled=false) - * - [11:29:34:768] [CLIENT BOUND] - LevelSoundEvent2Packet(sound=CREAKING_HEART_SPAWN, position=(233.0, 110.0, 4717.0), extraData=-1, identifier=minecraft:creaking, babySound=false, relativeVolumeDisabled=false) - * - [11:29:34:768] [CLIENT BOUND] - LevelSoundEvent2Packet(sound=CREAKING_HEART_SPAWN, position=(235.0, 113.0, 4722.0), extraData=13734, identifier=, babySound=false, relativeVolumeDisabled=false) - * - [11:29:34:768] [CLIENT BOUND] - LevelEventPacket(type=PARTICLE_MOB_BLOCK_SPAWN, position=(233.0, 110.0, 4717.0), data=769) - * - */ + public class CreakingEntity extends MonsterEntity { private Vector3i homePosition; @@ -70,53 +62,26 @@ public class CreakingEntity extends MonsterEntity { @Override public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { propertyManager.add(CREAKING_STATE, "neutral"); - propertyManager.add("minecraft:creaking_swaying_ticks", 0); + propertyManager.add(CREAKING_SWAYING_TICKS, 0); propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); } public void setCanMove(EntityMetadata> booleanEntityMetadata) { - if (booleanEntityMetadata.getValue()) { - setFlag(EntityFlag.BODY_ROTATION_BLOCKED, false); - - // unfreeze sound? SoundEvent.UNFREEZE - propertyManager.add(CREAKING_STATE, "hostile_unobserved"); - updateBedrockEntityProperties(); - } else { - setFlag(EntityFlag.BODY_ROTATION_BLOCKED, true); - propertyManager.add(CREAKING_STATE, "hostile_observed"); - updateBedrockEntityProperties(); - } - - GeyserImpl.getInstance().getLogger().warning("set can move; " + booleanEntityMetadata.toString()); + setFlag(EntityFlag.BODY_ROTATION_BLOCKED, !booleanEntityMetadata.getValue()); + propertyManager.add(CREAKING_STATE, booleanEntityMetadata.getValue() ? "hostile_unobserved" : "hostile_observed"); + updateBedrockEntityProperties(); } public void setActive(EntityMetadata> booleanEntityMetadata) { - if (booleanEntityMetadata.getValue()) { -// LevelSoundEvent2Packet addEntityPacket = new LevelSoundEvent2Packet(); -// addEntityPacket.setIdentifier("minecraft:creaking"); -// addEntityPacket.setPosition(position); -// addEntityPacket.setBabySound(false); -// addEntityPacket.setSound(SoundEvent.ACTIVATE); -// addEntityPacket.setExtraData(-1); -// session.sendUpstreamPacket(addEntityPacket); - -// setFlag(EntityFlag.HIDDEN_WHEN_INVISIBLE, true); -// setFlag(EntityFlag.BODY_ROTATION_BLOCKED, true); - } else { + if (!booleanEntityMetadata.getValue()) { propertyManager.add(CREAKING_STATE, "neutral"); } - GeyserImpl.getInstance().getLogger().warning("set active; " + booleanEntityMetadata.toString()); } public void setIsTearingDown(EntityMetadata> booleanEntityMetadata) { - GeyserImpl.getInstance().getLogger().warning("set isTearingDown; " + booleanEntityMetadata.toString()); if (booleanEntityMetadata.getValue()) { propertyManager.add(CREAKING_STATE, "crumbling"); updateBedrockEntityProperties(); -// LevelEventPacket levelEventPacket = new LevelEventPacket(); -// levelEventPacket.setType(ParticleType.CREAKING_CRUMBLE); -// levelEventPacket.setPosition(position); -// levelEventPacket.setData(0); } } @@ -134,7 +99,7 @@ public class CreakingEntity extends MonsterEntity { levelEventGenericPacket.setType(LevelEvent.PARTICLE_CREAKING_HEART_TRIAL); levelEventGenericPacket.setTag( NbtMap.builder() - .putInt("CreakingAmount", 0) + .putInt("CreakingAmount", 20) .putFloat("CreakingX", position.getX()) .putFloat("CreakingY", position.getY()) .putFloat("CreakingZ", position.getZ()) @@ -145,7 +110,6 @@ public class CreakingEntity extends MonsterEntity { .build() ); - GeyserImpl.getInstance().getLogger().warning(levelEventGenericPacket.toString()); session.sendUpstreamPacket(levelEventGenericPacket); } } 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 dfebb93dc..c67ea6545 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -30,7 +30,6 @@ 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; -import org.cloudburstmc.protocol.bedrock.data.ExperimentData; import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm; import org.cloudburstmc.protocol.bedrock.data.ResourcePackType; import org.cloudburstmc.protocol.bedrock.netty.codec.compression.CompressionStrategy; @@ -249,14 +248,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { stackPacket.getResourcePacks().add(new ResourcePackStackPacket.Entry(header.uuid().toString(), header.version().toString(), "")); } - if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) { - // Allow custom items to work - stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true)); - } - - // Required for experimental 1.21 features - stackPacket.getExperiments().add(new ExperimentData("updateAnnouncedLive2023", true)); - session.sendUpstreamPacket(stackPacket); break; 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 cedf9ab66..b61cb7815 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -150,7 +150,6 @@ import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.physics.CollisionManager; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; @@ -1671,8 +1670,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.getExperiments().add(new ExperimentData("upcoming_creator_features", true)); // Needed for certain molang queries used in blocks and items startGamePacket.getExperiments().add(new ExperimentData("experimental_molang_features", true)); - // Required for experimental 1.21 features - startGamePacket.getExperiments().add(new ExperimentData("updateAnnouncedLive2023", true)); startGamePacket.setVanillaVersion("*"); startGamePacket.setInventoriesServerAuthoritative(true); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java index fcbd3bb8c..556d8cd8d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java @@ -40,7 +40,6 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.Serverbound public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, SetLocalPlayerAsInitializedPacket packet) { - GeyserImpl.getInstance().getLogger().info(packet.toString()); if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) { if (!session.getUpstream().isInitialized()) { session.getUpstream().setInitialized(true); 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 index b8facaa10..c604f5be1 100644 --- 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 @@ -170,7 +170,6 @@ final class BedrockBlockActions { 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 - GeyserImpl.getInstance().getLogger().warning("abort break, not creative - item frame???"); Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector); if (itemFrameEntity != null) { ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 452312f88..64032d788 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 452312f88317cce019b8f336f485ffa7b2c19557 +Subproject commit 64032d7886e128858044e7e786479af3f1e876c8 From c298061d4dea3569a285b425bc4442d9e8445adc Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 8 Dec 2024 06:18:42 +0800 Subject: [PATCH 492/897] address review --- .../geyser/translator/inventory/LoomInventoryTranslator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index e294442f9..1fef4c4fd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -156,7 +156,10 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { inputCopy.setNetId(session.getNextItemNetId()); BannerPatternLayer bannerPatternLayer = BannerItem.getJavaBannerPattern(session, pattern); // TODO if (bannerPatternLayer != null) { - List patternsList = inputCopy.getComponentOrFallback(DataComponentType.BANNER_PATTERNS, new ArrayList<>()); + List patternsList = inputCopy.getComponent(DataComponentType.BANNER_PATTERNS); + if (patternsList == null) { + patternsList = new ArrayList<>(); + } patternsList.add(bannerPatternLayer); inputCopy.getOrCreateComponents().put(DataComponentType.BANNER_PATTERNS, patternsList); } From bd3377bfcc0e09368ec4e85a0a78ae4678911877 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 8 Dec 2024 06:20:32 +0800 Subject: [PATCH 493/897] update mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 64032d788..e8089e117 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 64032d7886e128858044e7e786479af3f1e876c8 +Subproject commit e8089e117605e60a5ced120926c49fae7617c665 From 1210639087d64b78213410b57df09508ab3149aa Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 8 Dec 2024 22:54:51 +0800 Subject: [PATCH 494/897] update item tags for 1.21.50 items --- .../resources/bedrock/item_tags.1_21_50.json | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/core/src/main/resources/bedrock/item_tags.1_21_50.json b/core/src/main/resources/bedrock/item_tags.1_21_50.json index d9e63ed26..b8b94d6f3 100644 --- a/core/src/main/resources/bedrock/item_tags.1_21_50.json +++ b/core/src/main/resources/bedrock/item_tags.1_21_50.json @@ -6,6 +6,7 @@ "minecraft:banner" ], "minecraft:boat": [ + "minecraft:pale_oak_chest_boat", "minecraft:cherry_chest_boat", "minecraft:oak_chest_boat", "minecraft:mangrove_boat", @@ -23,9 +24,11 @@ "minecraft:mangrove_chest_boat", "minecraft:cherry_boat", "minecraft:bamboo_raft", - "minecraft:bamboo_chest_raft" + "minecraft:bamboo_chest_raft", + "minecraft:pale_oak_boat" ], "minecraft:boats": [ + "minecraft:pale_oak_chest_boat", "minecraft:cherry_chest_boat", "minecraft:oak_chest_boat", "minecraft:mangrove_boat", @@ -43,7 +46,8 @@ "minecraft:mangrove_chest_boat", "minecraft:cherry_boat", "minecraft:bamboo_raft", - "minecraft:bamboo_chest_raft" + "minecraft:bamboo_chest_raft", + "minecraft:pale_oak_boat" ], "minecraft:bookshelf_books": [ "minecraft:written_book", @@ -151,7 +155,8 @@ "minecraft:oxidized_copper_door", "minecraft:waxed_copper_door", "minecraft:waxed_exposed_copper_door", - "minecraft:waxed_oxidized_copper_door" + "minecraft:waxed_oxidized_copper_door", + "minecraft:pale_oak_door" ], "minecraft:golden_tier": [ "minecraft:golden_sword", @@ -170,6 +175,7 @@ "minecraft:hanging_sign": [ "minecraft:mangrove_hanging_sign", "minecraft:bamboo_hanging_sign", + "minecraft:pale_oak_hanging_sign", "minecraft:spruce_hanging_sign", "minecraft:birch_hanging_sign", "minecraft:cherry_hanging_sign", @@ -318,6 +324,9 @@ "minecraft:golden_pickaxe", "minecraft:netherite_pickaxe" ], + "minecraft:is_shears": [ + "minecraft:shears" + ], "minecraft:is_shovel": [ "minecraft:iron_shovel", "minecraft:wooden_shovel", @@ -382,6 +391,7 @@ "minecraft:writable_book" ], "minecraft:logs": [ + "minecraft:stripped_oak_log", "minecraft:mangrove_wood", "minecraft:spruce_wood", "minecraft:stripped_cherry_wood", @@ -390,12 +400,14 @@ "minecraft:spruce_log", "minecraft:acacia_wood", "minecraft:stripped_acacia_wood", + "minecraft:pale_oak_wood", "minecraft:stripped_warped_hyphae", "minecraft:acacia_log", "minecraft:stripped_warped_stem", "minecraft:oak_log", "minecraft:birch_log", "minecraft:jungle_log", + "minecraft:stripped_pale_oak_wood", "minecraft:dark_oak_log", "minecraft:jungle_wood", "minecraft:stripped_jungle_wood", @@ -405,10 +417,10 @@ "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_pale_oak_log", "minecraft:stripped_mangrove_wood", "minecraft:crimson_hyphae", "minecraft:stripped_cherry_log", @@ -416,6 +428,7 @@ "minecraft:stripped_acacia_log", "minecraft:crimson_stem", "minecraft:warped_hyphae", + "minecraft:pale_oak_log", "minecraft:stripped_spruce_log", "minecraft:warped_stem", "minecraft:stripped_crimson_hyphae", @@ -424,6 +437,7 @@ "minecraft:stripped_mangrove_log" ], "minecraft:logs_that_burn": [ + "minecraft:stripped_oak_log", "minecraft:mangrove_wood", "minecraft:spruce_wood", "minecraft:stripped_cherry_wood", @@ -431,10 +445,12 @@ "minecraft:spruce_log", "minecraft:acacia_wood", "minecraft:stripped_acacia_wood", + "minecraft:pale_oak_wood", "minecraft:acacia_log", "minecraft:oak_log", "minecraft:birch_log", "minecraft:jungle_log", + "minecraft:stripped_pale_oak_wood", "minecraft:dark_oak_log", "minecraft:jungle_wood", "minecraft:stripped_jungle_wood", @@ -444,14 +460,15 @@ "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_pale_oak_log", "minecraft:stripped_mangrove_wood", "minecraft:stripped_cherry_log", "minecraft:stripped_birch_log", "minecraft:stripped_acacia_log", + "minecraft:pale_oak_log", "minecraft:stripped_spruce_log", "minecraft:cherry_wood", "minecraft:cherry_log", @@ -505,6 +522,7 @@ "minecraft:acacia_planks", "minecraft:bamboo_planks", "minecraft:warped_planks", + "minecraft:pale_oak_planks", "minecraft:crimson_planks", "minecraft:cherry_planks" ], @@ -521,6 +539,7 @@ "minecraft:bamboo_hanging_sign", "minecraft:warped_sign", "minecraft:spruce_sign", + "minecraft:pale_oak_hanging_sign", "minecraft:spruce_hanging_sign", "minecraft:acacia_sign", "minecraft:birch_hanging_sign", @@ -534,7 +553,8 @@ "minecraft:acacia_hanging_sign", "minecraft:dark_oak_hanging_sign", "minecraft:crimson_hanging_sign", - "minecraft:warped_hanging_sign" + "minecraft:warped_hanging_sign", + "minecraft:pale_oak_sign" ], "minecraft:soul_fire_base_blocks": [ "minecraft:soul_soil", @@ -596,6 +616,7 @@ "minecraft:piglin_spawn_egg", "minecraft:wither_skeleton_spawn_egg", "minecraft:donkey_spawn_egg", + "minecraft:creaking_spawn_egg", "minecraft:mule_spawn_egg", "minecraft:skeleton_horse_spawn_egg", "minecraft:zombie_horse_spawn_egg", @@ -667,6 +688,7 @@ "minecraft:golden_boots" ], "minecraft:trim_materials": [ + "minecraft:resin_brick", "minecraft:diamond", "minecraft:iron_ingot", "minecraft:gold_ingot", @@ -743,6 +765,7 @@ "minecraft:red_carpet", "minecraft:brown_carpet", "minecraft:light_blue_wool", + "minecraft:green_carpet", "minecraft:white_wool", "minecraft:magenta_wool", "minecraft:yellow_wool", @@ -756,8 +779,7 @@ "minecraft:orange_carpet", "minecraft:light_blue_carpet", "minecraft:gray_carpet", - "minecraft:light_gray_carpet", - "minecraft:green_carpet" + "minecraft:light_gray_carpet" ], "minecraft:warped_stems": [ "minecraft:stripped_warped_hyphae", @@ -771,6 +793,7 @@ "minecraft:spruce_slab", "minecraft:bamboo_slab", "minecraft:warped_slab", + "minecraft:pale_oak_slab", "minecraft:mangrove_slab", "minecraft:cherry_slab", "minecraft:jungle_slab", From 1fea22d980409c5a7c21fd7f438e918ca473fb0b Mon Sep 17 00:00:00 2001 From: RK_01 <50594595+RaphiMC@users.noreply.github.com> Date: Mon, 9 Dec 2024 06:21:12 +0100 Subject: [PATCH 495/897] Implement ViaProxy client IP passthrough (#5202) --- .../viaproxy/GeyserViaProxyPlugin.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java index b5e614468..498f7d7c3 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java @@ -24,15 +24,19 @@ */ package org.geysermc.geyser.platform.viaproxy; +import io.netty.channel.AbstractChannel; import net.lenni0451.lambdaevents.EventHandler; +import net.lenni0451.reflect.stream.RStream; import net.raphimc.vialegacy.api.LegacyProtocolVersion; import net.raphimc.viaproxy.ViaProxy; import net.raphimc.viaproxy.plugins.PluginManager; import net.raphimc.viaproxy.plugins.ViaProxyPlugin; +import net.raphimc.viaproxy.plugins.events.Client2ProxyChannelInitializeEvent; import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent; import net.raphimc.viaproxy.plugins.events.ProxyStartEvent; import net.raphimc.viaproxy.plugins.events.ProxyStopEvent; import net.raphimc.viaproxy.plugins.events.ShouldVerifyOnlineModeEvent; +import net.raphimc.viaproxy.plugins.events.types.ITyped; import org.apache.logging.log4j.LogManager; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserBootstrap; @@ -56,6 +60,7 @@ import org.geysermc.geyser.util.LoopbackUtil; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.nio.file.Files; import java.nio.file.Path; import java.util.UUID; @@ -109,6 +114,27 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst } } + @EventHandler + private void onClient2ProxyChannelInitialize(Client2ProxyChannelInitializeEvent event) { + if (event.getType() != ITyped.Type.POST || event.isLegacyPassthrough()) { + return; + } + if (System.getProperty("geyser.viaproxy.disableIpPassthrough") != null) { // Temporary until Configurate branch is merged + return; + } + + final GeyserSession session = GeyserImpl.getInstance().onlineConnections().stream() + .filter(c -> c.getDownstream() != null) + .filter(c -> c.getDownstream().getSession().getLocalAddress().equals(event.getChannel().remoteAddress())) + .findAny().orElse(null); + if (session != null) { + final SocketAddress realAddress = session.getSocketAddress(); + if (event.getChannel() instanceof AbstractChannel) { + RStream.of(AbstractChannel.class, event.getChannel()).fields().by("remoteAddress").set(realAddress); + } + } + } + @EventHandler private void onProxyStart(final ProxyStartEvent event) { this.onGeyserEnable(); From 8b232d7900c44d43d78a28cfc2cbd6aa558a12a9 Mon Sep 17 00:00:00 2001 From: LetsGoAway <68365423+letsgoawaydev@users.noreply.github.com> Date: Mon, 9 Dec 2024 22:58:04 +0800 Subject: [PATCH 496/897] Handle ClientboundTickingStatePacket correctly and fix Throwable Scales (#4850) * Proper tick rate handling * Fix frozen variable getter * Fix formatting i think third attempt * Formatting fix attempt 5 fsdiofhsdioufhvuisdhviuo9ds * Fix stuff, also fixed the sizing of throwables as they were to big * Move update ticking state * Update core/src/main/java/org/geysermc/geyser/session/GeyserSession.java Co-authored-by: rtm516 * Fixes for spaces and documentation * Missed a space * wait now ive fixed it * Fix languages * try again to fix languages * Fix Java doc comments for tickable interface * Fix javadoc comment in Geyser Session * fix comment * fix some tick rate stuffs * Fix build fail * fix some stuff * merge * test * Update languages * Update mappings * delete broken stuff * Fix cooldown * fix cooldowns * Update core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java Co-authored-by: chris * Update BoatEntity.java * Update GeyserSession.java * fix some stuff * Update CooldownUtils.java * fix some accidental formatting issues * Fix missing inport * Update GeyserSession.java * Update core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java Co-authored-by: chris * Update core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java Co-authored-by: chris * Fix missing import --------- Co-authored-by: rtm516 Co-authored-by: chris --- .../geyser/entity/EntityDefinitions.java | 5 +- .../geyser/entity/type/BoatEntity.java | 2 +- .../geyser/entity/type/EnderEyeEntity.java | 48 ++++++++ .../entity/type/ThrowableItemEntity.java | 55 +++++---- .../geysermc/geyser/entity/type/Tickable.java | 17 ++- .../geyser/session/GeyserSession.java | 114 +++++++++++------- .../geyser/session/cache/WorldCache.java | 10 +- .../BedrockMobEquipmentTranslator.java | 2 +- .../java/JavaTickingStateTranslator.java | 40 ++++++ .../java/JavaTickingStepTranslator.java | 40 ++++++ .../java/level/JavaCooldownTranslator.java | 2 +- .../JavaSetTitlesAnimationTranslator.java | 10 +- .../geysermc/geyser/util/CooldownUtils.java | 17 ++- 13 files changed, 278 insertions(+), 84 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/EnderEyeEntity.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaTickingStateTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaTickingStepTranslator.java 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 47b97c934..b2922a570 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -38,6 +38,7 @@ import org.geysermc.geyser.entity.type.ChestBoatEntity; import org.geysermc.geyser.entity.type.CommandBlockMinecartEntity; import org.geysermc.geyser.entity.type.DisplayBaseEntity; import org.geysermc.geyser.entity.type.EnderCrystalEntity; +import org.geysermc.geyser.entity.type.EnderEyeEntity; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.EvokerFangsEntity; import org.geysermc.geyser.entity.type.ExpOrbEntity; @@ -197,7 +198,7 @@ public final class EntityDefinitions { public static final EntityDefinition EVOKER_FANGS; public static final EntityDefinition EXPERIENCE_BOTTLE; public static final EntityDefinition EXPERIENCE_ORB; - public static final EntityDefinition EYE_OF_ENDER; + public static final EntityDefinition EYE_OF_ENDER; public static final EntityDefinition FALLING_BLOCK; public static final EntityDefinition FIREBALL; public static final EntityDefinition FIREWORK_ROCKET; @@ -345,7 +346,7 @@ public final class EntityDefinitions { .height(0.8f).width(0.5f) .identifier("minecraft:evocation_fang") .build(); - EYE_OF_ENDER = EntityDefinition.inherited(Entity::new, entityBase) + EYE_OF_ENDER = EntityDefinition.inherited(EnderEyeEntity::new, entityBase) .type(EntityType.EYE_OF_ENDER) .heightAndWidth(0.25f) .identifier("minecraft:eye_of_ender_signal") 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 86accea17..cae4dcd11 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 @@ -189,7 +189,7 @@ public class BoatEntity extends Entity implements Leashable, Tickable { session.sendDownstreamGamePacket(steerPacket); return; } - doTick = !doTick; // Run every 100 ms + doTick = !doTick; // Run every other tick if (!doTick || passengers.isEmpty()) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/EnderEyeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/EnderEyeEntity.java new file mode 100644 index 000000000..cc5a58f21 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/EnderEyeEntity.java @@ -0,0 +1,48 @@ +/* + * 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; + + +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.EntityDefinitions; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.UUID; + +public class EnderEyeEntity extends Entity { + public EnderEyeEntity(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 + protected void initializeMetadata() { + super.initializeMetadata(); + // Correct sizing + dirtyMetadata.put(EntityDataTypes.SCALE, 0.5f); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java index 55334010f..fbbe2de50 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java @@ -25,12 +25,14 @@ package org.geysermc.geyser.entity.type; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; 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.entity.EntityDefinitions; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.UUID; @@ -39,7 +41,7 @@ import java.util.UUID; */ public class ThrowableItemEntity extends ThrowableEntity { /** - * Number of ticks since the entity was spawned by the Java server + * Number of draw ticks since the entity was spawned by the Java server */ private int age; private boolean invisible; @@ -48,29 +50,38 @@ public class ThrowableItemEntity extends ThrowableEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); setFlag(EntityFlag.INVISIBLE, true); invisible = false; - } - - private void checkVisibility() { - if (invisible != getFlag(EntityFlag.INVISIBLE)) { - if (!invisible) { - Vector3f playerPos = session.getPlayerEntity().getPosition(); - // Prevent projectiles from blocking the player's screen - if (age >= 4 || position.distanceSquared(playerPos) > 16) { - setFlag(EntityFlag.INVISIBLE, false); - updateBedrockMetadata(); - } - } else { - setFlag(EntityFlag.INVISIBLE, true); - updateBedrockMetadata(); - } - } - age++; + age = 0; } @Override - public void tick() { + protected void initializeMetadata() { + super.initializeMetadata(); + // Correct sizing + dirtyMetadata.put(EntityDataTypes.SCALE, 0.5f); + } + + private void checkVisibility() { + age++; + + // Prevent projectiles from blocking the player's screen + if (session.isTickingFrozen()) { + // This may seem odd, but it matches java edition + Vector3f playerPos = session.getPlayerEntity().getPosition().down(EntityDefinitions.PLAYER.offset()); + setInvisible(playerPos.distanceSquared(position.add(0, definition.offset(), 0)) < 12.25); + } else { + setInvisible(age < 2); + } + + if (invisible != getFlag(EntityFlag.INVISIBLE)) { + setFlag(EntityFlag.INVISIBLE, invisible); + updateBedrockMetadata(); + } + } + + @Override + public void drawTick() { checkVisibility(); - super.tick(); + super.drawTick(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Tickable.java b/core/src/main/java/org/geysermc/geyser/entity/type/Tickable.java index 06bf45b3d..f61ff355f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Tickable.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Tickable.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 @@ -26,8 +26,21 @@ package org.geysermc.geyser.entity.type; /** - * Implemented onto anything that should have code ran every Minecraft tick - 50 milliseconds. + * Implemented onto anything that should have code ran every Minecraft tick. + * By default, the Java server runs at 20 TPS, 50 milliseconds for each tick. */ public interface Tickable { + /** + * This function gets called every tick at all times, even when the server requests that + * the game should be frozen. This should be used for updating things that are always + * client side updated on Java, regardless of if the server is frozen or not. + */ + default void drawTick() { + } + + /** + * This function gets called every game tick as long as the + * game tick loop isn't frozen. + */ void tick(); } 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 b4a8e6203..d9e99b3b8 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.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 @@ -183,6 +183,7 @@ 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.MathUtils; import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.network.BuiltinFlags; @@ -600,7 +601,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private boolean advancedTooltips = false; /** - * The thread that will run every 50 milliseconds - one Minecraft tick. + * The thread that will run every game tick. */ private ScheduledFuture tickThread = null; @@ -644,7 +645,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * Stores cookies sent by the Java server. */ - @Setter @Getter + @Setter private Map cookies = new Object2ObjectOpenHashMap<>(); private final GeyserCameraData cameraData; @@ -653,6 +654,16 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private MinecraftProtocol protocol; + private int nanosecondsPerTick = 50000000; + private float millisecondsPerTick = 50.0f; + private boolean tickingFrozen = false; + /** + * The amount of ticks requested by the server that the game should proceed with, even if the game tick loop is frozen. + */ + @Setter + private int stepTicks = 0; + + public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop tickEventLoop) { this.geyser = geyser; this.upstream = new UpstreamSession(bedrockServerSession); @@ -895,38 +906,38 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } task.cleanup(); // player is online -> remove pending authentication immediately return task.getAuthentication().handle((result, ex) -> { - if (ex != null) { - geyser.getLogger().error("Failed to log in with Microsoft code!", ex); - if (ex instanceof CompletionException ce - && ce.getCause() instanceof MinecraftRequestException mre - && mre.getResponse().getStatusCode() == 404) { - // Player is trying to join with a Microsoft account that doesn't have Java Edition purchased - disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", locale())); - } else { - disconnect(ex.toString()); - } - return false; - } + if (ex != null) { + geyser.getLogger().error("Failed to log in with Microsoft code!", ex); + if (ex instanceof CompletionException ce + && ce.getCause() instanceof MinecraftRequestException mre + && mre.getResponse().getStatusCode() == 404) { + // Player is trying to join with a Microsoft account that doesn't have Java Edition purchased + disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", locale())); + } else { + disconnect(ex.toString()); + } + return false; + } - StepMCProfile.MCProfile mcProfile = result.session().getMcProfile(); - StepMCToken.MCToken mcToken = mcProfile.getMcToken(); + StepMCProfile.MCProfile mcProfile = result.session().getMcProfile(); + StepMCToken.MCToken mcToken = mcProfile.getMcToken(); - this.protocol = new MinecraftProtocol( - new GameProfile(mcProfile.getId(), mcProfile.getName()), - mcToken.getAccessToken() - ); + this.protocol = new MinecraftProtocol( + new GameProfile(mcProfile.getId(), mcProfile.getName()), + mcToken.getAccessToken() + ); - try { - connectDownstream(); - } catch (Throwable t) { - t.printStackTrace(); - return false; - } + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + return false; + } - // Save our auth chain for later use - geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session()))); - return true; - }).getNow(false); + // Save our auth chain for later use + geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session()))); + return true; + }).getNow(false); } /** @@ -947,14 +958,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { boolean floodgate = this.remoteServer.authType() == AuthType.FLOODGATE; // Start ticking - tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); + tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS); TcpSession downstream; if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP downstream = new LocalSession(this.remoteServer.address(), this.remoteServer.port(), geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), - this.protocol, tickEventLoop); + this.protocol, this.tickEventLoop); this.downstream = new DownstreamSession(downstream); } else { downstream = new TcpClientSession(this.remoteServer.address(), this.remoteServer.port(), "0.0.0.0", 0, this.protocol, null, tickEventLoop); @@ -1077,11 +1088,6 @@ 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 @@ -1243,6 +1249,19 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { }, duration, timeUnit); } + public void updateTickingState(float tickRate, boolean frozen) { + tickThread.cancel(false); + + this.tickingFrozen = frozen; + + tickRate = MathUtils.clamp(tickRate, 1.0f, 10000.0f); + + millisecondsPerTick = 1000.0f / tickRate; + + nanosecondsPerTick = MathUtils.ceil(1000000000.0f / tickRate); + tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS); + } + private void executeRunnable(Runnable runnable) { try { runnable.run(); @@ -1251,10 +1270,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } catch (Throwable e) { geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); } + } /** - * Called every 50 milliseconds - one Minecraft tick. + * Called every Minecraft tick. */ protected void tick() { try { @@ -1280,13 +1300,21 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { isInWorldBorderWarningArea = false; } + boolean gameShouldUpdate = !tickingFrozen || stepTicks > 0; + if (stepTicks > 0) { + --stepTicks; + } + Entity vehicle = playerEntity.getVehicle(); if (vehicle instanceof ClientVehicle clientVehicle && vehicle.isValid()) { clientVehicle.getVehicleComponent().tickVehicle(); } for (Tickable entity : entityCache.getTickableEntities()) { - entity.tick(); + entity.drawTick(); + if (gameShouldUpdate) { + entity.tick(); + } } if (armAnimationTicks >= 0) { @@ -1424,7 +1452,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public void setClientData(BedrockClientData data) { this.clientData = data; this.inputCache.setInputMode( - org.cloudburstmc.protocol.bedrock.data.InputMode.values()[data.getCurrentInputMode().ordinal()]); + org.cloudburstmc.protocol.bedrock.data.InputMode.values()[data.getCurrentInputMode().ordinal()]); } /** @@ -1844,7 +1872,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Send a gamerule value to the client * * @param gameRule The gamerule to send - * @param value The value of the gamerule + * @param value The value of the gamerule */ public void sendGameRule(String gameRule, Object value) { GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket(); @@ -2110,7 +2138,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public UUID javaUuid() { - return playerEntity != null ? playerEntity.getUuid() : null ; + return playerEntity != null ? playerEntity.getUuid() : null; } @Override 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 609ac3f3b..eb57e0214 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 @@ -123,9 +123,13 @@ public final class WorldCache { SetTitlePacket titlePacket = new SetTitlePacket(); titlePacket.setType(SetTitlePacket.Type.TIMES); titlePacket.setText(""); - titlePacket.setFadeInTime(trueTitleFadeInTime); - titlePacket.setStayTime(trueTitleStayTime); - titlePacket.setFadeOutTime(trueTitleFadeOutTime); + + // We need a tick rate multiplier as otherwise the timings are incorrect on different tick rates because + // bedrock can only run at 20 TPS (50ms = 1 tick) + int tickrateMultiplier = Math.round(session.getMillisecondsPerTick()) / 50; + titlePacket.setFadeInTime(trueTitleFadeInTime * tickrateMultiplier); + titlePacket.setStayTime(trueTitleStayTime * tickrateMultiplier); + titlePacket.setFadeOutTime(trueTitleFadeOutTime * tickrateMultiplier); titlePacket.setPlatformOnlineId(""); titlePacket.setXuid(""); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java index 35ad942d0..64681723e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java @@ -66,7 +66,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator session.useItem(Hand.MAIN_HAND), - 50, TimeUnit.MILLISECONDS); + session.getNanosecondsPerTick(), TimeUnit.NANOSECONDS); } if (oldItem.getJavaId() != newItem.getJavaId()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaTickingStateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaTickingStateTranslator.java new file mode 100644 index 000000000..85d4974cf --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaTickingStateTranslator.java @@ -0,0 +1,40 @@ +/* + * 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; + +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.ClientboundTickingStatePacket; + +@Translator(packet = ClientboundTickingStatePacket.class) +public class JavaTickingStateTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundTickingStatePacket packet) { + session.updateTickingState(packet.getTickRate(), packet.isFrozen()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaTickingStepTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaTickingStepTranslator.java new file mode 100644 index 000000000..f898b762a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaTickingStepTranslator.java @@ -0,0 +1,40 @@ +/* + * 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; + +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.ClientboundTickingStepPacket; + +@Translator(packet = ClientboundTickingStepPacket.class) +public class JavaTickingStepTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundTickingStepPacket packet) { + session.setStepTicks(packet.getTickSteps()); + } +} 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 2b14f015f..4097f5b78 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 @@ -59,7 +59,7 @@ public class JavaCooldownTranslator extends PacketTranslator 20) return; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used + if (session.getAttackSpeed() == 0.0 || session.getAttackSpeed() > 20) { + return; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used + } // Set the times to stay a bit with no fade in nor out SetTitlePacket titlePacket = new SetTitlePacket(); titlePacket.setType(SetTitlePacket.Type.TIMES); @@ -83,6 +87,7 @@ public class CooldownUtils { /** * Keeps updating the cooldown until the bar is complete. + * * @param session GeyserSession * @param sessionPreference The type of cooldown the client prefers * @param lastHitTime The time of the last hit. Used to gauge how long the cooldown is taking. @@ -102,7 +107,7 @@ public class CooldownUtils { session.sendUpstreamPacket(titlePacket); if (hasCooldown(session)) { session.scheduleInEventLoop(() -> - computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 + computeCooldown(session, sessionPreference, lastHitTime), (long) restrain(session.getMillisecondsPerTick(), 50), TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 } else { SetTitlePacket removeTitlePacket = new SetTitlePacket(); removeTitlePacket.setType(SetTitlePacket.Type.CLEAR); @@ -115,8 +120,9 @@ public class CooldownUtils { private static boolean hasCooldown(GeyserSession session) { long time = System.currentTimeMillis() - session.getLastHitTime(); - double cooldown = restrain(((double) time) * session.getAttackSpeed() / 1000d, 1.5); - return cooldown < 1.1; + double tickrateMultiplier = Math.max(session.getMillisecondsPerTick() / 50, 1.0); + double cooldown = restrain(((double) time) * session.getAttackSpeed() / (tickrateMultiplier * 1000.0), 1.0); + return cooldown < 1.0; } @@ -128,7 +134,8 @@ public class CooldownUtils { private static String getTitle(GeyserSession session) { long time = System.currentTimeMillis() - session.getLastHitTime(); - double cooldown = restrain(((double) time) * session.getAttackSpeed() / 1000d, 1); + double tickrateMultiplier = Math.max(session.getMillisecondsPerTick() / 50, 1.0); + double cooldown = restrain(((double) time) * session.getAttackSpeed() / (tickrateMultiplier * 1000.0), 1.0); int darkGrey = (int) Math.floor(10d * cooldown); int grey = 10 - darkGrey; From 94c258a4c910ffe39e6ca3c09ec3ff492713f0c1 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 10 Dec 2024 01:26:36 +0800 Subject: [PATCH 497/897] Update loom (and gradle), create basic recipes when there are too many possible combinations, update adapters --- .../kotlin/geyser.base-conventions.gradle.kts | 4 +- .../java/JavaRecipeBookAddTranslator.java | 67 +++++++++++++++++-- gradle.properties | 3 - gradle/libs.versions.toml | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 6 files changed, 68 insertions(+), 14 deletions(-) diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 093f0a8c0..045015fe1 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -26,8 +26,6 @@ dependencies { } repositories { - // mavenLocal() - mavenCentral() // Floodgate, Cumulus etc. @@ -69,4 +67,6 @@ repositories { // For Adventure snapshots maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") + + //mavenLocal() } 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 index 96c5951d5..8e83c9f55 100644 --- 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 @@ -28,6 +28,7 @@ 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.ints.IntComparators; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; @@ -75,12 +76,14 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.Clientbound import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; @Translator(packet = ClientboundRecipeBookAddPacket.class) public class JavaRecipeBookAddTranslator extends PacketTranslator { @@ -386,10 +389,64 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator descriptors.get(0)).toList()), - output - ); + + int totalSimpleRecipes = inputs.stream().mapToInt(List::size).max().orElse(1); + + // Sort inputs to create "uniform" simple recipes, if possible + inputs = inputs.stream() + .map(descriptors -> descriptors.stream() + .sorted(ItemDescriptorWithCountComparator.INSTANCE) + .collect(Collectors.toList())) + .collect(Collectors.toList()); + + List> finalRecipes = new ArrayList<>(totalSimpleRecipes); + for (int i = 0; i < totalSimpleRecipes; i++) { + int current = i; + finalRecipes.add(inputs.stream().map(descriptors -> { + if (descriptors.size() > current) { + return descriptors.get(current); + } + return descriptors.get(0); + }).toList()); + } + + return Pair.of(finalRecipes, output); + } + + static class ItemDescriptorWithCountComparator implements Comparator { + + static ItemDescriptorWithCountComparator INSTANCE = new ItemDescriptorWithCountComparator(); + + @Override + public int compare(ItemDescriptorWithCount o1, ItemDescriptorWithCount o2) { + String tag1 = null, tag2 = null; + + // Collect item tags first + if (o1.getDescriptor() instanceof ItemTagDescriptor itemTagDescriptor) { + tag1 = itemTagDescriptor.getItemTag(); + } + + if (o2.getDescriptor() instanceof ItemTagDescriptor itemTagDescriptor) { + tag2 = itemTagDescriptor.getItemTag(); + } + + if (tag1 != null || tag2 != null) { + if (tag1 != null && tag2 != null) { + return tag1.compareTo(tag2); // Just sort based on their string id + } + + if (tag1 != null) { + return -1; + } + + return 1; // the second is an item tag; which should be r + } + + if (o1.getDescriptor() instanceof DefaultDescriptor defaultDescriptor1 && o2.getDescriptor() instanceof DefaultDescriptor defaultDescriptor2) { + return IntComparators.NATURAL_COMPARATOR.compare(defaultDescriptor1.getItemId().getRuntimeId(), defaultDescriptor2.getItemId().getRuntimeId()); + } + + throw new IllegalStateException("Unable to compare unknown item descriptors: " + o1 + " and " + o2); + } } } diff --git a/gradle.properties b/gradle.properties index 473c104f4..c380ec371 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,9 +6,6 @@ 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.6.0-SNAPSHOT diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 686064926..1166bab35 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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.15-SNAPSHOT" +adapters = "1.16-SNAPSHOT" cloud = "2.0.0-rc.2" cloud-minecraft = "2.0.0-beta.9" cloud-minecraft-modded = "2.0.0-beta.10" @@ -46,7 +46,7 @@ mockito = "5.+" indra = "3.1.3" shadow = "8.1.1" architectury-plugin = "3.4-SNAPSHOT" -architectury-loom = "1.7-SNAPSHOT" +architectury-loom = "1.9-SNAPSHOT" minotaur = "2.8.7" lombok = "8.4" blossom = "2.1.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c..94113f200 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a426..b740cf133 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. From 1f3590d48885d380fa1e06c8fbdced68d40b1d72 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 10 Dec 2024 03:01:09 +0800 Subject: [PATCH 498/897] revert map color changes --- .../org/geysermc/geyser/level/MapColor.java | 507 +++++++++--------- 1 file changed, 257 insertions(+), 250 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/MapColor.java b/core/src/main/java/org/geysermc/geyser/level/MapColor.java index 4b891e9b7..a599f9146 100644 --- a/core/src/main/java/org/geysermc/geyser/level/MapColor.java +++ b/core/src/main/java/org/geysermc/geyser/level/MapColor.java @@ -26,261 +26,268 @@ package org.geysermc.geyser.level; public enum MapColor { - COLOR_0(0), - COLOR_1(0), - COLOR_2(0), - COLOR_3(0), - COLOR_4(-10912473), - COLOR_5(-9594576), - COLOR_6(-8408520), - COLOR_7(-12362211), - COLOR_8(-5331853), - COLOR_9(-2766452), - COLOR_10(-530013), - COLOR_11(-8225962), - COLOR_12(-7566196), - COLOR_13(-5526613), - COLOR_14(-3684409), - COLOR_15(-9868951), - COLOR_16(-4980736), - COLOR_17(-2359296), - COLOR_18(-65536), - COLOR_19(-7929856), - COLOR_20(-9408332), - COLOR_21(-7697700), - COLOR_22(-6250241), - COLOR_23(-11250553), - COLOR_24(-9079435), - COLOR_25(-7303024), - COLOR_26(-5789785), - COLOR_27(-10987432), - COLOR_28(-16754944), - COLOR_29(-16750080), - COLOR_30(-16745472), - COLOR_31(-16760576), - COLOR_32(-4934476), - COLOR_33(-2302756), - COLOR_34(-1), - COLOR_35(-7895161), - COLOR_36(-9210239), - COLOR_37(-7499618), - COLOR_38(-5986120), - COLOR_39(-11118495), - COLOR_40(-9810890), - COLOR_41(-8233406), - COLOR_42(-6853299), - COLOR_43(-11585240), - COLOR_44(-11579569), - COLOR_45(-10461088), - COLOR_46(-9408400), - COLOR_47(-12895429), - COLOR_48(-13816396), - COLOR_49(-13158436), - COLOR_50(-12566273), - COLOR_51(-14605945), - COLOR_52(-10202062), - COLOR_53(-8690114), - COLOR_54(-7375032), - COLOR_55(-11845850), - COLOR_56(-4935252), - COLOR_57(-2303533), - COLOR_58(-779), - COLOR_59(-7895679), - COLOR_60(-6792924), - COLOR_61(-4559572), - COLOR_62(-2588877), - COLOR_63(-9288933), - COLOR_64(-8571496), - COLOR_65(-6733382), - COLOR_66(-5092136), - COLOR_67(-10606478), - COLOR_68(-12030824), - COLOR_69(-10976070), - COLOR_70(-10053160), - COLOR_71(-13217422), - COLOR_72(-6184668), - COLOR_73(-3816148), - COLOR_74(-1710797), - COLOR_75(-8816357), - COLOR_76(-10907631), - COLOR_77(-9588715), - COLOR_78(-8401895), - COLOR_79(-12358643), - COLOR_80(-5613196), - COLOR_81(-3117682), - COLOR_82(-884827), - COLOR_83(-8371369), - COLOR_84(-13290187), - COLOR_85(-12500671), - COLOR_86(-11776948), - COLOR_87(-14145496), - COLOR_88(-9671572), - COLOR_89(-8092540), - COLOR_90(-6710887), - COLOR_91(-11447983), - COLOR_92(-13280916), - COLOR_93(-12489340), - COLOR_94(-11763815), - COLOR_95(-14138543), - COLOR_96(-10933123), - COLOR_97(-9619815), - COLOR_98(-8437838), - COLOR_99(-12377762), - COLOR_100(-14404227), - COLOR_101(-13876839), - COLOR_102(-13415246), - COLOR_103(-14997410), - COLOR_104(-12045020), - COLOR_105(-10993364), - COLOR_106(-10073037), - COLOR_107(-13228005), - COLOR_108(-12035804), - COLOR_109(-10982100), - COLOR_110(-10059981), - COLOR_111(-13221093), - COLOR_112(-9690076), - COLOR_113(-8115156), - COLOR_114(-6737101), - COLOR_115(-11461861), - COLOR_116(-15658735), - COLOR_117(-15395563), - COLOR_118(-15132391), - COLOR_119(-15921907), - COLOR_120(-5199818), - COLOR_121(-2634430), - COLOR_122(-332211), - COLOR_123(-8094168), - COLOR_124(-12543338), - COLOR_125(-11551561), - COLOR_126(-10691627), - COLOR_127(-13601936), - COLOR_128(-13346124), - COLOR_129(-12620068), - COLOR_130(-11894529), - COLOR_131(-14204025), - COLOR_132(-16738008), - COLOR_133(-16729294), - COLOR_134(-16721606), - COLOR_135(-16748002), - COLOR_136(-10798046), - COLOR_137(-9483734), - COLOR_138(-8301007), - COLOR_139(-12309223), - COLOR_140(-11599616), - COLOR_141(-10485504), - COLOR_142(-9436672), - COLOR_143(-12910336), - COLOR_144(-7111567), - COLOR_145(-4941686), - COLOR_146(-3034719), - COLOR_147(-9544363), - COLOR_148(-9422567), - COLOR_149(-7780833), - COLOR_150(-6335964), - COLOR_151(-11261165), - COLOR_152(-9880244), - COLOR_153(-8369315), - COLOR_154(-6989972), - COLOR_155(-11653575), - COLOR_156(-11580319), - COLOR_157(-10461833), - COLOR_158(-9409398), - COLOR_159(-12895927), - COLOR_160(-8168167), - COLOR_161(-6262241), - COLOR_162(-4553436), - COLOR_163(-10336749), - COLOR_164(-12037595), - COLOR_165(-10984403), - COLOR_166(-9997003), - COLOR_167(-13222628), - COLOR_168(-9423305), - COLOR_169(-7716285), - COLOR_170(-6271666), - COLOR_171(-11261911), - COLOR_172(-14148584), - COLOR_173(-13556962), - COLOR_174(-13031133), - COLOR_175(-14805742), - COLOR_176(-10532027), - COLOR_177(-9151404), - COLOR_178(-7902366), - COLOR_179(-12109773), - COLOR_180(-12763072), - COLOR_181(-11841713), - COLOR_182(-11051940), - COLOR_183(-13750224), - COLOR_184(-11128002), - COLOR_185(-9879989), - COLOR_186(-8763048), - COLOR_187(-12573138), - COLOR_188(-13292736), - COLOR_189(-12503729), - COLOR_190(-11780516), - COLOR_191(-14147536), - COLOR_192(-13294824), - COLOR_193(-12506338), - COLOR_194(-11783645), - COLOR_195(-14149102), - COLOR_196(-13289187), - COLOR_197(-12499420), - COLOR_198(-11775446), - COLOR_199(-14144746), - COLOR_200(-10212832), - COLOR_201(-8768729), - COLOR_202(-7455698), - COLOR_203(-11854056), - COLOR_204(-15069429), - COLOR_205(-14740979), - COLOR_206(-14346736), - COLOR_207(-15529208), - COLOR_208(-8052446), - COLOR_209(-6084310), - COLOR_210(-4378575), - COLOR_211(-10217191), - COLOR_212(-9950140), - COLOR_213(-8440237), - COLOR_214(-7061663), - COLOR_215(-11656909), - COLOR_216(-12578540), - COLOR_217(-11594471), - COLOR_218(-10741475), - COLOR_219(-13628145), - COLOR_220(-15771554), - COLOR_221(-15569805), - COLOR_222(-15303034), - COLOR_223(-16039354), - COLOR_224(-14130078), - COLOR_225(-13469064), - COLOR_226(-12939636), - COLOR_227(-14791862), - COLOR_228(-12837077), - COLOR_229(-11918027), - COLOR_230(-11129794), - COLOR_231(-13822176), - COLOR_232(-15827107), - COLOR_233(-15623310), - COLOR_234(-15420283), - COLOR_235(-16097466), - COLOR_236(-12171706), - COLOR_237(-11119018), - COLOR_238(-10197916), - COLOR_239(-13355980), - COLOR_240(-6784153), - COLOR_241(-4548994), - COLOR_242(-2576493), - COLOR_243(-9282483), - COLOR_244(-10914455), - COLOR_245(-9596799), - COLOR_246(-8411242), - COLOR_247(-12363697); + COLOR_0(-1, -1, -1), + COLOR_1(-1, -1, -1), + COLOR_2(-1, -1, -1), + COLOR_3(-1, -1, -1), + COLOR_4(89, 125, 39), + COLOR_5(109, 153, 48), + COLOR_6(127, 178, 56), + COLOR_7(67, 94, 29), + COLOR_8(174, 164, 115), + COLOR_9(213, 201, 140), + COLOR_10(247, 233, 163), + COLOR_11(130, 123, 86), + COLOR_12(140, 140, 140), + COLOR_13(171, 171, 171), + COLOR_14(199, 199, 199), + COLOR_15(105, 105, 105), + COLOR_16(180, 0, 0), + COLOR_17(220, 0, 0), + COLOR_18(255, 0, 0), + COLOR_19(135, 0, 0), + COLOR_20(112, 112, 180), + COLOR_21(138, 138, 220), + COLOR_22(160, 160, 255), + COLOR_23(84, 84, 135), + COLOR_24(117, 117, 117), + COLOR_25(144, 144, 144), + COLOR_26(167, 167, 167), + COLOR_27(88, 88, 88), + COLOR_28(0, 87, 0), + COLOR_29(0, 106, 0), + COLOR_30(0, 124, 0), + COLOR_31(0, 65, 0), + COLOR_32(180, 180, 180), + COLOR_33(220, 220, 220), + COLOR_34(255, 255, 255), + COLOR_35(135, 135, 135), + COLOR_36(115, 118, 129), + COLOR_37(141, 144, 158), + COLOR_38(164, 168, 184), + COLOR_39(86, 88, 97), + COLOR_40(106, 76, 54), + COLOR_41(130, 94, 66), + COLOR_42(151, 109, 77), + COLOR_43(79, 57, 40), + COLOR_44(79, 79, 79), + COLOR_45(96, 96, 96), + COLOR_46(112, 112, 112), + COLOR_47(59, 59, 59), + COLOR_48(45, 45, 180), + COLOR_49(55, 55, 220), + COLOR_50(64, 64, 255), + COLOR_51(33, 33, 135), + COLOR_52(100, 84, 50), + COLOR_53(123, 102, 62), + COLOR_54(143, 119, 72), + COLOR_55(75, 63, 38), + COLOR_56(180, 177, 172), + COLOR_57(220, 217, 211), + COLOR_58(255, 252, 245), + COLOR_59(135, 133, 129), + COLOR_60(152, 89, 36), + COLOR_61(186, 109, 44), + COLOR_62(216, 127, 51), + COLOR_63(114, 67, 27), + COLOR_64(125, 53, 152), + COLOR_65(153, 65, 186), + COLOR_66(178, 76, 216), + COLOR_67(94, 40, 114), + COLOR_68(72, 108, 152), + COLOR_69(88, 132, 186), + COLOR_70(102, 153, 216), + COLOR_71(54, 81, 114), + COLOR_72(161, 161, 36), + COLOR_73(197, 197, 44), + COLOR_74(229, 229, 51), + COLOR_75(121, 121, 27), + COLOR_76(89, 144, 17), + COLOR_77(109, 176, 21), + COLOR_78(127, 204, 25), + COLOR_79(67, 108, 13), + COLOR_80(170, 89, 116), + COLOR_81(208, 109, 142), + COLOR_82(242, 127, 165), + COLOR_83(128, 67, 87), + COLOR_84(53, 53, 53), + COLOR_85(65, 65, 65), + COLOR_86(76, 76, 76), + COLOR_87(40, 40, 40), + COLOR_88(108, 108, 108), + COLOR_89(132, 132, 132), + COLOR_90(153, 153, 153), + COLOR_91(81, 81, 81), + COLOR_92(53, 89, 108), + COLOR_93(65, 109, 132), + COLOR_94(76, 127, 153), + COLOR_95(40, 67, 81), + COLOR_96(89, 44, 125), + COLOR_97(109, 54, 153), + COLOR_98(127, 63, 178), + COLOR_99(67, 33, 94), + COLOR_100(36, 53, 125), + COLOR_101(44, 65, 153), + COLOR_102(51, 76, 178), + COLOR_103(27, 40, 94), + COLOR_104(72, 53, 36), + COLOR_105(88, 65, 44), + COLOR_106(102, 76, 51), + COLOR_107(54, 40, 27), + COLOR_108(72, 89, 36), + COLOR_109(88, 109, 44), + COLOR_110(102, 127, 51), + COLOR_111(54, 67, 27), + COLOR_112(108, 36, 36), + COLOR_113(132, 44, 44), + COLOR_114(153, 51, 51), + COLOR_115(81, 27, 27), + COLOR_116(17, 17, 17), + COLOR_117(21, 21, 21), + COLOR_118(25, 25, 25), + COLOR_119(13, 13, 13), + COLOR_120(176, 168, 54), + COLOR_121(215, 205, 66), + COLOR_122(250, 238, 77), + COLOR_123(132, 126, 40), + COLOR_124(64, 154, 150), + COLOR_125(79, 188, 183), + COLOR_126(92, 219, 213), + COLOR_127(48, 115, 112), + COLOR_128(52, 90, 180), + COLOR_129(63, 110, 220), + COLOR_130(74, 128, 255), + COLOR_131(39, 67, 135), + COLOR_132(0, 153, 40), + COLOR_133(0, 187, 50), + COLOR_134(0, 217, 58), + COLOR_135(0, 114, 30), + COLOR_136(91, 60, 34), + COLOR_137(111, 74, 42), + COLOR_138(129, 86, 49), + COLOR_139(68, 45, 25), + COLOR_140(79, 1, 0), + COLOR_141(96, 1, 0), + COLOR_142(112, 2, 0), + COLOR_143(59, 1, 0), + COLOR_144(147, 124, 113), + COLOR_145(180, 152, 138), + COLOR_146(209, 177, 161), + COLOR_147(110, 93, 85), + COLOR_148(112, 57, 25), + COLOR_149(137, 70, 31), + COLOR_150(159, 82, 36), + COLOR_151(84, 43, 19), + COLOR_152(105, 61, 76), + COLOR_153(128, 75, 93), + COLOR_154(149, 87, 108), + COLOR_155(78, 46, 57), + COLOR_156(79, 76, 97), + COLOR_157(96, 93, 119), + COLOR_158(112, 108, 138), + COLOR_159(59, 57, 73), + COLOR_160(131, 93, 25), + COLOR_161(160, 114, 31), + COLOR_162(186, 133, 36), + COLOR_163(98, 70, 19), + COLOR_164(72, 82, 37), + COLOR_165(88, 100, 45), + COLOR_166(103, 117, 53), + COLOR_167(54, 61, 28), + COLOR_168(112, 54, 55), + COLOR_169(138, 66, 67), + COLOR_170(160, 77, 78), + COLOR_171(84, 40, 41), + COLOR_172(40, 28, 24), + COLOR_173(49, 35, 30), + COLOR_174(57, 41, 35), + COLOR_175(30, 21, 18), + COLOR_176(95, 75, 69), + COLOR_177(116, 92, 84), + COLOR_178(135, 107, 98), + COLOR_179(71, 56, 51), + COLOR_180(61, 64, 64), + COLOR_181(75, 79, 79), + COLOR_182(87, 92, 92), + COLOR_183(46, 48, 48), + COLOR_184(86, 51, 62), + COLOR_185(105, 62, 75), + COLOR_186(122, 73, 88), + COLOR_187(64, 38, 46), + COLOR_188(53, 43, 64), + COLOR_189(65, 53, 79), + COLOR_190(76, 62, 92), + COLOR_191(40, 32, 48), + COLOR_192(53, 35, 24), + COLOR_193(65, 43, 30), + COLOR_194(76, 50, 35), + COLOR_195(40, 26, 18), + COLOR_196(53, 57, 29), + COLOR_197(65, 70, 36), + COLOR_198(76, 82, 42), + COLOR_199(40, 43, 22), + COLOR_200(100, 42, 32), + COLOR_201(122, 51, 39), + COLOR_202(142, 60, 46), + COLOR_203(75, 31, 24), + COLOR_204(26, 15, 11), + COLOR_205(31, 18, 13), + COLOR_206(37, 22, 16), + COLOR_207(19, 11, 8), + COLOR_208(133, 33, 34), + COLOR_209(163, 41, 42), + COLOR_210(189, 48, 49), + COLOR_211(100, 25, 25), + COLOR_212(104, 44, 68), + COLOR_213(127, 54, 83), + COLOR_214(148, 63, 97), + COLOR_215(78, 33, 51), + COLOR_216(64, 17, 20), + COLOR_217(79, 21, 25), + COLOR_218(92, 25, 29), + COLOR_219(48, 13, 15), + COLOR_220(15, 88, 94), + COLOR_221(18, 108, 115), + COLOR_222(22, 126, 134), + COLOR_223(11, 66, 70), + COLOR_224(40, 100, 98), + COLOR_225(50, 122, 120), + COLOR_226(58, 142, 140), + COLOR_227(30, 75, 74), + COLOR_228(60, 31, 43), + COLOR_229(74, 37, 53), + COLOR_230(86, 44, 62), + COLOR_231(45, 23, 32), + COLOR_232(14, 127, 93), + COLOR_233(17, 155, 114), + COLOR_234(20, 180, 133), + COLOR_235(10, 95, 70), + COLOR_236(70, 70, 70), + COLOR_237(86, 86, 86), + COLOR_238(100, 100, 100), + COLOR_239(52, 52, 52), + COLOR_240(152, 123, 103), + COLOR_241(186, 150, 126), + COLOR_242(216, 175, 147), + COLOR_243(114, 92, 77), + COLOR_244(89, 117, 105), + COLOR_245(109, 144, 129), + COLOR_246(127, 167, 150), + COLOR_247(67, 88, 79); private static final MapColor[] VALUES = values(); private final int value; - MapColor(int value) { - this.value = value; + MapColor(int red, int green, int blue) { + int alpha = 255; + if (red == -1 && green == -1 && blue == -1) + alpha = 0; // transparent + + this.value = ((alpha & 0xFF) << 24) | + ((red & 0xFF) << 16) | + ((green & 0xFF) << 8) | + (blue & 0xFF); } public static MapColor fromId(int id) { From c575689f2e8cbc8c70882c064f585bdfe5ee01ad Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 10 Dec 2024 03:11:57 +0800 Subject: [PATCH 499/897] let's not spam debug mode with an unused entity event --- .../protocol/java/entity/JavaEntityEventTranslator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index 504348b5b..2e2734410 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -295,6 +295,9 @@ public class JavaEntityEventTranslator extends PacketTranslator Date: Mon, 9 Dec 2024 22:42:40 -0500 Subject: [PATCH 500/897] Some touch-ups --- .../main/kotlin/geyser.base-conventions.gradle.kts | 4 ++-- .../type/living/animal/tameable/WolfEntity.java | 6 +++++- .../entity/type/living/monster/CreakingEntity.java | 11 +++++++---- .../java/org/geysermc/geyser/item/type/Item.java | 12 +++++++++--- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 045015fe1..093f0a8c0 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -26,6 +26,8 @@ dependencies { } repositories { + // mavenLocal() + mavenCentral() // Floodgate, Cumulus etc. @@ -67,6 +69,4 @@ repositories { // For Adventure snapshots maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") - - //mavenLocal() } 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 1b06f3860..ff2d57aef 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 @@ -128,7 +128,11 @@ public class WolfEntity extends TameableEntity { public void setBody(ItemStack stack) { super.setBody(stack); isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); - repairableItems = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE); + if (stack != null && stack.getDataComponents() != null) { + repairableItems = stack.getDataComponents().get(DataComponentType.REPAIRABLE); + } else { + repairableItems = null; + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java index 1a26eb43b..1b9fdd8a4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java @@ -40,14 +40,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataTyp import java.util.Optional; import java.util.UUID; - public class CreakingEntity extends MonsterEntity { - - private Vector3i homePosition; - public static final String CREAKING_STATE = "minecraft:creaking_state"; public static final String CREAKING_SWAYING_TICKS = "minecraft:creaking_swaying_ticks"; + private Vector3i homePosition; + public CreakingEntity(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); } @@ -62,6 +60,11 @@ public class CreakingEntity extends MonsterEntity { @Override public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { propertyManager.add(CREAKING_STATE, "neutral"); + // also, the creaking seems to have this minecraft:creaking_swaying_ticks thingy + // which i guess is responsible for some animation? + // it's sent over the network, all 6 "stages" 50ms in between of each other. + // no clue what it's used for tbh, so i'm not gonna bother implementing it + // - chris propertyManager.add(CREAKING_SWAYING_TICKS, 0); propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); } 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 b12ab4d67..51750e7b1 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 @@ -49,10 +49,12 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.MinecraftKey; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; 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.DyedItemColor; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; +import org.jetbrains.annotations.UnmodifiableView; import java.util.ArrayList; import java.util.HashMap; @@ -103,14 +105,18 @@ public class Item { * Otherwise, prefer using GeyserItemStack's getComponent */ @NonNull + @UnmodifiableView public DataComponents gatherComponents(DataComponents others) { if (others == null) { return baseComponents; } - DataComponents components = baseComponents.clone(); - components.getDataComponents().putAll(others.getDataComponents()); - return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); + //noinspection UnstableApiUsage + var builder = ImmutableMap., DataComponent>builderWithExpectedSize( + baseComponents.getDataComponents().size() + others.getDataComponents().size()); + builder.putAll(baseComponents.getDataComponents()); + builder.putAll(others.getDataComponents()); + return new DataComponents(builder.build()); } @Nullable From 8779eab5e5e11a781dd04e558744aff3f9228bb1 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 10 Dec 2024 20:44:29 +0800 Subject: [PATCH 501/897] Revert a change, ensure that gathering all components works and doesn't throw due to duplicate keys --- .../entity/type/living/animal/tameable/WolfEntity.java | 6 +----- .../main/java/org/geysermc/geyser/item/type/Item.java | 10 +++------- 2 files changed, 4 insertions(+), 12 deletions(-) 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 ff2d57aef..1b06f3860 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 @@ -128,11 +128,7 @@ public class WolfEntity extends TameableEntity { public void setBody(ItemStack stack) { super.setBody(stack); isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); - if (stack != null && stack.getDataComponents() != null) { - repairableItems = stack.getDataComponents().get(DataComponentType.REPAIRABLE); - } else { - repairableItems = null; - } + repairableItems = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE); } @Override 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 51750e7b1..c5dff3ad0 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 @@ -49,7 +49,6 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; 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.DyedItemColor; @@ -111,12 +110,9 @@ public class Item { return baseComponents; } - //noinspection UnstableApiUsage - var builder = ImmutableMap., DataComponent>builderWithExpectedSize( - baseComponents.getDataComponents().size() + others.getDataComponents().size()); - builder.putAll(baseComponents.getDataComponents()); - builder.putAll(others.getDataComponents()); - return new DataComponents(builder.build()); + DataComponents components = baseComponents.clone(); + components.getDataComponents().putAll(others.getDataComponents()); + return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); } @Nullable From 94d77b403b4ee26516438d58e6fd7f8ac6a52128 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 10 Dec 2024 23:13:32 +0800 Subject: [PATCH 502/897] Add some code comments, update BungeeCord version check --- .../bungeecord/GeyserBungeePlugin.java | 2 +- .../living/animal/tameable/WolfEntity.java | 1 + .../geyser/inventory/GeyserItemStack.java | 13 +++++++++++++ .../org/geysermc/geyser/item/type/Item.java | 18 +++++++++++++++--- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 7adfd488f..290bf2a4e 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -83,7 +83,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { // Copied from ViaVersion. // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 try { - ProtocolConstants.class.getField("MINECRAFT_1_21"); + ProtocolConstants.class.getField("MINECRAFT_1_21_4"); } catch (NoSuchFieldException e) { geyserLogger.error(" / \\"); geyserLogger.error(" / \\"); 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 1b06f3860..b108c9fbe 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 @@ -128,6 +128,7 @@ public class WolfEntity extends TameableEntity { public void setBody(ItemStack stack) { super.setBody(stack); isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); + // Not using ItemStack#getDataComponents as that wouldn't include default item components repairableItems = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE); } 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 c595ea1b5..4ddff305e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -125,6 +125,10 @@ public class GeyserItemStack { return isEmpty() ? null : components; } + /** + * @return whether this GeyserItemStack has any additional components on top of + * the base item components. + */ public boolean hasNonBaseComponents() { return components != null; } @@ -137,6 +141,15 @@ public class GeyserItemStack { return components; } + /** + * Returns the stored data component for a given {@link DataComponentType}, or null. + *

    + * This method will first check the additional components that may exist, + * and fallback to the item's default (or, "base") components if need be. + * @param type the {@link DataComponentType} to query + * @return the value for said type, or null. + * @param the value's type + */ @Nullable public T getComponent(@NonNull DataComponentType type) { if (components == null) { 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 c5dff3ad0..19789e086 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 @@ -100,21 +100,33 @@ public class Item { } /** - * Returns a modifiable DataComponents map. Should only be used when it must be modified. - * Otherwise, prefer using GeyserItemStack's getComponent + * Returns an unmodifiable {@link DataComponents} view containing known data components. + * Optionally, additional components can be provided to replace (or add to) + * the items' base components. + * To add data components, use {@link GeyserItemStack#getOrCreateComponents()}. */ @NonNull @UnmodifiableView - public DataComponents gatherComponents(DataComponents others) { + public DataComponents gatherComponents(@Nullable DataComponents others) { if (others == null) { return baseComponents; } + // Start with the base components that always exist DataComponents components = baseComponents.clone(); + // Add all additional components; these can override base components! + // e.g. custom stack size components.getDataComponents().putAll(others.getDataComponents()); + + // Return an unmodified map of the merged components return new DataComponents(ImmutableMap.copyOf(components.getDataComponents())); } + /** + * Returns this items value (or null) for a specific {@link DataComponentType}. + * Prefer using {@link GeyserItemStack#getComponent(DataComponentType)} + * to also query additional components that would override the default ones. + */ @Nullable public T getComponent(@NonNull DataComponentType type) { return baseComponents.get(type); From 5b90b114b52131da79e9579adb359041c9b703b2 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 11 Dec 2024 01:28:30 +0800 Subject: [PATCH 503/897] Remove unneeded code in CodecProcessor, make Bungee version checker automatically check for the required version --- .../bungeecord/GeyserBungeePlugin.java | 25 ++--- .../geyser/network/CodecProcessor.java | 96 ++----------------- 2 files changed, 20 insertions(+), 101 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 290bf2a4e..918c13b93 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -41,6 +41,7 @@ import org.geysermc.geyser.command.CommandSourceConverter; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSource; @@ -58,6 +59,7 @@ import java.net.SocketAddress; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; +import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -80,18 +82,19 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { public void onGeyserInitialize() { GeyserLocale.init(this); - // Copied from ViaVersion. - // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 try { - ProtocolConstants.class.getField("MINECRAFT_1_21_4"); - } catch (NoSuchFieldException e) { - geyserLogger.error(" / \\"); - geyserLogger.error(" / \\"); - geyserLogger.error(" / | \\"); - geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); - geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); - geyserLogger.error(" / o \\"); - geyserLogger.error("/_____________\\"); + List supportedProtocols = ProtocolConstants.SUPPORTED_VERSION_IDS; + if (!supportedProtocols.contains(GameProtocol.getJavaProtocolVersion())) { + geyserLogger.error(" / \\"); + geyserLogger.error(" / \\"); + geyserLogger.error(" / | \\"); + geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); + geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); + geyserLogger.error(" / o \\"); + geyserLogger.error("/_____________\\"); + } + } catch (Throwable e) { + geyserLogger.warning("Unable to check the versions supported by this proxy! " + e.getMessage()); } if (!this.loadConfig()) { 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 15aa8bc2c..de654ed62 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -35,17 +35,11 @@ import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MoveEntityAbsolut 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; -import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventoryContentSerializer_v712; -import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventorySlotSerializer_v712; import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.MobArmorEquipmentSerializer_v712; -import org.cloudburstmc.protocol.bedrock.codec.v729.serializer.InventoryContentSerializer_v729; -import org.cloudburstmc.protocol.bedrock.codec.v729.serializer.InventorySlotSerializer_v729; import org.cloudburstmc.protocol.bedrock.codec.v748.serializer.InventoryContentSerializer_v748; import org.cloudburstmc.protocol.bedrock.codec.v748.serializer.InventorySlotSerializer_v748; import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket; @@ -95,6 +89,7 @@ import org.cloudburstmc.protocol.common.util.VarInts; /** * Processes the Bedrock codec to remove or modify unused or unsafe packets and fields. */ +@SuppressWarnings("deprecation") class CodecProcessor { /** @@ -126,27 +121,9 @@ class CodecProcessor { public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BedrockPacket packet) { } }; - /** * Serializer that throws an exception when trying to deserialize InventoryContentPacket since server-auth inventory is used. */ - private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V407 = new InventoryContentSerializer_v407() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { - throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!"); - } - }; - - /** - * Serializer that throws an exception when trying to deserialize InventoryContentPacket since server-auth inventory is used. - */ - private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V712 = new InventoryContentSerializer_v712() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { - throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!"); - } - }; - private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V748 = new InventoryContentSerializer_v748() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { @@ -154,40 +131,9 @@ class CodecProcessor { } }; - private static final BedrockPacketSerializer INVENTORY_CONTENT_SERIALIZER_V729 = new InventoryContentSerializer_v729() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) { - throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!"); - } - }; - - /** - * Serializer that throws an exception when trying to deserialize InventorySlotPacket since server-auth inventory is used. - */ - private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER_V407 = new InventorySlotSerializer_v407() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { - throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!"); - } - }; - /* * Serializer that throws an exception when trying to deserialize InventorySlotPacket since server-auth inventory is used. */ - private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER_V712 = new InventorySlotSerializer_v712() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { - throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!"); - } - }; - - private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER_V729 = new InventorySlotSerializer_v729() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { - throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!"); - } - }; - private static final BedrockPacketSerializer INVENTORY_SLOT_SERIALIZER_V748 = new InventorySlotSerializer_v748() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) { @@ -297,32 +243,6 @@ class CodecProcessor { @SuppressWarnings("unchecked") static BedrockCodec processCodec(BedrockCodec codec) { - boolean is748OrAbove = codec.getProtocolVersion() >= 748; - boolean is729OrAbove = codec.getProtocolVersion() >= 729; - boolean is712OrAbove = codec.getProtocolVersion() >= 712; - - BedrockPacketSerializer inventoryContentSerializer; - if (is748OrAbove) { - inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V748; - } else if (is729OrAbove) { - inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V729; - } else if (is712OrAbove) { - inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V712; - } else { - inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V407; - } - - BedrockPacketSerializer inventorySlotSerializer; - if (is748OrAbove) { - inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V748; - } else if (is729OrAbove) { - inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V729; - } else if (is712OrAbove) { - inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V712; - } else { - inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V407; - } - BedrockCodec.Builder codecBuilder = codec.toBuilder() // Illegal unused serverbound EDU packets .updateSerializer(PhotoTransferPacket.class, ILLEGAL_SERIALIZER) @@ -350,15 +270,15 @@ class CodecProcessor { .updateSerializer(AnvilDamagePacket.class, IGNORED_SERIALIZER) .updateSerializer(RefreshEntitlementsPacket.class, IGNORED_SERIALIZER) // Illegal when serverbound due to Geyser specific setup - .updateSerializer(InventoryContentPacket.class, inventoryContentSerializer) - .updateSerializer(InventorySlotPacket.class, inventorySlotSerializer) + .updateSerializer(InventoryContentPacket.class, INVENTORY_CONTENT_SERIALIZER_V748) + .updateSerializer(InventorySlotPacket.class, INVENTORY_SLOT_SERIALIZER_V748) .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) + .updateSerializer(MobArmorEquipmentPacket.class, MOB_ARMOR_EQUIPMENT_SERIALIZER_V712) .updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER) .updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER) .updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER) @@ -373,12 +293,8 @@ class CodecProcessor { // Ignored bidirectional packets .updateSerializer(ClientCacheStatusPacket.class, IGNORED_SERIALIZER) .updateSerializer(SimpleEventPacket.class, IGNORED_SERIALIZER) - .updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER); - - if (codec.getProtocolVersion() < 685) { - // Ignored bidirectional packets - codecBuilder.updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER); - } + .updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER) + .updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER); return codecBuilder.build(); } From b843be58d00b49044fe79c2028299a9ba7703919 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 11 Dec 2024 01:41:08 +0800 Subject: [PATCH 504/897] don't set an illegal serializer for removed packet --- .../main/java/org/geysermc/geyser/network/CodecProcessor.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 de654ed62..b3f3af5ff 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -83,7 +83,6 @@ import org.cloudburstmc.protocol.bedrock.packet.SettingsCommandPacket; import org.cloudburstmc.protocol.bedrock.packet.SimpleEventPacket; import org.cloudburstmc.protocol.bedrock.packet.SubChunkRequestPacket; import org.cloudburstmc.protocol.bedrock.packet.SubClientLoginPacket; -import org.cloudburstmc.protocol.bedrock.packet.TickSyncPacket; import org.cloudburstmc.protocol.common.util.VarInts; /** @@ -293,8 +292,7 @@ class CodecProcessor { // Ignored bidirectional packets .updateSerializer(ClientCacheStatusPacket.class, IGNORED_SERIALIZER) .updateSerializer(SimpleEventPacket.class, IGNORED_SERIALIZER) - .updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER) - .updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER); + .updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER); return codecBuilder.build(); } From 4d12c291087b371fc6ef937dfebc4c4e5e4c7474 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 10 Dec 2024 21:22:39 +0000 Subject: [PATCH 505/897] Fix default attribute modifiers, add more equipment slot group names for attribute modifiers (#5211) --- .../translator/item/ItemTranslator.java | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) 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 54bbe086c..691a320e5 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.item; +import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.format.NamedTextColor; @@ -38,6 +39,7 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockData; +import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; @@ -52,6 +54,7 @@ import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.auth.GameProfile.Texture; import org.geysermc.mcprotocollib.auth.GameProfile.TextureType; @@ -89,16 +92,21 @@ public final class ItemTranslator { ItemAttributeModifiers.EquipmentSlotGroup.FEET }; private static final DecimalFormat ATTRIBUTE_FORMAT = new DecimalFormat("0.#####"); + private static final Key BASE_ATTACK_DAMAGE_ID = MinecraftKey.key("base_attack_damage"); + private static final Key BASE_ATTACK_SPEED_ID = MinecraftKey.key("base_attack_speed"); static { - // These are the only slots that are used and have translation strings + // Maps slot groups to their respective translation names, ordered in their Java edition order in the item tooltip SLOT_NAMES = new EnumMap<>(ItemAttributeModifiers.EquipmentSlotGroup.class); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.ANY, "any"); SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.MAIN_HAND, "mainhand"); SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.OFF_HAND, "offhand"); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.HAND, "hand"); SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.FEET, "feet"); SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.LEGS, "legs"); SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.CHEST, "chest"); SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.HEAD, "head"); + SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.ARMOR, "armor"); SLOT_NAMES.put(ItemAttributeModifiers.EquipmentSlotGroup.BODY, "body"); } @@ -175,7 +183,7 @@ public final class ItemTranslator { ItemAttributeModifiers attributeModifiers = components.get(DataComponentType.ATTRIBUTE_MODIFIERS); if (attributeModifiers != null && attributeModifiers.isShowInTooltip() && !hideTooltips) { // only add if attribute modifiers do not indicate to hide them - addAttributeLore(attributeModifiers, nbtBuilder, session.locale()); + addAttributeLore(session, attributeModifiers, nbtBuilder, session.locale()); } if (session.isAdvancedTooltips() && !hideTooltips) { @@ -229,31 +237,17 @@ public final class ItemTranslator { * @param modifiers the attribute modifiers of the ItemStack * @param language the locale of the player */ - private static void addAttributeLore(ItemAttributeModifiers modifiers, BedrockItemBuilder builder, String language) { + private static void addAttributeLore(GeyserSession session, ItemAttributeModifiers modifiers, BedrockItemBuilder builder, String language) { // maps each slot to the modifiers applied when in such slot Map> slotsToModifiers = new HashMap<>(); for (ItemAttributeModifiers.Entry entry : modifiers.getModifiers()) { // convert the modifier tag to a lore entry - String loreEntry = attributeToLore(entry.getAttribute(), entry.getModifier(), language); + String loreEntry = attributeToLore(session, entry.getAttribute(), entry.getModifier(), language); if (loreEntry == null) { continue; // invalid or failed } - ItemAttributeModifiers.EquipmentSlotGroup slotGroup = entry.getSlot(); - if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ARMOR) { - // modifier applies to all armor slots - for (ItemAttributeModifiers.EquipmentSlotGroup slot : ARMOR_SLOT_NAMES) { - slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreEntry); - } - } else if (slotGroup == ItemAttributeModifiers.EquipmentSlotGroup.ANY) { - // modifier applies to all slots implicitly - for (var slot : SLOT_NAMES.keySet()) { - slotsToModifiers.computeIfAbsent(slot, s -> new ArrayList<>()).add(loreEntry); - } - } else { - // modifier applies to only the specified slot - slotsToModifiers.computeIfAbsent(slotGroup, s -> new ArrayList<>()).add(loreEntry); - } + slotsToModifiers.computeIfAbsent(entry.getSlot(), s -> new ArrayList<>()).add(loreEntry); } // iterate through the small array, not the map, so that ordering matches Java Edition @@ -279,7 +273,7 @@ public final class ItemTranslator { } @Nullable - private static String attributeToLore(int attribute, ItemAttributeModifiers.AttributeModifier modifier, String language) { + private static String attributeToLore(GeyserSession session, int attribute, ItemAttributeModifiers.AttributeModifier modifier, String language) { double amount = modifier.getAmount(); if (amount == 0) { return null; @@ -289,24 +283,35 @@ public final class ItemTranslator { // the namespace does not need to be present, but if it is, the java client ignores it as of pre-1.20.5 ModifierOperation operation = modifier.getOperation(); + boolean baseModifier = false; String operationTotal = switch (operation) { case ADD -> { - if (name.equals("generic.knockback_resistance")) { + if (name.equals("knockback_resistance")) { amount *= 10; } + + if (modifier.getId().equals(BASE_ATTACK_DAMAGE_ID)) { + amount += session.getPlayerEntity().attributeOrDefault(GeyserAttributeType.ATTACK_DAMAGE); + baseModifier = true; + } else if (modifier.getId().equals(BASE_ATTACK_SPEED_ID)) { + amount += session.getPlayerEntity().attributeOrDefault(GeyserAttributeType.ATTACK_SPEED); + baseModifier = true; + } + yield ATTRIBUTE_FORMAT.format(amount); } case ADD_MULTIPLIED_BASE, ADD_MULTIPLIED_TOTAL -> ATTRIBUTE_FORMAT.format(amount * 100) + "%"; }; - if (amount > 0) { + if (amount > 0 && !baseModifier) { operationTotal = "+" + operationTotal; } + Component attributeComponent = Component.text() .resetStyle() - .color(amount > 0 ? NamedTextColor.BLUE : NamedTextColor.RED) - .append(Component.text(operationTotal + " "), Component.translatable("attribute.name." + name)) + .color(baseModifier ? NamedTextColor.DARK_GREEN : amount > 0 ? NamedTextColor.BLUE : NamedTextColor.RED) + .append(Component.text(" " + operationTotal + " "), Component.translatable("attribute.name." + name)) .build(); return MessageTranslator.convertMessage(attributeComponent, language); From b2045a5b3d55eb51fd6caef9207bb082d860751a Mon Sep 17 00:00:00 2001 From: Valaphee The Meerkat <32491319+valaphee@users.noreply.github.com> Date: Wed, 11 Dec 2024 03:04:33 +0100 Subject: [PATCH 506/897] Fix skull mix-up by not reusing skulls (#5206) --- .../entity/type/player/SkullPlayerEntity.java | 11 ----- .../geyser/session/cache/SkullCache.java | 45 ++++--------------- 2 files changed, 9 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java index 1c5060de0..4c8d1d20b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java @@ -102,17 +102,6 @@ public class SkullPlayerEntity extends PlayerEntity { session.sendUpstreamPacket(addPlayerPacket); } - /** - * Hide the player entity so that it can be reused for a different skull. - */ - public void free() { - setFlag(EntityFlag.INVISIBLE, true); - updateBedrockMetadata(); - - // Move skull entity out of the way - moveAbsolute(session.getPlayerEntity().getPosition().up(128), 0, 0, 0, false, true); - } - public void updateSkull(SkullCache.Skull skull) { skullPosition = skull.getPosition(); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java index 0eec39b0b..a3cf1247f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java @@ -50,20 +50,14 @@ import java.util.*; public class SkullCache { private final int maxVisibleSkulls; private final boolean cullingEnabled; - + private final int skullRenderDistanceSquared; - - /** - * The time in milliseconds before unused skull entities are despawned - */ - private static final long CLEANUP_PERIOD = 10000; @Getter private final Map skulls = new Object2ObjectOpenHashMap<>(); private final List inRangeSkulls = new ArrayList<>(); - private final Deque unusedSkullEntities = new ArrayDeque<>(); private int totalSkullEntities = 0; private final GeyserSession session; @@ -188,43 +182,26 @@ public class SkullCache { } } } - - // Occasionally clean up unused entities as we want to keep skull - // entities around for later use, to reduce "player" pop-in - if ((System.currentTimeMillis() - lastCleanup) > CLEANUP_PERIOD) { - lastCleanup = System.currentTimeMillis(); - for (SkullPlayerEntity entity : unusedSkullEntities) { - entity.despawnEntity(); - totalSkullEntities--; - } - unusedSkullEntities.clear(); - } } private void assignSkullEntity(Skull skull) { if (skull.entity != null) { return; } - if (unusedSkullEntities.isEmpty()) { - if (!cullingEnabled || totalSkullEntities < maxVisibleSkulls) { - // Create a new entity - long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); - skull.entity = new SkullPlayerEntity(session, geyserId); - skull.entity.spawnEntity(); - skull.entity.updateSkull(skull); - totalSkullEntities++; - } - } else { - // Reuse an entity - skull.entity = unusedSkullEntities.removeFirst(); + if (!cullingEnabled || totalSkullEntities < maxVisibleSkulls) { + // Create a new entity + long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); + skull.entity = new SkullPlayerEntity(session, geyserId); + skull.entity.spawnEntity(); skull.entity.updateSkull(skull); + totalSkullEntities++; } } private void freeSkullEntity(Skull skull) { if (skull.entity != null) { - skull.entity.free(); - unusedSkullEntities.addFirst(skull.entity); + skull.entity.despawnEntity(); + totalSkullEntities--; skull.entity = null; } } @@ -250,10 +227,6 @@ public class SkullCache { } skulls.clear(); inRangeSkulls.clear(); - for (SkullPlayerEntity skull : unusedSkullEntities) { - skull.despawnEntity(); - } - unusedSkullEntities.clear(); totalSkullEntities = 0; lastPlayerPosition = null; } From b36bc9e95accc97b22d6993c0fd71fc6650c2e57 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 11 Dec 2024 23:31:23 +0800 Subject: [PATCH 507/897] Indicate 1.21.51 support --- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index bb7032d25..7aaeef87d 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -48,7 +48,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v766.CODEC.toBuilder() - .minecraftVersion("1.21.50") + .minecraftVersion("1.21.51") .build()); /** @@ -66,7 +66,9 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() .minecraftVersion("1.21.40 - 1.21.44") .build())); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.21.50 - 1.21.51") + .build()); } /** From f24ba549df44c2effec31b9ba82d319321b1129a Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 12 Dec 2024 09:13:04 +0800 Subject: [PATCH 508/897] Target master branch for mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index e8089e117..8707dd144 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit e8089e117605e60a5ced120926c49fae7617c665 +Subproject commit 8707dd144b20632f4a2f4b5497d8e5fb211e6c93 From c8dadd8342c5c8fba14a5da962700f741c3b116b Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 14 Dec 2024 18:31:24 +0000 Subject: [PATCH 509/897] Remove Java attribute entity type prefixes (#5228) --- .../entity/attribute/GeyserAttributeType.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index 833f2f46d..10e93810e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -35,22 +35,22 @@ import lombok.Getter; public enum GeyserAttributeType { // Universal Attributes - FOLLOW_RANGE("minecraft:generic.follow_range", "minecraft:follow_range", 0f, 2048f, 32f), - KNOCKBACK_RESISTANCE("minecraft:generic.knockback_resistance", "minecraft:knockback_resistance", 0f, 1f, 0f), - MOVEMENT_SPEED("minecraft:generic.movement_speed", "minecraft:movement", 0f, 1024f, 0.1f), - FLYING_SPEED("minecraft:generic.flying_speed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f), - ATTACK_DAMAGE("minecraft:generic.attack_damage", "minecraft:attack_damage", 0f, 2048f, 1f), - HORSE_JUMP_STRENGTH("minecraft:horse.jump_strength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f), - LUCK("minecraft:generic.luck", "minecraft:luck", -1024f, 1024f, 0f), + FOLLOW_RANGE("minecraft:follow_range", "minecraft:follow_range", 0f, 2048f, 32f), + KNOCKBACK_RESISTANCE("minecraft:knockback_resistance", "minecraft:knockback_resistance", 0f, 1f, 0f), + MOVEMENT_SPEED("minecraft:movement_speed", "minecraft:movement", 0f, 1024f, 0.1f), + FLYING_SPEED("minecraft:flying_speed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f), + ATTACK_DAMAGE("minecraft:attack_damage", "minecraft:attack_damage", 0f, 2048f, 1f), + HORSE_JUMP_STRENGTH("minecraft:jump_strength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f), + LUCK("minecraft:luck", "minecraft:luck", -1024f, 1024f, 0f), // Java Attributes - ARMOR("minecraft:generic.armor", null, 0f, 30f, 0f), - ARMOR_TOUGHNESS("minecraft:generic.armor_toughness", null, 0F, 20f, 0f), - ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f), - ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f), - MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f), - SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), - BLOCK_INTERACTION_RANGE("minecraft:player.block_interaction_range", null, 0.0f, 64f, 4.5f), + ARMOR("minecraft:armor", null, 0f, 30f, 0f), + ARMOR_TOUGHNESS("minecraft:armor_toughness", null, 0F, 20f, 0f), + ATTACK_KNOCKBACK("minecraft:attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f), + ATTACK_SPEED("minecraft:attack_speed", null, 0f, 1024f, 4f), + MAX_HEALTH("minecraft:max_health", null, 0f, 1024f, 20f), + SCALE("minecraft:scale", null, 0.0625f, 16f, 1f), + BLOCK_INTERACTION_RANGE("minecraft:block_interaction_range", null, 0.0f, 64f, 4.5f), MINING_EFFICIENCY("minecraft:mining_efficiency", null, 0f, 1024f, 0f), BLOCK_BREAK_SPEED("minecraft:block_break_speed", null, 0f, 1024f, 1f), SUBMERGED_MINING_SPEED("minecraft:submerged_mining_speed", null, 0f, 20f, 0.2f), From 54bdb639cba95b19d0d50f2727c8421d8754972f Mon Sep 17 00:00:00 2001 From: AlexDev_ <56083016+alexdev03@users.noreply.github.com> Date: Sun, 15 Dec 2024 16:15:55 +0100 Subject: [PATCH 510/897] Fix for plugins that use display entities as nametag (#5157) * Fix for display entity nametags * Added check * Moved lines count to TextDisplayEntity class Removed useless offset * Reset lines when text is null * Conversation changes * Changed y offset formula Removed space * Played around with the yOffset a bit --------- Co-authored-by: Tim203 --- .../geyser/entity/type/TextDisplayEntity.java | 16 ++++++++++++++++ .../org/geysermc/geyser/util/EntityUtils.java | 12 ++++++++++++ 2 files changed, 28 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java index 8b47ce1ed..0cd207c52 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java @@ -25,18 +25,25 @@ package org.geysermc.geyser.entity.type; +import lombok.Getter; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.jetbrains.annotations.Nullable; import java.util.UUID; // Note: 1.19.4 requires that the billboard is set to something in order to show, on Java Edition +@Getter public class TextDisplayEntity extends DisplayBaseEntity { + + private int lineCount; + public TextDisplayEntity(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.add(0, definition.offset(), 0), motion, yaw, pitch, headYaw); } @@ -61,5 +68,14 @@ public class TextDisplayEntity extends DisplayBaseEntity { public void setText(EntityMetadata entityMetadata) { this.dirtyMetadata.put(EntityDataTypes.NAME, MessageTranslator.convertMessage(entityMetadata.getValue())); + calculateLineCount(entityMetadata.getValue()); + } + + private void calculateLineCount(@Nullable Component text) { + if (text == null) { + lineCount = 0; + return; + } + lineCount = PlainTextComponentSerializer.plainText().serialize(text).split("\n").length; } } 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 034975b15..388162a49 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -209,6 +209,18 @@ public final class EntityUtils { zOffset = displayTranslation.getZ(); } } + case PLAYER -> { + if (passenger instanceof TextDisplayEntity textDisplay) { + Vector3f displayTranslation = textDisplay.getTranslation(); + int lines = textDisplay.getLineCount(); + if (displayTranslation != null && lines != 0) { + float multiplier = .1414f; + xOffset = displayTranslation.getX(); + yOffset += displayTranslation.getY() + multiplier * lines; + zOffset = displayTranslation.getZ(); + } + } + } } if (mount instanceof ChestBoatEntity) { xOffset = 0.15F; From a5c77a707241e07dae5654d17de1e1fd2ceec022 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 15 Dec 2024 22:40:14 +0000 Subject: [PATCH 511/897] Add extension update folder (#4929) * Add extension update folder * Check the update folder exists before trying to use it * Remove old jars under different names for the same extensions * Store file path to save on calls * Fix storing path * Update languages * Update core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java Co-authored-by: chris * Only pull data from the map once * Update core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> * Move to consumer function for processing extension folders * Add back some comments * Allow cleanup of multiple old extensions * Address review comments * Tidy logger calls --------- Co-authored-by: chris Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> --- .../extension/GeyserExtensionLoader.java | 136 ++++++++++++------ .../geyser/util/ThrowingBiConsumer.java | 42 ++++++ 2 files changed, 136 insertions(+), 42 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/util/ThrowingBiConsumer.java diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index a56e00671..10cbcf556 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -31,6 +31,7 @@ import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.api.util.ApiVersion; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.event.ExtensionEventBus; import org.geysermc.geyser.api.extension.Extension; @@ -42,6 +43,7 @@ import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; import org.geysermc.geyser.extension.event.GeyserExtensionEventBus; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.ThrowingBiConsumer; import java.io.IOException; import java.io.Reader; @@ -51,10 +53,12 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; import java.util.regex.Pattern; @RequiredArgsConstructor @@ -155,6 +159,7 @@ public class GeyserExtensionLoader extends ExtensionLoader { @Override protected void loadAllExtensions(@NonNull ExtensionManager extensionManager) { + GeyserLogger logger = GeyserImpl.getInstance().getLogger(); try { if (Files.notExists(extensionsDirectory)) { Files.createDirectory(extensionsDirectory); @@ -163,55 +168,68 @@ public class GeyserExtensionLoader extends ExtensionLoader { Map extensions = new LinkedHashMap<>(); Map loadedExtensions = new LinkedHashMap<>(); - Pattern[] extensionFilters = this.extensionFilters(); - List extensionPaths = Files.walk(extensionsDirectory).toList(); - extensionPaths.forEach(path -> { - if (Files.isDirectory(path)) { - return; - } + Path updateDirectory = extensionsDirectory.resolve("update"); + if (Files.isDirectory(updateDirectory)) { + // Step 1: Collect the extension files that currently exist so they can be replaced + Map> extensionFiles = new HashMap<>(); + this.processExtensionsFolder(extensionsDirectory, (path, description) -> { + extensionFiles.computeIfAbsent(description.id(), k -> new ArrayList<>()).add(path); + }, (path, e) -> { + // this file will throw again when we actually try to load extensions, and it will be handled there + }); - for (Pattern filter : extensionFilters) { - if (!filter.matcher(path.getFileName().toString()).matches()) { - return; - } - } - - try { - GeyserExtensionDescription description = this.extensionDescription(path); - - String name = description.name(); - String id = description.id(); - if (extensions.containsKey(id) || extensionManager.extension(id) != null) { - GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString())); - return; - } - - // Check whether an extensions' requested api version is compatible - ApiVersion.Compatibility compatibility = GeyserApi.api().geyserApiVersion().supportsRequestedVersion( - description.humanApiVersion(), - description.majorApiVersion(), - description.minorApiVersion() - ); - - if (compatibility != ApiVersion.Compatibility.COMPATIBLE) { - // Workaround for the switch to the Geyser API version instead of the Base API version in extensions - if (compatibility == ApiVersion.Compatibility.HUMAN_DIFFER && description.humanApiVersion() == 1) { - GeyserImpl.getInstance().getLogger().warning("The extension %s requested the Base API version %s, which is deprecated in favor of specifying the Geyser API version. Please update the extension, or contact its developer." - .formatted(name, description.apiVersion())); - } else { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); - return; + // Step 2: Move the updated/new extensions + this.processExtensionsFolder(updateDirectory, (path, description) -> { + // Remove the old extension files with the same ID if it exists + List oldExtensionFiles = extensionFiles.get(description.id()); + if (oldExtensionFiles != null) { + for (Path oldExtensionFile : oldExtensionFiles) { + Files.delete(oldExtensionFile); } } - GeyserExtensionContainer container = this.loadExtension(path, description); - extensions.put(id, path); - loadedExtensions.put(id, container); - } catch (Throwable e) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", path.getFileName(), path.toAbsolutePath()), e); + // Overwrite the extension with the new jar + Files.move(path, extensionsDirectory.resolve(path.getFileName()), StandardCopyOption.REPLACE_EXISTING); + }, (path, e) -> { + logger.error(GeyserLocale.getLocaleStringLog("geyser.extensions.update.failed", path.getFileName()), e); + }); + } + + // Step 3: Load the extensions + this.processExtensionsFolder(extensionsDirectory, (path, description) -> { + String name = description.name(); + String id = description.id(); + if (extensions.containsKey(id) || extensionManager.extension(id) != null) { + logger.warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString())); + return; } + + // Check whether an extensions' requested api version is compatible + ApiVersion.Compatibility compatibility = GeyserApi.api().geyserApiVersion().supportsRequestedVersion( + description.humanApiVersion(), + description.majorApiVersion(), + description.minorApiVersion() + ); + + if (compatibility != ApiVersion.Compatibility.COMPATIBLE) { + // Workaround for the switch to the Geyser API version instead of the Base API version in extensions + if (compatibility == ApiVersion.Compatibility.HUMAN_DIFFER && description.humanApiVersion() == 1) { + logger.warning("The extension %s requested the Base API version %s, which is deprecated in favor of specifying the Geyser API version. Please update the extension, or contact its developer." + .formatted(name, description.apiVersion())); + } else { + logger.error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); + return; + } + } + + GeyserExtensionContainer container = this.loadExtension(path, description); + extensions.put(id, path); + loadedExtensions.put(id, container); + }, (path, e) -> { + logger.error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", path.getFileName(), path.toAbsolutePath()), e); }); + // Step 4: Register the extensions for (GeyserExtensionContainer container : loadedExtensions.values()) { this.extensionContainers.put(container.extension(), container); this.register(container.extension(), extensionManager); @@ -221,6 +239,40 @@ public class GeyserExtensionLoader extends ExtensionLoader { } } + /** + * Process extension jars in a folder and call the accept or reject consumer based on the result + * + * @param directory the directory to process + * @param accept the consumer to call when an extension is accepted + * @param reject the consumer to call when an extension is rejected + * @throws IOException if an I/O error occurs + */ + private void processExtensionsFolder(Path directory, ThrowingBiConsumer accept, BiConsumer reject) throws IOException { + List extensionPaths = Files.list(directory).toList(); + Pattern[] extensionFilters = this.extensionFilters(); + extensionPaths.forEach(path -> { + if (Files.isDirectory(path)) { + return; + } + + // Only look at files that meet the extension filter + for (Pattern filter : extensionFilters) { + if (!filter.matcher(path.getFileName().toString()).matches()) { + return; + } + } + + try { + // Try load the description, so we know it's a valid extension + GeyserExtensionDescription description = this.extensionDescription(path); + + accept.acceptThrows(path, description); + } catch (Throwable e) { + reject.accept(path, e); + } + }); + } + @Override protected boolean isEnabled(@NonNull Extension extension) { return this.extensionContainers.get(extension).enabled; diff --git a/core/src/main/java/org/geysermc/geyser/util/ThrowingBiConsumer.java b/core/src/main/java/org/geysermc/geyser/util/ThrowingBiConsumer.java new file mode 100644 index 000000000..96adbb5c9 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/ThrowingBiConsumer.java @@ -0,0 +1,42 @@ +/* + * 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.util; + +import java.util.function.BiConsumer; + +@FunctionalInterface +public interface ThrowingBiConsumer extends BiConsumer { + @Override + default void accept(T t, U u) { + try { + acceptThrows(t, u); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + void acceptThrows(T t, U u) throws Throwable; +} From 64c7adcacfb1ad39c7035ab0c9ccf81468e75485 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 16 Dec 2024 10:54:36 +0800 Subject: [PATCH 512/897] Fix: Geyser-Spigot not loading on 1.16.5, remove unused code --- .../geyser/entity/type/BoatEntity.java | 34 ++++++------------- .../geyser/entity/type/ChestBoatEntity.java | 6 ---- .../DataComponentRegistryPopulator.java | 3 +- gradle/libs.versions.toml | 6 ++-- 4 files changed, 16 insertions(+), 33 deletions(-) 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 04df96361..7d789fb2a 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,8 +32,6 @@ 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.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; @@ -220,10 +218,6 @@ 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()); @@ -236,23 +230,17 @@ public class BoatEntity extends Entity implements Leashable, Tickable { * 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), - PALE_OAK(Items.PALE_OAK_BOAT, Items.PALE_OAK_CHEST_BOAT); + OAK, + SPRUCE, + BIRCH, + JUNGLE, + ACACIA, + DARK_OAK, + MANGROVE, + BAMBOO, + CHERRY, + PALE_OAK; - private final Item pickItem; - final Item chestPickItem; - - BoatVariant(Item pickItem, Item chestPickItem) { - this.pickItem = pickItem; - this.chestPickItem = chestPickItem; - } + BoatVariant() {} } } 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 967da41df..5475ca772 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,7 +27,6 @@ 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; @@ -49,9 +48,4 @@ 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/registry/populator/DataComponentRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java index 386c795d2..d8547bbfc 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java @@ -55,7 +55,8 @@ public final class DataComponentRegistryPopulator { GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); List defaultComponents; try (InputStream stream = bootstrap.getResourceOrThrow("java/item_data_components.json")) { - JsonElement rootElement = JsonParser.parseReader(new InputStreamReader(stream)); + //noinspection deprecation - 1.16.5 breaks otherwise + JsonElement rootElement = new JsonParser().parse(new InputStreamReader(stream)); JsonArray jsonArray = rootElement.getAsJsonArray(); defaultComponents = new ObjectArrayList<>(jsonArray.size()); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1166bab35..b90436644 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,9 +10,9 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol-connection = "3.0.0.Beta5-20241203.200249-19" -protocol-common = "3.0.0.Beta5-20241203.200249-19" -protocol-codec = "3.0.0.Beta5-20241203.200249-19" +protocol-connection = "3.0.0.Beta5-20241213.160944-20" +protocol-common = "3.0.0.Beta5-20241213.160944-20" +protocol-codec = "3.0.0.Beta5-20241213.160944-20" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" mcprotocollib = "1.21.4-SNAPSHOT" From 006fe75e5af5f5686fb18051415663cb8ceaaa1b Mon Sep 17 00:00:00 2001 From: Adri Date: Sun, 22 Dec 2024 03:51:13 +0100 Subject: [PATCH 513/897] fix: Wrong map colors (#5238) --- .../org/geysermc/geyser/level/MapColor.java | 416 +++++++++--------- 1 file changed, 208 insertions(+), 208 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/MapColor.java b/core/src/main/java/org/geysermc/geyser/level/MapColor.java index a599f9146..f4b4fb697 100644 --- a/core/src/main/java/org/geysermc/geyser/level/MapColor.java +++ b/core/src/main/java/org/geysermc/geyser/level/MapColor.java @@ -30,26 +30,26 @@ public enum MapColor { COLOR_1(-1, -1, -1), COLOR_2(-1, -1, -1), COLOR_3(-1, -1, -1), - COLOR_4(89, 125, 39), - COLOR_5(109, 153, 48), - COLOR_6(127, 178, 56), - COLOR_7(67, 94, 29), - COLOR_8(174, 164, 115), - COLOR_9(213, 201, 140), - COLOR_10(247, 233, 163), - COLOR_11(130, 123, 86), + COLOR_4(39, 125, 89), + COLOR_5(48, 153, 109), + COLOR_6(56, 178, 127), + COLOR_7(29, 94, 67), + COLOR_8(115, 164, 174), + COLOR_9(140, 201, 213), + COLOR_10(163, 233, 247), + COLOR_11(86, 123, 130), COLOR_12(140, 140, 140), COLOR_13(171, 171, 171), COLOR_14(199, 199, 199), COLOR_15(105, 105, 105), - COLOR_16(180, 0, 0), - COLOR_17(220, 0, 0), - COLOR_18(255, 0, 0), - COLOR_19(135, 0, 0), - COLOR_20(112, 112, 180), - COLOR_21(138, 138, 220), - COLOR_22(160, 160, 255), - COLOR_23(84, 84, 135), + COLOR_16(0, 0, 180), + COLOR_17(0, 0, 220), + COLOR_18(0, 0, 255), + COLOR_19(0, 0, 135), + COLOR_20(180, 112, 112), + COLOR_21(220, 138, 138), + COLOR_22(255, 160, 160), + COLOR_23(135, 84, 84), COLOR_24(117, 117, 117), COLOR_25(144, 144, 144), COLOR_26(167, 167, 167), @@ -62,54 +62,54 @@ public enum MapColor { COLOR_33(220, 220, 220), COLOR_34(255, 255, 255), COLOR_35(135, 135, 135), - COLOR_36(115, 118, 129), - COLOR_37(141, 144, 158), - COLOR_38(164, 168, 184), - COLOR_39(86, 88, 97), - COLOR_40(106, 76, 54), - COLOR_41(130, 94, 66), - COLOR_42(151, 109, 77), - COLOR_43(79, 57, 40), + COLOR_36(129, 118, 115), + COLOR_37(158, 144, 141), + COLOR_38(184, 168, 164), + COLOR_39(97, 88, 86), + COLOR_40(54, 76, 106), + COLOR_41(66, 94, 130), + COLOR_42(77, 109, 151), + COLOR_43(40, 57, 79), COLOR_44(79, 79, 79), COLOR_45(96, 96, 96), COLOR_46(112, 112, 112), COLOR_47(59, 59, 59), - COLOR_48(45, 45, 180), - COLOR_49(55, 55, 220), - COLOR_50(64, 64, 255), - COLOR_51(33, 33, 135), - COLOR_52(100, 84, 50), - COLOR_53(123, 102, 62), - COLOR_54(143, 119, 72), - COLOR_55(75, 63, 38), - COLOR_56(180, 177, 172), - COLOR_57(220, 217, 211), - COLOR_58(255, 252, 245), - COLOR_59(135, 133, 129), - COLOR_60(152, 89, 36), - COLOR_61(186, 109, 44), - COLOR_62(216, 127, 51), - COLOR_63(114, 67, 27), - COLOR_64(125, 53, 152), - COLOR_65(153, 65, 186), - COLOR_66(178, 76, 216), - COLOR_67(94, 40, 114), - COLOR_68(72, 108, 152), - COLOR_69(88, 132, 186), - COLOR_70(102, 153, 216), - COLOR_71(54, 81, 114), - COLOR_72(161, 161, 36), - COLOR_73(197, 197, 44), - COLOR_74(229, 229, 51), - COLOR_75(121, 121, 27), - COLOR_76(89, 144, 17), - COLOR_77(109, 176, 21), - COLOR_78(127, 204, 25), - COLOR_79(67, 108, 13), - COLOR_80(170, 89, 116), - COLOR_81(208, 109, 142), - COLOR_82(242, 127, 165), - COLOR_83(128, 67, 87), + COLOR_48(180, 45, 45), + COLOR_49(220, 55, 55), + COLOR_50(255, 64, 64), + COLOR_51(135, 33, 33), + COLOR_52(50, 84, 100), + COLOR_53(62, 102, 123), + COLOR_54(72, 119, 143), + COLOR_55(38, 63, 75), + COLOR_56(172, 177, 180), + COLOR_57(211, 217, 220), + COLOR_58(245, 252, 255), + COLOR_59(129, 133, 135), + COLOR_60(36, 89, 152), + COLOR_61(44, 109, 186), + COLOR_62(51, 127, 216), + COLOR_63(27, 67, 114), + COLOR_64(152, 53, 125), + COLOR_65(186, 65, 153), + COLOR_66(216, 76, 178), + COLOR_67(114, 40, 94), + COLOR_68(152, 108, 72), + COLOR_69(186, 132, 88), + COLOR_70(216, 153, 102), + COLOR_71(114, 81, 54), + COLOR_72(36, 161, 161), + COLOR_73(44, 197, 197), + COLOR_74(51, 229, 229), + COLOR_75(27, 121, 121), + COLOR_76(17, 144, 89), + COLOR_77(21, 176, 109), + COLOR_78(25, 204, 127), + COLOR_79(13, 108, 67), + COLOR_80(116, 89, 170), + COLOR_81(142, 109, 208), + COLOR_82(165, 127, 242), + COLOR_83(87, 67, 128), COLOR_84(53, 53, 53), COLOR_85(65, 65, 65), COLOR_86(76, 76, 76), @@ -118,162 +118,162 @@ public enum MapColor { COLOR_89(132, 132, 132), COLOR_90(153, 153, 153), COLOR_91(81, 81, 81), - COLOR_92(53, 89, 108), - COLOR_93(65, 109, 132), - COLOR_94(76, 127, 153), - COLOR_95(40, 67, 81), - COLOR_96(89, 44, 125), - COLOR_97(109, 54, 153), - COLOR_98(127, 63, 178), - COLOR_99(67, 33, 94), - COLOR_100(36, 53, 125), - COLOR_101(44, 65, 153), - COLOR_102(51, 76, 178), - COLOR_103(27, 40, 94), - COLOR_104(72, 53, 36), - COLOR_105(88, 65, 44), - COLOR_106(102, 76, 51), - COLOR_107(54, 40, 27), - COLOR_108(72, 89, 36), - COLOR_109(88, 109, 44), - COLOR_110(102, 127, 51), - COLOR_111(54, 67, 27), - COLOR_112(108, 36, 36), - COLOR_113(132, 44, 44), - COLOR_114(153, 51, 51), - COLOR_115(81, 27, 27), + COLOR_92(108, 89, 53), + COLOR_93(132, 109, 65), + COLOR_94(153, 127, 76), + COLOR_95(81, 67, 40), + COLOR_96(125, 44, 89), + COLOR_97(153, 54, 109), + COLOR_98(178, 63, 127), + COLOR_99(94, 33, 67), + COLOR_100(125, 53, 36), + COLOR_101(153, 65, 44), + COLOR_102(178, 76, 51), + COLOR_103(94, 40, 27), + COLOR_104(36, 53, 72), + COLOR_105(44, 65, 88), + COLOR_106(51, 76, 102), + COLOR_107(27, 40, 54), + COLOR_108(36, 89, 72), + COLOR_109(44, 109, 88), + COLOR_110(51, 127, 102), + COLOR_111(27, 67, 54), + COLOR_112(36, 36, 108), + COLOR_113(44, 44, 132), + COLOR_114(51, 51, 153), + COLOR_115(27, 27, 81), COLOR_116(17, 17, 17), COLOR_117(21, 21, 21), COLOR_118(25, 25, 25), COLOR_119(13, 13, 13), - COLOR_120(176, 168, 54), - COLOR_121(215, 205, 66), - COLOR_122(250, 238, 77), - COLOR_123(132, 126, 40), - COLOR_124(64, 154, 150), - COLOR_125(79, 188, 183), - COLOR_126(92, 219, 213), - COLOR_127(48, 115, 112), - COLOR_128(52, 90, 180), - COLOR_129(63, 110, 220), - COLOR_130(74, 128, 255), - COLOR_131(39, 67, 135), - COLOR_132(0, 153, 40), - COLOR_133(0, 187, 50), - COLOR_134(0, 217, 58), - COLOR_135(0, 114, 30), - COLOR_136(91, 60, 34), - COLOR_137(111, 74, 42), - COLOR_138(129, 86, 49), - COLOR_139(68, 45, 25), - COLOR_140(79, 1, 0), - COLOR_141(96, 1, 0), - COLOR_142(112, 2, 0), - COLOR_143(59, 1, 0), - COLOR_144(147, 124, 113), - COLOR_145(180, 152, 138), - COLOR_146(209, 177, 161), - COLOR_147(110, 93, 85), - COLOR_148(112, 57, 25), - COLOR_149(137, 70, 31), - COLOR_150(159, 82, 36), - COLOR_151(84, 43, 19), - COLOR_152(105, 61, 76), - COLOR_153(128, 75, 93), - COLOR_154(149, 87, 108), - COLOR_155(78, 46, 57), - COLOR_156(79, 76, 97), - COLOR_157(96, 93, 119), - COLOR_158(112, 108, 138), - COLOR_159(59, 57, 73), - COLOR_160(131, 93, 25), - COLOR_161(160, 114, 31), - COLOR_162(186, 133, 36), - COLOR_163(98, 70, 19), - COLOR_164(72, 82, 37), - COLOR_165(88, 100, 45), - COLOR_166(103, 117, 53), - COLOR_167(54, 61, 28), - COLOR_168(112, 54, 55), - COLOR_169(138, 66, 67), - COLOR_170(160, 77, 78), - COLOR_171(84, 40, 41), - COLOR_172(40, 28, 24), - COLOR_173(49, 35, 30), - COLOR_174(57, 41, 35), - COLOR_175(30, 21, 18), - COLOR_176(95, 75, 69), - COLOR_177(116, 92, 84), - COLOR_178(135, 107, 98), - COLOR_179(71, 56, 51), - COLOR_180(61, 64, 64), - COLOR_181(75, 79, 79), - COLOR_182(87, 92, 92), - COLOR_183(46, 48, 48), - COLOR_184(86, 51, 62), - COLOR_185(105, 62, 75), - COLOR_186(122, 73, 88), - COLOR_187(64, 38, 46), - COLOR_188(53, 43, 64), - COLOR_189(65, 53, 79), - COLOR_190(76, 62, 92), - COLOR_191(40, 32, 48), - COLOR_192(53, 35, 24), - COLOR_193(65, 43, 30), - COLOR_194(76, 50, 35), - COLOR_195(40, 26, 18), - COLOR_196(53, 57, 29), - COLOR_197(65, 70, 36), - COLOR_198(76, 82, 42), - COLOR_199(40, 43, 22), - COLOR_200(100, 42, 32), - COLOR_201(122, 51, 39), - COLOR_202(142, 60, 46), - COLOR_203(75, 31, 24), - COLOR_204(26, 15, 11), - COLOR_205(31, 18, 13), - COLOR_206(37, 22, 16), - COLOR_207(19, 11, 8), - COLOR_208(133, 33, 34), - COLOR_209(163, 41, 42), - COLOR_210(189, 48, 49), - COLOR_211(100, 25, 25), - COLOR_212(104, 44, 68), - COLOR_213(127, 54, 83), - COLOR_214(148, 63, 97), - COLOR_215(78, 33, 51), - COLOR_216(64, 17, 20), - COLOR_217(79, 21, 25), - COLOR_218(92, 25, 29), - COLOR_219(48, 13, 15), - COLOR_220(15, 88, 94), - COLOR_221(18, 108, 115), - COLOR_222(22, 126, 134), - COLOR_223(11, 66, 70), - COLOR_224(40, 100, 98), - COLOR_225(50, 122, 120), - COLOR_226(58, 142, 140), - COLOR_227(30, 75, 74), - COLOR_228(60, 31, 43), - COLOR_229(74, 37, 53), - COLOR_230(86, 44, 62), - COLOR_231(45, 23, 32), - COLOR_232(14, 127, 93), - COLOR_233(17, 155, 114), - COLOR_234(20, 180, 133), - COLOR_235(10, 95, 70), + COLOR_120(54, 168, 176), + COLOR_121(66, 205, 215), + COLOR_122(77, 238, 250), + COLOR_123(40, 126, 132), + COLOR_124(150, 154, 64), + COLOR_125(183, 188, 79), + COLOR_126(213, 219, 92), + COLOR_127(112, 115, 48), + COLOR_128(180, 90, 52), + COLOR_129(220, 110, 63), + COLOR_130(255, 128, 74), + COLOR_131(135, 67, 39), + COLOR_132(40, 153, 0), + COLOR_133(50, 187, 0), + COLOR_134(58, 217, 0), + COLOR_135(30, 114, 0), + COLOR_136(34, 60, 91), + COLOR_137(42, 74, 111), + COLOR_138(49, 86, 129), + COLOR_139(25, 45, 68), + COLOR_140(0, 1, 79), + COLOR_141(0, 1, 96), + COLOR_142(0, 2, 112), + COLOR_143(0, 1, 59), + COLOR_144(113, 124, 147), + COLOR_145(138, 152, 180), + COLOR_146(161, 177, 209), + COLOR_147(85, 93, 110), + COLOR_148(25, 57, 112), + COLOR_149(31, 70, 137), + COLOR_150(36, 82, 159), + COLOR_151(19, 43, 84), + COLOR_152(76, 61, 105), + COLOR_153(93, 75, 128), + COLOR_154(108, 87, 149), + COLOR_155(57, 46, 78), + COLOR_156(97, 76, 79), + COLOR_157(119, 93, 96), + COLOR_158(138, 108, 112), + COLOR_159(73, 57, 59), + COLOR_160(25, 93, 131), + COLOR_161(31, 114, 160), + COLOR_162(36, 133, 186), + COLOR_163(19, 70, 98), + COLOR_164(37, 82, 72), + COLOR_165(45, 100, 88), + COLOR_166(53, 117, 103), + COLOR_167(28, 61, 54), + COLOR_168(55, 54, 112), + COLOR_169(67, 66, 138), + COLOR_170(78, 77, 160), + COLOR_171(41, 40, 84), + COLOR_172(24, 28, 40), + COLOR_173(30, 35, 49), + COLOR_174(35, 41, 57), + COLOR_175(18, 21, 30), + COLOR_176(69, 75, 95), + COLOR_177(84, 92, 116), + COLOR_178(98, 107, 135), + COLOR_179(51, 56, 71), + COLOR_180(64, 64, 61), + COLOR_181(79, 79, 75), + COLOR_182(92, 92, 87), + COLOR_183(48, 48, 46), + COLOR_184(62, 51, 86), + COLOR_185(75, 62, 105), + COLOR_186(88, 73, 122), + COLOR_187(46, 38, 64), + COLOR_188(64, 43, 53), + COLOR_189(79, 53, 65), + COLOR_190(92, 62, 76), + COLOR_191(48, 32, 40), + COLOR_192(24, 35, 53), + COLOR_193(30, 43, 65), + COLOR_194(35, 50, 76), + COLOR_195(18, 26, 40), + COLOR_196(29, 57, 53), + COLOR_197(36, 70, 65), + COLOR_198(42, 82, 76), + COLOR_199(22, 43, 40), + COLOR_200(32, 42, 100), + COLOR_201(39, 51, 122), + COLOR_202(46, 60, 142), + COLOR_203(24, 31, 75), + COLOR_204(11, 15, 26), + COLOR_205(13, 18, 31), + COLOR_206(16, 22, 37), + COLOR_207(8, 11, 19), + COLOR_208(34, 33, 133), + COLOR_209(42, 41, 163), + COLOR_210(49, 48, 189), + COLOR_211(25, 25, 100), + COLOR_212(68, 44, 104), + COLOR_213(83, 54, 127), + COLOR_214(97, 63, 148), + COLOR_215(51, 33, 78), + COLOR_216(20, 17, 64), + COLOR_217(25, 21, 79), + COLOR_218(29, 25, 92), + COLOR_219(15, 13, 48), + COLOR_220(94, 88, 15), + COLOR_221(115, 108, 18), + COLOR_222(134, 126, 22), + COLOR_223(70, 66, 11), + COLOR_224(98, 100, 40), + COLOR_225(120, 122, 50), + COLOR_226(140, 142, 58), + COLOR_227(74, 75, 30), + COLOR_228(43, 31, 60), + COLOR_229(53, 37, 74), + COLOR_230(62, 44, 86), + COLOR_231(32, 23, 45), + COLOR_232(93, 127, 14), + COLOR_233(114, 155, 17), + COLOR_234(133, 180, 20), + COLOR_235(70, 95, 10), COLOR_236(70, 70, 70), COLOR_237(86, 86, 86), COLOR_238(100, 100, 100), COLOR_239(52, 52, 52), - COLOR_240(152, 123, 103), - COLOR_241(186, 150, 126), - COLOR_242(216, 175, 147), - COLOR_243(114, 92, 77), - COLOR_244(89, 117, 105), - COLOR_245(109, 144, 129), - COLOR_246(127, 167, 150), - COLOR_247(67, 88, 79); + COLOR_240(103, 123, 152), + COLOR_241(126, 150, 186), + COLOR_242(147, 175, 216), + COLOR_243(77, 92, 114), + COLOR_244(105, 117, 89), + COLOR_245(129, 144, 109), + COLOR_246(150, 167, 127), + COLOR_247(79, 88, 67); private static final MapColor[] VALUES = values(); From 7b5c1bb370ae88409bb89b8c78c824a36fe1bc43 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Mon, 23 Dec 2024 03:29:40 +0800 Subject: [PATCH 514/897] Bump mcpl and mappings --- core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 8707dd144..e277062f3 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 8707dd144b20632f4a2f4b5497d8e5fb211e6c93 +Subproject commit e277062f3bccbe772baefcd631f0a5442311467c diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b90436644..65cef50f8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20241213.160944-20" protocol-codec = "3.0.0.Beta5-20241213.160944-20" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21.4-SNAPSHOT" +mcprotocollib = "1.21.4-20241222.190029-11" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 030b935d8a1953bc9735ce4bd95b6c105d047b2d Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 24 Dec 2024 00:18:26 +0800 Subject: [PATCH 515/897] Fix: item frames showing names for items without a custom name (fixes https://github.com/GeyserMC/Geyser/issues/5194) --- .../geyser/entity/type/ItemFrameEntity.java | 17 +++++++++++++---- .../geyser/item/type/ShulkerBoxItem.java | 2 +- .../geyser/translator/item/ItemTranslator.java | 6 +++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java index f38e727c0..acb3df2b6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java @@ -113,14 +113,23 @@ public class ItemFrameEntity extends Entity { if (entityMetadata.getValue() != null) { this.heldItem = entityMetadata.getValue(); ItemData itemData = ItemTranslator.translateToBedrock(session, heldItem); - String customIdentifier = session.getItemMappings().getCustomIdMappings().get(itemData.getDefinition().getRuntimeId()); NbtMapBuilder builder = NbtMap.builder(); - builder.putByte("Count", (byte) itemData.getCount()); - if (itemData.getTag() != null) { - builder.put("tag", itemData.getTag()); + NbtMap itemDataTag = itemData.getTag(); + if (itemDataTag != null) { + // Remove custom name that Geyser sets for items due to translating default components + String customName = ItemTranslator.getCustomName(session, heldItem.getDataComponents(), + session.getItemMappings().getMapping(heldItem), 'f', false); + if (customName == null) { + // No custom name found, must modify tag if custom name exists + NbtMapBuilder copy = itemDataTag.toBuilder(); + copy.remove("display"); // Also removes lore, but, should not matter + itemDataTag = copy.build(); + } + + builder.put("tag", itemDataTag); } builder.putShort("Damage", (short) itemData.getDamage()); builder.putString("Name", customIdentifier != null ? customIdentifier : session.getItemMappings().getMapping(entityMetadata.getValue()).getBedrockIdentifier()); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index c3b739adc..d8d2c347d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -98,7 +98,7 @@ public class ShulkerBoxItem extends BlockItem { // Only the display name is what we have interest in, so just translate that if relevant if (boxComponents != null) { - String customName = ItemTranslator.getCustomName(session, boxComponents, boxMapping, '7'); + String customName = ItemTranslator.getCustomName(session, boxComponents, boxMapping, '7', true); if (customName != null) { boxItemNbt.putCompound("tag", NbtMap.builder() .putCompound("display", NbtMap.builder() 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 691a320e5..96b64f56d 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 @@ -173,7 +173,7 @@ public final class ItemTranslator { javaItem.translateComponentsToBedrock(session, components, nbtBuilder); Rarity rarity = Rarity.fromId(components.getOrDefault(DataComponentType.RARITY, 0)); - String customName = getCustomName(session, components, bedrockItem, rarity.getColor()); + String customName = getCustomName(session, components, bedrockItem, rarity.getColor(), true); if (customName != null) { nbtBuilder.setCustomName(customName); } @@ -493,7 +493,7 @@ public final class ItemTranslator { * @param translationColor if this item is not available on Java, the color that the new name should be. * Normally, this should just be white, but for shulker boxes this should be gray. */ - public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor) { + public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor, boolean includeDefault) { if (components != null) { // ItemStack#getHoverName as of 1.20.5 Component customName = components.get(DataComponentType.CUSTOM_NAME); @@ -514,7 +514,7 @@ public final class ItemTranslator { } } customName = components.get(DataComponentType.ITEM_NAME); - if (customName != null) { + if (customName != null && includeDefault) { // Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition // behavior as of 1.21 return ChatColor.RESET + ChatColor.ESCAPE + translationColor + MessageTranslator.convertMessage(customName, session.locale()); From 6bd60d42339482580dd7f501d5ff436f63945a97 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 24 Dec 2024 01:43:04 +0800 Subject: [PATCH 516/897] Fix: Default components breaking item stacking while crafting. --- .../geysermc/geyser/entity/type/ItemFrameEntity.java | 12 +----------- .../java/org/geysermc/geyser/item/type/Item.java | 11 +++++++++-- .../translator/inventory/InventoryTranslator.java | 2 +- .../geyser/translator/item/BedrockItemBuilder.java | 5 +++-- .../geyser/translator/item/ItemTranslator.java | 2 +- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java index acb3df2b6..ba3dfb79d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java @@ -118,17 +118,7 @@ public class ItemFrameEntity extends Entity { NbtMapBuilder builder = NbtMap.builder(); builder.putByte("Count", (byte) itemData.getCount()); NbtMap itemDataTag = itemData.getTag(); - if (itemDataTag != null) { - // Remove custom name that Geyser sets for items due to translating default components - String customName = ItemTranslator.getCustomName(session, heldItem.getDataComponents(), - session.getItemMappings().getMapping(heldItem), 'f', false); - if (customName == null) { - // No custom name found, must modify tag if custom name exists - NbtMapBuilder copy = itemDataTag.toBuilder(); - copy.remove("display"); // Also removes lore, but, should not matter - itemDataTag = copy.build(); - } - + if (itemData.getTag() != null) { builder.put("tag", itemDataTag); } builder.putShort("Damage", (short) itemData.getDamage()); 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 19789e086..738d57788 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 @@ -191,7 +191,9 @@ public class Item { } Integer repairCost = components.get(DataComponentType.REPAIR_COST); - if (repairCost != null) { + // Java sets repair cost to 0 on all items via default components, that trips up Bedrock crafting. + // See https://github.com/GeyserMC/Geyser/issues/5220 for more details + if (repairCost != null && repairCost != 0) { builder.putInt("RepairCost", repairCost); } @@ -202,7 +204,12 @@ public class Item { // Prevents the client from trying to stack items with untranslated components // Relies on correct hash code implementation, and some luck - builder.putInt("GeyserHash", components.hashCode()); // TODO: don't rely on this + // However, we should only set a hash when the components differ from the default ones, + // otherwise Bedrock can't stack these when crafting items since it's predicted recipe output + // does not contain the GeyserHash. See https://github.com/GeyserMC/Geyser/issues/5220 for more details + if (!baseComponents.equals(components)) { + builder.putInt("GeyserHash", components.hashCode()); // TODO: don't rely on this + } } /** 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 f7e3bfc2a..b4f507af5 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 @@ -246,7 +246,7 @@ public abstract class InventoryTranslator { boolean isSourceCursor = isCursor(transferAction.getSource()); boolean isDestCursor = isCursor(transferAction.getDestination()); - if ((this) instanceof PlayerInventoryTranslator) { + if (this instanceof PlayerInventoryTranslator) { if (destSlot == 5) { //only set the head if the destination is the head slot GeyserItemStack javaItem = inventory.getItem(sourceSlot); diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java index e989288c2..2f51c0007 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/BedrockItemBuilder.java @@ -122,12 +122,13 @@ public final class BedrockItemBuilder { */ @Nullable public NbtMap build() { - if (customName != null || lore != null) { + boolean validLore = lore != null && !lore.isEmpty(); + if (customName != null || validLore) { NbtMapBuilder display = NbtMap.builder(); if (customName != null) { display.putString("Name", customName); } - if (lore != null) { + if (validLore) { display.putList("Lore", NbtType.STRING, lore); } getOrCreateNbt().put("display", display.build()); 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 96b64f56d..b8959c7b8 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 @@ -173,7 +173,7 @@ public final class ItemTranslator { javaItem.translateComponentsToBedrock(session, components, nbtBuilder); Rarity rarity = Rarity.fromId(components.getOrDefault(DataComponentType.RARITY, 0)); - String customName = getCustomName(session, components, bedrockItem, rarity.getColor(), true); + String customName = getCustomName(session, components, bedrockItem, rarity.getColor(), false); if (customName != null) { nbtBuilder.setCustomName(customName); } From 623ec2bb8fbeda967b94e6c95c19ceba0b9692ba Mon Sep 17 00:00:00 2001 From: rtm516 Date: Fri, 27 Dec 2024 04:53:22 +0000 Subject: [PATCH 517/897] Fix map colors (#5239) * Revert "fix: Wrong map colors (#5238)" This reverts commit 006fe75e5af5f5686fb18051415663cb8ceaaa1b. * Correctly send BGR over the network for map colors --- .../org/geysermc/geyser/level/MapColor.java | 426 +++++++++--------- .../java/level/JavaMapItemDataTranslator.java | 2 +- 2 files changed, 216 insertions(+), 212 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/MapColor.java b/core/src/main/java/org/geysermc/geyser/level/MapColor.java index f4b4fb697..da0c0a4b2 100644 --- a/core/src/main/java/org/geysermc/geyser/level/MapColor.java +++ b/core/src/main/java/org/geysermc/geyser/level/MapColor.java @@ -30,26 +30,26 @@ public enum MapColor { COLOR_1(-1, -1, -1), COLOR_2(-1, -1, -1), COLOR_3(-1, -1, -1), - COLOR_4(39, 125, 89), - COLOR_5(48, 153, 109), - COLOR_6(56, 178, 127), - COLOR_7(29, 94, 67), - COLOR_8(115, 164, 174), - COLOR_9(140, 201, 213), - COLOR_10(163, 233, 247), - COLOR_11(86, 123, 130), + COLOR_4(89, 125, 39), + COLOR_5(109, 153, 48), + COLOR_6(127, 178, 56), + COLOR_7(67, 94, 29), + COLOR_8(174, 164, 115), + COLOR_9(213, 201, 140), + COLOR_10(247, 233, 163), + COLOR_11(130, 123, 86), COLOR_12(140, 140, 140), COLOR_13(171, 171, 171), COLOR_14(199, 199, 199), COLOR_15(105, 105, 105), - COLOR_16(0, 0, 180), - COLOR_17(0, 0, 220), - COLOR_18(0, 0, 255), - COLOR_19(0, 0, 135), - COLOR_20(180, 112, 112), - COLOR_21(220, 138, 138), - COLOR_22(255, 160, 160), - COLOR_23(135, 84, 84), + COLOR_16(180, 0, 0), + COLOR_17(220, 0, 0), + COLOR_18(255, 0, 0), + COLOR_19(135, 0, 0), + COLOR_20(112, 112, 180), + COLOR_21(138, 138, 220), + COLOR_22(160, 160, 255), + COLOR_23(84, 84, 135), COLOR_24(117, 117, 117), COLOR_25(144, 144, 144), COLOR_26(167, 167, 167), @@ -62,54 +62,54 @@ public enum MapColor { COLOR_33(220, 220, 220), COLOR_34(255, 255, 255), COLOR_35(135, 135, 135), - COLOR_36(129, 118, 115), - COLOR_37(158, 144, 141), - COLOR_38(184, 168, 164), - COLOR_39(97, 88, 86), - COLOR_40(54, 76, 106), - COLOR_41(66, 94, 130), - COLOR_42(77, 109, 151), - COLOR_43(40, 57, 79), + COLOR_36(115, 118, 129), + COLOR_37(141, 144, 158), + COLOR_38(164, 168, 184), + COLOR_39(86, 88, 97), + COLOR_40(106, 76, 54), + COLOR_41(130, 94, 66), + COLOR_42(151, 109, 77), + COLOR_43(79, 57, 40), COLOR_44(79, 79, 79), COLOR_45(96, 96, 96), COLOR_46(112, 112, 112), COLOR_47(59, 59, 59), - COLOR_48(180, 45, 45), - COLOR_49(220, 55, 55), - COLOR_50(255, 64, 64), - COLOR_51(135, 33, 33), - COLOR_52(50, 84, 100), - COLOR_53(62, 102, 123), - COLOR_54(72, 119, 143), - COLOR_55(38, 63, 75), - COLOR_56(172, 177, 180), - COLOR_57(211, 217, 220), - COLOR_58(245, 252, 255), - COLOR_59(129, 133, 135), - COLOR_60(36, 89, 152), - COLOR_61(44, 109, 186), - COLOR_62(51, 127, 216), - COLOR_63(27, 67, 114), - COLOR_64(152, 53, 125), - COLOR_65(186, 65, 153), - COLOR_66(216, 76, 178), - COLOR_67(114, 40, 94), - COLOR_68(152, 108, 72), - COLOR_69(186, 132, 88), - COLOR_70(216, 153, 102), - COLOR_71(114, 81, 54), - COLOR_72(36, 161, 161), - COLOR_73(44, 197, 197), - COLOR_74(51, 229, 229), - COLOR_75(27, 121, 121), - COLOR_76(17, 144, 89), - COLOR_77(21, 176, 109), - COLOR_78(25, 204, 127), - COLOR_79(13, 108, 67), - COLOR_80(116, 89, 170), - COLOR_81(142, 109, 208), - COLOR_82(165, 127, 242), - COLOR_83(87, 67, 128), + COLOR_48(45, 45, 180), + COLOR_49(55, 55, 220), + COLOR_50(64, 64, 255), + COLOR_51(33, 33, 135), + COLOR_52(100, 84, 50), + COLOR_53(123, 102, 62), + COLOR_54(143, 119, 72), + COLOR_55(75, 63, 38), + COLOR_56(180, 177, 172), + COLOR_57(220, 217, 211), + COLOR_58(255, 252, 245), + COLOR_59(135, 133, 129), + COLOR_60(152, 89, 36), + COLOR_61(186, 109, 44), + COLOR_62(216, 127, 51), + COLOR_63(114, 67, 27), + COLOR_64(125, 53, 152), + COLOR_65(153, 65, 186), + COLOR_66(178, 76, 216), + COLOR_67(94, 40, 114), + COLOR_68(72, 108, 152), + COLOR_69(88, 132, 186), + COLOR_70(102, 153, 216), + COLOR_71(54, 81, 114), + COLOR_72(161, 161, 36), + COLOR_73(197, 197, 44), + COLOR_74(229, 229, 51), + COLOR_75(121, 121, 27), + COLOR_76(89, 144, 17), + COLOR_77(109, 176, 21), + COLOR_78(127, 204, 25), + COLOR_79(67, 108, 13), + COLOR_80(170, 89, 116), + COLOR_81(208, 109, 142), + COLOR_82(242, 127, 165), + COLOR_83(128, 67, 87), COLOR_84(53, 53, 53), COLOR_85(65, 65, 65), COLOR_86(76, 76, 76), @@ -118,162 +118,162 @@ public enum MapColor { COLOR_89(132, 132, 132), COLOR_90(153, 153, 153), COLOR_91(81, 81, 81), - COLOR_92(108, 89, 53), - COLOR_93(132, 109, 65), - COLOR_94(153, 127, 76), - COLOR_95(81, 67, 40), - COLOR_96(125, 44, 89), - COLOR_97(153, 54, 109), - COLOR_98(178, 63, 127), - COLOR_99(94, 33, 67), - COLOR_100(125, 53, 36), - COLOR_101(153, 65, 44), - COLOR_102(178, 76, 51), - COLOR_103(94, 40, 27), - COLOR_104(36, 53, 72), - COLOR_105(44, 65, 88), - COLOR_106(51, 76, 102), - COLOR_107(27, 40, 54), - COLOR_108(36, 89, 72), - COLOR_109(44, 109, 88), - COLOR_110(51, 127, 102), - COLOR_111(27, 67, 54), - COLOR_112(36, 36, 108), - COLOR_113(44, 44, 132), - COLOR_114(51, 51, 153), - COLOR_115(27, 27, 81), + COLOR_92(53, 89, 108), + COLOR_93(65, 109, 132), + COLOR_94(76, 127, 153), + COLOR_95(40, 67, 81), + COLOR_96(89, 44, 125), + COLOR_97(109, 54, 153), + COLOR_98(127, 63, 178), + COLOR_99(67, 33, 94), + COLOR_100(36, 53, 125), + COLOR_101(44, 65, 153), + COLOR_102(51, 76, 178), + COLOR_103(27, 40, 94), + COLOR_104(72, 53, 36), + COLOR_105(88, 65, 44), + COLOR_106(102, 76, 51), + COLOR_107(54, 40, 27), + COLOR_108(72, 89, 36), + COLOR_109(88, 109, 44), + COLOR_110(102, 127, 51), + COLOR_111(54, 67, 27), + COLOR_112(108, 36, 36), + COLOR_113(132, 44, 44), + COLOR_114(153, 51, 51), + COLOR_115(81, 27, 27), COLOR_116(17, 17, 17), COLOR_117(21, 21, 21), COLOR_118(25, 25, 25), COLOR_119(13, 13, 13), - COLOR_120(54, 168, 176), - COLOR_121(66, 205, 215), - COLOR_122(77, 238, 250), - COLOR_123(40, 126, 132), - COLOR_124(150, 154, 64), - COLOR_125(183, 188, 79), - COLOR_126(213, 219, 92), - COLOR_127(112, 115, 48), - COLOR_128(180, 90, 52), - COLOR_129(220, 110, 63), - COLOR_130(255, 128, 74), - COLOR_131(135, 67, 39), - COLOR_132(40, 153, 0), - COLOR_133(50, 187, 0), - COLOR_134(58, 217, 0), - COLOR_135(30, 114, 0), - COLOR_136(34, 60, 91), - COLOR_137(42, 74, 111), - COLOR_138(49, 86, 129), - COLOR_139(25, 45, 68), - COLOR_140(0, 1, 79), - COLOR_141(0, 1, 96), - COLOR_142(0, 2, 112), - COLOR_143(0, 1, 59), - COLOR_144(113, 124, 147), - COLOR_145(138, 152, 180), - COLOR_146(161, 177, 209), - COLOR_147(85, 93, 110), - COLOR_148(25, 57, 112), - COLOR_149(31, 70, 137), - COLOR_150(36, 82, 159), - COLOR_151(19, 43, 84), - COLOR_152(76, 61, 105), - COLOR_153(93, 75, 128), - COLOR_154(108, 87, 149), - COLOR_155(57, 46, 78), - COLOR_156(97, 76, 79), - COLOR_157(119, 93, 96), - COLOR_158(138, 108, 112), - COLOR_159(73, 57, 59), - COLOR_160(25, 93, 131), - COLOR_161(31, 114, 160), - COLOR_162(36, 133, 186), - COLOR_163(19, 70, 98), - COLOR_164(37, 82, 72), - COLOR_165(45, 100, 88), - COLOR_166(53, 117, 103), - COLOR_167(28, 61, 54), - COLOR_168(55, 54, 112), - COLOR_169(67, 66, 138), - COLOR_170(78, 77, 160), - COLOR_171(41, 40, 84), - COLOR_172(24, 28, 40), - COLOR_173(30, 35, 49), - COLOR_174(35, 41, 57), - COLOR_175(18, 21, 30), - COLOR_176(69, 75, 95), - COLOR_177(84, 92, 116), - COLOR_178(98, 107, 135), - COLOR_179(51, 56, 71), - COLOR_180(64, 64, 61), - COLOR_181(79, 79, 75), - COLOR_182(92, 92, 87), - COLOR_183(48, 48, 46), - COLOR_184(62, 51, 86), - COLOR_185(75, 62, 105), - COLOR_186(88, 73, 122), - COLOR_187(46, 38, 64), - COLOR_188(64, 43, 53), - COLOR_189(79, 53, 65), - COLOR_190(92, 62, 76), - COLOR_191(48, 32, 40), - COLOR_192(24, 35, 53), - COLOR_193(30, 43, 65), - COLOR_194(35, 50, 76), - COLOR_195(18, 26, 40), - COLOR_196(29, 57, 53), - COLOR_197(36, 70, 65), - COLOR_198(42, 82, 76), - COLOR_199(22, 43, 40), - COLOR_200(32, 42, 100), - COLOR_201(39, 51, 122), - COLOR_202(46, 60, 142), - COLOR_203(24, 31, 75), - COLOR_204(11, 15, 26), - COLOR_205(13, 18, 31), - COLOR_206(16, 22, 37), - COLOR_207(8, 11, 19), - COLOR_208(34, 33, 133), - COLOR_209(42, 41, 163), - COLOR_210(49, 48, 189), - COLOR_211(25, 25, 100), - COLOR_212(68, 44, 104), - COLOR_213(83, 54, 127), - COLOR_214(97, 63, 148), - COLOR_215(51, 33, 78), - COLOR_216(20, 17, 64), - COLOR_217(25, 21, 79), - COLOR_218(29, 25, 92), - COLOR_219(15, 13, 48), - COLOR_220(94, 88, 15), - COLOR_221(115, 108, 18), - COLOR_222(134, 126, 22), - COLOR_223(70, 66, 11), - COLOR_224(98, 100, 40), - COLOR_225(120, 122, 50), - COLOR_226(140, 142, 58), - COLOR_227(74, 75, 30), - COLOR_228(43, 31, 60), - COLOR_229(53, 37, 74), - COLOR_230(62, 44, 86), - COLOR_231(32, 23, 45), - COLOR_232(93, 127, 14), - COLOR_233(114, 155, 17), - COLOR_234(133, 180, 20), - COLOR_235(70, 95, 10), + COLOR_120(176, 168, 54), + COLOR_121(215, 205, 66), + COLOR_122(250, 238, 77), + COLOR_123(132, 126, 40), + COLOR_124(64, 154, 150), + COLOR_125(79, 188, 183), + COLOR_126(92, 219, 213), + COLOR_127(48, 115, 112), + COLOR_128(52, 90, 180), + COLOR_129(63, 110, 220), + COLOR_130(74, 128, 255), + COLOR_131(39, 67, 135), + COLOR_132(0, 153, 40), + COLOR_133(0, 187, 50), + COLOR_134(0, 217, 58), + COLOR_135(0, 114, 30), + COLOR_136(91, 60, 34), + COLOR_137(111, 74, 42), + COLOR_138(129, 86, 49), + COLOR_139(68, 45, 25), + COLOR_140(79, 1, 0), + COLOR_141(96, 1, 0), + COLOR_142(112, 2, 0), + COLOR_143(59, 1, 0), + COLOR_144(147, 124, 113), + COLOR_145(180, 152, 138), + COLOR_146(209, 177, 161), + COLOR_147(110, 93, 85), + COLOR_148(112, 57, 25), + COLOR_149(137, 70, 31), + COLOR_150(159, 82, 36), + COLOR_151(84, 43, 19), + COLOR_152(105, 61, 76), + COLOR_153(128, 75, 93), + COLOR_154(149, 87, 108), + COLOR_155(78, 46, 57), + COLOR_156(79, 76, 97), + COLOR_157(96, 93, 119), + COLOR_158(112, 108, 138), + COLOR_159(59, 57, 73), + COLOR_160(131, 93, 25), + COLOR_161(160, 114, 31), + COLOR_162(186, 133, 36), + COLOR_163(98, 70, 19), + COLOR_164(72, 82, 37), + COLOR_165(88, 100, 45), + COLOR_166(103, 117, 53), + COLOR_167(54, 61, 28), + COLOR_168(112, 54, 55), + COLOR_169(138, 66, 67), + COLOR_170(160, 77, 78), + COLOR_171(84, 40, 41), + COLOR_172(40, 28, 24), + COLOR_173(49, 35, 30), + COLOR_174(57, 41, 35), + COLOR_175(30, 21, 18), + COLOR_176(95, 75, 69), + COLOR_177(116, 92, 84), + COLOR_178(135, 107, 98), + COLOR_179(71, 56, 51), + COLOR_180(61, 64, 64), + COLOR_181(75, 79, 79), + COLOR_182(87, 92, 92), + COLOR_183(46, 48, 48), + COLOR_184(86, 51, 62), + COLOR_185(105, 62, 75), + COLOR_186(122, 73, 88), + COLOR_187(64, 38, 46), + COLOR_188(53, 43, 64), + COLOR_189(65, 53, 79), + COLOR_190(76, 62, 92), + COLOR_191(40, 32, 48), + COLOR_192(53, 35, 24), + COLOR_193(65, 43, 30), + COLOR_194(76, 50, 35), + COLOR_195(40, 26, 18), + COLOR_196(53, 57, 29), + COLOR_197(65, 70, 36), + COLOR_198(76, 82, 42), + COLOR_199(40, 43, 22), + COLOR_200(100, 42, 32), + COLOR_201(122, 51, 39), + COLOR_202(142, 60, 46), + COLOR_203(75, 31, 24), + COLOR_204(26, 15, 11), + COLOR_205(31, 18, 13), + COLOR_206(37, 22, 16), + COLOR_207(19, 11, 8), + COLOR_208(133, 33, 34), + COLOR_209(163, 41, 42), + COLOR_210(189, 48, 49), + COLOR_211(100, 25, 25), + COLOR_212(104, 44, 68), + COLOR_213(127, 54, 83), + COLOR_214(148, 63, 97), + COLOR_215(78, 33, 51), + COLOR_216(64, 17, 20), + COLOR_217(79, 21, 25), + COLOR_218(92, 25, 29), + COLOR_219(48, 13, 15), + COLOR_220(15, 88, 94), + COLOR_221(18, 108, 115), + COLOR_222(22, 126, 134), + COLOR_223(11, 66, 70), + COLOR_224(40, 100, 98), + COLOR_225(50, 122, 120), + COLOR_226(58, 142, 140), + COLOR_227(30, 75, 74), + COLOR_228(60, 31, 43), + COLOR_229(74, 37, 53), + COLOR_230(86, 44, 62), + COLOR_231(45, 23, 32), + COLOR_232(14, 127, 93), + COLOR_233(17, 155, 114), + COLOR_234(20, 180, 133), + COLOR_235(10, 95, 70), COLOR_236(70, 70, 70), COLOR_237(86, 86, 86), COLOR_238(100, 100, 100), COLOR_239(52, 52, 52), - COLOR_240(103, 123, 152), - COLOR_241(126, 150, 186), - COLOR_242(147, 175, 216), - COLOR_243(77, 92, 114), - COLOR_244(105, 117, 89), - COLOR_245(129, 144, 109), - COLOR_246(150, 167, 127), - COLOR_247(79, 88, 67); + COLOR_240(152, 123, 103), + COLOR_241(186, 150, 126), + COLOR_242(216, 175, 147), + COLOR_243(114, 92, 77), + COLOR_244(89, 117, 105), + COLOR_245(109, 144, 129), + COLOR_246(127, 167, 150), + COLOR_247(67, 88, 79); private static final MapColor[] VALUES = values(); @@ -285,16 +285,20 @@ public enum MapColor { alpha = 0; // transparent this.value = ((alpha & 0xFF) << 24) | - ((red & 0xFF) << 16) | + ((blue & 0xFF) << 16) | ((green & 0xFF) << 8) | - (blue & 0xFF); + (red & 0xFF); } public static MapColor fromId(int id) { return id >= 0 && id < VALUES.length ? VALUES[id] : COLOR_0; } - public int getARGB() { + /** + * Get the ABGR value of the color, bedrock uses this over the network + * @return the int value of the color + */ + public int getABGR() { return value; } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java index 52a08ab29..94c4736c6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java @@ -65,7 +65,7 @@ public class JavaMapItemDataTranslator extends PacketTranslator Date: Sat, 4 Jan 2025 14:28:54 +0100 Subject: [PATCH 518/897] Add support for rcon console command senders (#5261) RemoteConsoleCommandSender does not inherit ConsoleCommandSender, so we gotta handle it explicitly. --- .../geyser/platform/spigot/command/SpigotCommandSource.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java index c1fb837c2..9f897b095 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java @@ -29,6 +29,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.command.RemoteConsoleCommandSender; import org.bukkit.entity.Player; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -76,7 +77,7 @@ public class SpigotCommandSource implements GeyserCommandSource { @Override public boolean isConsole() { - return handle instanceof ConsoleCommandSender; + return handle instanceof ConsoleCommandSender || handle instanceof RemoteConsoleCommandSender; } @Override From a19f0305fb8ffbeac4d6bbe00143841f5f9f9ff5 Mon Sep 17 00:00:00 2001 From: BugTeaON <99161186+BUGTeas@users.noreply.github.com> Date: Sun, 5 Jan 2025 19:41:35 +0800 Subject: [PATCH 519/897] Fix `item_name` component not working, improve display of custom effects and shulker box tooltips for item names (#5255) * Show custom effects information in HUD, and be able to hide it using hide_additional_tooltip component * Make vanilla default components no longer affect the translation of custom name (Fix item_name component not work) * Fix book title display in tooltips of shulker box * Fix colored item name display in tooltips of shulker box * Add some code comments * Block vanilla potion name translation when has hide_additional_tooltip component * Add some brackets --- .../geyser/entity/type/ItemFrameEntity.java | 12 ++- .../geysermc/geyser/item/type/PotionItem.java | 13 --- .../geyser/item/type/ShulkerBoxItem.java | 7 +- .../geyser/item/type/TippedArrowItem.java | 14 --- .../translator/item/ItemTranslator.java | 91 ++++++++++++++----- 5 files changed, 85 insertions(+), 52 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java index ba3dfb79d..afe0dcdc6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java @@ -118,7 +118,17 @@ public class ItemFrameEntity extends Entity { NbtMapBuilder builder = NbtMap.builder(); builder.putByte("Count", (byte) itemData.getCount()); NbtMap itemDataTag = itemData.getTag(); - if (itemData.getTag() != null) { + if (itemDataTag != null) { + // Remove custom name that Geyser sets for items due to translating non-"custom_name" components + String customName = ItemTranslator.getCustomName(session, heldItem.getDataComponents(), + session.getItemMappings().getMapping(heldItem), 'f', true, false); + if (customName == null) { + // No custom name found, must modify tag if custom name exists + NbtMapBuilder copy = itemDataTag.toBuilder(); + copy.remove("display"); // Also removes lore, but, should not matter + itemDataTag = copy.build(); + } + builder.put("tag", itemDataTag); } builder.putShort("Damage", (short) itemData.getDamage()); 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 4cc3756cd..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 @@ -34,9 +34,7 @@ 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.BedrockItemBuilder; import org.geysermc.geyser.translator.item.CustomItemTranslator; -import org.geysermc.geyser.translator.item.ItemTranslator; 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; @@ -70,17 +68,6 @@ public class PotionItem extends Item { return super.translateToBedrock(session, count, components, mapping, mappings); } - @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - // Make custom effect information visible - PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); - if (potionContents != null) { - ItemTranslator.addPotionEffectLore(potionContents, builder, session.locale()); - } - - super.translateComponentsToBedrock(session, components, builder); - } - @Override public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { Potion potion = Potion.getByBedrockId(itemData.getDamage()); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index d8d2c347d..5d14f748c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -35,6 +35,7 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.CustomItemTranslator; import org.geysermc.geyser.translator.item.ItemTranslator; @@ -98,8 +99,12 @@ public class ShulkerBoxItem extends BlockItem { // Only the display name is what we have interest in, so just translate that if relevant if (boxComponents != null) { - String customName = ItemTranslator.getCustomName(session, boxComponents, boxMapping, '7', true); + String customName = ItemTranslator.getCustomName(session, boxComponents, boxMapping, '7', false, true); if (customName != null) { + // Fix count display (e.g., x16) with incorrect color due to some items with colored names + if (customName.contains("" + ChatColor.ESCAPE)) { + customName += ChatColor.RESET + ChatColor.GRAY; + } boxItemNbt.putCompound("tag", NbtMap.builder() .putCompound("display", NbtMap.builder() .putString("Name", customName) 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 9e212ebef..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 @@ -25,15 +25,12 @@ 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.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.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.geyser.translator.item.ItemTranslator; 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; @@ -60,15 +57,4 @@ public class TippedArrowItem extends ArrowItem { } return super.translateToBedrock(session, count, components, mapping, mappings); } - - @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - // Make custom effect information visible - PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); - if (potionContents != null) { - ItemTranslator.addPotionEffectLore(potionContents, builder, session.locale()); - } - - super.translateComponentsToBedrock(session, components, builder); - } } 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 b8959c7b8..3f9bf7446 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 @@ -41,6 +41,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.type.Item; @@ -70,6 +71,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttribut import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectDetails; import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent; import java.text.DecimalFormat; import java.util.ArrayList; @@ -163,18 +165,25 @@ public final class ItemTranslator { .build(); } - public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents components) { + public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents customComponents) { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); // Populates default components that aren't sent over the network - components = javaItem.gatherComponents(components); + DataComponents components = javaItem.gatherComponents(customComponents); // Translate item-specific components javaItem.translateComponentsToBedrock(session, components, nbtBuilder); Rarity rarity = Rarity.fromId(components.getOrDefault(DataComponentType.RARITY, 0)); - String customName = getCustomName(session, components, bedrockItem, rarity.getColor(), false); + String customName = getCustomName(session, customComponents, bedrockItem, rarity.getColor(), false, false); if (customName != null) { + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + // Make custom effect information visible + // Ignore when item have "hide_additional_tooltip" component + if (potionContents != null && components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) == null) { + customName += getPotionEffectInfo(potionContents, session.locale()); + } + nbtBuilder.setCustomName(customName); } @@ -336,7 +345,8 @@ public final class ItemTranslator { Effect.INFESTED ); - public static void addPotionEffectLore(PotionContents contents, BedrockItemBuilder builder, String language) { + public static String getPotionEffectInfo(PotionContents contents, String language) { + StringBuilder finalText = new StringBuilder(); List effectInstanceList = contents.getCustomEffects(); for (MobEffectInstance effectInstance : effectInstanceList) { Effect effect = effectInstance.getEffect(); @@ -372,8 +382,40 @@ public final class ItemTranslator { .color((negativeEffectList.contains(effect)) ? NamedTextColor.RED : NamedTextColor.BLUE) .append(appendTranslatable) .build(); - builder.getOrCreateLore().add(MessageTranslator.convertMessage(component, language)); + // Bedrock supports wrap lines with '\n' in a single string in custom name + finalText.append('\n').append(MessageTranslator.convertMessage(component, language)); } + return finalText.toString(); + } + + public static String getPotionName(PotionContents contents, ItemMapping mapping, boolean hideAdditionalTooltip, String language) { + String customPotionName = contents.getCustomName(); + Potion potion = Potion.getByJavaId(contents.getPotionId()); + + if (customPotionName != null) { + // "custom_name" tag in "potion_contents" component + return MessageTranslator.convertMessage( + Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + customPotionName), + language); + } + if (!hideAdditionalTooltip && !contents.getCustomEffects().isEmpty()) { + // Make a name when has custom effects + String potionName; + if (potion != null) { + potionName = potion.toString().toLowerCase(Locale.ROOT); + if (potionName.startsWith("strong_")) { + potionName = potionName.substring(6); + } else if (potionName.startsWith("long_")) { + potionName = potionName.substring(4); + } + } else { + potionName = "empty"; + } + return MessageTranslator.convertMessage( + Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + potionName), + language); + } + return null; } private static void addAdvancedTooltips(@Nullable DataComponents components, BedrockItemBuilder builder, Item item, String language) { @@ -493,31 +535,34 @@ public final class ItemTranslator { * @param translationColor if this item is not available on Java, the color that the new name should be. * Normally, this should just be white, but for shulker boxes this should be gray. */ - public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor, boolean includeDefault) { + public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor, boolean customNameOnly, boolean includeAll) { if (components != null) { // ItemStack#getHoverName as of 1.20.5 Component customName = components.get(DataComponentType.CUSTOM_NAME); if (customName != null) { return MessageTranslator.convertMessage(customName, session.locale()); } - PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); - if (potionContents != null) { - // "custom_name" tag in "potion_contents" component - String customPotionName = potionContents.getCustomName(); - if (customPotionName != null) { - Component component = Component.text() - .resetStyle() - .color(NamedTextColor.WHITE) - .append(Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + customPotionName)) - .build(); - return MessageTranslator.convertMessage(component, session.locale()); + if (!customNameOnly) { + PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + if (potionContents != null) { + String potionName = getPotionName(potionContents, mapping, components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) != null, session.locale()); + if (potionName != null) { + return ChatColor.RESET + ChatColor.ESCAPE + translationColor + potionName; + } + } + if (includeAll) { + // Fix book title display in tooltips of shulker box + WrittenBookContent bookContent = components.get(DataComponentType.WRITTEN_BOOK_CONTENT); + if (bookContent != null) { + return ChatColor.RESET + ChatColor.ESCAPE + translationColor + bookContent.getTitle().getRaw(); + } + } + customName = components.get(DataComponentType.ITEM_NAME); + if (customName != null) { + // Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition + // behavior as of 1.21 + return ChatColor.RESET + ChatColor.ESCAPE + translationColor + MessageTranslator.convertMessage(customName, session.locale()); } - } - customName = components.get(DataComponentType.ITEM_NAME); - if (customName != null && includeDefault) { - // Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition - // behavior as of 1.21 - return ChatColor.RESET + ChatColor.ESCAPE + translationColor + MessageTranslator.convertMessage(customName, session.locale()); } } From ddd1afabd1a4be415209a248e03cf7a793e4056e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 5 Jan 2025 10:34:57 -0500 Subject: [PATCH 520/897] Bundle support (#5145) * Bundle support * Touchups * Correct bundle mapping * Grabbing a bundle from creative mode does work * Fix inserting items that already exist in a bundle * Add bundle drop workaround * Address review --- .../geyser/inventory/GeyserItemStack.java | 47 +- .../geysermc/geyser/inventory/Inventory.java | 8 +- .../geyser/inventory/click/Click.java | 3 + .../geyser/inventory/click/ClickPlan.java | 110 ++- .../geyser/session/GeyserSession.java | 12 + .../geyser/session/cache/BundleCache.java | 383 ++++++++ .../inventory/BundleInventoryTranslator.java | 339 +++++++ .../inventory/InventoryTranslator.java | 27 +- .../inventory/PlayerInventoryTranslator.java | 20 +- ...BedrockInventoryTransactionTranslator.java | 8 +- .../JavaContainerSetContentTranslator.java | 5 +- .../JavaContainerSetSlotTranslator.java | 1 + .../JavaSetCursorItemTranslator.java | 1 + .../JavaSetPlayerInventoryTranslator.java | 4 +- .../geysermc/geyser/util/InventoryUtils.java | 1 + .../geyser/util/thirdparty/Fraction.java | 911 ++++++++++++++++++ core/src/main/resources/mappings | 2 +- 17 files changed, 1856 insertions(+), 26 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/BundleCache.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/util/thirdparty/Fraction.java 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 4ddff305e..77ca7bfb5 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -39,6 +39,7 @@ 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.BundleCache; 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; @@ -59,19 +60,23 @@ public class GeyserItemStack { private DataComponents components; private int netId; + @EqualsAndHashCode.Exclude + private BundleCache.BundleData bundleData; + @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) @EqualsAndHashCode.Exclude private Item item; private GeyserItemStack(int javaId, int amount, DataComponents components) { - this(javaId, amount, components, 1); + this(javaId, amount, components, 1, null); } - private GeyserItemStack(int javaId, int amount, DataComponents components, int netId) { + private GeyserItemStack(int javaId, int amount, DataComponents components, int netId, BundleCache.BundleData bundleData) { this.javaId = javaId; this.amount = amount; this.components = components; this.netId = netId; + this.bundleData = bundleData; } public static @NonNull GeyserItemStack of(int javaId, int amount) { @@ -173,6 +178,24 @@ public class GeyserItemStack { return isEmpty() ? 0 : netId; } + public int getBundleId() { + if (isEmpty()) { + return -1; + } + + return bundleData == null ? -1 : bundleData.bundleId(); + } + + public void mergeBundleData(GeyserSession session, BundleCache.BundleData oldBundleData) { + if (oldBundleData != null && this.bundleData != null) { + // Old bundle; re-use old IDs + this.bundleData.updateNetIds(session, oldBundleData); + } else if (this.bundleData != null) { + // New bundle; allocate new ID + session.getBundleCache().markNewBundle(this.bundleData); + } + } + public void add(int add) { amount += add; } @@ -186,6 +209,21 @@ public class GeyserItemStack { } public @Nullable ItemStack getItemStack(int newAmount) { + if (isEmpty()) { + return null; + } + // Sync our updated bundle data to server, if applicable + // Not fresh from server? Then we have changes to apply!~ + if (bundleData != null && !bundleData.freshFromServer()) { + if (!bundleData.contents().isEmpty()) { + getOrCreateComponents().put(DataComponentType.BUNDLE_CONTENTS, bundleData.toComponent()); + } else { + if (components != null) { + // Empty list = no component = should delete + components.getDataComponents().remove(DataComponentType.BUNDLE_CONTENTS); + } + } + } return isEmpty() ? null : new ItemStack(javaId, newAmount, components); } @@ -196,7 +234,8 @@ public class GeyserItemStack { ItemData.Builder itemData = ItemTranslator.translateToBedrock(session, javaId, amount, components); itemData.netId(getNetId()); itemData.usingNetId(true); - return itemData.build(); + + return session.getBundleCache().checkForBundle(this, itemData); } public ItemMapping getMapping(GeyserSession session) { @@ -229,6 +268,6 @@ public class GeyserItemStack { } public GeyserItemStack copy(int newAmount) { - return isEmpty() ? EMPTY : new GeyserItemStack(javaId, newAmount, components == null ? null : components.clone(), netId); + return isEmpty() ? EMPTY : new GeyserItemStack(javaId, newAmount, components == null ? null : components.clone(), netId, bundleData == null ? null : bundleData.copy()); } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index 09d04f17c..c960ed1a2 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -142,15 +142,21 @@ public abstract class Inventory { } } - protected void updateItemNetId(GeyserItemStack oldItem, GeyserItemStack newItem, GeyserSession session) { + public static void updateItemNetId(GeyserItemStack oldItem, GeyserItemStack newItem, GeyserSession session) { if (!newItem.isEmpty()) { ItemDefinition oldMapping = ItemTranslator.getBedrockItemDefinition(session, oldItem); ItemDefinition newMapping = ItemTranslator.getBedrockItemDefinition(session, newItem); if (oldMapping.equals(newMapping)) { newItem.setNetId(oldItem.getNetId()); + newItem.mergeBundleData(session, oldItem.getBundleData()); } else { newItem.setNetId(session.getNextItemNetId()); + session.getBundleCache().markNewBundle(newItem.getBundleData()); + session.getBundleCache().onOldItemDelete(oldItem); } + } else { + // Empty item means no more bundle if one existed. + session.getBundleCache().onOldItemDelete(oldItem); } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java b/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java index 6897786c1..cf16d0b6f 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java @@ -31,7 +31,10 @@ import lombok.AllArgsConstructor; @AllArgsConstructor public enum Click { LEFT(ContainerActionType.CLICK_ITEM, ClickItemAction.LEFT_CLICK), + LEFT_BUNDLE(ContainerActionType.CLICK_ITEM, ClickItemAction.LEFT_CLICK), + LEFT_BUNDLE_FROM_CURSOR(ContainerActionType.CLICK_ITEM, ClickItemAction.LEFT_CLICK), RIGHT(ContainerActionType.CLICK_ITEM, ClickItemAction.RIGHT_CLICK), + RIGHT_BUNDLE(ContainerActionType.CLICK_ITEM, ClickItemAction.RIGHT_CLICK), LEFT_SHIFT(ContainerActionType.SHIFT_CLICK_ITEM, ShiftClickItemAction.LEFT_CLICK), DROP_ONE(ContainerActionType.DROP_ITEM, DropItemAction.DROP_FROM_SELECTED), DROP_ALL(ContainerActionType.DROP_ITEM, DropItemAction.DROP_SELECTED_STACK), diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index 9d6f4d3e3..d4344f6e8 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -25,19 +25,26 @@ package org.geysermc.geyser.inventory.click; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerActionType; -import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; -import org.geysermc.mcprotocollib.protocol.data.game.inventory.MoveToHotbarAction; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; -import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.BundleInventoryTranslator; import org.geysermc.geyser.translator.inventory.CraftingInventoryTranslator; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.geyser.util.thirdparty.Fraction; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerActionType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.MoveToHotbarAction; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSelectBundleItemPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import org.jetbrains.annotations.Contract; import java.util.ArrayList; @@ -52,7 +59,8 @@ public final class ClickPlan { */ private Int2ObjectMap changedItems; private GeyserItemStack simulatedCursor; - private boolean finished; + private int desiredBundleSlot; + private boolean executionBegan; private final GeyserSession session; private final InventoryTranslator translator; @@ -67,7 +75,7 @@ public final class ClickPlan { this.simulatedItems = new Int2ObjectOpenHashMap<>(inventory.getSize()); this.changedItems = null; this.simulatedCursor = session.getPlayerInventory().getCursor().copy(); - this.finished = false; + this.executionBegan = false; gridSize = translator.getGridSize(); } @@ -82,7 +90,7 @@ public final class ClickPlan { } public void add(Click click, int slot, boolean force) { - if (finished) + if (executionBegan) throw new UnsupportedOperationException("ClickPlan already executed"); if (click == Click.LEFT_OUTSIDE || click == Click.RIGHT_OUTSIDE) { @@ -97,6 +105,7 @@ public final class ClickPlan { } public void execute(boolean refresh) { + executionBegan = true; //update geyser inventory after simulation to avoid net id desync resetSimulation(); ListIterator planIter = plan.listIterator(); @@ -159,7 +168,27 @@ public final class ClickPlan { for (Int2ObjectMap.Entry simulatedSlot : simulatedItems.int2ObjectEntrySet()) { inventory.setItem(simulatedSlot.getIntKey(), simulatedSlot.getValue(), session); } - finished = true; + } + + public void executeForCreativeMode() { + executionBegan = true; + //update geyser inventory after simulation to avoid net id desync + resetSimulation(); + changedItems = new Int2ObjectOpenHashMap<>(); + for (ClickAction action : plan) { + simulateAction(action); + } + session.getPlayerInventory().setCursor(simulatedCursor, session); + for (Int2ObjectMap.Entry simulatedSlot : simulatedItems.int2ObjectEntrySet()) { + inventory.setItem(simulatedSlot.getIntKey(), simulatedSlot.getValue(), session); + } + for (Int2ObjectMap.Entry changedSlot : changedItems.int2ObjectEntrySet()) { + ItemStack value = changedSlot.getValue(); + ItemStack toSend = InventoryUtils.isEmpty(value) ? new ItemStack(-1, 0, null) : value; + session.sendDownstreamGamePacket( + new ServerboundSetCreativeModeSlotPacket((short) changedSlot.getIntKey(), toSend) + ); + } } public Inventory getInventory() { @@ -187,6 +216,10 @@ public final class ClickPlan { return simulatedItems.computeIfAbsent(slot, k -> inventory.getItem(slot).copy()); } + public void setDesiredBundleSlot(int desiredBundleSlot) { + this.desiredBundleSlot = desiredBundleSlot; + } + public GeyserItemStack getCursor() { return simulatedCursor; } @@ -275,8 +308,60 @@ public final class ClickPlan { } else if (InventoryUtils.canStack(cursor, clicked)) { cursor.sub(1); add(action.slot, clicked, 1); + } else { + // Can't stack, but both the cursor and the slot have an item + // (Called for bundles) + setCursor(clicked); + setItem(action.slot, cursor); } break; + case LEFT_BUNDLE: + Fraction bundleWeight = BundleInventoryTranslator.calculateBundleWeight(clicked.getBundleData().contents()); + int amountToAddInBundle = Math.min(BundleInventoryTranslator.capacityForItemStack(bundleWeight, cursor), cursor.getAmount()); + GeyserItemStack toInsertInBundle = cursor.copy(amountToAddInBundle); + if (executionBegan) { + clicked.getBundleData().contents().add(0, toInsertInBundle); + session.getBundleCache().onItemAdded(clicked); // Must be run before onSlotItemChange as the latter exports an ItemStack from the bundle + } + onSlotItemChange(action.slot, clicked); + cursor.sub(amountToAddInBundle); + break; + case LEFT_BUNDLE_FROM_CURSOR: + List contents = cursor.getBundleData().contents(); + bundleWeight = BundleInventoryTranslator.calculateBundleWeight(contents); + amountToAddInBundle = Math.min(BundleInventoryTranslator.capacityForItemStack(bundleWeight, clicked), clicked.getAmount()); + toInsertInBundle = clicked.copy(amountToAddInBundle); + if (executionBegan) { + cursor.getBundleData().contents().add(0, toInsertInBundle); + session.getBundleCache().onItemAdded(cursor); + } + sub(action.slot, clicked, amountToAddInBundle); + break; + case RIGHT_BUNDLE: + if (!cursor.isEmpty()) { + // Bundle should be in player's hand. + GeyserItemStack itemStack = cursor.getBundleData() + .contents() + .remove(0); + if (executionBegan) { + session.getBundleCache().onItemRemoved(cursor, 0); + } + setItem(action.slot, itemStack); + break; + } + + if (executionBegan) { + sendSelectedBundleSlot(action.slot); + } + GeyserItemStack itemStack = clicked.getBundleData() + .contents() + .remove(desiredBundleSlot); + if (executionBegan) { + session.getBundleCache().onItemRemoved(clicked, desiredBundleSlot); + } + onSlotItemChange(action.slot, clicked); + setCursor(itemStack); + break; case SWAP_TO_HOTBAR_1: swap(action.slot, inventory.getOffsetForHotbar(0), clicked); break; @@ -319,6 +404,11 @@ public final class ClickPlan { } } + private void sendSelectedBundleSlot(int slot) { + // Looks like this is also technically sent in creative mode. + session.sendDownstreamGamePacket(new ServerboundSelectBundleItemPacket(slot, desiredBundleSlot)); + } + /** * Swap between two inventory slots without a cursor. This should only be used with {@link ContainerActionType#MOVE_TO_HOTBAR_SLOT} */ 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 3bdf23e39..b3a38f32f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -158,6 +158,7 @@ import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.BedrockClientData; import org.geysermc.geyser.session.cache.AdvancementsCache; import org.geysermc.geyser.session.cache.BookEditCache; +import org.geysermc.geyser.session.cache.BundleCache; import org.geysermc.geyser.session.cache.ChunkCache; import org.geysermc.geyser.session.cache.EntityCache; import org.geysermc.geyser.session.cache.EntityEffectCache; @@ -275,6 +276,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final AdvancementsCache advancementsCache; private final BookEditCache bookEditCache; + private final BundleCache bundleCache; private final ChunkCache chunkCache; private final EntityCache entityCache; private final EntityEffectCache effectCache; @@ -677,6 +679,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.advancementsCache = new AdvancementsCache(this); this.bookEditCache = new BookEditCache(this); + this.bundleCache = new BundleCache(this); this.chunkCache = new ChunkCache(this); this.entityCache = new EntityCache(this); this.effectCache = new EntityEffectCache(); @@ -1352,6 +1355,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } } + this.bundleCache.tick(); + 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 @@ -1470,6 +1475,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { hand, worldCache.nextPredictionSequence(), playerEntity.getYaw(), playerEntity.getPitch())); } + public void releaseItem() { + // Followed to the Minecraft Protocol specification outlined at wiki.vg + ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO, + Direction.DOWN, 0); + sendDownstreamGamePacket(releaseItemPacket); + } + /** * Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display * blocking and sends a packet to the Java server. diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/BundleCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/BundleCache.java new file mode 100644 index 000000000..8ad31949b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/BundleCache.java @@ -0,0 +1,383 @@ +/* + * 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 org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.cloudburstmc.protocol.bedrock.packet.ContainerRegistryCleanupPacket; +import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; +import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.inventory.PlayerInventory; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public final class BundleCache { + private static final int BUNDLE_CONTAINER_ID = 125; // BDS 1.21.44 + private final GeyserSession session; + private int nextBundleId; + + private int releaseTick = -1; + + public BundleCache(GeyserSession session) { + this.session = session; + } + + /** + * Checks to see if the given item from the server is a bundle. + * If so, we initialize our bundle cache. + */ + public void initialize(GeyserItemStack itemStack) { + // Message before 1.21.4 - "Can't check for BUNDLE_CONTENTS, which may be missing if the bundle is empty." + // Now irrelevant, but keeping as-is for the time being. + if (session.getTagCache().is(ItemTag.BUNDLES, itemStack)) { + if (itemStack.getBundleData() != null) { + session.getGeyser().getLogger().warning("Stack has bundle data already! It should not!"); + if (session.getGeyser().getConfig().isDebugMode()) { + session.getGeyser().getLogger().debug("Player: " + session.javaUsername()); + session.getGeyser().getLogger().debug("Stack: " + itemStack); + } + } + + BundleData bundleData; + List rawContents = itemStack.getComponent(DataComponentType.BUNDLE_CONTENTS); + if (rawContents != null) { + // Use existing list and transform it to support net IDs + bundleData = new BundleData(session, rawContents); + } else { + // This is valid behavior (as of vanilla 1.21.2) if the bundle is empty. + // Create new list + bundleData = new BundleData(); + } + itemStack.setBundleData(bundleData); + } + } + + public void markNewBundle(@Nullable BundleData bundleData) { + if (bundleData == null) { + return; + } + if (bundleData.bundleId != -1) { + return; + } + bundleData.bundleId = nextBundleId++; + for (GeyserItemStack stack : bundleData.contents()) { + stack.setNetId(session.getNextItemNetId()); + session.getBundleCache().markNewBundle(stack.getBundleData()); + } + } + + public ItemData checkForBundle(GeyserItemStack itemStack, ItemData.Builder itemData) { + if (itemStack.getBundleData() == null) { + return itemData.build(); + } + // Not ideal, since Cloudburst NBT is immutable, but there isn't another ideal intersection between + // item instance tracking and item translation + // (Java just reads the contents of each item, while Bedrock kind of wants its own ID for each bundle item stack) + List contents = itemStack.getBundleData().contents(); + int containerId = itemStack.getBundleId(); + + if (containerId == -1) { + session.getGeyser().getLogger().warning("Bundle ID should not be -1!"); + } + + NbtMap nbt = itemData.build().getTag(); + NbtMapBuilder builder = nbt == null ? NbtMap.builder() : nbt.toBuilder(); + builder.putInt("bundle_id", containerId); + itemData.tag(builder.build()); + + // Now that the tag is updated... + ItemData finalItem = itemData.build(); + + if (!itemStack.getBundleData().triggerFullContentsUpdate) { + // We are probably in the middle of updating one slot. Let's save bandwidth! :) + return finalItem; + } + + // This is how BDS does it, so while it isn't pretty, it is accurate. + // Ensure that all bundle slots are cleared when we re-send data. + // Otherwise, if we don't indicate an item for a slot, Bedrock will think + // the old item still exists. + ItemData[] array = new ItemData[64]; + Arrays.fill(array, ItemData.AIR); + List bedrockItems = Arrays.asList(array); + // Reverse order to ensure contents line up with Java. + int j = 0; + for (int i = contents.size() - 1; i >= 0; i--) { + // Ensure item data can be tracked + bedrockItems.set(j++, contents.get(i).getItemData(session)); + } + InventoryContentPacket packet = new InventoryContentPacket(); + packet.setContainerId(BUNDLE_CONTAINER_ID); + packet.setContents(bedrockItems); + packet.setContainerNameData(BundleCache.createContainer(containerId)); + packet.setStorageItem(finalItem); + session.sendUpstreamPacket(packet); + + return finalItem; + } + + /* + * We need to send an InventorySlotPacket to the Bedrock client so it updates its changes and doesn't desync. + */ + + public void onItemAdded(GeyserItemStack bundle) { + BundleData data = bundle.getBundleData(); + data.freshFromServer = false; + data.triggerFullContentsUpdate = false; + + List contents = data.contents(); + int bedrockSlot = platformConvertSlot(contents.size(), 0); + ItemData bedrockContent = contents.get(0).getItemData(session); + + sendInventoryPacket(data.bundleId(), bedrockSlot, bedrockContent, bundle.getItemData(session)); + + data.triggerFullContentsUpdate = true; + } + + public void onItemRemoved(GeyserItemStack bundle, int slot) { + // Whatever item used to be in here should have been removed *before* this was triggered. + BundleData data = bundle.getBundleData(); + data.freshFromServer = false; + data.triggerFullContentsUpdate = false; + + List contents = data.contents(); + ItemData baseBundle = bundle.getItemData(session); + // This first slot is now blank! + sendInventoryPacket(data.bundleId(), platformConvertSlot(contents.size() + 1, 0), ItemData.AIR, baseBundle); + // Adjust the index of every item that came before this item. + for (int i = 0; i < slot; i++) { + sendInventoryPacket(data.bundleId(), platformConvertSlot(contents.size(), i), + contents.get(i).getItemData(session), baseBundle); + } + + data.triggerFullContentsUpdate = true; + } + + private void sendInventoryPacket(int bundleId, int bedrockSlot, ItemData bedrockContent, ItemData baseBundle) { + InventorySlotPacket packet = new InventorySlotPacket(); + packet.setContainerId(BUNDLE_CONTAINER_ID); + packet.setItem(bedrockContent); + packet.setSlot(bedrockSlot); + packet.setContainerNameData(createContainer(bundleId)); + packet.setStorageItem(baseBundle); + session.sendUpstreamPacket(packet); + } + + /** + * If a bundle is no longer present in the working inventory, delete the cache + * from the client. + */ + public void onOldItemDelete(GeyserItemStack itemStack) { + if (itemStack.getBundleId() != -1) { + // Clean up old container ID, to match BDS behavior. + ContainerRegistryCleanupPacket packet = new ContainerRegistryCleanupPacket(); + packet.getContainers().add(createContainer(itemStack.getBundleId())); + session.sendUpstreamPacket(packet); + } + } + + public void onInventoryClose(Inventory inventory) { + if (inventory instanceof PlayerInventory) { + // Don't bother; items are still here. + return; + } + + for (int i = 0; i < inventory.getSize(); i++) { + GeyserItemStack item = inventory.getItem(i); + onOldItemDelete(item); + } + } + + /* All utilities to track when a release item packet should be sent. + * As of 1.21.50, Bedrock seems to be picky and inspecific when sending its own release packet, + * but if Java does not receive a release packet, then it will continue to drop items out of a bundle. + * This workaround releases items on behalf of the client if it does not send a packet, while respecting + * if Bedrock sends its own. */ + + public void awaitRelease() { + if (session.getTagCache().is(ItemTag.BUNDLES, session.getPlayerInventory().getItemInHand())) { + releaseTick = session.getTicks() + 1; + } + } + + public void markRelease() { + releaseTick = -1; + } + + public void tick() { + if (this.releaseTick != -1) { + if (session.getTicks() >= this.releaseTick) { + session.releaseItem(); + markRelease(); + } + } + } + + /** + * Bidirectional; works for both Bedrock and Java. + */ + public static int platformConvertSlot(int contentsSize, int rawSlot) { + return contentsSize - rawSlot - 1; + } + + public static FullContainerName createContainer(int id) { + return new FullContainerName(ContainerSlotType.DYNAMIC_CONTAINER, id); + } + + /** + * Primarily exists to support net IDs within bundles. + * Important to prevent accidental item deletion in creative mode. + */ + public static final class BundleData { + private final List contents; + /** + * Will be set to a positive integer after checking for existing bundle data. + */ + private int bundleId = -1; + /** + * If false, blocks a complete InventoryContentPacket being sent to the server. + */ + private boolean triggerFullContentsUpdate = true; + /** + * Sets whether data is accurate from the server; if so, any old bundle contents + * will be overwritten. + * This will be set to false if we are the most recent change-makers. + */ + private boolean freshFromServer = true; + + BundleData(GeyserSession session, List contents) { + this(); + for (ItemStack content : contents) { + GeyserItemStack itemStack = GeyserItemStack.from(content); + // Check recursively + session.getBundleCache().initialize(itemStack); + this.contents.add(itemStack); + } + } + + BundleData() { + this.contents = new ArrayList<>(); + } + + public int bundleId() { + return bundleId; + } + + public List contents() { + return contents; + } + + public boolean freshFromServer() { + return freshFromServer; + } + + public List toComponent() { + List component = new ArrayList<>(this.contents.size()); + for (GeyserItemStack content : this.contents) { + component.add(content.getItemStack()); + } + return component; + } + + /** + * Merge in changes from the server and re-use net IDs where possible. + */ + public void updateNetIds(GeyserSession session, BundleData oldData) { + List oldContents = oldData.contents(); + // Items can't exactly be rearranged in a bundle; they can only be removed at an index, or inserted. + int oldIndex = 0; + for (int newIndex = 0; newIndex < this.contents.size(); newIndex++) { + GeyserItemStack itemStack = this.contents.get(newIndex); + if (oldIndex >= oldContents.size()) { + // Assume new item if it goes out of bounds of our existing stack + if (this.freshFromServer) { + // Only update net IDs for new items if the data is fresh from server. + // Otherwise, we can update net IDs for something that already has + // net IDs allocated, which can cause desyncs. + Inventory.updateItemNetId(GeyserItemStack.EMPTY, itemStack, session); + session.getBundleCache().markNewBundle(itemStack.getBundleData()); + } + continue; + } + + GeyserItemStack oldItem = oldContents.get(oldIndex); + // If it stacks with the old item at this index, then + if (!InventoryUtils.canStack(oldItem, itemStack)) { + // New item? + boolean found = false; + if (oldIndex + 1 < oldContents.size()) { + oldItem = oldContents.get(oldIndex + 1); + if (InventoryUtils.canStack(oldItem, itemStack)) { + // Permanently increment and assume all contents shifted here + oldIndex++; + found = true; + } + } + if (!found && oldIndex - 1 >= 0) { + oldItem = oldContents.get(oldIndex - 1); + if (InventoryUtils.canStack(oldItem, itemStack)) { + // Permanently decrement and assume all contents shifted here + oldIndex--; + found = true; + } + } + if (!found) { + oldItem = GeyserItemStack.EMPTY; + } + } + + if (oldItem != GeyserItemStack.EMPTY || this.freshFromServer) { + Inventory.updateItemNetId(oldItem, itemStack, session); + } + oldIndex++; + } + this.bundleId = oldData.bundleId(); + } + + public BundleData copy() { + BundleData data = new BundleData(); + data.bundleId = this.bundleId; + for (GeyserItemStack content : this.contents) { + data.contents.add(content.copy()); + } + data.freshFromServer = this.freshFromServer; + return data; + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java new file mode 100644 index 000000000..1b42e537f --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java @@ -0,0 +1,339 @@ +/* + * 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.inventory; + +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.IntSets; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +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.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.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.inventory.click.Click; +import org.geysermc.geyser.inventory.click.ClickPlan; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.BundleCache; +import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.geyser.util.thirdparty.Fraction; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; + +import java.util.List; + +import static org.geysermc.geyser.translator.inventory.InventoryTranslator.*; + +public final class BundleInventoryTranslator { + /** + * @return a processed bundle interaction, or null to resume normal transaction handling. + */ + @Nullable + static ItemStackResponse handleBundle(GeyserSession session, InventoryTranslator translator, Inventory inventory, ItemStackRequest request, boolean sendCreativePackets) { + TransferItemStackRequestAction action = null; + for (ItemStackRequestAction requestAction : request.getActions()) { + if (requestAction instanceof SwapAction swapAction) { + if (isBundle(swapAction.getSource()) && isBundle(swapAction.getDestination())) { + // Can be seen when inserting an item that's already present within the bundle + continue; + } + return null; + } + + if (!(requestAction instanceof TransferItemStackRequestAction transferAction)) { + // No other known bundle action that does not use transfer actions + return null; + } + boolean sourceIsBundle = isBundle(transferAction.getSource()); + boolean destIsBundle = isBundle(transferAction.getDestination()); + if (sourceIsBundle && destIsBundle) { + // The client is rearranging the bundle inventory; we're going to ignore translating these actions. + continue; + } + if (sourceIsBundle || destIsBundle) { + // This action is moving to a bundle or moving out of a bundle. This is the one we want to track + action = transferAction; + } else { + // Neither location is a bundle location. We don't need to deal with this here. + return null; + } + } + if (action == null) { + return null; + } + + ClickPlan plan = new ClickPlan(session, translator, inventory); + if (isBundle(action.getDestination())) { + // Placing into bundle + var bundleSlotData = action.getDestination(); + var inventorySlotData = action.getSource(); + int bundleId = bundleSlotData.getContainerName().getDynamicId(); + GeyserItemStack cursor = session.getPlayerInventory().getCursor(); + + if (cursor.getBundleId() == bundleId) { + List contents = cursor.getBundleData().contents(); + // Placing items into bundles can mean their contents are empty + + // We are currently holding the bundle and trying to pick an item up. + int sourceSlot = translator.bedrockSlotToJava(inventorySlotData); + GeyserItemStack sourceItem = inventory.getItem(sourceSlot); + if (sourceItem.isEmpty()) { + // This would be treated as just... plumping the bundle down, + // and that should not be called here. + return rejectRequest(request); + } + if (inventorySlotData.getStackNetworkId() != sourceItem.getNetId()) { + return rejectRequest(request); + } + + // Note that this is also called in ClickPlan. Not ideal... + Fraction bundleWeight = calculateBundleWeight(contents); + int allowedCapacity = Math.min(capacityForItemStack(bundleWeight, sourceItem), sourceItem.getAmount()); + + if (action.getCount() != allowedCapacity) { + // Might trigger if bundle weight is different between Java and Bedrock (see calculateBundleWeight) + return rejectRequest(request); + } + + plan.add(Click.LEFT_BUNDLE_FROM_CURSOR, sourceSlot); + if (sendCreativePackets) { + plan.executeForCreativeMode(); + } else { + plan.execute(false); + } + return acceptRequest(request, translator.makeContainerEntries(session, inventory, IntSets.singleton(sourceSlot))); + } + + for (int javaSlot = 0; javaSlot < inventory.getSize(); javaSlot++) { + GeyserItemStack bundle = inventory.getItem(javaSlot); + if (bundle.getBundleId() != bundleId) { + continue; + } + + if (!translator.checkNetId(session, inventory, inventorySlotData)) { + return rejectRequest(request); + } + + // Placing items into bundles can mean their contents are empty + // Bundle slot does not matter; Java always appends an item to the beginning of a bundle inventory + + IntSet affectedSlots = new IntOpenHashSet(2); + affectedSlots.add(javaSlot); + + boolean slotIsInventory = !isCursor(inventorySlotData); + int sourceSlot; + // If source is cursor, logic lines up better with Java. + if (slotIsInventory) { + // Simulate picking up the item and adding it to our cursor, + // which is what Java would expect + sourceSlot = translator.bedrockSlotToJava(inventorySlotData); + plan.add(Click.LEFT, sourceSlot); + affectedSlots.add(sourceSlot); + } else { + sourceSlot = -1; + } + + Fraction bundleWeight = calculateBundleWeight(bundle.getBundleData().contents()); + // plan.getCursor() covers if we just picked up the item above from a slot + int allowedCapacity = Math.min(capacityForItemStack(bundleWeight, plan.getCursor()), plan.getCursor().getAmount()); + if (action.getCount() != allowedCapacity) { + // Might trigger if bundle weight is different between Java and Bedrock (see calculateBundleWeight) + return rejectRequest(request); + } + + plan.add(Click.LEFT_BUNDLE, javaSlot); + + if (slotIsInventory && allowedCapacity != plan.getCursor().getAmount()) { + // We will need to place the item back in its original slot. + plan.add(Click.LEFT, sourceSlot); + } + + if (sendCreativePackets) { + plan.executeForCreativeMode(); + } else { + plan.execute(false); + } + return acceptRequest(request, translator.makeContainerEntries(session, inventory, affectedSlots)); + } + + // Could not find bundle in inventory + + } else { + // Taking from bundle + var bundleSlotData = action.getSource(); + var inventorySlotData = action.getDestination(); + int bundleId = bundleSlotData.getContainerName().getDynamicId(); + GeyserItemStack cursor = session.getPlayerInventory().getCursor(); + if (cursor.getBundleId() == bundleId) { + // We are currently holding the bundle + List contents = cursor.getBundleData().contents(); + if (contents.isEmpty()) { + // Nothing would be ejected? + return rejectRequest(request); + } + + // Can't select bundle slots while holding bundle in any version; don't set desired bundle slot + + if (bundleSlotData.getStackNetworkId() != contents.get(0).getNetId()) { + // We're pulling out the first item; if something mismatches, wuh oh. + return rejectRequest(request); + } + + int destSlot = translator.bedrockSlotToJava(inventorySlotData); + if (!inventory.getItem(destSlot).isEmpty()) { + // Illegal action to place an item down on an existing stack, even if + // the bundle contains the item. + return rejectRequest(request); + } + plan.add(Click.RIGHT_BUNDLE, destSlot); + if (sendCreativePackets) { + plan.executeForCreativeMode(); + } else { + plan.execute(false); + } + return acceptRequest(request, translator.makeContainerEntries(session, inventory, IntSets.singleton(destSlot))); + } + + // We need context of what slot the bundle is in. + for (int javaSlot = 0; javaSlot < inventory.getSize(); javaSlot++) { + GeyserItemStack bundle = inventory.getItem(javaSlot); + if (bundle.getBundleId() != bundleId) { + continue; + } + + List contents = bundle.getBundleData().contents(); + int rawSelectedSlot = bundleSlotData.getSlot(); + if (rawSelectedSlot >= contents.size()) { + // Illegal? + return rejectRequest(request); + } + + // Bedrock's indexes are flipped around - first item shown to it is the last index. + int slot = BundleCache.platformConvertSlot(contents.size(), rawSelectedSlot); + plan.setDesiredBundleSlot(slot); + + // We'll need it even if the final destination isn't the cursor. + // I can't think of a situation where we shouldn't reject it and use a temp slot, + // but we will see. + if (!cursor.isEmpty()) { + return rejectRequest(request); + } + + IntSet affectedSlots = new IntOpenHashSet(2); + affectedSlots.add(javaSlot); + GeyserItemStack bundledItem = contents.get(slot); + if (bundledItem.getNetId() != bundleSlotData.getStackNetworkId()) { + // !!! + return rejectRequest(request); + } + + plan.add(Click.RIGHT_BUNDLE, javaSlot); + // If false, simple logic that matches nicely with Java Edition + if (!isCursor(inventorySlotData)) { + // Alas, two-click time. + int destSlot = translator.bedrockSlotToJava(inventorySlotData); + GeyserItemStack existing = inventory.getItem(destSlot); + + // Empty slot is good, but otherwise let's just check that + // the two can stack... + if (!existing.isEmpty()) { + if (!InventoryUtils.canStack(bundledItem, existing)) { + return rejectRequest(request); + } + } + + // Copy the full stack to the new slot. + plan.add(Click.LEFT, destSlot); + affectedSlots.add(destSlot); + } + + if (sendCreativePackets) { + plan.executeForCreativeMode(); + } else { + plan.execute(false); + } + return acceptRequest(request, translator.makeContainerEntries(session, inventory, affectedSlots)); + } + + // Could not find bundle in inventory + } + return rejectRequest(request); + } + + private static final Fraction BUNDLE_IN_BUNDLE_WEIGHT = Fraction.getFraction(1, 16); + + public static Fraction calculateBundleWeight(List contents) { + Fraction fraction = Fraction.ZERO; + + for (GeyserItemStack content : contents) { + fraction = fraction.add(calculateWeight(content) + .multiplyBy(Fraction.getFraction(content.getAmount(), 1))); + } + + return fraction; + } + + private static Fraction calculateWeight(GeyserItemStack itemStack) { + if (itemStack.getBundleData() != null) { + return BUNDLE_IN_BUNDLE_WEIGHT.add(calculateBundleWeight(itemStack.getBundleData().contents())); + } + DataComponents components = itemStack.getComponents(); + if (components != null) { + // NOTE: this seems to be Java-only, so it can technically cause a bundle weight desync, + // but it'll be so rare we can probably ignore it. + List bees = components.get(DataComponentType.BEES); + if (bees != null && !bees.isEmpty()) { + // Bees be heavy, I guess. + return Fraction.ONE; + } + } + return Fraction.getFraction(1, itemStack.getComponentOrFallback(DataComponentType.MAX_STACK_SIZE, itemStack.asItem().defaultMaxStackSize())); + } + + public static int capacityForItemStack(Fraction bundleWeight, GeyserItemStack itemStack) { + Fraction inverse = Fraction.ONE.subtract(bundleWeight); + return Math.max(inverse.divideBy(calculateWeight(itemStack)).intValue(), 0); + } + + static boolean isBundle(ItemStackRequestSlotData slotData) { + return slotData.getContainerName().getContainer() == ContainerSlotType.DYNAMIC_CONTAINER; + } + + static boolean isBundle(ClickPlan plan, int slot) { + return isBundle(plan.getItem(slot)); + } + + static boolean isBundle(GeyserItemStack stack) { + return stack.getBundleData() != null; + } + + private BundleInventoryTranslator() { + } +} 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 b4f507af5..e6c670eea 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 @@ -86,6 +86,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.geysermc.geyser.translator.inventory.BundleInventoryTranslator.isBundle; + @AllArgsConstructor public abstract class InventoryTranslator { @@ -241,6 +243,13 @@ public abstract class InventoryTranslator { return rejectRequest(request); } + // Might be a bundle action... let's check. + ItemStackResponse bundleResponse = BundleInventoryTranslator.handleBundle(session, this, inventory, request, false); + if (bundleResponse != null) { + // We can simplify a lot of logic because we aren't expecting multi-slot interactions. + return bundleResponse; + } + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); int destSlot = bedrockSlotToJava(transferAction.getDestination()); boolean isSourceCursor = isCursor(transferAction.getSource()); @@ -393,6 +402,7 @@ public abstract class InventoryTranslator { break; } case SWAP: { + // TODO breaks with bundles SwapAction swapAction = (SwapAction) action; ItemStackRequestSlotData source = swapAction.getSource(); ItemStackRequestSlotData destination = swapAction.getDestination(); @@ -426,18 +436,24 @@ public abstract class InventoryTranslator { } } + // A note on all the bundle checks for clicks... + // Left clicking in these contexts can count as using the bundle + // and adding the stack to the contents of the bundle. + // In these cases, we can safely use right-clicking while holding the bundle + // as its stack size is 1. + if (isSourceCursor && isDestCursor) { //??? return rejectRequest(request); } else if (isSourceCursor) { //swap cursor if (InventoryUtils.canStack(cursor, plan.getItem(destSlot))) { //TODO: cannot simply swap if cursor stacks with slot (temp slot) return rejectRequest(request); } - plan.add(Click.LEFT, destSlot); + plan.add(isBundle(plan, destSlot) || isBundle(cursor) ? Click.RIGHT : Click.LEFT, destSlot); } else if (isDestCursor) { //swap cursor if (InventoryUtils.canStack(cursor, plan.getItem(sourceSlot))) { //TODO return rejectRequest(request); } - plan.add(Click.LEFT, sourceSlot); + plan.add(isBundle(plan, sourceSlot) || isBundle(cursor) ? Click.RIGHT : Click.LEFT, sourceSlot); } else { if (!cursor.isEmpty()) { //TODO: (temp slot) return rejectRequest(request); @@ -449,7 +465,7 @@ public abstract class InventoryTranslator { return rejectRequest(request); } plan.add(Click.LEFT, sourceSlot); //pickup source into cursor - plan.add(Click.LEFT, destSlot); //swap cursor with dest slot + plan.add(isBundle(plan, sourceSlot) || isBundle(plan, destSlot) ? Click.RIGHT : Click.LEFT, destSlot); //swap cursor with dest slot plan.add(Click.LEFT, sourceSlot); //release cursor onto source } break; @@ -915,6 +931,11 @@ public abstract class InventoryTranslator { } public boolean checkNetId(GeyserSession session, Inventory inventory, ItemStackRequestSlotData slotInfoData) { + if (BundleInventoryTranslator.isBundle(slotInfoData)) { + // Will thoroughly be investigated, if needed, in bundle checks. + return true; + } + int netId = slotInfoData.getStackNetworkId(); // "In my testing, sometimes the client thinks the netId of an item in the crafting grid is 1, even though we never said it was. // I think it only happens when we manually set the grid but that was my quick fix" diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 445b4715b..371d61714 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -265,6 +265,15 @@ public class PlayerInventoryTranslator extends InventoryTranslator { return rejectRequest(request, false); } + // Might be a bundle action... let's check. + // If we're in creative mode, instead of replacing logic (more hassle for updates), + // let's just reuse as much logic as possible!! + ItemStackResponse bundleResponse = BundleInventoryTranslator.handleBundle(session, this, inventory, request, true); + if (bundleResponse != null) { + // We can simplify a lot of logic because we aren't expecting multi-slot interactions. + return bundleResponse; + } + int transferAmount = transferAction.getCount(); if (isCursor(transferAction.getDestination())) { int sourceSlot = bedrockSlotToJava(transferAction.getSource()); @@ -415,6 +424,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { @Override protected ItemStackResponse translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { ItemStack javaCreativeItem = null; + boolean bundle = false; IntSet affectedSlots = new IntOpenHashSet(); CraftState craftState = CraftState.START; for (ItemStackRequestAction action : request.getActions()) { @@ -469,8 +479,10 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (isCursor(transferAction.getDestination())) { if (session.getPlayerInventory().getCursor().isEmpty()) { GeyserItemStack newItemStack = GeyserItemStack.from(javaCreativeItem); + session.getBundleCache().initialize(newItemStack); newItemStack.setAmount(transferAction.getCount()); session.getPlayerInventory().setCursor(newItemStack, session); + bundle = newItemStack.getBundleData() != null; } else { session.getPlayerInventory().getCursor().add(transferAction.getCount()); } @@ -479,8 +491,10 @@ public class PlayerInventoryTranslator extends InventoryTranslator { int destSlot = bedrockSlotToJava(transferAction.getDestination()); if (inventory.getItem(destSlot).isEmpty()) { GeyserItemStack newItemStack = GeyserItemStack.from(javaCreativeItem); + session.getBundleCache().initialize(newItemStack); newItemStack.setAmount(transferAction.getCount()); inventory.setItem(destSlot, newItemStack, session); + bundle = newItemStack.getBundleData() != null; } else { inventory.getItem(destSlot).add(transferAction.getCount()); } @@ -520,7 +534,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator { int slot = it.nextInt(); sendCreativeAction(session, inventory, slot); } - return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); + // On the bundle check: + // We can also accept the request, but sending a bad request indicates to Geyser to refresh the inventory + // and we need to refresh the inventory to send the bundle ID/inventory to the client. + // It's not great, but I don't want to create a container class for request responses + return bundle ? rejectRequest(request, false) : acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); } private static void sendCreativeAction(GeyserSession session, Inventory inventory, int slot) { 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 422c45b9b..db1a05011 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 @@ -411,6 +411,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator legacySlots = packet.getLegacySlots(); if (packet.getActions().size() == 1 && !legacySlots.isEmpty()) { InventoryActionData actionData = packet.getActions().get(0); @@ -439,10 +441,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator 0 || stateId != inventory.getStateId()); inventory.setStateId(stateId); - session.getPlayerInventory().setCursor(GeyserItemStack.from(packet.getCarriedItem()), session); + GeyserItemStack cursor = GeyserItemStack.from(packet.getCarriedItem()); + session.getBundleCache().initialize(cursor); + session.getPlayerInventory().setCursor(cursor, session); InventoryUtils.updateCursor(session); if (session.getInventoryTranslator() instanceof SmithingInventoryTranslator) { 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 fe61c8579..0ef547248 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 @@ -93,6 +93,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslatorThis class is immutable, and interoperable with most methods that accept + * a {@link Number}.

    + * + *

    Note that this class is intended for common use cases, it is int + * based and thus suffers from various overflow issues. For a BigInteger based + * equivalent, please see the Commons Math BigFraction class.

    + * + * @since 2.0 + */ +// Geyser: Java Edition uses this for 1.21.3 bundle calculation. Rather than +// Reimplementing an open-source class or bringing in a whole library, +// the single class is used to ensure accuracy. +public final class Fraction extends Number implements Comparable { + + /** + * Required for serialization support. Lang version 2.0. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 65382027393090L; + + /** + * {@link Fraction} representation of 0. + */ + public static final Fraction ZERO = new Fraction(0, 1); + /** + * {@link Fraction} representation of 1. + */ + public static final Fraction ONE = new Fraction(1, 1); + /** + * {@link Fraction} representation of 1/2. + */ + public static final Fraction ONE_HALF = new Fraction(1, 2); + /** + * {@link Fraction} representation of 1/3. + */ + public static final Fraction ONE_THIRD = new Fraction(1, 3); + /** + * {@link Fraction} representation of 2/3. + */ + public static final Fraction TWO_THIRDS = new Fraction(2, 3); + /** + * {@link Fraction} representation of 1/4. + */ + public static final Fraction ONE_QUARTER = new Fraction(1, 4); + /** + * {@link Fraction} representation of 2/4. + */ + public static final Fraction TWO_QUARTERS = new Fraction(2, 4); + /** + * {@link Fraction} representation of 3/4. + */ + public static final Fraction THREE_QUARTERS = new Fraction(3, 4); + /** + * {@link Fraction} representation of 1/5. + */ + public static final Fraction ONE_FIFTH = new Fraction(1, 5); + /** + * {@link Fraction} representation of 2/5. + */ + public static final Fraction TWO_FIFTHS = new Fraction(2, 5); + /** + * {@link Fraction} representation of 3/5. + */ + public static final Fraction THREE_FIFTHS = new Fraction(3, 5); + /** + * {@link Fraction} representation of 4/5. + */ + public static final Fraction FOUR_FIFTHS = new Fraction(4, 5); + + + /** + * Add two integers, checking for overflow. + * + * @param x an addend + * @param y an addend + * @return the sum {@code x+y} + * @throws ArithmeticException if the result can not be represented as + * an int + */ + private static int addAndCheck(final int x, final int y) { + final long s = (long) x + (long) y; + if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: add"); + } + return (int) s; + } + /** + * Creates a {@link Fraction} instance from a {@code double} value. + * + *
    + * + * @param value the double value to convert + * @return a new fraction instance that is close to the value + * @throws ArithmeticException if {@code |value| > Integer.MAX_VALUE} + * or {@code value = NaN} + * @throws ArithmeticException if the calculated denominator is {@code zero} + * @throws ArithmeticException if the algorithm does not converge + */ + public static Fraction getFraction(double value) { + final int sign = value < 0 ? -1 : 1; + value = Math.abs(value); + if (value > Integer.MAX_VALUE || Double.isNaN(value)) { + throw new ArithmeticException("The value must not be greater than Integer.MAX_VALUE or NaN"); + } + final int wholeNumber = (int) value; + value -= wholeNumber; + + int numer0 = 0; // the pre-previous + int denom0 = 1; // the pre-previous + int numer1 = 1; // the previous + int denom1 = 0; // the previous + int numer2; // the current, setup in calculation + int denom2; // the current, setup in calculation + int a1 = (int) value; + int a2; + double x1 = 1; + double x2; + double y1 = value - a1; + double y2; + double delta1, delta2 = Double.MAX_VALUE; + double fraction; + int i = 1; + do { + delta1 = delta2; + a2 = (int) (x1 / y1); + x2 = y1; + y2 = x1 - a2 * y1; + numer2 = a1 * numer1 + numer0; + denom2 = a1 * denom1 + denom0; + fraction = (double) numer2 / (double) denom2; + delta2 = Math.abs(value - fraction); + a1 = a2; + x1 = x2; + y1 = y2; + numer0 = numer1; + denom0 = denom1; + numer1 = numer2; + denom1 = denom2; + i++; + } while (delta1 > delta2 && denom2 <= 10000 && denom2 > 0 && i < 25); + if (i == 25) { + throw new ArithmeticException("Unable to convert double to fraction"); + } + return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0); + } + + /** + * Creates a {@link Fraction} instance with the 2 parts + * of a fraction Y/Z. + * + *

    Any negative signs are resolved to be on the numerator.

    + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + * @return a new fraction instance + * @throws ArithmeticException if the denominator is {@code zero} + * or the denominator is {@code negative} and the numerator is {@code Integer#MIN_VALUE} + */ + public static Fraction getFraction(int numerator, int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (denominator < 0) { + if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate"); + } + numerator = -numerator; + denominator = -denominator; + } + return new Fraction(numerator, denominator); + } + /** + * Creates a {@link Fraction} instance with the 3 parts + * of a fraction X Y/Z. + * + *

    The negative sign must be passed in on the whole number part.

    + * + * @param whole the whole number, for example the one in 'one and three sevenths' + * @param numerator the numerator, for example the three in 'one and three sevenths' + * @param denominator the denominator, for example the seven in 'one and three sevenths' + * @return a new fraction instance + * @throws ArithmeticException if the denominator is {@code zero} + * @throws ArithmeticException if the denominator is negative + * @throws ArithmeticException if the numerator is negative + * @throws ArithmeticException if the resulting numerator exceeds + * {@code Integer.MAX_VALUE} + */ + public static Fraction getFraction(final int whole, final int numerator, final int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (denominator < 0) { + throw new ArithmeticException("The denominator must not be negative"); + } + if (numerator < 0) { + throw new ArithmeticException("The numerator must not be negative"); + } + final long numeratorValue; + if (whole < 0) { + numeratorValue = whole * (long) denominator - numerator; + } else { + numeratorValue = whole * (long) denominator + numerator; + } + if (numeratorValue < Integer.MIN_VALUE || numeratorValue > Integer.MAX_VALUE) { + throw new ArithmeticException("Numerator too large to represent as an Integer."); + } + return new Fraction((int) numeratorValue, denominator); + } + /** + * Creates a Fraction from a {@link String}. + * + *

    The formats accepted are:

    + * + *
      + *
    1. {@code double} String containing a dot
    2. + *
    3. 'X Y/Z'
    4. + *
    5. 'Y/Z'
    6. + *
    7. 'X' (a simple whole number)
    8. + *
    + *

    and a .

    + * + * @param str the string to parse, must not be {@code null} + * @return the new {@link Fraction} instance + * @throws NullPointerException if the string is {@code null} + * @throws NumberFormatException if the number format is invalid + */ + public static Fraction getFraction(String str) { + Objects.requireNonNull(str, "str"); + // parse double format + int pos = str.indexOf('.'); + if (pos >= 0) { + return getFraction(Double.parseDouble(str)); + } + + // parse X Y/Z format + pos = str.indexOf(' '); + if (pos > 0) { + final int whole = Integer.parseInt(str.substring(0, pos)); + str = str.substring(pos + 1); + pos = str.indexOf('/'); + if (pos < 0) { + throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z"); + } + final int numer = Integer.parseInt(str.substring(0, pos)); + final int denom = Integer.parseInt(str.substring(pos + 1)); + return getFraction(whole, numer, denom); + } + + // parse Y/Z format + pos = str.indexOf('/'); + if (pos < 0) { + // simple whole number + return getFraction(Integer.parseInt(str), 1); + } + final int numer = Integer.parseInt(str.substring(0, pos)); + final int denom = Integer.parseInt(str.substring(pos + 1)); + return getFraction(numer, denom); + } + + /** + * Creates a reduced {@link Fraction} instance with the 2 parts + * of a fraction Y/Z. + * + *

    For example, if the input parameters represent 2/4, then the created + * fraction will be 1/2.

    + * + *

    Any negative signs are resolved to be on the numerator.

    + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + * @return a new fraction instance, with the numerator and denominator reduced + * @throws ArithmeticException if the denominator is {@code zero} + */ + public static Fraction getReducedFraction(int numerator, int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (numerator == 0) { + return ZERO; // normalize zero. + } + // allow 2^k/-2^31 as a valid fraction (where k>0) + if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) { + numerator /= 2; + denominator /= 2; + } + if (denominator < 0) { + if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate"); + } + numerator = -numerator; + denominator = -denominator; + } + // simplify fraction. + final int gcd = greatestCommonDivisor(numerator, denominator); + numerator /= gcd; + denominator /= gcd; + return new Fraction(numerator, denominator); + } + + /** + * Gets the greatest common divisor of the absolute value of + * two numbers, using the "binary gcd" method which avoids + * division and modulo operations. See Knuth 4.5.2 algorithm B. + * This algorithm is due to Josef Stein (1961). + * + * @param u a non-zero number + * @param v a non-zero number + * @return the greatest common divisor, never zero + */ + private static int greatestCommonDivisor(int u, int v) { + // From Commons Math: + if (u == 0 || v == 0) { + if (u == Integer.MIN_VALUE || v == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: gcd is 2^31"); + } + return Math.abs(u) + Math.abs(v); + } + // if either operand is abs 1, return 1: + if (Math.abs(u) == 1 || Math.abs(v) == 1) { + return 1; + } + // keep u and v negative, as negative integers range down to + // -2^31, while positive numbers can only be as large as 2^31-1 + // (i.e. we can't necessarily negate a negative number without + // overflow) + if (u > 0) { + u = -u; + } // make u negative + if (v > 0) { + v = -v; + } // make v negative + // B1. [Find power of 2] + int k = 0; + while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are both even... + u /= 2; + v /= 2; + k++; // cast out twos. + } + if (k == 31) { + throw new ArithmeticException("overflow: gcd is 2^31"); + } + // B2. Initialize: u and v have been divided by 2^k and at least + // one is odd. + int t = (u & 1) == 1 ? v : -(u / 2)/* B3 */; + // t negative: u was odd, v may be even (t replaces v) + // t positive: u was even, v is odd (t replaces u) + do { + /* assert u<0 && v<0; */ + // B4/B3: cast out twos from t. + while ((t & 1) == 0) { // while t is even. + t /= 2; // cast out twos + } + // B5 [reset max(u,v)] + if (t > 0) { + u = -t; + } else { + v = t; + } + // B6/B3. at this point both u and v should be odd. + t = (v - u) / 2; + // |u| larger: t positive (replace u) + // |v| larger: t negative (replace v) + } while (t != 0); + return -u * (1 << k); // gcd is u*2^k + } + + /** + * Multiply two integers, checking for overflow. + * + * @param x a factor + * @param y a factor + * @return the product {@code x*y} + * @throws ArithmeticException if the result can not be represented as + * an int + */ + private static int mulAndCheck(final int x, final int y) { + final long m = (long) x * (long) y; + if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: mul"); + } + return (int) m; + } + + /** + * Multiply two non-negative integers, checking for overflow. + * + * @param x a non-negative factor + * @param y a non-negative factor + * @return the product {@code x*y} + * @throws ArithmeticException if the result can not be represented as + * an int + */ + private static int mulPosAndCheck(final int x, final int y) { + /* assert x>=0 && y>=0; */ + final long m = (long) x * (long) y; + if (m > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: mulPos"); + } + return (int) m; + } + + /** + * Subtract two integers, checking for overflow. + * + * @param x the minuend + * @param y the subtrahend + * @return the difference {@code x-y} + * @throws ArithmeticException if the result can not be represented as + * an int + */ + private static int subAndCheck(final int x, final int y) { + final long s = (long) x - (long) y; + if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: add"); + } + return (int) s; + } + + /** + * The numerator number part of the fraction (the three in three sevenths). + */ + private final int numerator; + + /** + * The denominator number part of the fraction (the seven in three sevenths). + */ + private final int denominator; + + /** + * Cached output hashCode (class is immutable). + */ + private transient int hashCode; + + /** + * Cached output toString (class is immutable). + */ + private transient String toString; + + /** + * Cached output toProperString (class is immutable). + */ + private transient String toProperString; + + /** + * Constructs a {@link Fraction} instance with the 2 parts + * of a fraction Y/Z. + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + */ + private Fraction(final int numerator, final int denominator) { + this.numerator = numerator; + this.denominator = denominator; + } + + /** + * Gets a fraction that is the positive equivalent of this one. + *

    More precisely: {@code (fraction >= 0 ? this : -fraction)}

    + * + *

    The returned fraction is not reduced.

    + * + * @return {@code this} if it is positive, or a new positive fraction + * instance with the opposite signed numerator + */ + public Fraction abs() { + if (numerator >= 0) { + return this; + } + return negate(); + } + + /** + * Adds the value of this fraction to another, returning the result in reduced form. + * The algorithm follows Knuth, 4.5.1. + * + * @param fraction the fraction to add, must not be {@code null} + * @return a {@link Fraction} instance with the resulting values + * @throws NullPointerException if the fraction is {@code null} + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * {@code Integer.MAX_VALUE} + */ + public Fraction add(final Fraction fraction) { + return addSub(fraction, true /* add */); + } + + /** + * Implement add and subtract using algorithm described in Knuth 4.5.1. + * + * @param fraction the fraction to subtract, must not be {@code null} + * @param isAdd true to add, false to subtract + * @return a {@link Fraction} instance with the resulting values + * @throws IllegalArgumentException if the fraction is {@code null} + * @throws ArithmeticException if the resulting numerator or denominator + * cannot be represented in an {@code int}. + */ + private Fraction addSub(final Fraction fraction, final boolean isAdd) { + Objects.requireNonNull(fraction, "fraction"); + // zero is identity for addition. + if (numerator == 0) { + return isAdd ? fraction : fraction.negate(); + } + if (fraction.numerator == 0) { + return this; + } + // if denominators are randomly distributed, d1 will be 1 about 61% + // of the time. + final int d1 = greatestCommonDivisor(denominator, fraction.denominator); + if (d1 == 1) { + // result is ( (u*v' +/- u'v) / u'v') + final int uvp = mulAndCheck(numerator, fraction.denominator); + final int upv = mulAndCheck(fraction.numerator, denominator); + return new Fraction(isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv), mulPosAndCheck(denominator, + fraction.denominator)); + } + // the quantity 't' requires 65 bits of precision; see knuth 4.5.1 + // exercise 7. we're going to use a BigInteger. + // t = u(v'/d1) +/- v(u'/d1) + final BigInteger uvp = BigInteger.valueOf(numerator).multiply(BigInteger.valueOf(fraction.denominator / d1)); + final BigInteger upv = BigInteger.valueOf(fraction.numerator).multiply(BigInteger.valueOf(denominator / d1)); + final BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv); + // but d2 doesn't need extra precision because + // d2 = gcd(t,d1) = gcd(t mod d1, d1) + final int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue(); + final int d2 = tmodd1 == 0 ? d1 : greatestCommonDivisor(tmodd1, d1); + + // result is (t/d2) / (u'/d1)(v'/d2) + final BigInteger w = t.divide(BigInteger.valueOf(d2)); + if (w.bitLength() > 31) { + throw new ArithmeticException("overflow: numerator too large after multiply"); + } + return new Fraction(w.intValue(), mulPosAndCheck(denominator / d1, fraction.denominator / d2)); + } + + /** + * Compares this object to another based on size. + * + *

    Note: this class has a natural ordering that is inconsistent + * with equals, because, for example, equals treats 1/2 and 2/4 as + * different, whereas compareTo treats them as equal. + * + * @param other the object to compare to + * @return -1 if this is less, 0 if equal, +1 if greater + * @throws ClassCastException if the object is not a {@link Fraction} + * @throws NullPointerException if the object is {@code null} + */ + @Override + public int compareTo(final Fraction other) { + if (this == other) { + return 0; + } + if (numerator == other.numerator && denominator == other.denominator) { + return 0; + } + + // otherwise see which is less + final long first = (long) numerator * (long) other.denominator; + final long second = (long) other.numerator * (long) denominator; + return Long.compare(first, second); + } + + /** + * Divide the value of this fraction by another. + * + * @param fraction the fraction to divide by, must not be {@code null} + * @return a {@link Fraction} instance with the resulting values + * @throws NullPointerException if the fraction is {@code null} + * @throws ArithmeticException if the fraction to divide by is zero + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * {@code Integer.MAX_VALUE} + */ + public Fraction divideBy(final Fraction fraction) { + Objects.requireNonNull(fraction, "fraction"); + if (fraction.numerator == 0) { + throw new ArithmeticException("The fraction to divide by must not be zero"); + } + return multiplyBy(fraction.invert()); + } + + /** + * Gets the fraction as a {@code double}. This calculates the fraction + * as the numerator divided by denominator. + * + * @return the fraction as a {@code double} + */ + @Override + public double doubleValue() { + return (double) numerator / (double) denominator; + } + + /** + * Compares this fraction to another object to test if they are equal.. + * + *

    To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.

    + * + * @param obj the reference object with which to compare + * @return {@code true} if this object is equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Fraction)) { + return false; + } + final Fraction other = (Fraction) obj; + return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator(); + } + + /** + * Gets the fraction as a {@code float}. This calculates the fraction + * as the numerator divided by denominator. + * + * @return the fraction as a {@code float} + */ + @Override + public float floatValue() { + return (float) numerator / (float) denominator; + } + + /** + * Gets the denominator part of the fraction. + * + * @return the denominator fraction part + */ + public int getDenominator() { + return denominator; + } + + /** + * Gets the numerator part of the fraction. + * + *

    This method may return a value greater than the denominator, an + * improper fraction, such as the seven in 7/4.

    + * + * @return the numerator fraction part + */ + public int getNumerator() { + return numerator; + } + + /** + * Gets the proper numerator, always positive. + * + *

    An improper fraction 7/4 can be resolved into a proper one, 1 3/4. + * This method returns the 3 from the proper fraction.

    + * + *

    If the fraction is negative such as -7/4, it can be resolved into + * -1 3/4, so this method returns the positive proper numerator, 3.

    + * + * @return the numerator fraction part of a proper fraction, always positive + */ + public int getProperNumerator() { + return Math.abs(numerator % denominator); + } + + /** + * Gets the proper whole part of the fraction. + * + *

    An improper fraction 7/4 can be resolved into a proper one, 1 3/4. + * This method returns the 1 from the proper fraction.

    + * + *

    If the fraction is negative such as -7/4, it can be resolved into + * -1 3/4, so this method returns the positive whole part -1.

    + * + * @return the whole fraction part of a proper fraction, that includes the sign + */ + public int getProperWhole() { + return numerator / denominator; + } + + /** + * Gets a hashCode for the fraction. + * + * @return a hash code value for this object + */ + @Override + public int hashCode() { + if (hashCode == 0) { + // hash code update should be atomic. + hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator(); + } + return hashCode; + } + + /** + * Gets the fraction as an {@code int}. This returns the whole number + * part of the fraction. + * + * @return the whole number fraction part + */ + @Override + public int intValue() { + return numerator / denominator; + } + + /** + * Gets a fraction that is the inverse (1/fraction) of this one. + * + *

    The returned fraction is not reduced.

    + * + * @return a new fraction instance with the numerator and denominator + * inverted. + * @throws ArithmeticException if the fraction represents zero. + */ + public Fraction invert() { + if (numerator == 0) { + throw new ArithmeticException("Unable to invert zero."); + } + if (numerator==Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate numerator"); + } + if (numerator<0) { + return new Fraction(-denominator, -numerator); + } + return new Fraction(denominator, numerator); + } + + /** + * Gets the fraction as a {@code long}. This returns the whole number + * part of the fraction. + * + * @return the whole number fraction part + */ + @Override + public long longValue() { + return (long) numerator / denominator; + } + + /** + * Multiplies the value of this fraction by another, returning the + * result in reduced form. + * + * @param fraction the fraction to multiply by, must not be {@code null} + * @return a {@link Fraction} instance with the resulting values + * @throws NullPointerException if the fraction is {@code null} + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * {@code Integer.MAX_VALUE} + */ + public Fraction multiplyBy(final Fraction fraction) { + Objects.requireNonNull(fraction, "fraction"); + if (numerator == 0 || fraction.numerator == 0) { + return ZERO; + } + // knuth 4.5.1 + // make sure we don't overflow unless the result *must* overflow. + final int d1 = greatestCommonDivisor(numerator, fraction.denominator); + final int d2 = greatestCommonDivisor(fraction.numerator, denominator); + return getReducedFraction(mulAndCheck(numerator / d1, fraction.numerator / d2), + mulPosAndCheck(denominator / d2, fraction.denominator / d1)); + } + + /** + * Gets a fraction that is the negative (-fraction) of this one. + * + *

    The returned fraction is not reduced.

    + * + * @return a new fraction instance with the opposite signed numerator + */ + public Fraction negate() { + // the positive range is one smaller than the negative range of an int. + if (numerator==Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: too large to negate"); + } + return new Fraction(-numerator, denominator); + } + + /** + * Gets a fraction that is raised to the passed in power. + * + *

    The returned fraction is in reduced form.

    + * + * @param power the power to raise the fraction to + * @return {@code this} if the power is one, {@link #ONE} if the power + * is zero (even if the fraction equals ZERO) or a new fraction instance + * raised to the appropriate power + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * {@code Integer.MAX_VALUE} + */ + public Fraction pow(final int power) { + if (power == 1) { + return this; + } + if (power == 0) { + return ONE; + } + if (power < 0) { + if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated. + return this.invert().pow(2).pow(-(power / 2)); + } + return this.invert().pow(-power); + } + final Fraction f = this.multiplyBy(this); + if (power % 2 == 0) { // if even... + return f.pow(power / 2); + } + return f.pow(power / 2).multiplyBy(this); + } + + /** + * Reduce the fraction to the smallest values for the numerator and + * denominator, returning the result. + * + *

    For example, if this fraction represents 2/4, then the result + * will be 1/2.

    + * + * @return a new reduced fraction instance, or this if no simplification possible + */ + public Fraction reduce() { + if (numerator == 0) { + return equals(ZERO) ? this : ZERO; + } + final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator); + if (gcd == 1) { + return this; + } + return getFraction(numerator / gcd, denominator / gcd); + } + + /** + * Subtracts the value of another fraction from the value of this one, + * returning the result in reduced form. + * + * @param fraction the fraction to subtract, must not be {@code null} + * @return a {@link Fraction} instance with the resulting values + * @throws NullPointerException if the fraction is {@code null} + * @throws ArithmeticException if the resulting numerator or denominator + * cannot be represented in an {@code int}. + */ + public Fraction subtract(final Fraction fraction) { + return addSub(fraction, false /* subtract */); + } + + /** + * Gets the fraction as a proper {@link String} in the format X Y/Z. + * + *

    The format used in 'wholeNumber numerator/denominator'. + * If the whole number is zero it will be omitted. If the numerator is zero, + * only the whole number is returned.

    + * + * @return a {@link String} form of the fraction + */ + public String toProperString() { + if (toProperString == null) { + if (numerator == 0) { + toProperString = "0"; + } else if (numerator == denominator) { + toProperString = "1"; + } else if (numerator == -1 * denominator) { + toProperString = "-1"; + } else if ((numerator > 0 ? -numerator : numerator) < -denominator) { + // note that we do the magnitude comparison test above with + // NEGATIVE (not positive) numbers, since negative numbers + // have a larger range. otherwise numerator==Integer.MIN_VALUE + // is handled incorrectly. + final int properNumerator = getProperNumerator(); + if (properNumerator == 0) { + toProperString = Integer.toString(getProperWhole()); + } else { + toProperString = getProperWhole() + " " + properNumerator + "/" + getDenominator(); + } + } else { + toProperString = getNumerator() + "/" + getDenominator(); + } + } + return toProperString; + } + + /** + * Gets the fraction as a {@link String}. + * + *

    The format used is 'numerator/denominator' always. + * + * @return a {@link String} form of the fraction + */ + @Override + public String toString() { + if (toString == null) { + toString = getNumerator() + "/" + getDenominator(); + } + return toString; + } +} diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index e277062f3..6808d0e16 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit e277062f3bccbe772baefcd631f0a5442311467c +Subproject commit 6808d0e16a85e5e569d9d7f89ace59c73196c1f4 From 65f7bdb3c025d6f07c09abbdea73d88fb56f0fec Mon Sep 17 00:00:00 2001 From: Oliver <59418903+Oliver-makes-code@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:57:27 -0600 Subject: [PATCH 521/897] Fix modded items not having a bedrock ID set (#5271) --- .../geyser/registry/populator/CustomItemRegistryPopulator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 3d2ca4ef9..ec1e16e79 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -143,6 +143,7 @@ public class CustomItemRegistryPopulator { Items.register(item, customItemData.javaId()); ItemMapping customItemMapping = ItemMapping.builder() + .bedrockIdentifier(customIdentifier) .bedrockDefinition(new SimpleItemDefinition(customIdentifier, customItemId, true)) .bedrockData(0) .bedrockBlockDefinition(null) From 1267b2e5ab1c6293930d84c54eda7709344e0833 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Thu, 9 Jan 2025 20:53:01 +0000 Subject: [PATCH 522/897] Update fabric.mod.json to new fabric api mod id (#5272) --- bootstrap/mod/fabric/src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json index 4f50768f4..a1c786c2f 100644 --- a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json @@ -24,7 +24,7 @@ ], "depends": { "fabricloader": ">=0.16.7", - "fabric": "*", + "fabric-api": "*", "minecraft": ">=1.21.4" } } From 58e2f17e08998c4945153c2bb25b7259f3d4e217 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 12 Jan 2025 20:44:33 +0100 Subject: [PATCH 523/897] Fix: Brand message being sent too early (#5265) * Fix: Brand message not being sent, send lowercase locale, ensure the MCPL default listener comes first * Refactor disconnect handling * apparently default listeners aren't always first... huh * fix issue with bundle cache attempting to check a null inventory --- .../event/bedrock/SessionDisconnectEvent.java | 2 +- .../connection/GeyserBedrockPingEvent.java | 6 +- .../event/java/ServerDefineCommandsEvent.java | 2 +- .../api/event/java/ServerTransferEvent.java | 2 +- .../java/org/geysermc/geyser/GeyserImpl.java | 5 +- .../type/SessionDisconnectEventImpl.java} | 27 +- .../geyser/network/InvalidPacketHandler.java | 10 +- .../geyser/session/DownstreamSession.java | 5 +- .../geyser/session/GeyserSession.java | 220 ++-------------- .../geyser/session/GeyserSessionAdapter.java | 242 ++++++++++++++++++ .../SessionDisconnectListener.java} | 61 ++--- .../java/JavaLoginFinishedTranslator.java | 3 +- .../player/JavaTransferPacketTranslator.java | 4 +- .../geysermc/geyser/util/InventoryUtils.java | 2 +- 14 files changed, 338 insertions(+), 253 deletions(-) rename core/src/main/java/org/geysermc/geyser/{translator/protocol/java/JavaDisconnectTranslator.java => event/type/SessionDisconnectEventImpl.java} (61%) create mode 100644 core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java rename core/src/main/java/org/geysermc/geyser/{translator/protocol/java/JavaLoginDisconnectTranslator.java => session/SessionDisconnectListener.java} (58%) diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionDisconnectEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionDisconnectEvent.java index 05e3415a0..f97f32f92 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionDisconnectEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionDisconnectEvent.java @@ -50,7 +50,7 @@ public class SessionDisconnectEvent extends ConnectionEvent { } /** - * Sets the disconnect reason, thereby overriding th original reason. + * Sets the disconnect message shown to the Bedrock client. * * @param disconnectReason the reason for the disconnect */ diff --git a/api/src/main/java/org/geysermc/geyser/api/event/connection/GeyserBedrockPingEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/connection/GeyserBedrockPingEvent.java index 10ccb93d5..64d3cb44f 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/connection/GeyserBedrockPingEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/connection/GeyserBedrockPingEvent.java @@ -33,10 +33,10 @@ import org.geysermc.event.Event; import java.net.InetSocketAddress; /** - * Called whenever Geyser gets pinged + * Called whenever Geyser gets pinged by a Bedrock client. *

    - * This event allows you to modify/obtain the MOTD, maximum player count, and current number of players online, - * Geyser will reply to the client with what was given. + * This event allows you to modify/obtain the MOTD, maximum player count, and current number of players online. + * Geyser will reply to the client with the information provided in this event. */ public interface GeyserBedrockPingEvent extends Event { diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerDefineCommandsEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerDefineCommandsEvent.java index 299c9d6dd..40268d5b2 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerDefineCommandsEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerDefineCommandsEvent.java @@ -37,7 +37,7 @@ import java.util.Set; *
    * This event is mapped to the existence of Brigadier on the server. */ -public class ServerDefineCommandsEvent extends ConnectionEvent implements Cancellable { +public final class ServerDefineCommandsEvent extends ConnectionEvent implements Cancellable { private final Set commands; private boolean cancelled; diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java index 594e28ef0..f32d84f6a 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java @@ -37,7 +37,7 @@ import java.util.Map; * Fired when the Java server sends a transfer request to a different Java server. * Geyser Extensions can listen to this event and set a target server ip/port for Bedrock players to be transferred to. */ -public class ServerTransferEvent extends ConnectionEvent { +public final class ServerTransferEvent extends ConnectionEvent { private final String host; private final int port; diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 065c1f0cc..5171c0633 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -74,6 +74,7 @@ import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.erosion.UnixSocketClientListener; import org.geysermc.geyser.event.GeyserEventBus; +import org.geysermc.geyser.event.type.SessionDisconnectEventImpl; import org.geysermc.geyser.extension.GeyserExtensionManager; import org.geysermc.geyser.impl.MinecraftVersionImpl; import org.geysermc.geyser.level.BedrockDimension; @@ -86,6 +87,7 @@ import org.geysermc.geyser.registry.provider.ProviderSupplier; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.PendingMicrosoftAuthentication; +import org.geysermc.geyser.session.SessionDisconnectListener; import org.geysermc.geyser.session.SessionManager; import org.geysermc.geyser.session.cache.RegistryCache; import org.geysermc.geyser.skin.FloodgateSkinUploader; @@ -101,7 +103,6 @@ import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.geyser.util.NewsHandler; import org.geysermc.geyser.util.VersionCheckUtils; import org.geysermc.geyser.util.WebUtils; -import org.geysermc.mcprotocollib.network.tcp.TcpSession; import java.io.File; import java.io.FileWriter; @@ -266,6 +267,8 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { // Register our general permissions when possible eventBus.subscribe(this, GeyserRegisterPermissionsEvent.class, Permissions::register); + // Replace disconnect messages whenever necessary + eventBus.subscribe(this, SessionDisconnectEventImpl.class, SessionDisconnectListener::onSessionDisconnect); startInstance(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/event/type/SessionDisconnectEventImpl.java similarity index 61% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java rename to core/src/main/java/org/geysermc/geyser/event/type/SessionDisconnectEventImpl.java index 0012390cb..b746979df 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/event/type/SessionDisconnectEventImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2025 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,19 +23,26 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.protocol.java; +package org.geysermc.geyser.event.type; -import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundDisconnectPacket; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.event.bedrock.SessionDisconnectEvent; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; -@Translator(packet = ClientboundDisconnectPacket.class) -public class JavaDisconnectTranslator extends PacketTranslator { +/** + * A wrapper around the {@link SessionDisconnectEvent} that allows + * Geyser to access the underlying component when replacing disconnect messages. + */ +@Getter +public class SessionDisconnectEventImpl extends SessionDisconnectEvent { - @Override - public void translate(GeyserSession session, ClientboundDisconnectPacket packet) { - session.disconnect(MessageTranslator.convertMessage(packet.getReason(), session.locale())); + private final Component reasonComponent; + + public SessionDisconnectEventImpl(@NonNull GeyserSession session, Component reason) { + super(session, MessageTranslator.convertToPlainText(reason, session.locale())); + this.reasonComponent = reason; } } diff --git a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java index 1b653891e..974d6fdce 100644 --- a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java @@ -28,6 +28,8 @@ package org.geysermc.geyser.network; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import lombok.RequiredArgsConstructor; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.session.GeyserSession; import java.util.stream.Stream; @@ -45,16 +47,20 @@ public class InvalidPacketHandler extends ChannelInboundHandlerAdapter { .findFirst() .orElse(cause); + GeyserLogger logger = GeyserImpl.getInstance().getLogger(); if (!(rootCause instanceof IllegalArgumentException)) { // Kick users that cause exceptions - session.getGeyser().getLogger().warning("Exception caught in session of" + session.bedrockUsername() + ": " + rootCause.getMessage()); + logger.warning("Exception caught in session of" + session.bedrockUsername() + ": " + rootCause.getMessage()); session.disconnect("An internal error occurred!"); return; } // Kick users that try to send illegal packets - session.getGeyser().getLogger().warning(rootCause.getMessage()); + logger.warning("Illegal packet from " + session.bedrockUsername() + ": " + rootCause.getMessage()); + if (logger.isDebug()) { + cause.printStackTrace(); + } session.disconnect("Invalid packet received!"); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java index 8845cdbea..c1db89484 100644 --- a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.session; import lombok.Getter; import lombok.RequiredArgsConstructor; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.mcprotocollib.network.packet.Packet; import org.geysermc.mcprotocollib.network.tcp.TcpSession; @@ -41,11 +42,11 @@ public class DownstreamSession { this.session.send(packet); } - public void disconnect(String reason) { + public void disconnect(Component reason) { this.session.disconnect(reason); } - public void disconnect(String reason, Throwable throwable) { + public void disconnect(Component reason, Throwable throwable) { this.session.disconnect(reason, throwable); } 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 b3a38f32f..111b966f7 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -41,6 +41,7 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; import net.raphimc.minecraftauth.responsehandler.exception.MinecraftRequestException; import net.raphimc.minecraftauth.step.java.StepMCProfile; import net.raphimc.minecraftauth.step.java.StepMCToken; @@ -109,9 +110,6 @@ import org.geysermc.api.util.InputMode; import org.geysermc.api.util.UiProfile; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; -import org.geysermc.floodgate.crypto.FloodgateCipher; -import org.geysermc.floodgate.util.BedrockData; -import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.bedrock.camera.CameraData; import org.geysermc.geyser.api.bedrock.camera.CameraShake; @@ -121,9 +119,7 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; import org.geysermc.geyser.api.event.bedrock.SessionDisconnectEvent; import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent; -import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.RemoteServer; -import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -138,6 +134,7 @@ import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.erosion.AbstractGeyserboundPacketHandler; import org.geysermc.geyser.erosion.ErosionCancellationException; import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler; +import org.geysermc.geyser.event.type.SessionDisconnectEventImpl; import org.geysermc.geyser.impl.camera.CameraDefinitions; import org.geysermc.geyser.impl.camera.GeyserCameraData; import org.geysermc.geyser.inventory.Inventory; @@ -174,11 +171,8 @@ import org.geysermc.geyser.session.cache.TagCache; import org.geysermc.geyser.session.cache.TeleportCache; import org.geysermc.geyser.session.cache.WorldBorder; import org.geysermc.geyser.session.cache.WorldCache; -import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.text.MinecraftLocale; 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; @@ -187,19 +181,13 @@ import org.geysermc.geyser.util.MathUtils; import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.network.BuiltinFlags; -import org.geysermc.mcprotocollib.network.Session; -import org.geysermc.mcprotocollib.network.event.session.ConnectedEvent; -import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent; -import org.geysermc.mcprotocollib.network.event.session.PacketErrorEvent; -import org.geysermc.mcprotocollib.network.event.session.PacketSendingEvent; -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; -import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; @@ -212,7 +200,6 @@ 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.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.ServerboundClientTickEndPacket; @@ -221,9 +208,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.Serv import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; -import java.net.ConnectException; import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -231,6 +216,7 @@ import java.util.BitSet; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Queue; import java.util.Set; @@ -359,8 +345,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Exposed for GeyserConnect usage protected boolean sentSpawnPacket; - private boolean loggedIn; - private boolean loggingIn; + boolean loggedIn; + boolean loggingIn; @Setter private boolean spawned; @@ -525,11 +511,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private long blockBreakStartTime; - /** - * // TODO - */ - private long destroyProgress; - /** * Stores whether the player intended to place a bucket. */ @@ -658,6 +639,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final GeyserEntityData entityData; + @Getter(AccessLevel.MODULE) private MinecraftProtocol protocol; private int nanosecondsPerTick = 50000000; @@ -962,7 +944,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.cookies = loginEvent.cookies(); this.remoteServer = loginEvent.remoteServer(); - boolean floodgate = this.remoteServer.authType() == AuthType.FLOODGATE; // Start ticking tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS); @@ -1001,188 +982,30 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // We'll handle this since we have the registry data on hand downstream.setFlag(MinecraftConstants.SEND_BLANK_KNOWN_PACKS_RESPONSE, false); - downstream.addListener(new SessionAdapter() { - @Override - public void packetSending(PacketSendingEvent event) { - //todo move this somewhere else - if (event.getPacket() instanceof ClientIntentionPacket) { - String addressSuffix; - if (floodgate) { - byte[] encryptedData; + // We manually add the default listener to ensure the order of listeners. + protocol.setUseDefaultListeners(false); - try { - FloodgateSkinUploader skinUploader = geyser.getSkinUploader(); - FloodgateCipher cipher = geyser.getCipher(); + // MCPL listener comes first to handle protocol state switching before Geyser translates packets + downstream.addListener(new ClientListener(ProtocolState.LOGIN, loginEvent.transferring())); + // Geyser adapter second to ensure translating packets in the correct states + downstream.addListener(new GeyserSessionAdapter(this)); - String bedrockAddress = upstream.getAddress().getAddress().getHostAddress(); - // both BungeeCord and Velocity remove the IPv6 scope (if there is one) for Spigot - int ipv6ScopeIndex = bedrockAddress.indexOf('%'); - if (ipv6ScopeIndex != -1) { - bedrockAddress = bedrockAddress.substring(0, ipv6ScopeIndex); - } - - encryptedData = cipher.encryptFromString(BedrockData.of( - clientData.getGameVersion(), - authData.name(), - authData.xuid(), - clientData.getDeviceOs().ordinal(), - clientData.getLanguageCode(), - clientData.getUiProfile().ordinal(), - clientData.getCurrentInputMode().ordinal(), - bedrockAddress, - skinUploader.getId(), - skinUploader.getVerifyCode() - ).toString()); - } catch (Exception e) { - geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), e); - disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.floodgate.encrypt_fail", getClientData().getLanguageCode())); - return; - } - - addressSuffix = '\0' + new String(encryptedData, StandardCharsets.UTF_8); - } else { - addressSuffix = ""; - } - - ClientIntentionPacket intentionPacket = event.getPacket(); - - String address; - if (geyser.getConfig().getRemote().isForwardHost()) { - address = clientData.getServerAddress().split(":")[0]; - } else { - address = intentionPacket.getHostname(); - } - - event.setPacket(intentionPacket.withHostname(address + addressSuffix)); - } - } - - @Override - public void connected(ConnectedEvent event) { - loggingIn = false; - loggedIn = true; - - if (downstream instanceof LocalSession) { - // Connected directly to the server - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.remote.connect_internal", - authData.name(), protocol.getProfile().getName())); - } else { - // Connected to an IP address - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.remote.connect", - authData.name(), protocol.getProfile().getName(), remoteServer.address())); - } - - UUID uuid = protocol.getProfile().getId(); - if (uuid == null) { - // Set what our UUID *probably* is going to be - if (remoteServer.authType() == AuthType.FLOODGATE) { - uuid = new UUID(0, Long.parseLong(authData.xuid())); - } else { - uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + protocol.getProfile().getName()).getBytes(StandardCharsets.UTF_8)); - } - } - playerEntity.setUuid(uuid); - playerEntity.setUsername(protocol.getProfile().getName()); - - String locale = clientData.getLanguageCode(); - - // Let the user know there locale may take some time to download - // as it has to be extracted from a JAR - if (locale.equalsIgnoreCase("en_us") && !MinecraftLocale.LOCALE_MAPPINGS.containsKey("en_us")) { - // This should probably be left hardcoded as it will only show for en_us clients - sendMessage("Loading your locale (en_us); if this isn't already downloaded, this may take some time"); - } - - // Download and load the language for the player - MinecraftLocale.downloadAndLoadLocale(locale); - } - - @Override - public void disconnected(DisconnectedEvent event) { - loggingIn = false; - - String disconnectMessage; - Throwable cause = event.getCause(); - if (cause instanceof UnexpectedEncryptionException) { - if (remoteServer.authType() != AuthType.FLOODGATE) { - // Server expects online mode - disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.authentication_type_mismatch", locale()); - // Explain that they may be looking for Floodgate. - geyser.getLogger().warning(GeyserLocale.getLocaleStringLog( - geyser.getPlatformType() == PlatformType.STANDALONE ? - "geyser.network.remote.floodgate_explanation_standalone" - : "geyser.network.remote.floodgate_explanation_plugin", - Constants.FLOODGATE_DOWNLOAD_LOCATION - )); - } else { - // Likely that Floodgate is not configured correctly. - disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.floodgate_login_error", locale()); - if (geyser.getPlatformType() == PlatformType.STANDALONE) { - geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.remote.floodgate_login_error_standalone")); - } - } - } else if (cause instanceof ConnectException) { - // Server is offline, probably - disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.server_offline", locale()); - } else { - disconnectMessage = MessageTranslator.convertMessage(event.getReason()); - } - - if (downstream instanceof LocalSession) { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.remote.disconnect_internal", authData.name(), disconnectMessage)); - } else { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.remote.disconnect", authData.name(), remoteServer.address(), disconnectMessage)); - } - if (cause != null) { - if (cause.getMessage() != null) { - GeyserImpl.getInstance().getLogger().error(cause.getMessage()); - } else { - GeyserImpl.getInstance().getLogger().error("An exception occurred: ", cause); - } - if (geyser.getConfig().isDebugMode()) { - cause.printStackTrace(); - } - } - if ((!GeyserSession.this.closed && GeyserSession.this.loggedIn) || cause != null) { - // GeyserSession is disconnected via session.disconnect() called indirectly be the server - // This needs to be "initiated" here when there is an exception, but also when the Netty connection - // is closed without a disconnect packet - in this case, closed will still be false, but loggedIn - // will also be true as GeyserSession#disconnect will not have been called. - GeyserSession.this.disconnect(disconnectMessage); - } - - loggedIn = false; - } - - @Override - public void packetReceived(Session session, Packet packet) { - Registries.JAVA_PACKET_TRANSLATORS.translate(packet.getClass(), packet, GeyserSession.this, true); - } - - @Override - public void packetError(PacketErrorEvent event) { - geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.downstream_error", - (event.getPacketClass() != null ? "(" + event.getPacketClass().getSimpleName() + ")" : "") + - event.getCause().getMessage()) - ); - if (geyser.getConfig().isDebugMode()) - event.getCause().printStackTrace(); - event.setSuppress(true); - } - }); + downstream.connect(false, loginEvent.transferring()); if (!daylightCycle) { setDaylightCycle(true); } - - downstream.connect(false, loginEvent.transferring()); } public void disconnect(String reason) { + disconnect(Component.text(reason)); + } + + public void disconnect(Component reason) { if (!closed) { loggedIn = false; - SessionDisconnectEvent disconnectEvent = new SessionDisconnectEvent(this, reason); + SessionDisconnectEvent disconnectEvent = new SessionDisconnectEventImpl(this, reason); if (authData != null && clientData != null) { // can occur if player disconnects before Bedrock auth finishes // Fire SessionDisconnectEvent geyser.getEventBus().fire(disconnectEvent); @@ -1819,7 +1642,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } if (protocol.getOutboundState() != intendedState) { - geyser.getLogger().debug("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " outbound state"); + geyser.getLogger().warning("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " outbound state. Current state: " + protocol.getOutboundState().name()); return; } @@ -2016,7 +1839,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Send a packet to the server to indicate client render distance, locale, skin parts, and hand preference. */ public void sendJavaClientSettings() { - ServerboundClientInformationPacket clientSettingsPacket = new ServerboundClientInformationPacket(locale(), + // Locale is lowercase on Java - (https://github.com/GeyserMC/Geyser/issues/5235) + ServerboundClientInformationPacket clientSettingsPacket = new ServerboundClientInformationPacket(locale().toLowerCase(Locale.ROOT), getRenderDistance(), ChatVisibility.FULL, true, SKIN_PARTS, HandPreference.RIGHT_HAND, false, true, ParticleStatus.ALL); // TODO particle status sendDownstreamPacket(clientSettingsPacket); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java new file mode 100644 index 000000000..9e17e9cd3 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2025 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; + +import org.geysermc.floodgate.crypto.FloodgateCipher; +import org.geysermc.floodgate.util.BedrockData; +import org.geysermc.geyser.Constants; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.network.AuthType; +import org.geysermc.geyser.api.util.PlatformType; +import org.geysermc.geyser.network.netty.LocalSession; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.session.auth.BedrockClientData; +import org.geysermc.geyser.skin.FloodgateSkinUploader; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.mcprotocollib.network.Session; +import org.geysermc.mcprotocollib.network.event.session.ConnectedEvent; +import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent; +import org.geysermc.mcprotocollib.network.event.session.PacketErrorEvent; +import org.geysermc.mcprotocollib.network.event.session.PacketSendingEvent; +import org.geysermc.mcprotocollib.network.event.session.SessionAdapter; +import org.geysermc.mcprotocollib.network.packet.Packet; +import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException; +import org.geysermc.mcprotocollib.protocol.packet.handshake.serverbound.ClientIntentionPacket; + +import java.net.ConnectException; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +public class GeyserSessionAdapter extends SessionAdapter { + + private final GeyserImpl geyser; + private final GeyserSession geyserSession; + private final boolean floodgate; + private final String locale; + + public GeyserSessionAdapter(GeyserSession session) { + this.geyserSession = session; + this.floodgate = session.remoteServer().authType() == AuthType.FLOODGATE; + this.geyser = GeyserImpl.getInstance(); + this.locale = session.locale(); + } + + @Override + public void packetSending(PacketSendingEvent event) { + if (event.getPacket() instanceof ClientIntentionPacket) { + BedrockClientData clientData = geyserSession.getClientData(); + + String addressSuffix; + if (floodgate) { + byte[] encryptedData; + + try { + FloodgateSkinUploader skinUploader = geyser.getSkinUploader(); + FloodgateCipher cipher = geyser.getCipher(); + + String bedrockAddress = geyserSession.getUpstream().getAddress().getAddress().getHostAddress(); + // both BungeeCord and Velocity remove the IPv6 scope (if there is one) for Spigot + int ipv6ScopeIndex = bedrockAddress.indexOf('%'); + if (ipv6ScopeIndex != -1) { + bedrockAddress = bedrockAddress.substring(0, ipv6ScopeIndex); + } + + encryptedData = cipher.encryptFromString(BedrockData.of( + clientData.getGameVersion(), + geyserSession.bedrockUsername(), + geyserSession.xuid(), + clientData.getDeviceOs().ordinal(), + clientData.getLanguageCode(), + clientData.getUiProfile().ordinal(), + clientData.getCurrentInputMode().ordinal(), + bedrockAddress, + skinUploader.getId(), + skinUploader.getVerifyCode() + ).toString()); + } catch (Exception e) { + geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), e); + geyserSession.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.floodgate.encrypt_fail", locale)); + return; + } + + addressSuffix = '\0' + new String(encryptedData, StandardCharsets.UTF_8); + } else { + addressSuffix = ""; + } + + ClientIntentionPacket intentionPacket = event.getPacket(); + + String address; + if (geyser.getConfig().getRemote().isForwardHost()) { + address = clientData.getServerAddress().split(":")[0]; + } else { + address = intentionPacket.getHostname(); + } + + event.setPacket(intentionPacket.withHostname(address + addressSuffix)); + } + } + + @Override + public void connected(ConnectedEvent event) { + geyserSession.loggingIn = false; + geyserSession.loggedIn = true; + + if (geyserSession.getDownstream().getSession() instanceof LocalSession) { + // Connected directly to the server + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.remote.connect_internal", + geyserSession.bedrockUsername(), geyserSession.getProtocol().getProfile().getName())); + } else { + // Connected to an IP address + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.remote.connect", + geyserSession.bedrockUsername(), geyserSession.getProtocol().getProfile().getName(), geyserSession.remoteServer().address())); + } + + UUID uuid = geyserSession.getProtocol().getProfile().getId(); + if (uuid == null) { + // Set what our UUID *probably* is going to be + if (geyserSession.remoteServer().authType() == AuthType.FLOODGATE) { + uuid = new UUID(0, Long.parseLong(geyserSession.xuid())); + } else { + uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + geyserSession.getProtocol().getProfile().getName()).getBytes(StandardCharsets.UTF_8)); + } + } + geyserSession.getPlayerEntity().setUuid(uuid); + geyserSession.getPlayerEntity().setUsername(geyserSession.getProtocol().getProfile().getName()); + + String locale = geyserSession.getClientData().getLanguageCode(); + + // Let the user know there locale may take some time to download + // as it has to be extracted from a JAR + if (locale.equalsIgnoreCase("en_us") && !MinecraftLocale.LOCALE_MAPPINGS.containsKey("en_us")) { + // This should probably be left hardcoded as it will only show for en_us clients + geyserSession.sendMessage("Loading your locale (en_us); if this isn't already downloaded, this may take some time"); + } + + // Download and load the language for the player + MinecraftLocale.downloadAndLoadLocale(locale); + } + + @Override + public void disconnected(DisconnectedEvent event) { + geyserSession.loggingIn = false; + + String disconnectMessage, customDisconnectMessage = null; + Throwable cause = event.getCause(); + if (cause instanceof UnexpectedEncryptionException) { + if (geyserSession.remoteServer().authType() != AuthType.FLOODGATE) { + // Server expects online mode + customDisconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.authentication_type_mismatch", locale); + // Explain that they may be looking for Floodgate. + geyser.getLogger().warning(GeyserLocale.getLocaleStringLog( + geyser.getPlatformType() == PlatformType.STANDALONE ? + "geyser.network.remote.floodgate_explanation_standalone" + : "geyser.network.remote.floodgate_explanation_plugin", + Constants.FLOODGATE_DOWNLOAD_LOCATION + )); + } else { + // Likely that Floodgate is not configured correctly. + customDisconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.floodgate_login_error", locale); + if (geyser.getPlatformType() == PlatformType.STANDALONE) { + geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.remote.floodgate_login_error_standalone")); + } + } + } else if (cause instanceof ConnectException) { + // Server is offline, probably + customDisconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.server_offline", locale); + } + + // Use our helpful disconnect message whenever possible + disconnectMessage = customDisconnectMessage != null ? customDisconnectMessage : MessageTranslator.convertMessage(event.getReason());; + + if (geyserSession.getDownstream().getSession() instanceof LocalSession) { + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.remote.disconnect_internal", geyserSession.bedrockUsername(), disconnectMessage)); + } else { + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.remote.disconnect", geyserSession.bedrockUsername(), geyserSession.remoteServer().address(), disconnectMessage)); + } + if (cause != null) { + if (cause.getMessage() != null) { + GeyserImpl.getInstance().getLogger().error(cause.getMessage()); + } else { + GeyserImpl.getInstance().getLogger().error("An exception occurred: ", cause); + } + if (geyser.getConfig().isDebugMode()) { + cause.printStackTrace(); + } + } + if ((!geyserSession.isClosed() && geyserSession.loggedIn) || cause != null) { + // GeyserSession is disconnected via session.disconnect() called indirectly be the server + // This needs to be "initiated" here when there is an exception, but also when the Netty connection + // is closed without a disconnect packet - in this case, closed will still be false, but loggedIn + // will also be true as GeyserSession#disconnect will not have been called. + if (customDisconnectMessage != null) { + geyserSession.disconnect(customDisconnectMessage); + } else { + geyserSession.disconnect(event.getReason()); + } + } + + geyserSession.loggedIn = false; + } + + @Override + public void packetReceived(Session session, Packet packet) { + Registries.JAVA_PACKET_TRANSLATORS.translate(packet.getClass(), packet, geyserSession, true); + } + + @Override + public void packetError(PacketErrorEvent event) { + geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.downstream_error", + (event.getPacketClass() != null ? "(" + event.getPacketClass().getSimpleName() + ")" : "") + + event.getCause().getMessage()) + ); + if (geyser.getConfig().isDebugMode()) + event.getCause().printStackTrace(); + event.setSuppress(true); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/session/SessionDisconnectListener.java similarity index 58% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java rename to core/src/main/java/org/geysermc/geyser/session/SessionDisconnectListener.java index 0dd843dfa..da1ed75f4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionDisconnectListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2025 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,59 +23,59 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.protocol.java; +package org.geysermc.geyser.session; -import org.geysermc.mcprotocollib.protocol.packet.login.clientbound.ClientboundLoginDisconnectPacket; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TranslatableComponent; import org.geysermc.geyser.api.util.PlatformType; +import org.geysermc.geyser.event.type.SessionDisconnectEventImpl; import org.geysermc.geyser.network.GameProtocol; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; import java.util.List; -@Translator(packet = ClientboundLoginDisconnectPacket.class) -public class JavaLoginDisconnectTranslator extends PacketTranslator { +/** + * Geyser's internal listener to modify disconnection messages + * for user-friendly messages. + * By listening to the event instead of firing the event with the changed message, + * third-party-users are able to see the original disconnection message. + */ +public final class SessionDisconnectListener { - @Override - public void translate(GeyserSession session, ClientboundLoginDisconnectPacket packet) { - Component disconnectReason = packet.getReason(); + private SessionDisconnectListener() { + // no-op + } + + public static void onSessionDisconnect(SessionDisconnectEventImpl event) { + Component disconnectReason = event.getReasonComponent(); + GeyserSession session = (GeyserSession) event.connection(); String serverDisconnectMessage = MessageTranslator.convertMessage(disconnectReason, session.locale()); - String disconnectMessage; if (testForOutdatedServer(disconnectReason)) { String locale = session.locale(); PlatformType platform = session.getGeyser().getPlatformType(); String outdatedType = (platform == PlatformType.BUNGEECORD || platform == PlatformType.VELOCITY || platform == PlatformType.VIAPROXY) ? - "geyser.network.remote.outdated.proxy" : "geyser.network.remote.outdated.server"; - disconnectMessage = GeyserLocale.getPlayerLocaleString(outdatedType, locale, GameProtocol.getJavaVersions().get(0)) + '\n' - + GeyserLocale.getPlayerLocaleString("geyser.network.remote.original_disconnect_message", locale, serverDisconnectMessage); + "geyser.network.remote.outdated.proxy" : "geyser.network.remote.outdated.server"; + event.disconnectReason(GeyserLocale.getPlayerLocaleString(outdatedType, locale, GameProtocol.getJavaVersions().get(0)) + '\n' + + GeyserLocale.getPlayerLocaleString("geyser.network.remote.original_disconnect_message", locale, serverDisconnectMessage)); } else if (testForMissingProfilePublicKey(disconnectReason)) { - disconnectMessage = "Please set `enforce-secure-profile` to `false` in server.properties for Bedrock players to be able to connect." + '\n' - + GeyserLocale.getPlayerLocaleString("geyser.network.remote.original_disconnect_message", session.locale(), serverDisconnectMessage); - } else { - disconnectMessage = serverDisconnectMessage; + event.disconnectReason("Please set `enforce-secure-profile` to `false` in server.properties for Bedrock players to be able to connect." + '\n' + + GeyserLocale.getPlayerLocaleString("geyser.network.remote.original_disconnect_message", session.locale(), serverDisconnectMessage)); } - - // The client doesn't manually get disconnected so we have to do it ourselves - session.disconnect(disconnectMessage); } - private boolean testForOutdatedServer(Component disconnectReason) { + private static boolean testForOutdatedServer(Component disconnectReason) { if (disconnectReason instanceof TranslatableComponent component) { String key = component.key(); return "multiplayer.disconnect.incompatible".equals(key) || - // Seen with Velocity 1.18 rejecting a 1.19 client - "multiplayer.disconnect.outdated_client".equals(key) || - // Legacy string (starting from at least 1.15.2) - "multiplayer.disconnect.outdated_server".equals(key) - // Reproduced on 1.15.2 server with ViaVersion 4.0.0-21w20a with 1.18.2 Java client - || key.startsWith("Outdated server!"); + // Seen with Velocity 1.18 rejecting a 1.19 client + "multiplayer.disconnect.outdated_client".equals(key) || + // Legacy string (starting from at least 1.15.2) + "multiplayer.disconnect.outdated_server".equals(key) + // Reproduced on 1.15.2 server with ViaVersion 4.0.0-21w20a with 1.18.2 Java client + || key.startsWith("Outdated server!"); } else { if (disconnectReason instanceof TextComponent component) { if (component.content().startsWith("Outdated server!")) { @@ -95,7 +95,8 @@ public class JavaLoginDisconnectTranslator extends PacketTranslator Date: Wed, 15 Jan 2025 23:25:57 +0100 Subject: [PATCH 524/897] Only send the ServerboundClientTickEndPacket while in the GAME protocol state, make locale non-null Fixes https://github.com/GeyserMC/Geyser/issues/5278 --- .../main/java/org/geysermc/geyser/session/GeyserSession.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 111b966f7..f40dcfecc 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1180,7 +1180,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.bundleCache.tick(); - if (spawned) { + if (spawned && protocol.getOutboundState() == ProtocolState.GAME) { // 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); @@ -1400,7 +1400,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public String locale() { - return clientData.getLanguageCode(); + return clientData != null ? clientData.getLanguageCode() : GeyserLocale.getDefaultLocale(); } @Override From a7d475e7e45189d7448d4324b80e91cb2d39df40 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Fri, 17 Jan 2025 22:47:15 +0100 Subject: [PATCH 525/897] fix black particles around invisible area effect cloud entities --- core/src/main/java/org/geysermc/geyser/entity/type/Entity.java | 1 + .../geyser/entity/type/living/monster/CreakingEntity.java | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) 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 0d3214709..c986a8067 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 @@ -176,6 +176,7 @@ public class Entity implements GeyserEntity { setFlag(EntityFlag.HAS_COLLISION, true); setFlag(EntityFlag.CAN_SHOW_NAME, true); setFlag(EntityFlag.CAN_CLIMB, true); + setFlag(EntityFlag.HIDDEN_WHEN_INVISIBLE, true); // Let the Java server (or us) supply all sounds for an entity setClientSideSilent(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java index 1b9fdd8a4..166cdc053 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreakingEntity.java @@ -53,7 +53,6 @@ public class CreakingEntity extends MonsterEntity { @Override protected void initializeMetadata() { super.initializeMetadata(); - setFlag(EntityFlag.HIDDEN_WHEN_INVISIBLE, true); setFlag(EntityFlag.FIRE_IMMUNE, true); } From 613718a52d108871efc5569615cc68f93e96098c Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Sat, 18 Jan 2025 13:53:09 +0100 Subject: [PATCH 526/897] Implement session restructure mcpl PR, fix disconnect messages in configuration stage (#5196) * Implement session restructure mcpl PR * Bump mcpl * Update mcpl api usage * Update MCPL to release, fix https://github.com/GeyserMC/Geyser/issues/5281 (https://github.com/GeyserMC/MCProtocolLib/commit/1daf036f57096692b4a18778f8c6e0c12dc7b424) * Use correct mcpl dependency * apparently 1.21.4-1 doesn't exist? back to snapshots then --------- Co-authored-by: onebeastchris --- .../platform/spigot/GeyserSpigotInjector.java | 7 +- .../type/SessionDisconnectEventImpl.java | 2 +- .../updater/AnvilInventoryUpdater.java | 3 +- .../netty/LocalChannelWithRemoteAddress.java | 7 +- .../geyser/network/netty/LocalSession.java | 151 ++++-------------- .../geyser/session/DownstreamSession.java | 4 +- .../geyser/session/GeyserSession.java | 58 +++---- .../translator/item/CustomItemTranslator.java | 4 +- gradle/libs.versions.toml | 2 +- 9 files changed, 79 insertions(+), 159 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index 9f7e21579..3098ef0e0 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.platform.spigot; +import org.geysermc.mcprotocollib.protocol.MinecraftConstants; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer; import io.netty.bootstrap.ServerBootstrap; @@ -176,9 +177,9 @@ public class GeyserSpigotInjector extends GeyserInjector { */ private void workAroundWeirdBug(GeyserBootstrap bootstrap) { MinecraftProtocol protocol = new MinecraftProtocol(); - LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().address(), - bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress, - InetAddress.getLoopbackAddress().getHostAddress(), protocol, Runnable::run); + LocalSession session = new LocalSession(this.serverSocketAddress, InetAddress.getLoopbackAddress().getHostAddress(), protocol, Runnable::run); + session.setFlag(MinecraftConstants.CLIENT_HOST, bootstrap.getGeyserConfig().getRemote().address()); + session.setFlag(MinecraftConstants.CLIENT_PORT, bootstrap.getGeyserConfig().getRemote().port()); session.connect(); } diff --git a/core/src/main/java/org/geysermc/geyser/event/type/SessionDisconnectEventImpl.java b/core/src/main/java/org/geysermc/geyser/event/type/SessionDisconnectEventImpl.java index b746979df..c845b2399 100644 --- a/core/src/main/java/org/geysermc/geyser/event/type/SessionDisconnectEventImpl.java +++ b/core/src/main/java/org/geysermc/geyser/event/type/SessionDisconnectEventImpl.java @@ -42,7 +42,7 @@ public class SessionDisconnectEventImpl extends SessionDisconnectEvent { private final Component reasonComponent; public SessionDisconnectEventImpl(@NonNull GeyserSession session, Component reason) { - super(session, MessageTranslator.convertToPlainText(reason, session.locale())); + super(session, MessageTranslator.convertMessageRaw(reason, session.locale())); this.reasonComponent = reason; } } 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 3ea78a942..aadaeb356 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 @@ -47,6 +47,7 @@ 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.data.game.item.component.Unbreakable; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import java.util.List; @@ -424,7 +425,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { private boolean hasDurability(GeyserItemStack itemStack) { if (itemStack.asItem().defaultMaxDamage() > 0) { - return itemStack.getComponentOrFallback(DataComponentType.UNBREAKABLE, false); + return itemStack.getComponent(DataComponentType.UNBREAKABLE) != null; } return false; } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java index ac2b6898a..dacb4de69 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java @@ -28,18 +28,19 @@ package org.geysermc.geyser.network.netty; import io.netty.channel.local.LocalChannel; import java.net.InetSocketAddress; +import java.net.SocketAddress; /** * Client -> server storing the spoofed remote address. */ public class LocalChannelWithRemoteAddress extends LocalChannel { - private InetSocketAddress spoofedAddress; + private SocketAddress spoofedAddress; - public InetSocketAddress spoofedRemoteAddress() { + public SocketAddress spoofedRemoteAddress() { return spoofedAddress; } - public void spoofedRemoteAddress(InetSocketAddress socketAddress) { + public void spoofedRemoteAddress(SocketAddress socketAddress) { this.spoofedAddress = socketAddress; } } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 3b86a0bf9..e1847bdee 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -27,150 +27,65 @@ package org.geysermc.geyser.network.netty; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelInitializer; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFactory; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.DefaultEventLoopGroup; +import io.netty.channel.ReflectiveChannelFactory; import io.netty.channel.unix.PreferredDirectByteBufAllocator; -import io.netty.handler.codec.haproxy.HAProxyCommand; -import io.netty.handler.codec.haproxy.HAProxyMessage; -import io.netty.handler.codec.haproxy.HAProxyMessageEncoder; -import io.netty.handler.codec.haproxy.HAProxyProtocolVersion; -import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol; -import io.netty.handler.timeout.ReadTimeoutHandler; -import io.netty.handler.timeout.WriteTimeoutHandler; -import io.netty.util.concurrent.DefaultThreadFactory; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.mcprotocollib.network.BuiltinFlags; -import org.geysermc.mcprotocollib.network.codec.PacketCodecHelper; +import org.geysermc.mcprotocollib.network.helper.NettyHelper; +import org.geysermc.mcprotocollib.network.netty.MinecraftChannelInitializer; import org.geysermc.mcprotocollib.network.packet.PacketProtocol; -import org.geysermc.mcprotocollib.network.tcp.FlushHandler; -import org.geysermc.mcprotocollib.network.tcp.TcpFlowControlHandler; -import org.geysermc.mcprotocollib.network.tcp.TcpPacketCodec; -import org.geysermc.mcprotocollib.network.tcp.TcpPacketCompression; -import org.geysermc.mcprotocollib.network.tcp.TcpPacketEncryptor; -import org.geysermc.mcprotocollib.network.tcp.TcpPacketSizer; -import org.geysermc.mcprotocollib.network.tcp.TcpSession; -import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; +import org.geysermc.mcprotocollib.network.session.ClientNetworkSession; -import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; /** * Manages a Minecraft Java session over our LocalChannel implementations. */ -public final class LocalSession extends TcpSession { - private static DefaultEventLoopGroup DEFAULT_EVENT_LOOP_GROUP; +public final class LocalSession extends ClientNetworkSession { private static PreferredDirectByteBufAllocator PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR = null; - private final SocketAddress targetAddress; - private final String clientIp; - private final PacketCodecHelper codecHelper; + private final SocketAddress spoofedRemoteAddress; - public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, Executor packetHandlerExecutor) { - super(host, port, protocol, packetHandlerExecutor); - this.targetAddress = targetAddress; - this.clientIp = clientIp; - this.codecHelper = protocol.createHelper(); + public LocalSession(SocketAddress targetAddress, String clientIp, PacketProtocol protocol, Executor packetHandlerExecutor) { + super(targetAddress, protocol, packetHandlerExecutor, null, null); + this.spoofedRemoteAddress = new InetSocketAddress(clientIp, 0); } @Override - public void connect(boolean wait, boolean transferring) { - if (this.disconnected) { - throw new IllegalStateException("Connection has already been disconnected."); - } - - if (DEFAULT_EVENT_LOOP_GROUP == null) { - DEFAULT_EVENT_LOOP_GROUP = new DefaultEventLoopGroup(new DefaultThreadFactory(this.getClass(), true)); - Runtime.getRuntime().addShutdownHook(new Thread( - () -> DEFAULT_EVENT_LOOP_GROUP.shutdownGracefully(100, 500, TimeUnit.MILLISECONDS))); - } - - final Bootstrap bootstrap = new Bootstrap(); - bootstrap.channel(LocalChannelWithRemoteAddress.class); - bootstrap.handler(new ChannelInitializer() { - @Override - public void initChannel(@NonNull LocalChannelWithRemoteAddress channel) { - channel.spoofedRemoteAddress(new InetSocketAddress(clientIp, 0)); - PacketProtocol protocol = getPacketProtocol(); - protocol.newClientSession(LocalSession.this, transferring); - - ChannelPipeline pipeline = channel.pipeline(); - - addHAProxySupport(pipeline); - - pipeline.addLast("read-timeout", new ReadTimeoutHandler(getFlag(BuiltinFlags.READ_TIMEOUT, 30))); - pipeline.addLast("write-timeout", new WriteTimeoutHandler(getFlag(BuiltinFlags.WRITE_TIMEOUT, 0))); - - pipeline.addLast("encryption", new TcpPacketEncryptor()); - pipeline.addLast("sizer", new TcpPacketSizer(protocol.getPacketHeader(), getCodecHelper())); - pipeline.addLast("compression", new TcpPacketCompression(getCodecHelper())); - - pipeline.addLast("flow-control", new TcpFlowControlHandler()); - pipeline.addLast("codec", new TcpPacketCodec(LocalSession.this, true)); - pipeline.addLast("flush-handler", new FlushHandler()); - pipeline.addLast("manager", LocalSession.this); - } - }).group(DEFAULT_EVENT_LOOP_GROUP).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getFlag(BuiltinFlags.CLIENT_CONNECT_TIMEOUT, 30) * 1000); + protected ChannelFactory getChannelFactory() { + return new ReflectiveChannelFactory<>(LocalChannelWithRemoteAddress.class); + } + @Override + protected void setOptions(Bootstrap bootstrap) { if (PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR != null) { bootstrap.option(ChannelOption.ALLOCATOR, PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR); } - - bootstrap.remoteAddress(targetAddress); - - CompletableFuture handleFuture = new CompletableFuture<>(); - bootstrap.connect().addListener((futureListener) -> { - if (!futureListener.isSuccess()) { - exceptionCaught(null, futureListener.cause()); - } - - handleFuture.complete(null); - }); - - if (wait) { - handleFuture.join(); - } } @Override - public MinecraftCodecHelper getCodecHelper() { - return (MinecraftCodecHelper) this.codecHelper; - } + protected ChannelHandler getChannelHandler() { + return new MinecraftChannelInitializer<>(channel -> { + PacketProtocol protocol = getPacketProtocol(); + protocol.newClientSession(LocalSession.this); - // TODO duplicate code - private void addHAProxySupport(ChannelPipeline pipeline) { - InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); - if (clientAddress != null) { - pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() { - @Override - public void channelActive(@NonNull ChannelHandlerContext ctx) throws Exception { - HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6; - InetSocketAddress remoteAddress; - if (ctx.channel().remoteAddress() instanceof InetSocketAddress) { - remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); - } else { - remoteAddress = new InetSocketAddress(host, port); - } - ctx.channel().writeAndFlush(new HAProxyMessage( - HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol, - clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(), - clientAddress.getPort(), remoteAddress.getPort() - )); - ctx.pipeline().remove(this); - ctx.pipeline().remove("proxy-protocol-encoder"); - super.channelActive(ctx); - } - }); - pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE); - } - } + return LocalSession.this; + }, true) { + @Override + public void initChannel(@NonNull Channel channel) throws Exception { + ((LocalChannelWithRemoteAddress) channel).spoofedRemoteAddress(spoofedRemoteAddress); + + NettyHelper.initializeHAProxySupport(LocalSession.this, channel); + + super.initChannel(channel); + } + }; + } /** * Should only be called when direct ByteBufs should be preferred. At this moment, this should only be called on BungeeCord. diff --git a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java index c1db89484..22827ccfa 100644 --- a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java @@ -29,14 +29,14 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.mcprotocollib.network.ClientSession; import org.geysermc.mcprotocollib.network.packet.Packet; -import org.geysermc.mcprotocollib.network.tcp.TcpSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; @Getter @RequiredArgsConstructor public class DownstreamSession { - private final TcpSession session; + private final ClientSession session; public void sendPacket(@NonNull Packet packet) { this.session.send(packet); 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 f40dcfecc..1cb5d1fd4 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -181,9 +181,9 @@ import org.geysermc.geyser.util.MathUtils; import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.network.BuiltinFlags; +import org.geysermc.mcprotocollib.network.ClientSession; 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.network.session.ClientNetworkSession; import org.geysermc.mcprotocollib.protocol.ClientListener; import org.geysermc.mcprotocollib.protocol.MinecraftConstants; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; @@ -199,6 +199,7 @@ 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.data.handshake.HandshakeIntent; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundClientInformationPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket; @@ -770,7 +771,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Default move speed // Bedrock clients move very fast by default until they get an attribute packet correcting the speed attributesPacket.setAttributes(Collections.singletonList( - GeyserAttributeType.MOVEMENT_SPEED.getAttribute())); + GeyserAttributeType.MOVEMENT_SPEED.getAttribute())); upstream.sendPacket(attributesPacket); GameRulesChangedPacket gamerulePacket = new GameRulesChangedPacket(); @@ -826,8 +827,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { StepMCToken.MCToken mcToken = mcProfile.getMcToken(); protocol = new MinecraftProtocol( - new GameProfile(mcProfile.getId(), mcProfile.getName()), - mcToken.getAccessToken() + new GameProfile(mcProfile.getId(), mcProfile.getName()), + mcToken.getAccessToken() ); geyser.saveAuthChain(bedrockUsername(), GSON.toJson(step.toJson(response))); return Boolean.TRUE; @@ -872,7 +873,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { sendUpstreamPacket(packet); final PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getOrCreateTask( - getAuthData().xuid() + getAuthData().xuid() ); if (task.getAuthentication() != null && task.getAuthentication().isDone()) { onMicrosoftLoginComplete(task); @@ -898,8 +899,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { if (ex != null) { geyser.getLogger().error("Failed to log in with Microsoft code!", ex); if (ex instanceof CompletionException ce - && ce.getCause() instanceof MinecraftRequestException mre - && mre.getResponse().getStatusCode() == 404) { + && ce.getCause() instanceof MinecraftRequestException mre + && mre.getResponse().getStatusCode() == 404) { // Player is trying to join with a Microsoft account that doesn't have Java Edition purchased disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", locale())); } else { @@ -912,8 +913,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { StepMCToken.MCToken mcToken = mcProfile.getMcToken(); this.protocol = new MinecraftProtocol( - new GameProfile(mcProfile.getId(), mcProfile.getName()), - mcToken.getAccessToken() + new GameProfile(mcProfile.getId(), mcProfile.getName()), + mcToken.getAccessToken() ); try { @@ -937,7 +938,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { GeyserImpl.getInstance().eventBus().fire(loginEvent); if (loginEvent.isCancelled()) { String disconnectReason = loginEvent.disconnectReason() == null ? - BedrockDisconnectReasons.DISCONNECTED : loginEvent.disconnectReason(); + BedrockDisconnectReasons.DISCONNECTED : loginEvent.disconnectReason(); disconnect(disconnectReason); return; } @@ -948,15 +949,17 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Start ticking tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS); - TcpSession downstream; + ClientSession downstream; if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP - downstream = new LocalSession(this.remoteServer.address(), this.remoteServer.port(), - geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), - this.protocol, this.tickEventLoop); + downstream = new LocalSession(geyser.getBootstrap().getSocketAddress(), + upstream.getAddress().getAddress().getHostAddress(), + this.protocol, this.tickEventLoop); + downstream.setFlag(MinecraftConstants.CLIENT_HOST, this.remoteServer.address()); + downstream.setFlag(MinecraftConstants.CLIENT_PORT, this.remoteServer.port()); this.downstream = new DownstreamSession(downstream); } else { - downstream = new TcpClientSession(this.remoteServer.address(), this.remoteServer.port(), "0.0.0.0", 0, this.protocol, null, tickEventLoop); + downstream = new ClientNetworkSession(new InetSocketAddress(this.remoteServer.address(), this.remoteServer.port()), this.protocol, tickEventLoop, null, null); this.downstream = new DownstreamSession(downstream); boolean resolveSrv = false; @@ -986,11 +989,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { protocol.setUseDefaultListeners(false); // MCPL listener comes first to handle protocol state switching before Geyser translates packets - downstream.addListener(new ClientListener(ProtocolState.LOGIN, loginEvent.transferring())); + downstream.addListener(new ClientListener(HandshakeIntent.LOGIN)); // Geyser adapter second to ensure translating packets in the correct states downstream.addListener(new GeyserSessionAdapter(this)); - downstream.connect(false, loginEvent.transferring()); + downstream.setFlag(BuiltinFlags.CLIENT_TRANSFERRING, loginEvent.transferring()); + downstream.connect(false); if (!daylightCycle) { setDaylightCycle(true); @@ -1287,7 +1291,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public void setClientData(BedrockClientData data) { this.clientData = data; this.inputCache.setInputMode( - org.cloudburstmc.protocol.bedrock.data.InputMode.values()[data.getCurrentInputMode().ordinal()]); + org.cloudburstmc.protocol.bedrock.data.InputMode.values()[data.getCurrentInputMode().ordinal()]); } /** @@ -1295,7 +1299,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { */ public void useItem(Hand hand) { sendDownstreamGamePacket(new ServerboundUseItemPacket( - hand, worldCache.nextPredictionSequence(), playerEntity.getYaw(), playerEntity.getPitch())); + hand, worldCache.nextPredictionSequence(), playerEntity.getYaw(), playerEntity.getPitch())); } public void releaseItem() { @@ -1351,7 +1355,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private boolean disableBlocking() { if (playerEntity.getFlag(EntityFlag.BLOCKING)) { ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, - Vector3i.ZERO, Direction.DOWN, 0); + Vector3i.ZERO, Direction.DOWN, 0); sendDownstreamGamePacket(releaseItemPacket); playerEntity.setFlag(EntityFlag.BLOCKING, false); return true; @@ -1361,7 +1365,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public void requestOffhandSwap() { ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, - Direction.DOWN, 0); + Direction.DOWN, 0); sendDownstreamGamePacket(swapHandsPacket); } @@ -1585,7 +1589,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { unconfirmedTeleport.resetUnconfirmedFor(); geyser.getLogger().debug("Resending teleport " + unconfirmedTeleport.getTeleportConfirmId()); getPlayerEntity().moveAbsolute(Vector3f.from(unconfirmedTeleport.getX(), unconfirmedTeleport.getY(), unconfirmedTeleport.getZ()), - unconfirmedTeleport.getYaw(), unconfirmedTeleport.getPitch(), playerEntity.isOnGround(), true); + unconfirmedTeleport.getYaw(), unconfirmedTeleport.getPitch(), playerEntity.isOnGround(), true); } } @@ -1841,8 +1845,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public void sendJavaClientSettings() { // Locale is lowercase on Java - (https://github.com/GeyserMC/Geyser/issues/5235) ServerboundClientInformationPacket clientSettingsPacket = new ServerboundClientInformationPacket(locale().toLowerCase(Locale.ROOT), - getRenderDistance(), ChatVisibility.FULL, true, SKIN_PARTS, - HandPreference.RIGHT_HAND, false, true, ParticleStatus.ALL); // TODO particle status + getRenderDistance(), ChatVisibility.FULL, true, SKIN_PARTS, + HandPreference.RIGHT_HAND, false, true, ParticleStatus.ALL); // TODO particle status sendDownstreamPacket(clientSettingsPacket); } @@ -1895,8 +1899,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return switch (pose) { case SNEAKING -> 1.27f; case SWIMMING, - FALL_FLYING, // Elytra - SPIN_ATTACK -> 0.4f; // Trident spin attack + FALL_FLYING, // Elytra + SPIN_ATTACK -> 0.4f; // Trident spin attack case SLEEPING -> 0.2f; default -> EntityDefinitions.PLAYER.offset(); }; diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java index fdc90c215..c6318c461 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java @@ -119,9 +119,7 @@ public final class CustomItemTranslator { private static boolean isDamagableItem(DataComponents components) { // mapping.getMaxDamage > 0 should also be checked (return false if not true) but we already check prior to this function - Boolean unbreakable = components.get(DataComponentType.UNBREAKABLE); - // Tag must either not be present or be set to false - return unbreakable == null || !unbreakable; + return components.get(DataComponentType.UNBREAKABLE) == null; } private CustomItemTranslator() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 65cef50f8..598fb4779 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20241213.160944-20" protocol-codec = "3.0.0.Beta5-20241213.160944-20" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21.4-20241222.190029-11" +mcprotocollib = "1.21.4-20250118.113140-16" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From dff7cf2136dfde6d513f28386444709e54968130 Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Sat, 18 Jan 2025 17:10:27 +0100 Subject: [PATCH 527/897] Use vanilla dns resolving (#5283) * Use vanilla dns resolving * Update gradle/libs.versions.toml Co-authored-by: chris * Update gradle/libs.versions.toml Co-authored-by: chris --------- Co-authored-by: chris --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 598fb4779..e5e8a3faa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20241213.160944-20" protocol-codec = "3.0.0.Beta5-20241213.160944-20" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21.4-20250118.113140-16" +mcprotocollib = "1.21.4-20250118.154631-17" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 98f9bf6b6281a268e9ae1ac1eccb2c4a10dfebde Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 19 Jan 2025 14:29:58 +0100 Subject: [PATCH 528/897] Fix issues with Geyser-Spigot that occurring with older server versions --- .../geyser/entity/type/TextDisplayEntity.java | 2 +- .../geyser/network/netty/LocalSession.java | 16 ++++++++++++++++ .../geysermc/geyser/session/GeyserSession.java | 5 +++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java index 0cd207c52..ccd93d12a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java @@ -67,7 +67,7 @@ public class TextDisplayEntity extends DisplayBaseEntity { } public void setText(EntityMetadata entityMetadata) { - this.dirtyMetadata.put(EntityDataTypes.NAME, MessageTranslator.convertMessage(entityMetadata.getValue())); + this.dirtyMetadata.put(EntityDataTypes.NAME, MessageTranslator.convertMessage(entityMetadata.getValue(), session.locale())); calculateLineCount(entityMetadata.getValue()); } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index e1847bdee..0f6e6b5bc 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -31,8 +31,11 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelOption; +import io.netty.channel.DefaultEventLoopGroup; +import io.netty.channel.EventLoopGroup; import io.netty.channel.ReflectiveChannelFactory; import io.netty.channel.unix.PreferredDirectByteBufAllocator; +import io.netty.util.concurrent.DefaultThreadFactory; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.mcprotocollib.network.helper.NettyHelper; import org.geysermc.mcprotocollib.network.netty.MinecraftChannelInitializer; @@ -42,11 +45,13 @@ import org.geysermc.mcprotocollib.network.session.ClientNetworkSession; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; /** * Manages a Minecraft Java session over our LocalChannel implementations. */ public final class LocalSession extends ClientNetworkSession { + private static DefaultEventLoopGroup DEFAULT_EVENT_LOOP_GROUP; private static PreferredDirectByteBufAllocator PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR = null; private final SocketAddress spoofedRemoteAddress; @@ -68,6 +73,17 @@ public final class LocalSession extends ClientNetworkSession { } } + @Override + protected EventLoopGroup getEventLoopGroup() { + if (DEFAULT_EVENT_LOOP_GROUP == null) { + DEFAULT_EVENT_LOOP_GROUP = new DefaultEventLoopGroup(new DefaultThreadFactory(this.getClass(), true)); + Runtime.getRuntime().addShutdownHook(new Thread( + () -> DEFAULT_EVENT_LOOP_GROUP.shutdownGracefully(100, 500, TimeUnit.MILLISECONDS))); + } + + return DEFAULT_EVENT_LOOP_GROUP; + } + @Override protected ChannelHandler getChannelHandler() { return new MinecraftChannelInitializer<>(channel -> { 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 1cb5d1fd4..fc8f82dd0 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -173,6 +173,7 @@ import org.geysermc.geyser.session.cache.WorldBorder; import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.text.GeyserLocale; 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; @@ -1025,7 +1026,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Downstream's disconnect will fire an event that prints a log message // Otherwise, we print a message here String address = geyser.getConfig().isLogPlayerIpAddresses() ? upstream.getAddress().getAddress().toString() : ""; - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.disconnect", address, reason)); + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.disconnect", address, MessageTranslator.convertMessage(reason))); } // Disconnect upstream if necessary @@ -1646,7 +1647,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } if (protocol.getOutboundState() != intendedState) { - geyser.getLogger().warning("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " outbound state. Current state: " + protocol.getOutboundState().name()); + geyser.getLogger().debug("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " outbound state. Current state: " + protocol.getOutboundState().name()); return; } From 5836dabcdaa8945762d690f7e2784895959060dd Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:11:09 +0100 Subject: [PATCH 529/897] Use mcpl staticify PR (#5284) * Use mcpl staticify PR * Fix missing generic arg * Update libs.versions.toml --- .../org/geysermc/geyser/level/WorldManager.java | 5 ++--- .../registry/loader/RecipeRegistryLoader.java | 16 ++++++++-------- .../DataComponentRegistryPopulator.java | 8 +++----- .../geyser/session/DownstreamSession.java | 10 ---------- .../level/JavaLevelChunkWithLightTranslator.java | 3 ++- .../scoreboard/network/ScoreboardIssueTests.java | 2 +- gradle/libs.versions.toml | 2 +- 7 files changed, 17 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index a85462108..c33fc7665 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -39,7 +39,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; 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.ItemCodecHelper; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import java.util.HashMap; @@ -203,9 +202,9 @@ public abstract class WorldManager { try { Map, DataComponent> components = new HashMap<>(); Int2ObjectMaps.fastForEach(map, entry -> { - DataComponentType type = DataComponentType.from(entry.getIntKey()); + DataComponentType type = DataComponentType.from(entry.getIntKey()); ByteBuf buf = Unpooled.wrappedBuffer(entry.getValue()); - DataComponent value = type.readDataComponent(ItemCodecHelper.INSTANCE, buf); + DataComponent value = type.readDataComponent(buf); components.put(type, value); }); return new DataComponents(components); 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 4cbd2ea47..74c36c00a 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 @@ -31,7 +31,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; -import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; 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; @@ -81,10 +81,10 @@ public abstract class RecipeRegistryLoader implements RegistryLoader getShapelessRecipes(List recipes, MinecraftCodecHelper helper) { + private static List getShapelessRecipes(List recipes) { List deserializedRecipes = new ObjectArrayList<>(recipes.size()); for (NbtMap recipe : recipes) { - ItemStack output = toItemStack(recipe.getCompound("output"), helper); + ItemStack output = toItemStack(recipe.getCompound("output")); List rawInputs = recipe.getList("inputs", NbtType.COMPOUND); Ingredient[] javaInputs = new Ingredient[rawInputs.size()]; for (int i = 0; i < rawInputs.size(); i++) { @@ -95,16 +95,16 @@ public abstract class RecipeRegistryLoader implements RegistryLoader getShapedRecipes(List recipes, MinecraftCodecHelper helper) { + private static List getShapedRecipes(List recipes) { List deserializedRecipes = new ObjectArrayList<>(recipes.size()); for (NbtMap recipe : recipes) { - ItemStack output = toItemStack(recipe.getCompound("output"), helper); + ItemStack output = toItemStack(recipe.getCompound("output")); List shape = recipe.getList("shape", NbtType.INT_ARRAY); // In the recipes mapping, each recipe is mapped by a number List letterToRecipe = new ArrayList<>(); for (NbtMap rawInput : recipe.getList("inputs", NbtType.COMPOUND)) { - letterToRecipe.add(toItemStack(rawInput, helper)); + letterToRecipe.add(toItemStack(rawInput)); } Ingredient[] inputs = new Ingredient[shape.size() * shape.get(0).length]; @@ -126,14 +126,14 @@ public abstract class RecipeRegistryLoader implements RegistryLoader dataComponentType = DataComponentType.from(varInt); - DataComponent dataComponent = dataComponentType.readDataComponent(ItemCodecHelper.INSTANCE, buf); + DataComponent dataComponent = dataComponentType.readDataComponent(buf); map.put(dataComponentType, dataComponent); } diff --git a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java index 22827ccfa..a55f84ab2 100644 --- a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java @@ -31,7 +31,6 @@ import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.mcprotocollib.network.ClientSession; import org.geysermc.mcprotocollib.network.packet.Packet; -import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; @Getter @RequiredArgsConstructor @@ -53,13 +52,4 @@ public class DownstreamSession { public boolean isClosed() { return !this.session.isConnected(); } - - /** - * Gets the codec helper for this session. - * - * @return the codec helper for this session - */ - public MinecraftCodecHelper getCodecHelper() { - return (MinecraftCodecHelper) this.session.getCodecHelper(); - } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index af3c8595e..f4b74be02 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -61,6 +61,7 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; import org.geysermc.mcprotocollib.protocol.data.game.chunk.BitStorage; import org.geysermc.mcprotocollib.protocol.data.game.chunk.ChunkSection; import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; @@ -115,7 +116,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator[]{ new ByteEntityMetadata(0, MetadataType.BYTE, (byte) 0x20), new ObjectEntityMetadata<>(2, MetadataType.OPTIONAL_CHAT, Optional.of(Component.text("tesss"))), new BooleanEntityMetadata(3, MetadataType.BOOLEAN, true) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e5e8a3faa..f74de4de0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20241213.160944-20" protocol-codec = "3.0.0.Beta5-20241213.160944-20" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21.4-20250118.154631-17" +mcprotocollib = "1.21.4-20250121.131208-18" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From c666028eb695e616c7c75bd72a27e0eec3674b52 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 29 Jan 2025 00:42:44 +0100 Subject: [PATCH 530/897] Update Bedrock network library fixes https://github.com/GeyserMC/Geyser/issues/4971 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f74de4de0..2943521e0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ websocket = "1.5.1" protocol-connection = "3.0.0.Beta5-20241213.160944-20" protocol-common = "3.0.0.Beta5-20241213.160944-20" protocol-codec = "3.0.0.Beta5-20241213.160944-20" -raknet = "1.0.0.CR3-20240416.144209-1" +raknet = "1.0.0.CR3-20250128.101054-17" minecraftauth = "4.1.1" mcprotocollib = "1.21.4-20250121.131208-18" adventure = "4.14.0" From da6e2f678ba1d18f035061629254ba1c08b920ab Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 29 Jan 2025 18:18:14 +0100 Subject: [PATCH 531/897] Fix custom stone cutter recipes closes https://github.com/GeyserMC/Geyser/issues/5257, closes https://github.com/GeyserMC/Geyser/issues/5268 --- .../inventory/StonecutterContainer.java | 2 +- .../session/cache/tags/GeyserHolderSet.java | 20 ++++++++++++++----- .../java/JavaUpdateRecipesTranslator.java | 18 +++++++++-------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java index 269a4fb7d..1eb115847 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.inventory; -import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; public class StonecutterContainer extends Container { /** 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 index c77f0a642..227436efc 100644 --- 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 @@ -33,6 +33,7 @@ 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; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.List; import java.util.Objects; @@ -54,15 +55,24 @@ public final class GeyserHolderSet { private final int @Nullable [] holders; public GeyserHolderSet(JavaRegistryKey registry, int @NonNull [] holders) { - this.registry = registry; - this.tag = null; - this.holders = holders; + this(registry, null, holders); } public GeyserHolderSet(JavaRegistryKey registry, @NonNull Tag tagId) { + this(registry, tagId, null); + } + + private GeyserHolderSet(JavaRegistryKey registry, @Nullable Tag tag, int @Nullable [] holders) { this.registry = registry; - this.tag = tagId; - this.holders = null; + this.tag = tag; + this.holders = holders; + } + + /** + * Constructs a {@link GeyserHolderSet} from a MCPL HolderSet. + */ + public static GeyserHolderSet fromHolderSet(JavaRegistryKey registry, @NonNull HolderSet holderSet) { + return new GeyserHolderSet<>(registry, new Tag<>(registry, holderSet.getLocation()), holderSet.getHolders()); } /** diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 3872321af..db2d2d403 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -45,6 +45,8 @@ import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.item.Items; 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.GeyserHolderSet; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -120,16 +122,16 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator 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; - } if (!(recipe.recipe() instanceof ItemStackSlotDisplay)) { - session.getGeyser().getLogger().debug("Ignoring stonecutter recipe for weird output: " + recipe); + session.getGeyser().getLogger().warning("Ignoring stonecutter recipe for weird output: " + recipe); continue; } - rawStonecutterData.computeIfAbsent(ingredient.getHolders()[0], $ -> new ArrayList<>()).add(recipe); + + int[] ingredients = GeyserHolderSet.fromHolderSet(JavaRegistries.ITEM, recipe.input().getValues()) + .resolveRaw(session.getTagCache()); + for (int ingredient : ingredients) { + rawStonecutterData.computeIfAbsent(ingredient, $ -> new ArrayList<>()).add(recipe); + } } Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); @@ -142,7 +144,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Date: Thu, 30 Jan 2025 01:34:07 +0000 Subject: [PATCH 532/897] Add new issue types to templates (#5312) * Add new issue types to templates * Update bug_report.yml * Update feature_request.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 3 ++- .github/ISSUE_TEMPLATE/feature_request.yml | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 036d838ef..ecdb8deed 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,11 +1,12 @@ name: Bug report description: Create a report to help us improve +type: Bug body: - type: markdown attributes: value: | Thanks for taking the time to fill out this bug report for Geyser! Fill out the following form to your best ability to help us fix the problem. - Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://discord.gg/geysermc), [the FAQ](https://github.com/GeyserMC/Geyser/wiki/FAQ) or the [Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues). + Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://discord.gg/geysermc), [the FAQ](https://geysermc.org/wiki/geyser/faq) or the [Common Issues](https://geysermc.org/wiki/geyser/common-issues). - type: textarea attributes: label: Describe the bug diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index d0e42478b..872e30b8e 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,12 +1,13 @@ name: Feature request description: Suggest an idea for this project labels: "Feature Request" +type: Feature body: - type: markdown attributes: value: | Thanks for taking the time to fill out this feature request for Geyser! Please fill out the following form to your best ability to help us understand your feature request and significantly improve the chance of getting added. - For anything else than a feature request, use: [our Discord server](https://discord.gg/geysermc), [the FAQ](https://github.com/GeyserMC/Geyser/wiki/FAQ) or [the Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues). + For anything else than a feature request, use: [our Discord server](https://discord.gg/geysermc), [the FAQ](https://geysermc.org/wiki/geyser/faq) or the [Common Issues](https://geysermc.org/wiki/geyser/common-issues). - type: textarea attributes: label: What feature do you want to see added? @@ -18,4 +19,4 @@ body: label: Are there any alternatives? description: List any alternatives you might have tried validations: - required: true \ No newline at end of file + required: true From ea13e588cd21a815cecf180b9e0bc3039b087e39 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 2 Feb 2025 15:16:34 +0100 Subject: [PATCH 533/897] Fix: non-vanilla custom blockstate registration (#5310) * Try fixing custom blockstate registration * another attempt; round two * register collisions * don't register block states twice --- .../custom/nonvanilla/JavaBlockItem.java | 7 -- .../custom/nonvanilla/JavaBlockState.java | 2 +- .../geyser/level/block/type/Block.java | 14 ++- .../geyser/registry/BlockRegistries.java | 2 +- .../populator/BlockRegistryPopulator.java | 70 +-------------- .../CustomBlockRegistryPopulator.java | 86 ++++++++++++++++++- 6 files changed, 101 insertions(+), 80 deletions(-) delete mode 100644 api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockItem.java diff --git a/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockItem.java b/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockItem.java deleted file mode 100644 index 5143246d9..000000000 --- a/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockItem.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.geysermc.geyser.api.block.custom.nonvanilla; - -import org.checkerframework.checker.index.qual.NonNegative; -import org.checkerframework.checker.nullness.qual.NonNull; - -public record JavaBlockItem(@NonNull String identifier, @NonNegative int javaId, @NonNegative int stackSize) { -} diff --git a/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockState.java b/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockState.java index 0dd0d3b33..61b868cc3 100644 --- a/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockState.java +++ b/api/src/main/java/org/geysermc/geyser/api/block/custom/nonvanilla/JavaBlockState.java @@ -70,7 +70,7 @@ public interface JavaBlockState { @Nullable String pistonBehavior(); /** - * Gets whether the block state has block entity + * Gets whether the block state has a block entity * * @return whether the block state has block entity * @deprecated Does not have an effect. If you were using this to diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index a005fc103..494946c4a 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -240,7 +240,8 @@ public class Block { private Supplier pickItem; // We'll use this field after building - private Property[] propertyKeys; + private Property[] propertyKeys = null; + private @Nullable Integer javaId = null; /** * For states that we're just tracking for mirroring Java states. @@ -298,11 +299,18 @@ public class Block { return this; } + public Builder javaId(int javaId) { + this.javaId = javaId; + return this; + } + private List build(Block block) { if (states.isEmpty()) { - BlockState state = new BlockState(block, BlockRegistries.BLOCK_STATES.get().size()); + if (javaId == null) { + javaId = BlockRegistries.BLOCK_STATES.get().size(); + } + BlockState state = new BlockState(block, javaId); BlockRegistries.BLOCK_STATES.get().add(state); - propertyKeys = null; return List.of(state); } else if (states.size() == 1) { // We can optimize because we don't need to worry about combinations diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 521d67542..b7316605b 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -135,9 +135,9 @@ public class BlockRegistries { CustomSkullRegistryPopulator.populate(); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.PRE_INIT); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION); - CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA); COLLISIONS.load(); + CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index e86bfe7c4..cb002d6f0 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -32,8 +32,6 @@ import com.google.common.collect.Interner; import com.google.common.collect.Interners; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -52,19 +50,14 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; -import org.geysermc.geyser.item.Items; 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.level.block.type.FlowerPotBlock; -import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.GeyserBedrockBlock; -import org.geysermc.geyser.util.BlockUtils; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.io.DataInputStream; import java.io.InputStream; @@ -72,7 +65,6 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; -import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -114,8 +106,8 @@ public final class BlockRegistryPopulator { * Stores the raw blocks NBT until it is no longer needed. */ private static List BLOCKS_NBT; - private static int MIN_CUSTOM_RUNTIME_ID = -1; - private static int JAVA_BLOCKS_SIZE = -1; + public static int MIN_CUSTOM_RUNTIME_ID = -1; + public static int JAVA_BLOCKS_SIZE = -1; private static void nullifyBlocksNbt() { BLOCKS_NBT = null; @@ -411,19 +403,6 @@ public final class BlockRegistryPopulator { throw new AssertionError("Unable to load Java block mappings", e); } - JAVA_BLOCKS_SIZE = BlockRegistries.BLOCK_STATES.get().size(); - - if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) { - MIN_CUSTOM_RUNTIME_ID = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet().stream().min(Comparator.comparing(JavaBlockState::javaId)).orElseThrow().javaId(); - int maxCustomRuntimeID = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet().stream().max(Comparator.comparing(JavaBlockState::javaId)).orElseThrow().javaId(); - - if (MIN_CUSTOM_RUNTIME_ID < blocksNbt.size()) { - throw new RuntimeException("Non vanilla custom block state overrides runtime ID must start after the last vanilla block state (" + JAVA_BLOCKS_SIZE + ")"); - } - - JAVA_BLOCKS_SIZE = maxCustomRuntimeID + 1; // Runtime ids start at 0, so we need to add 1 - } - int javaRuntimeId = -1; for (BlockState javaBlockState : BlockRegistries.BLOCK_STATES.get()) { javaRuntimeId++; @@ -432,49 +411,8 @@ public final class BlockRegistryPopulator { BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId); } - if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) { - IntSet usedNonVanillaRuntimeIDs = new IntOpenHashSet(); - - for (JavaBlockState javaBlockState : BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet()) { - if (!usedNonVanillaRuntimeIDs.add(javaBlockState.javaId())) { - throw new RuntimeException("Duplicate runtime ID " + javaBlockState.javaId() + " for non vanilla Java block state " + javaBlockState.identifier()); - } - - String javaId = javaBlockState.identifier(); - int stateRuntimeId = javaBlockState.javaId(); - String pistonBehavior = javaBlockState.pistonBehavior(); - - Block.Builder builder = Block.builder() - .destroyTime(javaBlockState.blockHardness()) - .pushReaction(pistonBehavior == null ? PistonBehavior.NORMAL : PistonBehavior.getByName(pistonBehavior)); - if (!javaBlockState.canBreakWithHand()) { - builder.requiresCorrectToolForDrops(); - } - String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier()); - String pickItem = javaBlockState.pickItem(); - Block block = new Block(cleanJavaIdentifier, builder) { - @Override - public ItemStack pickItem(BlockState state) { - if (this.item == null) { - this.item = Registries.JAVA_ITEM_IDENTIFIERS.get(pickItem); - if (this.item == null) { - GeyserImpl.getInstance().getLogger().warning("We could not find item " + pickItem - + " for getting the item for block " + javaBlockState.identifier()); - this.item = Items.AIR; - } - } - return new ItemStack(this.item.javaId()); - } - }; - block.setJavaId(javaBlockState.stateGroupId()); - - BlockRegistries.JAVA_BLOCKS.registerWithAnyIndex(javaBlockState.stateGroupId(), block, Blocks.AIR); - BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, stateRuntimeId); - BlockRegistries.BLOCK_STATES.register(stateRuntimeId, new BlockState(block, stateRuntimeId)); - } - } - BLOCKS_NBT = blocksNbt; + JAVA_BLOCKS_SIZE = blocksNbt.size(); JsonNode blockInteractionsJson; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/interactions.json")) { @@ -485,8 +423,6 @@ public final class BlockRegistryPopulator { BlockRegistries.INTERACTIVE.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("always_consumes"))); BlockRegistries.INTERACTIVE_MAY_BUILD.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("requires_may_build"))); - - BlockRegistries.BLOCK_STATES.freeze(); } private static BitSet toBlockStateSet(ArrayNode node) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java index a43df3f52..46bfcb45e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java @@ -27,6 +27,8 @@ package org.geysermc.geyser.registry.populator; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; @@ -48,23 +50,38 @@ import org.geysermc.geyser.api.block.custom.property.CustomBlockProperty; import org.geysermc.geyser.api.block.custom.property.PropertyType; import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCustomBlocksEvent; import org.geysermc.geyser.api.util.CreativeCategory; +import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.GeyserCustomBlockComponents; import org.geysermc.geyser.level.block.GeyserCustomBlockData; import org.geysermc.geyser.level.block.GeyserCustomBlockState; import org.geysermc.geyser.level.block.GeyserGeometryComponent; import org.geysermc.geyser.level.block.GeyserMaterialInstance; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.physics.BoundingBox; +import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.mappings.MappingsConfigReader; import org.geysermc.geyser.registry.type.CustomSkull; +import org.geysermc.geyser.translator.collision.OtherCollision; +import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.geysermc.geyser.registry.populator.BlockRegistryPopulator.JAVA_BLOCKS_SIZE; +import static org.geysermc.geyser.registry.populator.BlockRegistryPopulator.MIN_CUSTOM_RUNTIME_ID; public class CustomBlockRegistryPopulator { @@ -231,6 +248,73 @@ public class CustomBlockRegistryPopulator { */ private static void populateNonVanilla() { BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.set(NON_VANILLA_BLOCK_STATE_OVERRIDES); + + if (NON_VANILLA_BLOCK_STATE_OVERRIDES.isEmpty()) { + // Nothing left to register, freeze block state registry + BlockRegistries.BLOCK_STATES.freeze(); + return; + } + + MIN_CUSTOM_RUNTIME_ID = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet().stream().min(Comparator.comparing(JavaBlockState::javaId)).orElseThrow().javaId(); + int maxCustomRuntimeID = BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet().stream().max(Comparator.comparing(JavaBlockState::javaId)).orElseThrow().javaId(); + + if (MIN_CUSTOM_RUNTIME_ID < BlockRegistries.BLOCK_STATES.get().size()) { + throw new RuntimeException("Non vanilla custom block state overrides runtime ID must start after the last vanilla block state (" + JAVA_BLOCKS_SIZE + ")"); + } + + JAVA_BLOCKS_SIZE = maxCustomRuntimeID + 1; // Runtime ids start at 0, so we need to add 1 + + // Now: Vanilla blocks are already loaded and registered; let's load non-vanilla properly too + IntSet usedNonVanillaRuntimeIDs = new IntOpenHashSet(); + + for (JavaBlockState javaBlockState : BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().keySet()) { + if (!usedNonVanillaRuntimeIDs.add(javaBlockState.javaId())) { + throw new RuntimeException("Duplicate runtime ID " + javaBlockState.javaId() + " for non vanilla Java block state " + javaBlockState.identifier()); + } + + String javaId = javaBlockState.identifier(); + int stateRuntimeId = javaBlockState.javaId(); + String pistonBehavior = javaBlockState.pistonBehavior(); + + Block.Builder builder = Block.builder() + .javaId(stateRuntimeId) + .destroyTime(javaBlockState.blockHardness()) + .pushReaction(pistonBehavior == null ? PistonBehavior.NORMAL : PistonBehavior.getByName(pistonBehavior)); + if (!javaBlockState.canBreakWithHand()) { + builder.requiresCorrectToolForDrops(); + } + String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier()); + String pickItem = javaBlockState.pickItem(); + Block block = new Block(cleanJavaIdentifier, builder) { + @Override + public ItemStack pickItem(BlockState state) { + if (this.item == null) { + this.item = Registries.JAVA_ITEM_IDENTIFIERS.get(pickItem); + if (this.item == null) { + GeyserImpl.getInstance().getLogger().warning("We could not find item " + pickItem + + " for getting the item for block " + javaBlockState.identifier()); + this.item = Items.AIR; + } + } + return new ItemStack(this.item.javaId()); + } + }; + block.setJavaId(javaBlockState.stateGroupId()); + + BlockRegistries.JAVA_BLOCKS.registerWithAnyIndex(javaBlockState.stateGroupId(), block, Blocks.AIR); + BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, stateRuntimeId); + + // TODO register different collision types? + BoundingBox[] geyserCollisions = Arrays.stream(javaBlockState.collision()) + .map(box -> new BoundingBox(box.middleX(), box.middleY(), box.middleZ(), + box.sizeX(), box.sizeY(), box.sizeZ())) + .toArray(BoundingBox[]::new); + OtherCollision collision = new OtherCollision(geyserCollisions); + BlockRegistries.COLLISIONS.registerWithAnyIndex(javaBlockState.javaId(), collision, collision); + } + + BlockRegistries.BLOCK_STATES.freeze(); + if (!NON_VANILLA_BLOCK_STATE_OVERRIDES.isEmpty()) { GeyserImpl.getInstance().getLogger().info("Registered " + NON_VANILLA_BLOCK_STATE_OVERRIDES.size() + " non-vanilla block overrides."); } From 0416b55959a16880d37f24545d0063e90fe51ce8 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 4 Feb 2025 16:57:37 +0100 Subject: [PATCH 534/897] Fix: Looms modifying default data components causing visual bugs Closes https://github.com/GeyserMC/Geyser/issues/5273 --- .../geyser/inventory/GeyserItemStack.java | 5 +++-- .../updater/AnvilInventoryUpdater.java | 5 ++--- .../inventory/BundleInventoryTranslator.java | 2 +- .../inventory/LoomInventoryTranslator.java | 19 ++++++++----------- 4 files changed, 14 insertions(+), 17 deletions(-) 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 77ca7bfb5..c4a3542d1 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -50,6 +50,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemSta import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; import java.util.HashMap; +import java.util.function.Supplier; @Data public class GeyserItemStack { @@ -169,9 +170,9 @@ public class GeyserItemStack { return value; } - public T getComponentOrFallback(@NonNull DataComponentType type, T def) { + public T getComponentElseGet(@NonNull DataComponentType type, Supplier supplier) { T value = getComponent(type); - return value == null ? def : value; + return value == null ? supplier.get() : value; } public int getNetId() { 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 aadaeb356..8282607af 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 @@ -47,7 +47,6 @@ 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.data.game.item.component.Unbreakable; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import java.util.List; @@ -420,7 +419,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } private int getRepairCost(GeyserItemStack itemStack) { - return itemStack.getComponentOrFallback(DataComponentType.REPAIR_COST, 0); + return itemStack.getComponentElseGet(DataComponentType.REPAIR_COST, () -> 0); } private boolean hasDurability(GeyserItemStack itemStack) { @@ -431,6 +430,6 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } private int getDamage(GeyserItemStack itemStack) { - return itemStack.getComponentOrFallback(DataComponentType.DAMAGE, 0); + return itemStack.getComponentElseGet(DataComponentType.DAMAGE, () -> 0); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java index 1b42e537f..bbe94ba95 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java @@ -314,7 +314,7 @@ public final class BundleInventoryTranslator { return Fraction.ONE; } } - return Fraction.getFraction(1, itemStack.getComponentOrFallback(DataComponentType.MAX_STACK_SIZE, itemStack.asItem().defaultMaxStackSize())); + return Fraction.getFraction(1, itemStack.getComponentElseGet(DataComponentType.MAX_STACK_SIZE, () -> itemStack.asItem().defaultMaxStackSize())); } public static int capacityForItemStack(Fraction bundleWeight, GeyserItemStack itemStack) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 1fef4c4fd..998108154 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -93,10 +93,8 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { PATTERN_TO_INDEX.put("vhr", index++); PATTERN_TO_INDEX.put("hhb", index++); PATTERN_TO_INDEX.put("bo", index++); - index++; // Bordure indented, does not appear to exist in Bedrock? PATTERN_TO_INDEX.put("gra", index++); PATTERN_TO_INDEX.put("gru", index); - // Bricks do not appear to be a pattern on Bedrock, either } public LoomInventoryTranslator() { @@ -120,7 +118,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { @Override protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) { - // If the LOOM_MATERIAL slot is not empty, we are crafting a pattern that does not come from an item + // If the LOOM_MATERIAL slot is empty, we are crafting a pattern that does not come from an item return action.getType() == ItemStackRequestActionType.CRAFT_LOOM && inventory.getItem(2).isEmpty(); } @@ -135,10 +133,6 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { return rejectRequest(request); } - // Get the patterns compound tag - List newBlockEntityTag = craftData.getResultItems()[0].getTag().getList("Patterns", NbtType.COMPOUND); - // Get the pattern that the Bedrock client requests - the last pattern in the Patterns list - NbtMap pattern = newBlockEntityTag.get(newBlockEntityTag.size() - 1); String bedrockPattern = ((CraftLoomAction) headerData).getPatternId(); // Get the Java index of this pattern @@ -146,6 +140,12 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { if (index == -1) { return rejectRequest(request); } + + // Get the patterns compound tag + List newBlockEntityTag = craftData.getResultItems()[0].getTag().getList("Patterns", NbtType.COMPOUND); + // Get the pattern that the Bedrock client requests - the last pattern in the Patterns list + NbtMap pattern = newBlockEntityTag.get(newBlockEntityTag.size() - 1); + // Java's formula: 4 * row + col // And the Java loom window has a fixed row/width of four // So... Number / 4 = row (so we don't have to bother there), and number % 4 is our column, which leads us back to our index. :) @@ -156,10 +156,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { inputCopy.setNetId(session.getNextItemNetId()); BannerPatternLayer bannerPatternLayer = BannerItem.getJavaBannerPattern(session, pattern); // TODO if (bannerPatternLayer != null) { - List patternsList = inputCopy.getComponent(DataComponentType.BANNER_PATTERNS); - if (patternsList == null) { - patternsList = new ArrayList<>(); - } + List patternsList = new ArrayList<>(inputCopy.getComponentElseGet(DataComponentType.BANNER_PATTERNS, ArrayList::new)); patternsList.add(bannerPatternLayer); inputCopy.getOrCreateComponents().put(DataComponentType.BANNER_PATTERNS, patternsList); } From b96f9157e9ebb7aca2409620ea3c75964cb09db1 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 6 Feb 2025 18:40:32 +0100 Subject: [PATCH 535/897] Fix: Use real barrels whenever possible instead of fak chest workaround Fixes https://github.com/GeyserMC/Geyser/issues/5292, fixes https://github.com/GeyserMC/Geyser/issues/5294 --- .../chest/SingleChestInventoryTranslator.java | 7 +++---- .../org/geysermc/geyser/util/InventoryUtils.java | 12 ++++++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java index 264b2eb29..94bdeb281 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java @@ -38,15 +38,14 @@ import org.geysermc.geyser.session.GeyserSession; public class SingleChestInventoryTranslator extends ChestInventoryTranslator { private final InventoryHolder holder; - // TODO add barrel??? public SingleChestInventoryTranslator(int size) { super(size, 27); this.holder = new BlockInventoryHolder(Blocks.CHEST.defaultBlockState().withValue(Properties.CHEST_TYPE, ChestType.SINGLE), ContainerType.CONTAINER, - Blocks.ENDER_CHEST, Blocks.TRAPPED_CHEST) { + Blocks.ENDER_CHEST, Blocks.TRAPPED_CHEST, Blocks.BARREL) { @Override protected boolean isValidBlock(BlockState blockState) { - if (blockState.is(Blocks.ENDER_CHEST)) { - // Can't have double ender chests + if (blockState.is(Blocks.ENDER_CHEST) || blockState.is(Blocks.BARREL)) { + // Can't have double ender chests or barrels return true; } 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 b71caa1dc..042f37a89 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -45,6 +45,7 @@ import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.level.BedrockDimension; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; @@ -173,15 +174,22 @@ public class InventoryUtils { if (position.getY() < minY) { return null; } - if (position.getY() >= maxY) { + if (position.getY() >= maxY || !canUseWorldSpace(session, position)) { position = flatPlayerPosition.sub(0, 4, 0); - if (position.getY() >= maxY) { + if (position.getY() >= maxY || !canUseWorldSpace(session, position)) { return null; } } return position; } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean canUseWorldSpace(GeyserSession session, Vector3i position) { + BlockState state = session.getGeyser().getWorldManager().blockAt(session, position); + // Block entities require more data to be restored; so let's avoid using these positions + return state.block().blockEntityType() == null; + } + public static void updateCursor(GeyserSession session) { InventorySlotPacket cursorPacket = new InventorySlotPacket(); cursorPacket.setContainerId(ContainerId.UI); From c98796aeb6fa121f33f598dfa46a09bb117c7531 Mon Sep 17 00:00:00 2001 From: Roch Blondiaux <68775690+RochBlondiaux@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:03:31 +0100 Subject: [PATCH 536/897] Implemented a way to close forms from floodgate (#5247) * feat: send close form packet when receiving empty form data * use session#closeForm --------- Co-authored-by: Roch Blonndiaux Co-authored-by: onebeastchris --- .../protocol/java/JavaCustomPayloadTranslator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java index c3108167b..d5c3c246c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java @@ -67,6 +67,12 @@ public class JavaCustomPayloadTranslator extends PacketTranslator { byte[] data = packet.getData(); + // If the data is empty, we just need to close the form + if (data.length == 0) { + session.closeForm(); + return; + } + // receive: first byte is form type, second and third are the id, remaining is the form data // respond: first and second byte id, remaining is form response data @@ -96,7 +102,6 @@ public class JavaCustomPayloadTranslator extends PacketTranslator { byte[] data = packet.getData(); From b8477aa40190172ce56031d15edbf17f69e74bb6 Mon Sep 17 00:00:00 2001 From: Roman Alexander Date: Wed, 12 Feb 2025 03:38:24 +0900 Subject: [PATCH 537/897] 1.21.60 (#5325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial changes * More work on 1.21.60's fun changes * I misread 😅 * Use 1.21.60 mappings for updated item components * Fix: Creative up/down flight --------- Co-authored-by: onebeastchris --- .../java/org/geysermc/geyser/Constants.java | 3 - .../java/org/geysermc/geyser/GeyserImpl.java | 51 - .../geyser/item/GeyserCustomMappingData.java | 3 +- .../geysermc/geyser/network/GameProtocol.java | 14 +- .../geyser/network/LoggingPacketHandler.java | 12 +- .../registry/PacketTranslatorRegistry.java | 2 + .../populator/BlockRegistryPopulator.java | 36 +- .../CreativeItemRegistryPopulator.java | 48 +- .../CustomItemRegistryPopulator.java | 17 +- .../populator/ItemRegistryPopulator.java | 141 +- .../registry/type/GeyserItemDefinition.java | 49 - .../geyser/registry/type/ItemMappings.java | 8 +- .../type/NonVanillaItemRegistration.java | 5 +- .../geyser/registry/type/PaletteItem.java | 4 +- .../geyser/session/GeyserSession.java | 11 +- .../inventory/PlayerInventoryTranslator.java | 10 +- .../resources/bedrock/biome_definitions.dat | Bin 37891 -> 39004 bytes .../bedrock/block_palette.1_21_60.nbt | Bin 0 -> 193020 bytes .../bedrock/creative_items.1_21_60.json | 8917 +++++++++++++ .../resources/bedrock/item_components.nbt | Bin 0 -> 12649 bytes .../resources/bedrock/item_tags.1_21_60.json | 829 ++ .../bedrock/runtime_item_states.1_21_60.json | 10730 ++++++++++++++++ core/src/main/resources/languages | 2 +- core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 6 +- 25 files changed, 20694 insertions(+), 206 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/type/GeyserItemDefinition.java create mode 100644 core/src/main/resources/bedrock/block_palette.1_21_60.nbt create mode 100644 core/src/main/resources/bedrock/creative_items.1_21_60.json create mode 100644 core/src/main/resources/bedrock/item_components.nbt create mode 100644 core/src/main/resources/bedrock/item_tags.1_21_60.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_21_60.json diff --git a/core/src/main/java/org/geysermc/geyser/Constants.java b/core/src/main/java/org/geysermc/geyser/Constants.java index 7f00075d8..2b58e7e84 100644 --- a/core/src/main/java/org/geysermc/geyser/Constants.java +++ b/core/src/main/java/org/geysermc/geyser/Constants.java @@ -36,9 +36,6 @@ public final class Constants { public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://geysermc.org/download#floodgate"; public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download"; - - @Deprecated - static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json"; static final String SAVED_AUTH_CHAINS_FILE = "saved-auth-chains.json"; public static final String GEYSER_CUSTOM_NAMESPACE = "geyser_custom"; diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 5171c0633..e81d528aa 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -29,7 +29,6 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; import io.netty.channel.epoll.Epoll; import io.netty.util.NettyRuntime; import io.netty.util.concurrent.DefaultThreadFactory; @@ -39,8 +38,6 @@ import lombok.Getter; import lombok.Setter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession; -import net.raphimc.minecraftauth.step.msa.StepMsaToken; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -99,7 +96,6 @@ import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.AssetUtils; import org.geysermc.geyser.util.CooldownUtils; import org.geysermc.geyser.util.Metrics; -import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.geyser.util.NewsHandler; import org.geysermc.geyser.util.VersionCheckUtils; import org.geysermc.geyser.util.WebUtils; @@ -566,53 +562,6 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { // May be written/read to on multiple threads from each GeyserSession as well as writing the config savedAuthChains = new ConcurrentHashMap<>(); - // TODO Remove after a while - just a migration help - //noinspection deprecation - File refreshTokensFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile(); - if (refreshTokensFile.exists()) { - logger.info("Migrating refresh tokens to auth chains..."); - TypeReference> type = new TypeReference<>() { }; - Map refreshTokens = null; - try { - refreshTokens = JSON_MAPPER.readValue(refreshTokensFile, type); - } catch (IOException e) { - // ignored - we'll just delete this file :)) - } - - if (refreshTokens != null) { - List validUsers = config.getSavedUserLogins(); - final Gson gson = new Gson(); - for (Map.Entry entry : refreshTokens.entrySet()) { - String user = entry.getKey(); - if (!validUsers.contains(user)) { - continue; - } - - // Migrate refresh tokens to auth chains - try { - StepFullJavaSession javaSession = PendingMicrosoftAuthentication.AUTH_FLOW.apply(false, 10); - StepFullJavaSession.FullJavaSession fullJavaSession = javaSession.getFromInput( - MinecraftAuthLogger.INSTANCE, - PendingMicrosoftAuthentication.AUTH_CLIENT, - new StepMsaToken.RefreshToken(entry.getValue()) - ); - - String authChain = gson.toJson(javaSession.toJson(fullJavaSession)); - savedAuthChains.put(user, authChain); - } catch (Exception e) { - GeyserImpl.getInstance().getLogger().warning("Could not migrate " + entry.getKey() + " to an auth chain! " + - "They will need to sign in the next time they join Geyser."); - } - - // Ensure the new additions are written to the file - scheduleAuthChainsWrite(); - } - } - - // Finally: Delete it. Goodbye! - refreshTokensFile.delete(); - } - File authChainsFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_AUTH_CHAINS_FILE).toFile(); if (authChainsFile.exists()) { TypeReference> type = new TypeReference<>() { }; diff --git a/core/src/main/java/org/geysermc/geyser/item/GeyserCustomMappingData.java b/core/src/main/java/org/geysermc/geyser/item/GeyserCustomMappingData.java index d71f2e548..22c457179 100644 --- a/core/src/main/java/org/geysermc/geyser/item/GeyserCustomMappingData.java +++ b/core/src/main/java/org/geysermc/geyser/item/GeyserCustomMappingData.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.item; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; -import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; -public record GeyserCustomMappingData(ComponentItemData componentItemData, ItemDefinition itemDefinition, String stringId, int integerId) { +public record GeyserCustomMappingData(ItemDefinition itemDefinition, String stringId, int integerId) { } diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 7aaeef87d..8625dfac5 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; +import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; @@ -47,8 +48,8 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v766.CODEC.toBuilder() - .minecraftVersion("1.21.51") + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v776.CODEC.toBuilder() + .minecraftVersion("1.21.60") .build()); /** @@ -66,9 +67,10 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() .minecraftVersion("1.21.40 - 1.21.44") .build())); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v766.CODEC.toBuilder() .minecraftVersion("1.21.50 - 1.21.51") - .build()); + .build())); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } /** @@ -91,6 +93,10 @@ public final class GameProtocol { return session.getUpstream().getProtocolVersion() == Bedrock_v748.CODEC.getProtocolVersion(); } + public static boolean isPreCreativeInventoryRewrite(int protocolVersion) { + return protocolVersion < 776; + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index 910f76ffb..2d8db9517 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -896,4 +896,14 @@ public class LoggingPacketHandler implements BedrockPacketHandler { public PacketSignal handle(TrimDataPacket packet) { return defaultHandler(packet); } -} \ No newline at end of file + + @Override + public PacketSignal handle(MovementPredictionSyncPacket packet) { + return defaultHandler(packet); + } + + @Override + public PacketSignal handle(ServerboundDiagnosticsPacket packet) { + return defaultHandler(packet); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java index e81935edf..3fd79b8a6 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.registry; +import org.cloudburstmc.protocol.bedrock.packet.ServerboundDiagnosticsPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundTabListPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchStartPacket; @@ -49,6 +50,7 @@ public class PacketTranslatorRegistry extends AbstractMappedRegistry, Remapper>builder() .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), Conversion766_748::remapBlock) - .put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), tag -> tag) // TODO: Finish me + .put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), tag -> { + final String name = tag.getString("name"); + if (name.equals("minecraft:creaking_heart") && tag.getCompound("states").containsKey("active")) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + builder.remove("active"); + builder.putString("creaking_heart_state", "awake"); + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + if ((name.endsWith("_door") || name.endsWith("fence_gate")) && tag.getCompound("states").containsKey("direction")) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + Integer directionCardinality = (Integer) builder.remove("direction"); + switch (directionCardinality) { + case 0: + builder.putString("minecraft:cardinal_direction", "south"); + break; + case 1: + builder.putString("minecraft:cardinal_direction", "west"); + break; + case 2: + builder.putString( "minecraft:cardinal_direction" , "north"); + break; + case 3: + builder.putString("minecraft:cardinal_direction", "east"); + break; + default: + throw new AssertionError("Invalid direction: " + directionCardinality); + } + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + return tag; + }) .build(); // We can keep this strong as nothing should be garbage collected diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java index 01dcd38a6..633957f8e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java @@ -31,6 +31,9 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; +import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemCategory; +import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemData; +import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemGroup; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; @@ -42,11 +45,13 @@ import org.geysermc.geyser.registry.type.GeyserMappingItem; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Base64; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.BiPredicate; -import java.util.function.Consumer; public class CreativeItemRegistryPopulator { private static final List> JAVA_ONLY_ITEM_FILTER = List.of( @@ -54,7 +59,42 @@ public class CreativeItemRegistryPopulator { (identifier, data) -> identifier.equals("minecraft:empty_map") && data == 2 ); - static void populate(ItemRegistryPopulator.PaletteVersion palette, Map definitions, Map items, Consumer itemConsumer) { + static List readCreativeItemGroups(ItemRegistryPopulator.PaletteVersion palette, List creativeItemData) { + GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); + + JsonNode creativeItemEntries; + try (InputStream stream = bootstrap.getResourceOrThrow(String.format("bedrock/creative_items.%s.json", palette.version()))) { + creativeItemEntries = GeyserImpl.JSON_MAPPER.readTree(stream).get("groups"); + } catch (Exception e) { + throw new AssertionError("Unable to load creative item groups", e); + } + + List creativeItemGroups = new ArrayList<>(); + for (JsonNode creativeItemEntry : creativeItemEntries) { + CreativeItemCategory category = CreativeItemCategory.valueOf(creativeItemEntry.get("category").asText().toUpperCase(Locale.ROOT)); + String name = creativeItemEntry.get("name").asText(); + + JsonNode icon = creativeItemEntry.get("icon"); + String identifier = icon.get("id").asText(); + + ItemData itemData; + if (identifier.equals("minecraft:air")) { + itemData = ItemData.AIR; + } else { + itemData = creativeItemData.stream() + .map(CreativeItemData::getItem) + .filter(item -> item.getDefinition().getIdentifier().equals(identifier)) + .findFirst() + .orElseThrow(); + } + + creativeItemGroups.add(new CreativeItemGroup(category, name, itemData)); + } + + return creativeItemGroups; + } + + static void populate(ItemRegistryPopulator.PaletteVersion palette, Map definitions, Map items, BiConsumer itemConsumer) { GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); // Load creative items @@ -72,7 +112,9 @@ public class CreativeItemRegistryPopulator { continue; } - itemConsumer.accept(itemBuilder); + int groupId = itemNode.get("groupId") != null ? itemNode.get("groupId").asInt() : 0; + + itemConsumer.accept(itemBuilder, groupId); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index ec1e16e79..cd19ab147 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -33,7 +33,6 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; -import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomRenderOffsets; @@ -106,12 +105,10 @@ public class CustomItemRegistryPopulator { } public static GeyserCustomMappingData registerCustomItem(String customItemName, Item javaItem, GeyserMappingItem mapping, CustomItemData customItemData, int bedrockId, int protocolVersion) { - ItemDefinition itemDefinition = new SimpleItemDefinition(customItemName, bedrockId, true); - NbtMapBuilder builder = createComponentNbt(customItemData, javaItem, mapping, customItemName, bedrockId, protocolVersion); - ComponentItemData componentItemData = new ComponentItemData(customItemName, builder.build()); + ItemDefinition itemDefinition = new SimpleItemDefinition(customItemName, bedrockId, 1, true, builder.build()); - return new GeyserCustomMappingData(componentItemData, itemDefinition, customItemName, bedrockId); + return new GeyserCustomMappingData(itemDefinition, customItemName, bedrockId); } static boolean initialCheck(String identifier, CustomItemData item, Map mappings) { @@ -142,9 +139,11 @@ public class CustomItemRegistryPopulator { Item item = new Item(customIdentifier, Item.builder().components(components)); Items.register(item, customItemData.javaId()); + NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId, + customItemData.isHat(), customItemData.displayHandheld(), protocolVersion); ItemMapping customItemMapping = ItemMapping.builder() .bedrockIdentifier(customIdentifier) - .bedrockDefinition(new SimpleItemDefinition(customIdentifier, customItemId, true)) + .bedrockDefinition(new SimpleItemDefinition(customIdentifier, customItemId, 1, true, builder.build())) .bedrockData(0) .bedrockBlockDefinition(null) .toolType(customItemData.toolType()) @@ -153,11 +152,7 @@ public class CustomItemRegistryPopulator { .javaItem(item) .build(); - NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId, - customItemData.isHat(), customItemData.displayHandheld(), protocolVersion); - ComponentItemData componentItemData = new ComponentItemData(customIdentifier, builder.build()); - - return new NonVanillaItemRegistration(componentItemData, item, customItemMapping); + return new NonVanillaItemRegistration(item, customItemMapping); } private static NbtMapBuilder createComponentNbt(CustomItemData customItemData, Item javaItem, GeyserMappingItem mapping, diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index f7b45ba1d..6e269b5a3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -47,10 +47,12 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; +import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; -import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; +import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemData; +import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemGroup; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserBootstrap; @@ -68,6 +70,7 @@ import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; @@ -147,6 +150,7 @@ public class ItemRegistryPopulator { List paletteVersions = new ArrayList<>(2); paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping)); paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v766.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_60", Bedrock_v776.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -161,7 +165,8 @@ public class ItemRegistryPopulator { } NbtMap vanillaComponents; - try (InputStream stream = bootstrap.getResourceOrThrow("mappings/item_components.nbt")) { + // TODO e.g. breeze rod icon does not load with our modified item components + try (InputStream stream = bootstrap.getResourceOrThrow("bedrock/item_components.nbt")) { vanillaComponents = (NbtMap) NbtUtils.createGZIPReader(stream, true, true).readTag(); } catch (Exception e) { throw new AssertionError("Unable to load Bedrock item components", e); @@ -195,7 +200,8 @@ public class ItemRegistryPopulator { // Used for custom items int nextFreeBedrockId = 0; - List componentItemData = new ObjectArrayList<>(); + // TODO yeet + List componentItemData = new ObjectArrayList<>(); Int2ObjectMap registry = new Int2ObjectOpenHashMap<>(); Map definitions = new Object2ObjectLinkedOpenHashMap<>(); @@ -206,7 +212,15 @@ public class ItemRegistryPopulator { nextFreeBedrockId = id + 1; } - ItemDefinition definition = new SimpleItemDefinition(entry.getName().intern(), id, false); + NbtMap components = null; + if (entry.isComponentBased()) { + components = vanillaComponents.getCompound(entry.getName()); + if (components == null) { + throw new RuntimeException("Could not find vanilla components for vanilla component based item! " + entry.getName()); + } + } + + ItemDefinition definition = new SimpleItemDefinition(entry.getName().intern(), id, entry.getVersion(), entry.isComponentBased(), components); definitions.put(entry.getName(), definition); registry.put(definition.getRuntimeId(), definition); } @@ -222,7 +236,7 @@ public class ItemRegistryPopulator { // Temporary mapping to create stored items Map javaItemToMapping = new Object2ObjectOpenHashMap<>(); - List creativeItems = new ArrayList<>(); + List creativeItems = new ArrayList<>(); Set noBlockDefinitions = new ObjectOpenHashSet<>(); // Fix: Usage of structure blocks/voids in recipes @@ -231,9 +245,9 @@ public class ItemRegistryPopulator { noBlockDefinitions.add("minecraft:structure_void"); AtomicInteger creativeNetId = new AtomicInteger(); - CreativeItemRegistryPopulator.populate(palette, definitions, items, itemBuilder -> { + CreativeItemRegistryPopulator.populate(palette, definitions, items, (itemBuilder, groupId) -> { ItemData item = itemBuilder.netId(creativeNetId.incrementAndGet()).build(); - creativeItems.add(item); + creativeItems.add(new CreativeItemData(item, item.getNetId(), groupId)); if (item.getBlockDefinition() != null) { String identifier = item.getDefinition().getIdentifier(); @@ -255,6 +269,13 @@ public class ItemRegistryPopulator { } }); + List creativeItemGroups; + if (GameProtocol.isPreCreativeInventoryRewrite(palette.protocolVersion)) { + creativeItemGroups = new ArrayList<>(); + } else { + creativeItemGroups = CreativeItemRegistryPopulator.readCreativeItemGroups(palette, creativeItems); + } + BlockMappings blockMappings = BlockRegistries.BLOCKS.forVersion(palette.protocolVersion()); Set javaOnlyItems = new ObjectOpenHashSet<>(); @@ -410,13 +431,13 @@ public class ItemRegistryPopulator { } for (int j = 0; j < creativeItems.size(); j++) { - ItemData itemData = creativeItems.get(j); - if (itemData.getDefinition().equals(definition)) { - if (itemData.getDamage() != 0) { + CreativeItemData itemData = creativeItems.get(j); + if (itemData.getItem().getDefinition().equals(definition)) { + if (itemData.getItem().getDamage() != 0) { break; } - NbtMap states = ((GeyserBedrockBlock) itemData.getBlockDefinition()).getState().getCompound("states"); + NbtMap states = ((GeyserBedrockBlock) itemData.getItem().getBlockDefinition()).getState().getCompound("states"); boolean valid = true; for (Map.Entry nbtEntry : requiredBlockStates.entrySet()) { @@ -432,19 +453,25 @@ public class ItemRegistryPopulator { int customProtocolId = nextFreeBedrockId++; mappingItem = mappingItem.withBedrockData(customProtocolId); bedrockIdentifier = customBlockData.identifier(); - definition = new SimpleItemDefinition(bedrockIdentifier, customProtocolId, true); + definition = new SimpleItemDefinition(bedrockIdentifier, customProtocolId, 1, false, null); registry.put(customProtocolId, definition); customBlockItemDefinitions.put(customBlockData, definition); customIdMappings.put(customProtocolId, bedrockIdentifier); - - creativeItems.set(j, itemData.toBuilder() + + CreativeItemData newData = new CreativeItemData(itemData.getItem().toBuilder() .definition(definition) .blockDefinition(bedrockBlock) .netId(itemData.getNetId()) .count(1) - .build()); + .build(), itemData.getNetId(), 0); + + creativeItems.set(j, newData); } else { - creativeItems.set(j, itemData.toBuilder().blockDefinition(bedrockBlock).build()); + CreativeItemData creativeItemData = new CreativeItemData(itemData.getItem().toBuilder() + .blockDefinition(bedrockBlock) + .build(), itemData.getNetId(), 0); + + creativeItems.set(j, creativeItemData); } break; } @@ -494,16 +521,17 @@ public class ItemRegistryPopulator { ); if (customItem.creativeCategory().isPresent()) { - creativeItems.add(ItemData.builder() + CreativeItemData creativeItemData = new CreativeItemData(ItemData.builder() .netId(creativeNetId.incrementAndGet()) .definition(customMapping.itemDefinition()) .blockDefinition(null) .count(1) - .build()); + .build(), creativeNetId.get(), customItem.creativeCategory().getAsInt()); + creativeItems.add(creativeItemData); } // ComponentItemData - used to register some custom properties - componentItemData.add(customMapping.componentItemData()); + componentItemData.add(customMapping.itemDefinition()); customItemOptions.add(Pair.of(customItem.customItemOptions(), customMapping.itemDefinition())); registry.put(customMapping.integerId(), customMapping.itemDefinition()); @@ -564,9 +592,11 @@ public class ItemRegistryPopulator { if (customItemsAllowed) { // Add furnace minecart - ItemDefinition definition = new SimpleItemDefinition("geysermc:furnace_minecart", nextFreeBedrockId, true); + int furnaceMinecartId = nextFreeBedrockId++; + ItemDefinition definition = new SimpleItemDefinition("geysermc:furnace_minecart", furnaceMinecartId, 1, true, registerFurnaceMinecart(furnaceMinecartId)); definitions.put("geysermc:furnace_minecart", definition); registry.put(definition.getRuntimeId(), definition); + componentItemData.add(definition); mappings.set(Items.FURNACE_MINECART.javaId(), ItemMapping.builder() .javaItem(Items.FURNACE_MINECART) @@ -577,13 +607,12 @@ public class ItemRegistryPopulator { .customItemOptions(Collections.emptyList()) // TODO check for custom items with furnace minecart .build()); - creativeItems.add(ItemData.builder() - .netId(creativeNetId.incrementAndGet()) - .definition(definition) - .count(1) - .build()); - - registerFurnaceMinecart(nextFreeBedrockId++, componentItemData, palette.protocolVersion); + creativeItems.add(new CreativeItemData(ItemData.builder() + .usingNetId(true) + .netId(creativeNetId.incrementAndGet()) + .definition(definition) + .count(1) + .build(), creativeNetId.get(), 99)); // todo do not hardcode! // Register any completely custom items given to us IntSet registeredJavaIds = new IntOpenHashSet(); // Used to check for duplicate item java ids @@ -598,7 +627,7 @@ public class ItemRegistryPopulator { int customItemId = nextFreeBedrockId++; NonVanillaItemRegistration registration = CustomItemRegistryPopulator.registerCustomItem(customItem, customItemId, palette.protocolVersion); - componentItemData.add(registration.componentItemData()); + componentItemData.add(registration.mapping().getBedrockDefinition()); ItemMapping mapping = registration.mapping(); Item javaItem = registration.javaItem(); while (javaItem.javaId() >= mappings.size()) { @@ -609,34 +638,17 @@ public class ItemRegistryPopulator { registry.put(customItemId, mapping.getBedrockDefinition()); if (customItem.creativeCategory().isPresent()) { - creativeItems.add(ItemData.builder() - .definition(registration.mapping().getBedrockDefinition()) - .netId(creativeNetId.incrementAndGet()) - .count(1) - .build()); + CreativeItemData creativeItemData = new CreativeItemData(ItemData.builder() + .definition(registration.mapping().getBedrockDefinition()) + .netId(creativeNetId.incrementAndGet()) + .count(1) + .build(), creativeNetId.get(), customItem.creativeCategory().getAsInt()); + + creativeItems.add(creativeItemData); } } } - for (Map.Entry entry : vanillaComponents.entrySet()) { - String id = entry.getKey(); - ItemDefinition definition = definitions.get(id); - if (definition == null) { - // Newer item most likely - GeyserImpl.getInstance().getLogger().debug( - "Skipping vanilla component " + id + " for protocol " + palette.protocolVersion() - ); - continue; - } - - NbtMapBuilder root = NbtMap.builder() - .putString("name", id) - .putInt("id", definition.getRuntimeId()) - .putCompound("components", (NbtMap) entry.getValue()); - - componentItemData.add(new ComponentItemData(id, root.build())); - } - // Register the item forms of custom blocks if (BlockRegistries.CUSTOM_BLOCKS.get().length != 0) { for (CustomBlockData customBlock : BlockRegistries.CUSTOM_BLOCKS.get()) { @@ -654,7 +666,8 @@ public class ItemRegistryPopulator { int customProtocolId = nextFreeBedrockId++; String identifier = customBlock.identifier(); - final ItemDefinition definition = new SimpleItemDefinition(identifier, customProtocolId, true); + // TODO verify + final ItemDefinition definition = new SimpleItemDefinition(identifier, customProtocolId, 1, false, null); registry.put(customProtocolId, definition); customBlockItemDefinitions.put(customBlock, definition); customIdMappings.put(customProtocolId, identifier); @@ -662,24 +675,26 @@ public class ItemRegistryPopulator { GeyserBedrockBlock bedrockBlock = blockMappings.getCustomBlockStateDefinitions().getOrDefault(customBlock.defaultBlockState(), null); if (bedrockBlock != null && customBlock.includedInCreativeInventory()) { - creativeItems.add(ItemData.builder() - .definition(definition) - .blockDefinition(bedrockBlock) - .netId(creativeNetId.incrementAndGet()) - .count(1) - .build()); + CreativeItemData creativeItemData = new CreativeItemData(ItemData.builder() + .definition(definition) + .blockDefinition(bedrockBlock) + .netId(creativeNetId.incrementAndGet()) + .count(1) + .build(), creativeNetId.get(), customBlock.creativeCategory().id()); + creativeItems.add(creativeItemData); } } } ItemMappings itemMappings = ItemMappings.builder() .items(mappings.toArray(new ItemMapping[0])) - .creativeItems(creativeItems.toArray(new ItemData[0])) + .creativeItems(creativeItems) + .creativeItemGroups(creativeItemGroups) .itemDefinitions(registry) + .componentItemData(componentItemData) .storedItems(new StoredItemMappings(javaItemToMapping)) .javaOnlyItems(javaOnlyItems) .buckets(buckets) - .componentItemData(componentItemData) .lightBlocks(lightBlocks) .lodestoneCompass(lodestoneEntry) .customIdMappings(customIdMappings) @@ -692,7 +707,7 @@ public class ItemRegistryPopulator { } } - private static void registerFurnaceMinecart(int nextFreeBedrockId, List componentItemData, int protocolVersion) { + private static NbtMap registerFurnaceMinecart(int nextFreeBedrockId) { NbtMapBuilder builder = NbtMap.builder(); builder.putString("name", "geysermc:furnace_minecart") .putInt("id", nextFreeBedrockId); @@ -727,6 +742,6 @@ public class ItemRegistryPopulator { componentBuilder.putCompound("item_properties", itemProperties.build()); builder.putCompound("components", componentBuilder.build()); - componentItemData.add(new ComponentItemData("geysermc:furnace_minecart", builder.build())); + return builder.build(); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/GeyserItemDefinition.java b/core/src/main/java/org/geysermc/geyser/registry/type/GeyserItemDefinition.java deleted file mode 100644 index fa1cb9985..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/type/GeyserItemDefinition.java +++ /dev/null @@ -1,49 +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.registry.type; - -import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; -import org.geysermc.geyser.item.type.Item; - -/** - * Implements ItemDefinition while also providing a reference to our item mappings. - */ -public record GeyserItemDefinition(Item javaItem, String identifier, boolean componentBased, int runtimeId) implements ItemDefinition { - @Override - public String getIdentifier() { - return identifier; - } - - @Override - public boolean isComponentBased() { - return componentBased; - } - - @Override - public int getRuntimeId() { - return runtimeId; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index 8aae05fdc..4ebe11bae 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -32,7 +32,8 @@ import lombok.Value; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; -import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; +import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemData; +import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemGroup; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.common.DefinitionRegistry; import org.geysermc.geyser.GeyserImpl; @@ -61,7 +62,8 @@ public class ItemMappings implements DefinitionRegistry { ItemMapping lodestoneCompass; Int2ObjectMap lightBlocks; - ItemData[] creativeItems; + List creativeItemGroups; + List creativeItems; Int2ObjectMap itemDefinitions; StoredItemMappings storedItems; @@ -70,7 +72,7 @@ public class ItemMappings implements DefinitionRegistry { List buckets; List boats; - List componentItemData; + List componentItemData; // TODO get rid of? Int2ObjectMap customIdMappings; Object2ObjectMap customBlockItemDefinitions; diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/NonVanillaItemRegistration.java b/core/src/main/java/org/geysermc/geyser/registry/type/NonVanillaItemRegistration.java index 16ac51749..3868845ac 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/NonVanillaItemRegistration.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/NonVanillaItemRegistration.java @@ -25,11 +25,10 @@ package org.geysermc.geyser.registry.type; -import org.cloudburstmc.protocol.bedrock.data.inventory.ComponentItemData; import org.geysermc.geyser.item.type.Item; /** * The return data of a successful registration of a custom item. */ -public record NonVanillaItemRegistration(ComponentItemData componentItemData, Item javaItem, ItemMapping mapping) { -} \ No newline at end of file +public record NonVanillaItemRegistration(Item javaItem, ItemMapping mapping) { +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/PaletteItem.java b/core/src/main/java/org/geysermc/geyser/registry/type/PaletteItem.java index bf202ddb3..9b51d672b 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/PaletteItem.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/PaletteItem.java @@ -31,4 +31,6 @@ import lombok.Data; public class PaletteItem { String name; int id; -} \ No newline at end of file + int version; + boolean componentBased; +} 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 fc8f82dd0..14a7f42a9 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -147,6 +147,7 @@ import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.physics.CollisionManager; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; @@ -739,10 +740,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { sentSpawnPacket = true; syncEntityProperties(); - if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) { + if (GameProtocol.isPreCreativeInventoryRewrite(this.protocolVersion())) { ItemComponentPacket componentPacket = new ItemComponentPacket(); componentPacket.getItems().addAll(itemMappings.getComponentItemData()); upstream.sendPacket(componentPacket); + } else { + ItemComponentPacket componentPacket = new ItemComponentPacket(); + componentPacket.getItems().addAll(itemMappings.getItemDefinitions().values()); + upstream.sendPacket(componentPacket); } ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false); @@ -760,7 +765,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { upstream.sendPacket(cameraPresetsPacket); CreativeContentPacket creativePacket = new CreativeContentPacket(); - creativePacket.setContents(this.itemMappings.getCreativeItems()); + creativePacket.getContents().addAll(this.itemMappings.getCreativeItems()); + creativePacket.getGroups().addAll(this.itemMappings.getCreativeItemGroups()); upstream.sendPacket(creativePacket); PlayStatusPacket playStatusPacket = new PlayStatusPacket(); @@ -1820,6 +1826,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { abilityLayer.setFlySpeed(flySpeed); // https://github.com/GeyserMC/Geyser/issues/3139 as of 1.19.10 abilityLayer.setWalkSpeed(walkSpeed == 0f ? 0.01f : walkSpeed); + abilityLayer.setVerticalFlySpeed(1.0f); Collections.addAll(abilityLayer.getAbilitiesSet(), USED_ABILITIES); updateAbilitiesPacket.getAbilityLayers().add(abilityLayer); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 371d61714..c69293717 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; +import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; @@ -63,6 +64,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.function.IntFunction; public class PlayerInventoryTranslator extends InventoryTranslator { @@ -437,13 +439,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { craftState = CraftState.RECIPE_ID; int creativeId = creativeAction.getCreativeItemNetworkId() - 1; - ItemData[] creativeItems = session.getItemMappings().getCreativeItems(); - if (creativeId < 0 || creativeId >= creativeItems.length) { + List creativeItems = session.getItemMappings().getCreativeItems(); + if (creativeId < 0 || creativeId >= creativeItems.size()) { return rejectRequest(request); } // Reference the creative items list we send to the client to know what it's asking of us - ItemData creativeItem = creativeItems[creativeId]; - javaCreativeItem = ItemTranslator.translateToJava(session, creativeItem); + CreativeItemData creativeItem = creativeItems.get(creativeId); + javaCreativeItem = ItemTranslator.translateToJava(session, creativeItem.getItem()); break; } case CRAFT_RESULTS_DEPRECATED: { diff --git a/core/src/main/resources/bedrock/biome_definitions.dat b/core/src/main/resources/bedrock/biome_definitions.dat index e59a99ce2a5c5ffc11489ea1a9d42285e77f137a..07a3c2abbfdaee113ff8c5eba53bb06319034833 100644 GIT binary patch delta 1825 zcmb7^O-K}B7{{3%+#Oe4cWg7z_CpjCzeY1y3akzmx@zJfB+JIpoJDqa+;(;SKwU{F zB0r)(86HFnf)Xp?rBeiX42gn*kOB`zT}p&5b%|zYbM4T!?;Z!<-~68U`9JS7`M~gT z)v(&nVm88Ilyw!jLIG(|4T*zN&@YCiV6UY1i*ocsQhWW95(489$U1wO#V<35I#V$v zGHtAYicWgLEV}AU0MHn{DVc z?e#SwN*K>lY^=5#Ywo6G4C%$wZg_1PRIn=>js zUa5Q7CvT70D`aoF??X;tpX zho~_UQRX-;vth9yx>o2D!1aM;J?nh5gbycOM`R-WBu!gIR-72!+YE`LY8`#6#Z*`l zlERXzN;KIzh%)A2G%D)I!2R*;_-zt<)*=o#Jv_F?SM*(QCsLZ6B5RRPX=rS>;!#@@ zR);c4*3}m#ou3d*@Q-j9uQ6kL+Lg2~mY9d+#rscHe<~I?YMcIXF9hO=UQ0coJXZt45^?%Lukc8Y#_8_I-BL0ZDv|)>Jp;z zCw#OZ`k|Ys=tBAkx{>NK5}kCZ5kWVB(9ew!Qhn#!vTmQB?|IJip0#ikGbO=Xhi<7a(e`&VylM7d8uV&?=zJu^*FG5kXfNtB$t}dsbEhze|Rv zQ$oObE3Yd>wn0FAr~=lsNP?~xB@m|tZ1{3fOMWluspUBuB_QFi!`*<0CI2GrPJS~urI)8-x?)YKAebqJ- zX`-{*W;#7&B4X#*gpbr3@?BL7oC&h#q(L%B*8_I1NL&wQ{hvoO1|05k;m&ChV_Fn@ zV+pPhk@#*b$4oF^6)~lS$*JCVJcVVgCJ(J}7AB$=;^?mzXbUgCICtvT!Y?%pX*j7j z1BMTrtW2%II)O=$n=Rj8bLQ L*57$)_7ndH#W5~s diff --git a/core/src/main/resources/bedrock/block_palette.1_21_60.nbt b/core/src/main/resources/bedrock/block_palette.1_21_60.nbt new file mode 100644 index 0000000000000000000000000000000000000000..57336ca95895f32c13f9c363e7714aba351c772b GIT binary patch literal 193020 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%0A%kIFe|~5Casa> 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 z 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

    $yNddTyWTn%yB8S|1;6X9b>lB-MNK|eK9vW) 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 PXYildUunut`0o7=`Y)TP literal 0 HcmV?d00001 diff --git a/core/src/main/resources/bedrock/creative_items.1_21_60.json b/core/src/main/resources/bedrock/creative_items.1_21_60.json new file mode 100644 index 000000000..52eda075b --- /dev/null +++ b/core/src/main/resources/bedrock/creative_items.1_21_60.json @@ -0,0 +1,8917 @@ +{ + "groups": [ + { + "name": "itemGroup.name.planks", + "category": "construction", + "icon": { + "id": "minecraft:oak_planks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19wbGFua3MECQBuYW1lX2hhc2ilMDLR92rQ4wMKAG5ldHdvcmtfaWS2GotyCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "itemGroup.name.walls", + "category": "construction", + "icon": { + "id": "minecraft:cobblestone_wall", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSLY2XwCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.fence", + "category": "construction", + "icon": { + "id": "minecraft:oak_fence", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAAAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZDvPEXcKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.fenceGate", + "category": "construction", + "icon": { + "id": "minecraft:fence_gate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAAAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWRAoluQCgYAc3RhdGVzAQsAaW5fd2FsbF9iaXQACBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCABvcGVuX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.stairs", + "category": "construction", + "icon": { + "id": "minecraft:stone_stairs", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZDcCv+MKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.door", + "category": "construction", + "icon": { + "id": "minecraft:wooden_door" + } + }, + { + "name": "itemGroup.name.trapdoor", + "category": "construction", + "icon": { + "id": "minecraft:trapdoor", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAAAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkyTAWkAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "", + "category": "construction", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.glass", + "category": "construction", + "icon": { + "id": "minecraft:glass", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lk0hdLNwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + } + }, + { + "name": "itemGroup.name.glassPane", + "category": "construction", + "icon": { + "id": "minecraft:glass_pane", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWRGwixuCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "", + "category": "construction", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.slab", + "category": "construction", + "icon": { + "id": "minecraft:smooth_stone_slab", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRsAbWluZWNyYWZ0OnNtb290aF9zdG9uZV9zbGFiBAkAbmFtZV9oYXNon5I1yVw74uMDCgBuZXR3b3JrX2lkqvjcBQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.stoneBrick", + "category": "construction", + "icon": { + "id": "minecraft:stone_bricks", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2JyaWNrcwQJAG5hbWVfaGFzaGAiQu8VWVJRAwoAbmV0d29ya19pZH2DjXUKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "", + "category": "construction", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.sandstone", + "category": "construction", + "icon": { + "id": "minecraft:sandstone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZPsXMaQKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "", + "category": "construction", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.copper", + "category": "construction", + "icon": { + "id": "minecraft:copper_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZIiUodwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "", + "category": "construction", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.wool", + "category": "construction", + "icon": { + "id": "minecraft:white_wool", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAAAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWSO8paQCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "itemGroup.name.woolCarpet", + "category": "construction", + "icon": { + "id": "minecraft:white_carpet", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAAAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZEahDFcKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.concretePowder", + "category": "construction", + "icon": { + "id": "minecraft:white_concrete_powder", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTtAAAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZJPZY8AKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.concrete", + "category": "construction", + "icon": { + "id": "minecraft:white_concrete", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAAAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lk3MAYQAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + } + }, + { + "name": "itemGroup.name.stainedClay", + "category": "construction", + "icon": { + "id": "minecraft:hardened_clay", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAAAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRBCOrrCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "itemGroup.name.glazedTerracotta", + "category": "construction", + "icon": { + "id": "minecraft:white_glazed_terracotta", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAAAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkIlj9AAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "", + "category": "construction", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.ore", + "category": "nature", + "icon": { + "id": "minecraft:iron_ore", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAAAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lk3loneQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + } + }, + { + "name": "itemGroup.name.stone", + "category": "nature", + "icon": { + "id": "minecraft:stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkIQ4xgAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.log", + "category": "nature", + "icon": { + "id": "minecraft:oak_log", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAAAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWQjfjoxCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.wood", + "category": "nature", + "icon": { + "id": "minecraft:oak_wood", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha193b29kBAkAbmFtZV9oYXNoqQIkuVPyJX0DCgBuZXR3b3JrX2lku2G1YAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "itemGroup.name.leaves", + "category": "nature", + "icon": { + "id": "minecraft:oak_leaves", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19sZWF2ZXMECQBuYW1lX2hhc2h6O4xGqA2oKgMKAG5ldHdvcmtfaWT98c59CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.sapling", + "category": "nature", + "icon": { + "id": "minecraft:oak_sapling", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZRUAbWluZWNyYWZ0Om9ha19zYXBsaW5nBAkAbmFtZV9oYXNoogXcT9QfjiUDCgBuZXR3b3JrX2lkG22C+AoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.seed", + "category": "nature", + "icon": { + "id": "minecraft:wheat_seeds" + } + }, + { + "name": "itemGroup.name.crop", + "category": "nature", + "icon": { + "id": "minecraft:wheat" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.grass", + "category": "nature", + "icon": { + "id": "minecraft:fern", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPBAAACAQAbmFtZQ4AbWluZWNyYWZ0OmZlcm4ECQBuYW1lX2hhc2iHbj3yXFn4owMKAG5ldHdvcmtfaWQKC6u7CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "itemGroup.name.coral_decorations", + "category": "nature", + "icon": { + "id": "minecraft:fire_coral", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAwAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWS9vF0UCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "itemGroup.name.flower", + "category": "nature", + "icon": { + "id": "minecraft:dandelion", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRhbmRlbGlvbgQJAG5hbWVfaGFzaBJ3bEUi+Nn/AwoAbmV0d29ya19pZBjjC44KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "itemGroup.name.dye", + "category": "nature", + "icon": { + "id": "minecraft:yellow_dye" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.rawFood", + "category": "nature", + "icon": { + "id": "minecraft:chicken" + } + }, + { + "name": "itemGroup.name.mushroom", + "category": "nature", + "icon": { + "id": "minecraft:brown_mushroom", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAAAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkLh1OXAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.monsterStoneEgg", + "category": "nature", + "icon": { + "id": "minecraft:infested_stone", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRgAbWluZWNyYWZ0OmluZmVzdGVkX3N0b25lBAkAbmFtZV9oYXNoxnRcHDu4zqQDCgBuZXR3b3JrX2lkpfcnsgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.mobEgg", + "category": "nature", + "icon": { + "id": "minecraft:chicken_spawn_egg" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.coral", + "category": "nature", + "icon": { + "id": "minecraft:tube_coral_block", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRoAbWluZWNyYWZ0OnR1YmVfY29yYWxfYmxvY2sECQBuYW1lX2hhc2iGkaiR7Eot4wMKAG5ldHdvcmtfaWQPNJ6sCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "itemGroup.name.sculk", + "category": "nature", + "icon": { + "id": "minecraft:sculk", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lkyqUPPgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + } + }, + { + "name": "", + "category": "nature", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.helmet", + "category": "equipment", + "icon": { + "id": "minecraft:leather_helmet" + } + }, + { + "name": "itemGroup.name.chestplate", + "category": "equipment", + "icon": { + "id": "minecraft:leather_chestplate" + } + }, + { + "name": "itemGroup.name.leggings", + "category": "equipment", + "icon": { + "id": "minecraft:leather_leggings" + } + }, + { + "name": "itemGroup.name.boots", + "category": "equipment", + "icon": { + "id": "minecraft:leather_boots" + } + }, + { + "name": "itemGroup.name.sword", + "category": "equipment", + "icon": { + "id": "minecraft:wooden_sword" + } + }, + { + "name": "itemGroup.name.axe", + "category": "equipment", + "icon": { + "id": "minecraft:wooden_axe" + } + }, + { + "name": "itemGroup.name.pickaxe", + "category": "equipment", + "icon": { + "id": "minecraft:wooden_pickaxe" + } + }, + { + "name": "itemGroup.name.shovel", + "category": "equipment", + "icon": { + "id": "minecraft:wooden_shovel" + } + }, + { + "name": "itemGroup.name.hoe", + "category": "equipment", + "icon": { + "id": "minecraft:wooden_hoe" + } + }, + { + "name": "", + "category": "equipment", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.arrow", + "category": "equipment", + "icon": { + "id": "minecraft:arrow" + } + }, + { + "name": "", + "category": "equipment", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.cookedFood", + "category": "equipment", + "icon": { + "id": "minecraft:cooked_chicken" + } + }, + { + "name": "itemGroup.name.miscFood", + "category": "equipment", + "icon": { + "id": "minecraft:bread" + } + }, + { + "name": "", + "category": "equipment", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.goatHorn", + "category": "equipment", + "icon": { + "id": "minecraft:goat_horn" + } + }, + { + "name": "", + "category": "equipment", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.bundles", + "category": "equipment", + "icon": { + "id": "minecraft:bundle" + } + }, + { + "name": "itemGroup.name.horseArmor", + "category": "equipment", + "icon": { + "id": "minecraft:leather_horse_armor" + } + }, + { + "name": "", + "category": "equipment", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.potion", + "category": "equipment", + "icon": { + "id": "minecraft:potion" + } + }, + { + "name": "itemGroup.name.splashPotion", + "category": "equipment", + "icon": { + "id": "minecraft:splash_potion" + } + }, + { + "name": "itemGroup.name.lingeringPotion", + "category": "equipment", + "icon": { + "id": "minecraft:lingering_potion" + } + }, + { + "name": "itemGroup.name.ominousBottle", + "category": "equipment", + "icon": { + "id": "minecraft:ominous_bottle" + } + }, + { + "name": "", + "category": "equipment", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.bed", + "category": "items", + "icon": { + "id": "minecraft:bed" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.candles", + "category": "items", + "icon": { + "id": "minecraft:candle", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZHsBMA0KBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.anvil", + "category": "items", + "icon": { + "id": "minecraft:anvil", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkqXzNjwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.chest", + "category": "items", + "icon": { + "id": "minecraft:chest", + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AAAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkDkOFvAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.shulkerBox", + "category": "items", + "icon": { + "id": "minecraft:undyed_shulker_box", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAAAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZJ8rxp0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.record", + "category": "items", + "icon": { + "id": "minecraft:music_disc_13" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.sign", + "category": "items", + "icon": { + "id": "minecraft:oak_sign" + } + }, + { + "name": "itemGroup.name.hanging_sign", + "category": "items", + "icon": { + "id": "minecraft:oak_hanging_sign" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.skull", + "category": "items", + "icon": { + "id": "minecraft:creeper_head", + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHBAAACAQAbmFtZRYAbWluZWNyYWZ0OmNyZWVwZXJfaGVhZAQJAG5hbWVfaGFzaCvAGFMS/RqVAwoAbmV0d29ya19pZEfskXYKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.enchantedBook", + "category": "items", + "icon": { + "id": "minecraft:enchanted_book", + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" + } + }, + { + "name": "itemGroup.name.boat", + "category": "items", + "icon": { + "id": "minecraft:oak_boat" + } + }, + { + "name": "itemGroup.name.chestboat", + "category": "items", + "icon": { + "id": "minecraft:oak_chest_boat" + } + }, + { + "name": "itemGroup.name.rail", + "category": "items", + "icon": { + "id": "minecraft:rail", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWR+Sp6YCgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "itemGroup.name.minecart", + "category": "items", + "icon": { + "id": "minecraft:minecart" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.buttons", + "category": "items", + "icon": { + "id": "minecraft:wooden_button", + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAAAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWSU07kYCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.pressurePlate", + "category": "items", + "icon": { + "id": "minecraft:wooden_pressure_plate", + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAAAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZDRzPNwKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24hPBUBAA==" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + }, + { + "name": "itemGroup.name.banner", + "category": "items", + "icon": { + "id": "minecraft:banner" + } + }, + { + "name": "itemGroup.name.banner_pattern", + "category": "items", + "icon": { + "id": "minecraft:creeper_banner_pattern" + } + }, + { + "name": "itemGroup.name.potterySherds", + "category": "items", + "icon": { + "id": "minecraft:archer_pottery_sherd" + } + }, + { + "name": "itemGroup.name.smithing_templates", + "category": "items", + "icon": { + "id": "minecraft:netherite_upgrade_smithing_template" + } + }, + { + "name": "itemGroup.name.firework", + "category": "items", + "icon": { + "id": "minecraft:firework_rocket" + } + }, + { + "name": "itemGroup.name.fireworkStars", + "category": "items", + "icon": { + "id": "minecraft:firework_star" + } + }, + { + "name": "", + "category": "items", + "icon": { + "id": "minecraft:air" + } + } + ], + "items": [ + { + "id": "minecraft:oak_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19wbGFua3MECQBuYW1lX2hhc2ilMDLR92rQ4wMKAG5ldHdvcmtfaWS2GotyCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:spruce_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAwAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9wbGFua3MECQBuYW1lX2hhc2iumBkmFGFE8gMKAG5ldHdvcmtfaWSo8TFgCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:birch_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3BsYW5rcwQJAG5hbWVfaGFzaLrrAKJqV2WFAwoAbmV0d29ya19pZL+e3ZAKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:jungle_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAwAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9wbGFua3MECQBuYW1lX2hhc2iBM3k4T3FAugMKAG5ldHdvcmtfaWSXUmBCCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:acacia_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAwAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9wbGFua3MECQBuYW1lX2hhc2g60edJxO5/aAMKAG5ldHdvcmtfaWTUXozECgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dark_oak_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3BsYW5rcwQJAG5hbWVfaGFzaAr64wkQ9cA7AwoAbmV0d29ya19pZFbMeR0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mangrove_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3BsYW5rcwQJAG5hbWVfaGFzaPvLtcEA0F8xAwoAbmV0d29ya19pZEvnlCYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cherry_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9wbGFua3MECQBuYW1lX2hhc2hNIvVh/lVW7gMKAG5ldHdvcmtfaWQTXpRoCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pale_oak_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjBAAACAQAbmFtZRkAbWluZWNyYWZ0OnBhbGVfb2FrX3BsYW5rcwQJAG5hbWVfaGFzaDbrgXmqzgxDAwoAbmV0d29ya19pZFpM6OoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bamboo_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19wbGFua3MECQBuYW1lX2hhc2gYnjNz7SCCjgMKAG5ldHdvcmtfaWTi8ySSCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:bamboo_mosaic", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWMECQBuYW1lX2hhc2izSEgiMKOp/AMKAG5ldHdvcmtfaWQZ/p8xCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:crimson_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fcGxhbmtzBAkAbmFtZV9oYXNoJc5IKqNXJnwDCgBuZXR3b3JrX2lkwtJDdQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_planks", + "groupId": 0, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9wbGFua3MECQBuYW1lX2hhc2g3yGXEWhe6LgMKAG5ldHdvcmtfaWStTABvCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cobblestone_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2hZu/xE7lYtNgMKAG5ldHdvcmtfaWSLY2XwCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mossy_cobblestone_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKBAAACAQAbmFtZSAAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3dhbGwECQBuYW1lX2hhc2gHUQMwwFQeNQMKAG5ldHdvcmtfaWRzPhG8CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:granite_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLBAAACAQAbmFtZRYAbWluZWNyYWZ0OmdyYW5pdGVfd2FsbAQJAG5hbWVfaGFzaE1GmM5AU0qUAwoAbmV0d29ya19pZE/UoPUKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:diorite_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMBAAACAQAbmFtZRYAbWluZWNyYWZ0OmRpb3JpdGVfd2FsbAQJAG5hbWVfaGFzaF27l0QvdM8xAwoAbmV0d29ya19pZJe7jOwKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:andesite_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNBAAACAQAbmFtZRcAbWluZWNyYWZ0OmFuZGVzaXRlX3dhbGwECQBuYW1lX2hhc2gAL1Vay0kZjQMKAG5ldHdvcmtfaWRJGxdvCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:sandstone_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOBAAACAQAbmFtZRgAbWluZWNyYWZ0OnNhbmRzdG9uZV93YWxsBAkAbmFtZV9oYXNoYL2gu8a6HfgDCgBuZXR3b3JrX2lkHrhRjgoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_sandstone_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVBAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfd2FsbAQJAG5hbWVfaGFzaLAUUdOlo24MAwoAbmV0d29ya19pZI66BqAKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stone_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQBAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3dhbGwECQBuYW1lX2hhc2hQegufuP6vjAMKAG5ldHdvcmtfaWS4AsOKCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mossy_stone_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRBAAACAQAbmFtZSAAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3dhbGwECQBuYW1lX2hhc2i680zzUekp+wMKAG5ldHdvcmtfaWTQTaHPCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJyaWNrX3dhbGwECQBuYW1lX2hhc2gGJFLNjfgSCAMKAG5ldHdvcmtfaWSc5iUZCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:nether_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTSBAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl9icmlja193YWxsBAkAbmFtZV9oYXNoAxb5f2yQ5MYDCgBuZXR3b3JrX2lkAECPDAoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_nether_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWBAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBOtwkokUt3cAwoAbmV0d29ya19pZJykmZUKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:end_stone_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTBAAACAQAbmFtZR4AbWluZWNyYWZ0OmVuZF9zdG9uZV9icmlja193YWxsBAkAbmFtZV9oYXNoOsr1L9kJIAMDCgBuZXR3b3JrX2lkjuYlYgoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:prismarine_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUBAAACAQAbmFtZRkAbWluZWNyYWZ0OnByaXNtYXJpbmVfd2FsbAQJAG5hbWVfaGFzaDO5IGrYZu1/AwoAbmV0d29ya19pZB4nLYYKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:blackstone_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaMP8XppUSU1RAwoAbmV0d29ya19pZMbeBBsKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_blackstone_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfd2FsbAQJAG5hbWVfaGFzaP6SwV08YwzAAwoAbmV0d29ya19pZAJLsz8KBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_blackstone_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaBBIDZbHxiEzAwoAbmV0d29ya19pZEbLV8cKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cobbled_deepslate_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3dhbGwECQBuYW1lX2hhc2iECY5oKxeT+gMKAG5ldHdvcmtfaWRCnPrFCgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:deepslate_tile_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3dhbGwECQBuYW1lX2hhc2jz7N+PeuEXgQMKAG5ldHdvcmtfaWTqw4s4CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:polished_deepslate_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV93YWxsBAkAbmFtZV9oYXNoHxjTdj9pevMDCgBuZXR3b3JrX2lkIvBYYwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:deepslate_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja193YWxsBAkAbmFtZV9oYXNoEs3EQrjroyEDCgBuZXR3b3JrX2lkwlrCGwoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:tuff_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAwAACAQAbmFtZRMAbWluZWNyYWZ0OnR1ZmZfd2FsbAQJAG5hbWVfaGFzaMyeeu1IRf03AwoAbmV0d29ya19pZDkIrosKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:tuff_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AwAACAQAbmFtZRkAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfd2FsbAQJAG5hbWVfaGFzaIL0IyNCOsonAwoAbmV0d29ya19pZJW4T5UKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_tuff_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfd2FsbAQJAG5hbWVfaGFzaJVZj6QYWXUrAwoAbmV0d29ya19pZLU7dooKBgBzdGF0ZXMIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9lYXN0BABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfbm9ydGgEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9zb3V0aAQAbm9uZQgZAHdhbGxfY29ubmVjdGlvbl90eXBlX3dlc3QEAG5vbmUBDQB3YWxsX3Bvc3RfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mud_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja193YWxsBAkAbmFtZV9oYXNov9b98ATpUSwDCgBuZXR3b3JrX2lkH/1WZQoGAHN0YXRlcwgZAHdhbGxfY29ubmVjdGlvbl90eXBlX2Vhc3QEAG5vbmUIGgB3YWxsX2Nvbm5lY3Rpb25fdHlwZV9ub3J0aAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX3NvdXRoBABub25lCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfd2VzdAQAbm9uZQENAHdhbGxfcG9zdF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:resin_brick_wall", + "groupId": 1, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT4BAAACAQAbmFtZRoAbWluZWNyYWZ0OnJlc2luX2JyaWNrX3dhbGwECQBuYW1lX2hhc2iUkvfZlSl8+gMKAG5ldHdvcmtfaWSYW394CgYAc3RhdGVzCBkAd2FsbF9jb25uZWN0aW9uX3R5cGVfZWFzdAQAbm9uZQgaAHdhbGxfY29ubmVjdGlvbl90eXBlX25vcnRoBABub25lCBoAd2FsbF9jb25uZWN0aW9uX3R5cGVfc291dGgEAG5vbmUIGQB3YWxsX2Nvbm5lY3Rpb25fdHlwZV93ZXN0BABub25lAQ0Ad2FsbF9wb3N0X2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:oak_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAAAACAQAbmFtZRMAbWluZWNyYWZ0Om9ha19mZW5jZQQJAG5hbWVfaGFzaGEmid7AaCWRAwoAbmV0d29ya19pZDvPEXcKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:spruce_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAwAACAQAbmFtZRYAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZQQJAG5hbWVfaGFzaPQCm+aX1ZQeAwoAbmV0d29ya19pZD1QUEoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:birch_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AwAACAQAbmFtZRUAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlBAkAbmFtZV9oYXNo6CJ2ATpANfgDCgBuZXR3b3JrX2lkmCUV2QoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:jungle_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAwAACAQAbmFtZRYAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZQQJAG5hbWVfaGFzaOX4cD9uAmsdAwoAbmV0d29ya19pZHz1VxkKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:acacia_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AwAACAQAbmFtZRYAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZQQJAG5hbWVfaGFzaGjn+RlKVDH6AwoAbmV0d29ya19pZNVGubwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dark_oak_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAwAACAQAbmFtZRgAbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlBAkAbmFtZV9oYXNoGPj0gCgM0c0DCgBuZXR3b3JrX2lk2w+gEwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mangrove_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlBAkAbmFtZV9oYXNowwAd7tPu9bsDCgBuZXR3b3JrX2lkKEcd0goGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cherry_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAwAACAQAbmFtZRYAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZQQJAG5hbWVfaGFzaFmtUfHfTxcxAwoAbmV0d29ya19pZPCBxAIKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pale_oak_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeBAAACAQAbmFtZRgAbWluZWNyYWZ0OnBhbGVfb2FrX2ZlbmNlBAkAbmFtZV9oYXNobM05DVVUSxsDCgBuZXR3b3JrX2lkS7udAwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:bamboo_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19mZW5jZQQJAG5hbWVfaGFzaCKRbxfXsfkiAwoAbmV0d29ya19pZJNXKFcKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:nether_brick_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAAAACAQAbmFtZRwAbWluZWNyYWZ0Om5ldGhlcl9icmlja19mZW5jZQQJAG5hbWVfaGFzaA6030ngawxcAwoAbmV0d29ya19pZLnjLF4KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:crimson_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2UECQBuYW1lX2hhc2jhUhKv1HGj9AMKAG5ldHdvcmtfaWR3OH3OCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:warped_fence", + "groupId": 2, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAgAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9mZW5jZQQJAG5hbWVfaGFzaJfb3/YuKmOWAwoAbmV0d29ya19pZCpaGC8KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAAAACAQAbmFtZRQAbWluZWNyYWZ0OmZlbmNlX2dhdGUECQBuYW1lX2hhc2hTxpjEDmRzAwMKAG5ldHdvcmtfaWRAoluQCgYAc3RhdGVzAQsAaW5fd2FsbF9iaXQACBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCABvcGVuX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:spruce_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AAAACAQAbmFtZRsAbWluZWNyYWZ0OnNwcnVjZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoanTVB84HRbkDCgBuZXR3b3JrX2lkJL+vZAoGAHN0YXRlcwELAGluX3dhbGxfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:birch_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmJpcmNoX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2jmfPklI8azSwMKAG5ldHdvcmtfaWSlk1JPCgYAc3RhdGVzAQsAaW5fd2FsbF9iaXQACBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCABvcGVuX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:jungle_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS5AAAACAQAbmFtZRsAbWluZWNyYWZ0Omp1bmdsZV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNobYVQkfBomIcDCgBuZXR3b3JrX2lkjQubHgoGAHN0YXRlcwELAGluX3dhbGxfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:acacia_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS7AAAACAQAbmFtZRsAbWluZWNyYWZ0OmFjYWNpYV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoZnrLUx/XSekDCgBuZXR3b3JrX2lkoGH3cQoGAHN0YXRlcwELAGluX3dhbGxfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dark_oak_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS6AAAACAQAbmFtZR0AbWluZWNyYWZ0OmRhcmtfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2j2PTvdJJHcVQMKAG5ldHdvcmtfaWRS6WN3CgYAc3RhdGVzAQsAaW5fd2FsbF9iaXQACBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCABvcGVuX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mangrove_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1hbmdyb3ZlX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2i/kOhBKiI/dAMKAG5ldHdvcmtfaWQ5AL3/CgYAc3RhdGVzAQsAaW5fd2FsbF9iaXQACBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCABvcGVuX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cherry_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAwAACAQAbmFtZRsAbWluZWNyYWZ0OmNoZXJyeV9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoKWLgCk0z+PsDCgBuZXR3b3JrX2lkWfIkRAoGAHN0YXRlcwELAGluX3dhbGxfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pale_oak_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfBAAACAQAbmFtZR0AbWluZWNyYWZ0OnBhbGVfb2FrX2ZlbmNlX2dhdGUECQBuYW1lX2hhc2hCrHUtEPI3BgMKAG5ldHdvcmtfaWSO5QLnCgYAc3RhdGVzAQsAaW5fd2FsbF9iaXQACBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCABvcGVuX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bamboo_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJhbWJvb19mZW5jZV9nYXRlBAkAbmFtZV9oYXNopH1JrUgwdIADCgBuZXR3b3JrX2lkriggcAoGAHN0YXRlcwELAGluX3dhbGxfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:crimson_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNyaW1zb25fZmVuY2VfZ2F0ZQQJAG5hbWVfaGFzaHE3Gfd0Z2d2AwoAbmV0d29ya19pZGaT7SQKBgBzdGF0ZXMBCwBpbl93YWxsX2JpdAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_fence_gate", + "groupId": 3, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAgAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF9mZW5jZV9nYXRlBAkAbmFtZV9oYXNoy0oIBjDIG4kDCgBuZXR3b3JrX2lkO8ur6woGAHN0YXRlcwELAGluX3dhbGxfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQgAb3Blbl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:normal_stone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAQAACAQAbmFtZR0AbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hAEktZZOkGIwMKAG5ldHdvcmtfaWQeH1ALCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX3N0YWlycwQJAG5hbWVfaGFzaNRjqVC5GRVDAwoAbmV0d29ya19pZDcCv+MKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mossy_cobblestone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSyAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3N0YWlycwQJAG5hbWVfaGFzaMVSTq5z9n1RAwoAbmV0d29ya19pZFIfrhkKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:oak_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19zdGFpcnMECQBuYW1lX2hhc2jk/HFzdXy0FQMKAG5ldHdvcmtfaWQJjyzBCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:spruce_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9zdGFpcnMECQBuYW1lX2hhc2iznygw7uBPBQMKAG5ldHdvcmtfaWTv+is3CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:birch_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX3N0YWlycwQJAG5hbWVfaGFzaPfhbL619a3GAwoAbmV0d29ya19pZFyPlHAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:jungle_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9zdGFpcnMECQBuYW1lX2hhc2jodJsHUbOVxQMKAG5ldHdvcmtfaWR0z5d4CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:acacia_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9zdGFpcnMECQBuYW1lX2hhc2h3x1NmD43IqQMKAG5ldHdvcmtfaWS7Jwz6CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dark_oak_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX3N0YWlycwQJAG5hbWVfaGFzaMfwkbYPbNmAAwoAbmV0d29ya19pZCmBYKAKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mangrove_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX3N0YWlycwQJAG5hbWVfaGFzaNpUDY+uGMpyAwoAbmV0d29ya19pZChzUAsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cherry_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9zdGFpcnMECQBuYW1lX2hhc2jMtr0v9JY4zwMKAG5ldHdvcmtfaWRQwq31CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pale_oak_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnBAAACAQAbmFtZRkAbWluZWNyYWZ0OnBhbGVfb2FrX3N0YWlycwQJAG5hbWVfaGFzaJsYBq7wfPXaAwoAbmV0d29ya19pZE1U5UIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bamboo_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19zdGFpcnMECQBuYW1lX2hhc2jFOzWL8PalKwMKAG5ldHdvcmtfaWTVPh42CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:bamboo_mosaic_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc3RhaXJzBAkAbmFtZV9oYXNoNLPiveSHPaoDCgBuZXR3b3JrX2lk44PHjgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stone_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAAAACAQAbmFtZRwAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaN6tQViRo5cwAwoAbmV0d29ya19pZDMyMgIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mossy_stone_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAQAACAQAbmFtZSIAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaIB/Zv5YBPuYAwoAbmV0d29ya19pZANTOsMKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:sandstone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAAAACAQAbmFtZRoAbWluZWNyYWZ0OnNhbmRzdG9uZV9zdGFpcnMECQBuYW1lX2hhc2hOyA0BoYUOPQMKAG5ldHdvcmtfaWSV/834CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:smooth_sandstone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSwAQAACAQAbmFtZSEAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoB+CuCd8Ruz8DCgBuZXR3b3JrX2lksR+m8QoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:red_sandstone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS0AAAACAQAbmFtZR4AbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNoPs0LpHPL24YDCgBuZXR3b3JrX2lkLYVt3woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:smooth_red_sandstone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAQAACAQAbmFtZSUAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3N0YWlycwQJAG5hbWVfaGFzaBvjtQv5pf+MAwoAbmV0d29ya19pZMHNND8KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:granite_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAQAACAQAbmFtZRgAbWluZWNyYWZ0OmdyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNoGzpvtoqKQjgDCgBuZXR3b3JrX2lkPkcB1goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_granite_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc3RhaXJzBAkAbmFtZV9oYXNo3PvbSfEQklIDCgBuZXR3b3JrX2lkMmEm3AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:diorite_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAQAACAQAbmFtZRgAbWluZWNyYWZ0OmRpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoi73T8VQuZmcDCgBuZXR3b3JrX2lk6i6nBQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_diorite_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAQAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc3RhaXJzBAkAbmFtZV9oYXNoFKRJd5Wk5L0DCgBuZXR3b3JrX2lkbt2ioAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:andesite_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaO5w2FKBw76EAwoAbmV0d29ya19pZKhXEgUKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:polished_andesite_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAQAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3N0YWlycwQJAG5hbWVfaGFzaNcZZ/zmLInIAwoAbmV0d29ya19pZJTHrlEKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAAAACAQAbmFtZRYAbWluZWNyYWZ0OmJyaWNrX3N0YWlycwQJAG5hbWVfaGFzaMyt+cRDk5O2AwoAbmV0d29ya19pZNeMh58KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:nether_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAAAACAQAbmFtZR0AbWluZWNyYWZ0Om5ldGhlcl9icmlja19zdGFpcnMECQBuYW1lX2hhc2jRqIoOXgifBAMKAG5ldHdvcmtfaWQDiw5yCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_nether_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS3AQAACAQAbmFtZSEAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNogQvosSbcj7kDCgBuZXR3b3JrX2lkx2IMtAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:end_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSxAQAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2hmlAk+QhsUsQMKAG5ldHdvcmtfaWTN7KFaCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:quartz_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAAAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9zdGFpcnMECQBuYW1lX2hhc2hmvpvOqGi6egMKAG5ldHdvcmtfaWRmUTh7CgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:smooth_quartz_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4AQAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc3RhaXJzBAkAbmFtZV9oYXNoNZZ9rX0qZOsDCgBuZXR3b3JrX2lkzsgQyQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:purpur_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAAAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9zdGFpcnMECQBuYW1lX2hhc2ifwDxeezXD7gMKAG5ldHdvcmtfaWTT+rxiCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:prismarine_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAQAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfc3RhaXJzBAkAbmFtZV9oYXNooTHSZ+IrYtcDCgBuZXR3b3JrX2lkxTJfeAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dark_prismarine_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAQAACAQAbmFtZSAAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zdGFpcnMECQBuYW1lX2hhc2hIciLmam4o4AMKAG5ldHdvcmtfaWTVu7TCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:prismarine_bricks_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAQAACAQAbmFtZSIAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzX3N0YWlycwQJAG5hbWVfaGFzaNIjq1oBlZMMAwoAbmV0d29ya19pZGEFwLYKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:crimson_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fc3RhaXJzBAkAbmFtZV9oYXNoZJqIzCBpCq4DCgBuZXR3b3JrX2lktXE00AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9zdGFpcnMECQBuYW1lX2hhc2hOkY27jLD4RQMKAG5ldHdvcmtfaWQ+E5VrCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:blackstone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAgAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNokdoUb76p9McDCgBuZXR3b3JrX2lk5fWI5goGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_blackstone_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc3RhaXJzBAkAbmFtZV9oYXNolCFtFIE8MmADCgBuZXR3b3JrX2lkGTf7sgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_blackstone_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAgAACAQAbmFtZSoAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNonks6UlfpOmkDCgBuZXR3b3JrX2lkgYeOdAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cobbled_deepslate_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AgAACAQAbmFtZSIAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3N0YWlycwQJAG5hbWVfaGFzaPIfa+TpyJcIAwoAbmV0d29ya19pZJUvOYIKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:deepslate_tile_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3N0YWlycwQJAG5hbWVfaGFzaGFRFzB72mN2AwoAbmV0d29ya19pZJEOgIsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:polished_deepslate_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAgAACAQAbmFtZSMAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zdGFpcnMECQBuYW1lX2hhc2iNCYxVik9sGAMKAG5ldHdvcmtfaWSRVPnYCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:deepslate_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zdGFpcnMECQBuYW1lX2hhc2hIasOahEf83wMKAG5ldHdvcmtfaWQ1qEDCCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:tuff_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAwAACAQAbmFtZRUAbWluZWNyYWZ0OnR1ZmZfc3RhaXJzBAkAbmFtZV9oYXNoKjyNUBjcfZsDCgBuZXR3b3JrX2lk+LsycgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_tuff_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfc3RhaXJzBAkAbmFtZV9oYXNo8yuah8QI1dcDCgBuZXR3b3JrX2lkjLoU4AoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:tuff_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT0AwAACAQAbmFtZRsAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfc3RhaXJzBAkAbmFtZV9oYXNoWJpkAurUfKwDCgBuZXR3b3JrX2lkUMcjiwoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mud_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAgAACAQAbmFtZRoAbWluZWNyYWZ0Om11ZF9icmlja19zdGFpcnMECQBuYW1lX2hhc2gt3qxK1NWajAMKAG5ldHdvcmtfaWSm9N3MCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cut_copper_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAgAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoHfoAXYq5G3MDCgBuZXR3b3JrX2lkeetf7woGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:exposed_cut_copper_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAgAACAQAbmFtZSMAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2howneQGtZ9cgMKAG5ldHdvcmtfaWSg73zdCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:weathered_cut_copper_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAgAACAQAbmFtZSUAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaP+R5loXxrVgAwoAbmV0d29ya19pZOnbRf4KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:oxidized_cut_copper_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAgAACAQAbmFtZSQAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNo6Jeoq5rsPxsDCgBuZXR3b3JrX2lkmRjDnQoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_cut_copper_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAgAACAQAbmFtZSEAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoh07CQj0/SR8DCgBuZXR3b3JrX2lkmYqoqAoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_exposed_cut_copper_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zdGFpcnMECQBuYW1lX2hhc2guVct1ilmxTwMKAG5ldHdvcmtfaWQgCPROCgYAc3RhdGVzAQ8AdXBzaWRlX2Rvd25fYml0AAMQAHdlaXJkb19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_weathered_cut_copper_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAgAACAQAbmFtZSsAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3N0YWlycwQJAG5hbWVfaGFzaPXC8Sz/phCpAwoAbmV0d29ya19pZHlwHVsKBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS/AgAACAQAbmFtZSoAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc3RhaXJzBAkAbmFtZV9oYXNoaqGdkuhxVZUDCgBuZXR3b3JrX2lkYQXzzgoGAHN0YXRlcwEPAHVwc2lkZV9kb3duX2JpdAADEAB3ZWlyZG9fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:resin_brick_stairs", + "groupId": 4, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT3BAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlc2luX2JyaWNrX3N0YWlycwQJAG5hbWVfaGFzaGJwsbVlApWmAwoAbmV0d29ya19pZCPz+A0KBgBzdGF0ZXMBDwB1cHNpZGVfZG93bl9iaXQAAxAAd2VpcmRvX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:wooden_door", + "groupId": 5 + }, + { + "id": "minecraft:spruce_door", + "groupId": 5 + }, + { + "id": "minecraft:birch_door", + "groupId": 5 + }, + { + "id": "minecraft:jungle_door", + "groupId": 5 + }, + { + "id": "minecraft:acacia_door", + "groupId": 5 + }, + { + "id": "minecraft:dark_oak_door", + "groupId": 5 + }, + { + "id": "minecraft:mangrove_door", + "groupId": 5 + }, + { + "id": "minecraft:cherry_door", + "groupId": 5 + }, + { + "id": "minecraft:pale_oak_door", + "groupId": 5 + }, + { + "id": "minecraft:bamboo_door", + "groupId": 5 + }, + { + "id": "minecraft:iron_door", + "groupId": 5 + }, + { + "id": "minecraft:crimson_door", + "groupId": 5 + }, + { + "id": "minecraft:warped_door", + "groupId": 5 + }, + { + "id": "minecraft:copper_door", + "groupId": 5 + }, + { + "id": "minecraft:exposed_copper_door", + "groupId": 5 + }, + { + "id": "minecraft:weathered_copper_door", + "groupId": 5 + }, + { + "id": "minecraft:oxidized_copper_door", + "groupId": 5 + }, + { + "id": "minecraft:waxed_copper_door", + "groupId": 5 + }, + { + "id": "minecraft:waxed_exposed_copper_door", + "groupId": 5 + }, + { + "id": "minecraft:waxed_weathered_copper_door", + "groupId": 5 + }, + { + "id": "minecraft:waxed_oxidized_copper_door", + "groupId": 5 + }, + { + "id": "minecraft:trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAAAACAQAbmFtZRIAbWluZWNyYWZ0OnRyYXBkb29yBAkAbmFtZV9oYXNotYiAJGtN0xADCgBuZXR3b3JrX2lkyTAWkAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:spruce_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAQAACAQAbmFtZRkAbWluZWNyYWZ0OnNwcnVjZV90cmFwZG9vcgQJAG5hbWVfaGFzaOwlfbgBkUW4AwoAbmV0d29ya19pZPHy1K0KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:birch_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAQAACAQAbmFtZRgAbWluZWNyYWZ0OmJpcmNoX3RyYXBkb29yBAkAbmFtZV9oYXNoSLtLweOLJ7wDCgBuZXR3b3JrX2lkeJWDfgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:jungle_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAQAACAQAbmFtZRkAbWluZWNyYWZ0Omp1bmdsZV90cmFwZG9vcgQJAG5hbWVfaGFzaDP/TnM9wyCIAwoAbmV0d29ya19pZEy2fJoKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:acacia_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAQAACAQAbmFtZRkAbWluZWNyYWZ0OmFjYWNpYV90cmFwZG9vcgQJAG5hbWVfaGFzaMj8xi3vmEKOAwoAbmV0d29ya19pZOHj8E8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dark_oak_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAQAACAQAbmFtZRsAbWluZWNyYWZ0OmRhcmtfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNomB2GGJQ2aOMDCgBuZXR3b3JrX2lko5ZHTwoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:mangrove_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAgAACAQAbmFtZRsAbWluZWNyYWZ0Om1hbmdyb3ZlX3RyYXBkb29yBAkAbmFtZV9oYXNooV3kQsQUUmkDCgBuZXR3b3JrX2lkkF/mxAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cherry_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoZXJyeV90cmFwZG9vcgQJAG5hbWVfaGFzaH/PefpfdHgtAwoAbmV0d29ya19pZOA7eNgKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:pale_oak_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpBAAACAQAbmFtZRsAbWluZWNyYWZ0OnBhbGVfb2FrX3RyYXBkb29yBAkAbmFtZV9oYXNo5L0cQtjJA9oDCgBuZXR3b3JrX2lkVwhZTgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:bamboo_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJhbWJvb190cmFwZG9vcgQJAG5hbWVfaGFzaJrEOpsTwtKCAwoAbmV0d29ya19pZLvbPz8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:iron_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAAAACAQAbmFtZRcAbWluZWNyYWZ0Omlyb25fdHJhcGRvb3IECQBuYW1lX2hhc2gwA+IumsEiGQMKAG5ldHdvcmtfaWTvSVl/CgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:crimson_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT1AQAACAQAbmFtZRoAbWluZWNyYWZ0OmNyaW1zb25fdHJhcGRvb3IECQBuYW1lX2hhc2jHXufTnwUkYgMKAG5ldHdvcmtfaWQLjMYVCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:warped_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AQAACAQAbmFtZRkAbWluZWNyYWZ0OndhcnBlZF90cmFwZG9vcgQJAG5hbWVfaGFzaA20wG/+vkd6AwoAbmV0d29ya19pZHKR/hYKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:copper_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXBAAACAQAbmFtZRkAbWluZWNyYWZ0OmNvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaO9fXio+svKVAwoAbmV0d29ya19pZMCoRjEKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:exposed_copper_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYBAAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX3RyYXBkb29yBAkAbmFtZV9oYXNoYhDFUysN7qUDCgBuZXR3b3JrX2lkMzwGJgoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:weathered_copper_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZBAAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfdHJhcGRvb3IECQBuYW1lX2hhc2hFnEC282a1tgMKAG5ldHdvcmtfaWTk70oiCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:oxidized_copper_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQaBAAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaOJpG/XFexVwAwoAbmV0d29ya19pZPhi0J4KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_copper_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbBAAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaO0JUKUHqNU6AwoAbmV0d29ya19pZJC3ZuMKBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_exposed_copper_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcBAAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX3RyYXBkb29yBAkAbmFtZV9oYXNoBHHxCpkUzpgDCgBuZXR3b3JrX2lkw2XBGQoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAABCABvcGVuX2JpdAABDwB1cHNpZGVfZG93bl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_weathered_copper_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQdBAAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfdHJhcGRvb3IECQBuYW1lX2hhc2gH9Fi3JCF4egMKAG5ldHdvcmtfaWRkGU6TCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAEPAHVwc2lkZV9kb3duX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_oxidized_copper_trapdoor", + "groupId": 6, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeBAAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl90cmFwZG9vcgQJAG5hbWVfaGFzaNA/q9qAy6Z9AwoAbmV0d29ya19pZDgExS8KBgBzdGF0ZXMDCQBkaXJlY3Rpb24AAAAAAQgAb3Blbl9iaXQAAQ8AdXBzaWRlX2Rvd25fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:iron_bars", + "groupId": 7, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAAAACAQAbmFtZRMAbWluZWNyYWZ0Omlyb25fYmFycwQJAG5hbWVfaGFzaPuefWSNAe56AwoAbmV0d29ya19pZN2LB5IKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQUAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmdsYXNzBAkAbmFtZV9oYXNowGJByfWff6gDCgBuZXR3b3JrX2lk0hdLNwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:white_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAAAACAQAbmFtZR0AbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iHubqoMbu9fAMKAG5ldHdvcmtfaWRndBrUCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:light_gray_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaKKa+LrRsHQhAwoAbmV0d29ya19pZEv2giYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:gray_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAwAACAQAbmFtZRwAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaIETy7Y/HZREAwoAbmV0d29ya19pZDomVrUKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:black_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2iV6BCwpfDMmwMKAG5ldHdvcmtfaWSV7doJCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brown_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAwAACAQAbmFtZR0AbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2igsEiq5np8JgMKAG5ldHdvcmtfaWRMzE/lCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAwAACAQAbmFtZRsAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoCa2J12/lQoIDCgBuZXR3b3JrX2lk283lWAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:orange_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAwAACAQAbmFtZR4AbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNozgjAuvzhxGsDCgBuZXR3b3JrX2lkW5CkhQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:yellow_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAwAACAQAbmFtZR4AbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNo7EbHMd5WVugDCgBuZXR3b3JrX2lkkdDyXQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:lime_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAwAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBtZA1nZtwcFAwoAbmV0d29ya19pZDxX85UKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:green_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAwAACAQAbmFtZR0AbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3MECQBuYW1lX2hhc2h91ptDgbehWwMKAG5ldHdvcmtfaWTlDhnECgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cyan_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAwAACAQAbmFtZRwAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaBkIYQ8nQLqbAwoAbmV0d29ya19pZOL1lHsKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:light_blue_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAwAACAQAbmFtZSIAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaLt05n1G0fiSAwoAbmV0d29ya19pZNbwulIKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:blue_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaPhLocSfzduRAwoAbmV0d29ya19pZENsjFwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:purple_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAwAACAQAbmFtZR4AbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzBAkAbmFtZV9oYXNoJk0DhRO0szUDCgBuZXR3b3JrX2lkD98ZxgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:magenta_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAwAACAQAbmFtZR8AbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaFEDeFiJj3zSAwoAbmV0d29ya19pZG+iFRoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pink_stained_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzcwQJAG5hbWVfaGFzaDijTX87ywxhAwoAbmV0d29ya19pZKdEricKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:tinted_glass", + "groupId": 8, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAgAACAQAbmFtZRYAbWluZWNyYWZ0OnRpbnRlZF9nbGFzcwQJAG5hbWVfaGFzaAFZWSamk6KdAwoAbmV0d29ya19pZGSvWX8KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdsYXNzX3BhbmUECQBuYW1lX2hhc2gRSBHwNMQ4gQMKAG5ldHdvcmtfaWRGwixuCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:white_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAAAACAQAbmFtZSIAbWluZWNyYWZ0OndoaXRlX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaHgxQmgJVtRrAwoAbmV0d29ya19pZBEr/DYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:light_gray_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSJAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNon0aQw9lNkSEDCgBuZXR3b3JrX2lk9dp5VgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:gray_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSIAwAACAQAbmFtZSEAbWluZWNyYWZ0OmdyYXlfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNors74IIw+2MMDCgBuZXR3b3JrX2lkmrGO5woGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:black_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJsYWNrX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaOK/5ZRRd+M1AwoAbmV0d29ya19pZDv++oQKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:brown_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAwAACAQAbmFtZSIAbWluZWNyYWZ0OmJyb3duX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaLHeGJyRFTIWAwoAbmV0d29ya19pZMz9L0wKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:red_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAwAACAQAbmFtZSAAbWluZWNyYWZ0OnJlZF9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2gGr4x6JheAywMKAG5ldHdvcmtfaWQBjCTmCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:orange_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAwAACAQAbmFtZSMAbWluZWNyYWZ0Om9yYW5nZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hbHxPD2gEbEAMKAG5ldHdvcmtfaWSt/7a5CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:yellow_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAwAACAQAbmFtZSMAbWluZWNyYWZ0OnllbGxvd19zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2g9tl4aOCyZBwMKAG5ldHdvcmtfaWTXRAS7CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:lime_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAwAACAQAbmFtZSEAbWluZWNyYWZ0OmxpbWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3CtUyLwoGegDCgBuZXR3b3JrX2lkYJDnggoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:green_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAwAACAQAbmFtZSIAbWluZWNyYWZ0OmdyZWVuX3N0YWluZWRfZ2xhc3NfcGFuZQQJAG5hbWVfaGFzaJo6YP7IMy9SAwoAbmV0d29ya19pZHOnixoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cyan_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAwAACAQAbmFtZSEAbWluZWNyYWZ0OmN5YW5fc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoti97c6QrbLQDCgBuZXR3b3JrX2lkUqFUeQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:light_blue_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAwAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNovDg/gQle104DCgBuZXR3b3JrX2lkFuy4MQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:blue_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAwAACAQAbmFtZSEAbWluZWNyYWZ0OmJsdWVfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoGc57tiexbQMDCgBuZXR3b3JrX2lk1eBLUAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:purple_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAwAACAQAbmFtZSMAbWluZWNyYWZ0OnB1cnBsZV9zdGFpbmVkX2dsYXNzX3BhbmUECQBuYW1lX2hhc2hDJHYdd0FdfQMKAG5ldHdvcmtfaWSNsdK5CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:magenta_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAwAACAQAbmFtZSQAbWluZWNyYWZ0Om1hZ2VudGFfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNo3pcOw5bs5XoDCgBuZXR3b3JrX2lkVbOR7AoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:pink_stained_glass_pane", + "groupId": 9, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAwAACAQAbmFtZSEAbWluZWNyYWZ0OnBpbmtfc3RhaW5lZF9nbGFzc19wYW5lBAkAbmFtZV9oYXNoWRhSACMWgswDCgBuZXR3b3JrX2lkIR92xwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:ladder", + "groupId": 10, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBAAAACAQAbmFtZRAAbWluZWNyYWZ0OmxhZGRlcgQJAG5hbWVfaGFzaKBhqheJVOz+AwoAbmV0d29ya19pZCgvzlsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:scaffolding", + "groupId": 10, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNjYWZmb2xkaW5nBAkAbmFtZV9oYXNoYrkevrqcljwDCgBuZXR3b3JrX2lkD13mlAoGAHN0YXRlcwMJAHN0YWJpbGl0eQAAAAABDwBzdGFiaWxpdHlfY2hlY2sAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brick_block", + "groupId": 10, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAAAACAQAbmFtZRUAbWluZWNyYWZ0OmJyaWNrX2Jsb2NrBAkAbmFtZV9oYXNo5Qc2E005S3oDCgBuZXR3b3JrX2lkqeGWRgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:smooth_stone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAAAACAQAbmFtZRsAbWluZWNyYWZ0OnNtb290aF9zdG9uZV9zbGFiBAkAbmFtZV9oYXNon5I1yVw74uMDCgBuZXR3b3JrX2lkqvjcBQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:normal_stone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCBAAACAQAbmFtZRsAbWluZWNyYWZ0Om5vcm1hbF9zdG9uZV9zbGFiBAkAbmFtZV9oYXNoIvsjJLQdolcDCgBuZXR3b3JrX2lkC1zqRQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cobblestone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoBAAACAQAbmFtZRoAbWluZWNyYWZ0OmNvYmJsZXN0b25lX3NsYWIECQBuYW1lX2hhc2h5CXtW7vlQVgMKAG5ldHdvcmtfaWRDGyj2CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mossy_cobblestone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR3BAAACAQAbmFtZSAAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lX3NsYWIECQBuYW1lX2hhc2ijm1BCwB82VgMKAG5ldHdvcmtfaWR7ByMGCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:oak_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha19zbGFiBAkAbmFtZV9oYXNoJp1Cp1M4jlwDCgBuZXR3b3JrX2lkZH6+owoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:spruce_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV9zbGFiBAkAbmFtZV9oYXNodQi70jB238cDCgBuZXR3b3JrX2lkrriOYQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:birch_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3NsYWIECQBuYW1lX2hhc2gZPpfMxoOsTAMKAG5ldHdvcmtfaWThR9jyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:jungle_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV9zbGFiBAkAbmFtZV9oYXNo6gLs79NXak4DCgBuZXR3b3JrX2lk5ZiKgwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:acacia_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV9zbGFiBAkAbmFtZV9oYXNomSdFmDnv4OUDCgBuZXR3b3JrX2lkHttaXAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dark_oak_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3NsYWIECQBuYW1lX2hhc2hJjTohRFyhIQMKAG5ldHdvcmtfaWRMzDTyCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mangrove_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3NsYWIECQBuYW1lX2hhc2jYCcmhJPeNMwMKAG5ldHdvcmtfaWQx6U1yCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cherry_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV9zbGFiBAkAbmFtZV9oYXNoTt0MmVn/mqoDCgBuZXR3b3JrX2lk2VVsZQoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pale_oak_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlBAAACAQAbmFtZRcAbWluZWNyYWZ0OnBhbGVfb2FrX3NsYWIECQBuYW1lX2hhc2g9QqTGUjo2XgMKAG5ldHdvcmtfaWQoWvcmCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:bamboo_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQAAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJhbWJvb19zbGFiBAkAbmFtZV9oYXNoo1xuFqINeLYDCgBuZXR3b3JrX2lkVC+0twoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bamboo_mosaic_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAwAACAQAbmFtZRwAbWluZWNyYWZ0OmJhbWJvb19tb3NhaWNfc2xhYgQJAG5hbWVfaGFzaNbVRBZ/ChI3AwoAbmV0d29ya19pZOLZHFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stone_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqBAAACAQAbmFtZRoAbWluZWNyYWZ0OnN0b25lX2JyaWNrX3NsYWIECQBuYW1lX2hhc2js6EexuKuzrQMKAG5ldHdvcmtfaWRSsMxaCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mossy_stone_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAQAACAQAbmFtZSAAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrX3NsYWIECQBuYW1lX2hhc2hiA4kFUl4tHAMKAG5ldHdvcmtfaWS6joSOCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:sandstone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnBAAACAQAbmFtZRgAbWluZWNyYWZ0OnNhbmRzdG9uZV9zbGFiBAkAbmFtZV9oYXNo/GMI0MZnrhsDCgBuZXR3b3JrX2lkFP8WmwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cut_sandstone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDBAAACAQAbmFtZRwAbWluZWNyYWZ0OmN1dF9zYW5kc3RvbmVfc2xhYgQJAG5hbWVfaGFzaE+zxVQweViJAwoAbmV0d29ya19pZHsu74YKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:smooth_sandstone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4BAAACAQAbmFtZR8AbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmVfc2xhYgQJAG5hbWVfaGFzaIkmsO1gw3gnAwoAbmV0d29ya19pZFSiwP0KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_sandstone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmVfc2xhYgQJAG5hbWVfaGFzaEyDjeWlUHItAwoAbmV0d29ya19pZIT4rmwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cut_red_sandstone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEBAAACAQAbmFtZSAAbWluZWNyYWZ0OmN1dF9yZWRfc2FuZHN0b25lX3NsYWIECQBuYW1lX2hhc2hTVRS++snU3wMKAG5ldHdvcmtfaWSvIAviCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:smooth_red_sandstone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6BAAACAQAbmFtZSMAbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lX3NsYWIECQBuYW1lX2hhc2i9iN2UK272tgMKAG5ldHdvcmtfaWRUZrwJCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:granite_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/BAAACAQAbmFtZRYAbWluZWNyYWZ0OmdyYW5pdGVfc2xhYgQJAG5hbWVfaGFzaL0HprlAhhZwAwoAbmV0d29ya19pZIcIdc8KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_granite_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSABAAACAQAbmFtZR8AbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGVfc2xhYgQJAG5hbWVfaGFzaP6bXk5w2dGrAwoAbmV0d29ya19pZCsRy1cKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:diorite_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9BAAACAQAbmFtZRYAbWluZWNyYWZ0OmRpb3JpdGVfc2xhYgQJAG5hbWVfaGFzaM3ppS8v55sNAwoAbmV0d29ya19pZB+Pv9oKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_diorite_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+BAAACAQAbmFtZR8AbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGVfc2xhYgQJAG5hbWVfaGFzaLZlyJLkMPhyAwoAbmV0d29ya19pZFM0HYwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:andesite_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8BAAACAQAbmFtZRcAbWluZWNyYWZ0OmFuZGVzaXRlX3NsYWIECQBuYW1lX2hhc2icIrtuy/aosAMKAG5ldHdvcmtfaWTtXTtYCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_andesite_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7BAAACAQAbmFtZSAAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlX3NsYWIECQBuYW1lX2hhc2j56zJOfCF+3wMKAG5ldHdvcmtfaWRBs69FCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJyaWNrX3NsYWIECQBuYW1lX2hhc2hO/Da4jU2v4wMKAG5ldHdvcmtfaWRG/qphCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:nether_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsBAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl9icmlja19zbGFiBAkAbmFtZV9oYXNonymoa2zbbqMDCgBuZXR3b3JrX2lkquvR1QoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:red_nether_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5BAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaG89ujUk3Y64AwoAbmV0d29ya19pZEZIunAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:end_stone_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAQAACAQAbmFtZR4AbWluZWNyYWZ0OmVuZF9zdG9uZV9icmlja19zbGFiBAkAbmFtZV9oYXNo4tkxQtl+IyQDCgBuZXR3b3JrX2lkhByH/woGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:quartz_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrBAAACAQAbmFtZRUAbWluZWNyYWZ0OnF1YXJ0el9zbGFiBAkAbmFtZV9oYXNo9JMj3upfsbwDCgBuZXR3b3JrX2lkn2g2VAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:smooth_quartz_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBBAAACAQAbmFtZRwAbWluZWNyYWZ0OnNtb290aF9xdWFydHpfc2xhYgQJAG5hbWVfaGFzaHOSJv8ve0nmAwoAbmV0d29ya19pZFMk/JsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:purpur_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRzBAAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnB1cl9zbGFiBAkAbmFtZV9oYXNo4XeWbKpx2ScDCgBuZXR3b3JrX2lkRkga5goGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:prismarine_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0BAAACAQAbmFtZRkAbWluZWNyYWZ0OnByaXNtYXJpbmVfc2xhYgQJAG5hbWVfaGFzaI9x+1fY8QRfAwoAbmV0d29ya19pZBTUZhwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dark_prismarine_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR1BAAACAQAbmFtZR4AbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZV9zbGFiBAkAbmFtZV9oYXNoSsZGDkEL5ZUDCgBuZXR3b3JrX2lkNLQ8VwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:prismarine_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR2BAAACAQAbmFtZR8AbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaB1FSbVi97xJAwoAbmV0d29ya19pZEBwwFMKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:crimson_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc2xhYgQJAG5hbWVfaGFzaKZ+EfP0ZYOZAwoAbmV0d29ya19pZAxRUWAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:warped_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAgAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zbGFiBAkAbmFtZV9oYXNo/AT0e/Z9W7UDCgBuZXR3b3JrX2lk1yq11AoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:blackstone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAgAACAQAbmFtZRkAbWluZWNyYWZ0OmJsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaF/DD4ZUlNgtAwoAbmV0d29ya19pZGy1DjwKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_blackstone_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAgAACAQAbmFtZSIAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfc2xhYgQJAG5hbWVfaGFzaDYnuUs86EWfAwoAbmV0d29ya19pZJj2bXIKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_blackstone_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAgAACAQAbmFtZSgAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaKySLqvHc4xXAwoAbmV0d29ya19pZOyWX94KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cobbled_deepslate_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AgAACAQAbmFtZSAAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlX3NsYWIECQBuYW1lX2hhc2gwJIVWK1TM2QMKAG5ldHdvcmtfaWTYAoX5CgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_deepslate_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AgAACAQAbmFtZSEAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZV9zbGFiBAkAbmFtZV9oYXNoC/Adiz8k6RYDCgBuZXR3b3JrX2lkuFYMAAoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:deepslate_tile_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlX3NsYWIECQBuYW1lX2hhc2hPydV6emzIXAMKAG5ldHdvcmtfaWQwlbFCCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:deepslate_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSHAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja19zbGFiBAkAbmFtZV9oYXNoSv62V7iw10UDCgBuZXR3b3JrX2lkWMoragoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:tuff_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAwAACAQAbmFtZRMAbWluZWNyYWZ0OnR1ZmZfc2xhYgQJAG5hbWVfaGFzaIhCGdlIsnMUAwoAbmV0d29ya19pZN1dUL4KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_tuff_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAwAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmZfc2xhYgQJAG5hbWVfaGFzaLXdb48YvAsHAwoAbmV0d29ya19pZAnJ7W0KBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:tuff_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTyAwAACAQAbmFtZRkAbWluZWNyYWZ0OnR1ZmZfYnJpY2tfc2xhYgQJAG5hbWVfaGFzaLqPMjVCv5dIAwoAbmV0d29ya19pZOmeRhcKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:mud_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAgAACAQAbmFtZRgAbWluZWNyYWZ0Om11ZF9icmlja19zbGFiBAkAbmFtZV9oYXNoq/tGBQWkv08DCgBuZXR3b3JrX2lkl4nnMwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cut_copper_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAgAACAQAbmFtZRkAbWluZWNyYWZ0OmN1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaDsNpb2qs4iBAwoAbmV0d29ya19pZOTm2nsKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:exposed_cut_copper_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAgAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNoahQ5OwIQb7kDCgBuZXR3b3JrX2lkrUlZLwoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:weathered_cut_copper_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAgAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2hBIuGIOVVXogMKAG5ldHdvcmtfaWQgnaDiCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:oxidized_cut_copper_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAgAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaOptj9ycfpaDAwoAbmV0d29ya19pZMzFSRgKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_cut_copper_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaAlx6DZOCTHzAwoAbmV0d29ya19pZFRBvDAKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_exposed_cut_copper_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAgAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcl9zbGFiBAkAbmFtZV9oYXNo3KqS5OnhtRIDCgBuZXR3b3JrX2lkHTGcTgoGAHN0YXRlcwgXAG1pbmVjcmFmdDp2ZXJ0aWNhbF9oYWxmBgBib3R0b20AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_weathered_cut_copper_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAgAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyX3NsYWIECQBuYW1lX2hhc2gzZ1oX0HCFtwMKAG5ldHdvcmtfaWSgJR+XCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTAAgAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXJfc2xhYgQJAG5hbWVfaGFzaMjjTnLu1KcqAwoAbmV0d29ya19pZIxsnFYKBgBzdGF0ZXMIFwBtaW5lY3JhZnQ6dmVydGljYWxfaGFsZgYAYm90dG9tAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:resin_brick_slab", + "groupId": 11, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT1BAAACAQAbmFtZRoAbWluZWNyYWZ0OnJlc2luX2JyaWNrX3NsYWIECQBuYW1lX2hhc2hAGu/Hlaa12QMKAG5ldHdvcmtfaWSyDq8CCgYAc3RhdGVzCBcAbWluZWNyYWZ0OnZlcnRpY2FsX2hhbGYGAGJvdHRvbQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stone_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2JyaWNrcwQJAG5hbWVfaGFzaGAiQu8VWVJRAwoAbmV0d29ya19pZH2DjXUKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mossy_stone_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjBAAACAQAbmFtZRwAbWluZWNyYWZ0Om1vc3N5X3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaIZBO00MONRIAwoAbmV0d29ya19pZL2WDrAKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cracked_stone_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkBAAACAQAbmFtZR4AbWluZWNyYWZ0OmNyYWNrZWRfc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNocIkAp6riMz4DCgBuZXR3b3JrX2lkTWGeCwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:chiseled_stone_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlBAAACAQAbmFtZR8AbWluZWNyYWZ0OmNoaXNlbGVkX3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaMB2FPLLADkEAwoAbmV0d29ya19pZOIPn0IKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:smooth_stone", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2AQAACAQAbmFtZRYAbWluZWNyYWZ0OnNtb290aF9zdG9uZQQJAG5hbWVfaGFzaMwf87/JaTNvAwoAbmV0d29ya19pZLkZICEKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:end_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAAAACAQAbmFtZRQAbWluZWNyYWZ0OmVuZF9icmlja3MECQBuYW1lX2hhc2hIUFfxNLZaFgMKAG5ldHdvcmtfaWQ/vDihCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_blackstone_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoIHgsgIdzKXcDCgBuZXR3b3JrX2lkUw9b3woGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cracked_polished_blackstone_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAgAACAQAbmFtZSwAbWluZWNyYWZ0OmNyYWNrZWRfcG9saXNoZWRfYmxhY2tzdG9uZV9icmlja3MECQBuYW1lX2hhc2jQIO1GQDk80AMKAG5ldHdvcmtfaWQ3UlRYCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:gilded_blackstone", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAgAACAQAbmFtZRsAbWluZWNyYWZ0OmdpbGRlZF9ibGFja3N0b25lBAkAbmFtZV9oYXNoNoWt1ocG0HEDCgBuZXR3b3JrX2lktL8gUwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:chiseled_polished_blackstone", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAgAACAQAbmFtZSYAbWluZWNyYWZ0OmNoaXNlbGVkX3BvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2gzFa+kEjCJgAMKAG5ldHdvcmtfaWR2NJX2CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:deepslate_tiles", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAgAACAQAbmFtZRkAbWluZWNyYWZ0OmRlZXBzbGF0ZV90aWxlcwQJAG5hbWVfaGFzaGcLLx3NXAFvAwoAbmV0d29ya19pZI/G/xYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cracked_deepslate_tiles", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAgAACAQAbmFtZSEAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX3RpbGVzBAkAbmFtZV9oYXNo9zWgkFuMM1QDCgBuZXR3b3JrX2lkGwY6OgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:deepslate_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSGAgAACAQAbmFtZRoAbWluZWNyYWZ0OmRlZXBzbGF0ZV9icmlja3MECQBuYW1lX2hhc2gucvFmPdZxigMKAG5ldHdvcmtfaWSH4HDPCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:tuff_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAwAACAQAbmFtZRUAbWluZWNyYWZ0OnR1ZmZfYnJpY2tzBAkAbmFtZV9oYXNo/hbQ+mXSK7wDCgBuZXR3b3JrX2lk6gmIwQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cracked_deepslate_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAgAACAQAbmFtZSIAbWluZWNyYWZ0OmNyYWNrZWRfZGVlcHNsYXRlX2JyaWNrcwQJAG5hbWVfaGFzaN40aqhh9WqHAwoAbmV0d29ya19pZO9GPBQKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chiseled_deepslate", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAgAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaEU7/uRG8HSBAwoAbmV0d29ya19pZEqmI0EKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chiseled_tuff", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoaXNlbGVkX3R1ZmYECQBuYW1lX2hhc2iVliOT8OTQ9AMKAG5ldHdvcmtfaWTLNKOiCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:chiseled_tuff_bricks", + "groupId": 12, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT2AwAACAQAbmFtZR4AbWluZWNyYWZ0OmNoaXNlbGVkX3R1ZmZfYnJpY2tzBAkAbmFtZV9oYXNo3oQw6gmxYuADCgBuZXR3b3JrX2lkm3D8AgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cobblestone", + "groupId": 13, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYmJsZXN0b25lBAkAbmFtZV9oYXNoPoK7mGlSUz4DCgBuZXR3b3JrX2lkLm7RZwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mossy_cobblestone", + "groupId": 13, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAAAACAQAbmFtZRsAbWluZWNyYWZ0Om1vc3N5X2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoGJ67FCbkChMDCgBuZXR3b3JrX2lk/pYs1AoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cobbled_deepslate", + "groupId": 13, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AgAACAQAbmFtZRsAbWluZWNyYWZ0OmNvYmJsZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoLUz9Y/ywmLwDCgBuZXR3b3JrX2lkNwzZ+AoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:sandstone", + "groupId": 14, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNhbmRzdG9uZQQJAG5hbWVfaGFzaFEmWsEHFI1AAwoAbmV0d29ya19pZPsXMaQKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chiseled_sandstone", + "groupId": 14, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvBAAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX3NhbmRzdG9uZQQJAG5hbWVfaGFzaPEkxMvZmemgAwoAbmV0d29ya19pZGI5NB4KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cut_sandstone", + "groupId": 14, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSwBAAACAQAbmFtZRcAbWluZWNyYWZ0OmN1dF9zYW5kc3RvbmUECQBuYW1lX2hhc2ichLQc71njnQMKAG5ldHdvcmtfaWSmBLkRCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:smooth_sandstone", + "groupId": 14, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSxBAAACAQAbmFtZRoAbWluZWNyYWZ0OnNtb290aF9zYW5kc3RvbmUECQBuYW1lX2hhc2huR7XTwISyCAMKAG5ldHdvcmtfaWSzWj3UCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_sandstone", + "groupId": 14, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzAAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2jBO4Gv2v59uAMKAG5ldHdvcmtfaWRXRYxZCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:chiseled_red_sandstone", + "groupId": 14, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS7BAAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX3JlZF9zYW5kc3RvbmUECQBuYW1lX2hhc2gh5sX+ON054wMKAG5ldHdvcmtfaWT6Pw1PCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cut_red_sandstone", + "groupId": 14, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS8BAAACAQAbmFtZRsAbWluZWNyYWZ0OmN1dF9yZWRfc2FuZHN0b25lBAkAbmFtZV9oYXNoaOtka4NrQ1EDCgBuZXR3b3JrX2lk3r/JPAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:smooth_red_sandstone", + "groupId": 14, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS9BAAACAQAbmFtZR4AbWluZWNyYWZ0OnNtb290aF9yZWRfc2FuZHN0b25lBAkAbmFtZV9oYXNoqsNl8x36ju4DCgBuZXR3b3JrX2lk7x5DTwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:coal_block", + "groupId": 15, + "block_state_b64": "CgAAAwgAYmxvY2tfaWStAAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvYWxfYmxvY2sECQBuYW1lX2hhc2jH8QQP3t5PiAMKAG5ldHdvcmtfaWRo+sR+CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dried_kelp_block", + "groupId": 15, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAQAACAQAbmFtZRoAbWluZWNyYWZ0OmRyaWVkX2tlbHBfYmxvY2sECQBuYW1lX2hhc2iRoucexkrl8wMKAG5ldHdvcmtfaWQQCCrvCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:copper_block", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAgAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ibG9jawQJAG5hbWVfaGFzaDVxnehsGaZ1AwoAbmV0d29ya19pZIiUodwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:weathered_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAgAACAQAbmFtZRoAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2hJCQXbvobv+gMKAG5ldHdvcmtfaWQwM0lJCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:exposed_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAgAACAQAbmFtZRgAbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoQH3Fukmu3CEDCgBuZXR3b3JrX2lk72jFIwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:oxidized_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMDtJqR0G5Y7AwoAbmV0d29ya19pZGjN8bUKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAgAACAQAbmFtZRYAbWluZWNyYWZ0OndheGVkX2NvcHBlcgQJAG5hbWVfaGFzaPF+FG6Eh5fsAwoAbmV0d29ya19pZIjtz/0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_exposed_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAgAACAQAbmFtZR4AbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyBAkAbmFtZV9oYXNoig8IOc+SCikDCgBuZXR3b3JrX2lklz8yWQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_weathered_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAgAACAQAbmFtZSAAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXIECQBuYW1lX2hhc2gjtPq8MOdvKgMKAG5ldHdvcmtfaWSQ9Ln9CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_oxidized_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS9AgAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcgQJAG5hbWVfaGFzaMaORhsO+LzjAwoAbmV0d29ya19pZJhGfLEKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:copper_grate", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT/AwAACAQAbmFtZRYAbWluZWNyYWZ0OmNvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaC/JEFOWnmEcAwoAbmV0d29ya19pZC6YiiMKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:exposed_copper_grate", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQABAAACAQAbmFtZR4AbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX2dyYXRlBAkAbmFtZV9oYXNolFIBYLYU0IcDCgBuZXR3b3JrX2lk4UqptAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:weathered_copper_grate", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBBAAACAQAbmFtZSAAbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfZ3JhdGUECQBuYW1lX2hhc2jB3o8enlv1RgMKAG5ldHdvcmtfaWRih2pOCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:oxidized_copper_grate", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCBAAACAQAbmFtZR8AbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaBRfNhyndve7AwoAbmV0d29ya19pZKY2cnEKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_copper_grate", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDBAAACAQAbmFtZRwAbWluZWNyYWZ0OndheGVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaDmC92M2RO+HAwoAbmV0d29ya19pZH4og2AKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_exposed_copper_grate", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEBAAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX2dyYXRlBAkAbmFtZV9oYXNoWmd6B+hWwiEDCgBuZXR3b3JrX2lk8d4ZQwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_weathered_copper_grate", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFBAAACAQAbmFtZSYAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfZ3JhdGUECQBuYW1lX2hhc2hXfilVFDAiYQMKAG5ldHdvcmtfaWQqTGC1CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_oxidized_copper_grate", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGBAAACAQAbmFtZSUAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl9ncmF0ZQQJAG5hbWVfaGFzaEbeMT605GP4AwoAbmV0d29ya19pZOZjpkkKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cut_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAgAACAQAbmFtZRQAbWluZWNyYWZ0OmN1dF9jb3BwZXIECQBuYW1lX2hhc2hAfN3NGax3eAMKAG5ldHdvcmtfaWTnFBtYCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:exposed_cut_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAgAACAQAbmFtZRwAbWluZWNyYWZ0OmV4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaA85G3yv/w6pAwoAbmV0d29ya19pZMQhr0QKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:weathered_cut_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAgAACAQAbmFtZR4AbWluZWNyYWZ0OndlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoVgRV0fBaz88DCgBuZXR3b3JrX2lk/0cYugoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:oxidized_cut_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAgAACAQAbmFtZR0AbWluZWNyYWZ0Om94aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2iP8WmFWOkriwMKAG5ldHdvcmtfaWQPdce7CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_cut_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWReAgAACAQAbmFtZRoAbWluZWNyYWZ0OndheGVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2jumiwOZIqv2AMKAG5ldHdvcmtfaWQvuxx9CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_exposed_cut_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAgAACAQAbmFtZSIAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY3V0X2NvcHBlcgQJAG5hbWVfaGFzaPE/OfK6IoVMAwoAbmV0d29ya19pZHy5HkcKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_weathered_cut_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAgAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jdXRfY29wcGVyBAkAbmFtZV9oYXNoCA1xDp11bnwDCgBuZXR3b3JrX2lkDyEDVQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_oxidized_cut_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS+AgAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2N1dF9jb3BwZXIECQBuYW1lX2hhc2i1pZAsZYHLDAMKAG5ldHdvcmtfaWQ/wSkCCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:chiseled_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT3AwAACAQAbmFtZRkAbWluZWNyYWZ0OmNoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaIsW5pmpJEuQAwoAbmV0d29ya19pZHetwrkKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:exposed_chiseled_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT4AwAACAQAbmFtZSEAbWluZWNyYWZ0OmV4cG9zZWRfY2hpc2VsZWRfY29wcGVyBAkAbmFtZV9oYXNoOvrLJ0UowbgDCgBuZXR3b3JrX2lkZj7cPwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:weathered_chiseled_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT5AwAACAQAbmFtZSMAbWluZWNyYWZ0OndlYXRoZXJlZF9jaGlzZWxlZF9jb3BwZXIECQBuYW1lX2hhc2hh+42XlsWvGAMKAG5ldHdvcmtfaWS7Cy59CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:oxidized_chiseled_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT6AwAACAQAbmFtZSIAbWluZWNyYWZ0Om94aWRpemVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaLpTIsnfluiCAwoAbmV0d29ya19pZB9/jS8KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_chiseled_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AwAACAQAbmFtZR8AbWluZWNyYWZ0OndheGVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaFnXvXY5OinzAwoAbmV0d29ya19pZAcKtHsKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_exposed_chiseled_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT8AwAACAQAbmFtZScAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY2hpc2VsZWRfY29wcGVyBAkAbmFtZV9oYXNoHJdq+Pph6hMDCgBuZXR3b3JrX2lkdge7IAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_oxidized_chiseled_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9AwAACAQAbmFtZSgAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NoaXNlbGVkX2NvcHBlcgQJAG5hbWVfaGFzaMj49OvlTpgCAwoAbmV0d29ya19pZN/r+roKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_weathered_chiseled_copper", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AwAACAQAbmFtZSkAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jaGlzZWxlZF9jb3BwZXIECQBuYW1lX2hhc2hzuO+Sg9LYQwMKAG5ldHdvcmtfaWQ7AN7iCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:copper_bulb", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHBAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvcHBlcl9idWxiBAkAbmFtZV9oYXNo41TimHOsMWcDCgBuZXR3b3JrX2lkJnZvAgoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:exposed_copper_bulb", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIBAAACAQAbmFtZR0AbWluZWNyYWZ0OmV4cG9zZWRfY29wcGVyX2J1bGIECQBuYW1lX2hhc2g++f1wYLLCrAMKAG5ldHdvcmtfaWRLdMmGCgYAc3RhdGVzAQMAbGl0AAELAHBvd2VyZWRfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:weathered_copper_bulb", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQJBAAACAQAbmFtZR8AbWluZWNyYWZ0OndlYXRoZXJlZF9jb3BwZXJfYnVsYgQJAG5hbWVfaGFzaMEtsYfwRTXlAwoAbmV0d29ya19pZAp51LQKBgBzdGF0ZXMBAwBsaXQAAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:oxidized_copper_bulb", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKBAAACAQAbmFtZR4AbWluZWNyYWZ0Om94aWRpemVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNovnrBQZs8nDIDCgBuZXR3b3JrX2lkPsj0AAoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_copper_bulb", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLBAAACAQAbmFtZRsAbWluZWNyYWZ0OndheGVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNoGTg6TYllMiIDCgBuZXR3b3JrX2lk9m0WhgoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waxed_exposed_copper_bulb", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMBAAACAQAbmFtZSMAbWluZWNyYWZ0OndheGVkX2V4cG9zZWRfY29wcGVyX2J1bGIECQBuYW1lX2hhc2gI6xkPcvBDVwMKAG5ldHdvcmtfaWR7BRcACgYAc3RhdGVzAQMAbGl0AAELAHBvd2VyZWRfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:waxed_weathered_copper_bulb", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNBAAACAQAbmFtZSUAbWluZWNyYWZ0OndheGVkX3dlYXRoZXJlZF9jb3BwZXJfYnVsYgQJAG5hbWVfaGFzaMsUnmp3/VqVAwoAbmV0d29ya19pZEoworoKBgBzdGF0ZXMBAwBsaXQAAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:waxed_oxidized_copper_bulb", + "groupId": 16, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOBAAACAQAbmFtZSQAbWluZWNyYWZ0OndheGVkX294aWRpemVkX2NvcHBlcl9idWxiBAkAbmFtZV9oYXNoBFKxY3fjVq4DCgBuZXR3b3JrX2lkzrJ6aAoGAHN0YXRlcwEDAGxpdAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:iron_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAAAACAQAbmFtZRQAbWluZWNyYWZ0Omlyb25fYmxvY2sECQBuYW1lX2hhc2jYINmJQbvV/gMKAG5ldHdvcmtfaWRf7AbICgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:gold_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdvbGRfYmxvY2sECQBuYW1lX2hhc2iYLshvjtXzFwMKAG5ldHdvcmtfaWTDJGBcCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:emerald_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAAAACAQAbmFtZRcAbWluZWNyYWZ0OmVtZXJhbGRfYmxvY2sECQBuYW1lX2hhc2hK6QunqJznNAMKAG5ldHdvcmtfaWRk5+otCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:diamond_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AAAACAQAbmFtZRcAbWluZWNyYWZ0OmRpYW1vbmRfYmxvY2sECQBuYW1lX2hhc2iGKrxuvkytFQMKAG5ldHdvcmtfaWQQeQZXCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:lapis_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxhcGlzX2Jsb2NrBAkAbmFtZV9oYXNoDZ44xdb2zVoDCgBuZXR3b3JrX2lktVy0BAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:raw_copper_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAgAACAQAbmFtZRoAbWluZWNyYWZ0OnJhd19jb3BwZXJfYmxvY2sECQBuYW1lX2hhc2hw1KG0TNUGgwMKAG5ldHdvcmtfaWS1vGo/CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:raw_iron_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19pcm9uX2Jsb2NrBAkAbmFtZV9oYXNo9XyzNIQXxvwDCgBuZXR3b3JrX2lknms1QAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:raw_gold_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJhd19nb2xkX2Jsb2NrBAkAbmFtZV9oYXNo6YuwuLwfOBwDCgBuZXR3b3JrX2lkLiQ5gQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:quartz_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAAAACAQAbmFtZRYAbWluZWNyYWZ0OnF1YXJ0el9ibG9jawQJAG5hbWVfaGFzaCfpbqyIIvZCAwoAbmV0d29ya19pZE2axGsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:quartz_bricks", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAgAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9icmlja3MECQBuYW1lX2hhc2jSZO590dd8sAMKAG5ldHdvcmtfaWSc5xCLCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:quartz_pillar", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS5BAAACAQAbmFtZRcAbWluZWNyYWZ0OnF1YXJ0el9waWxsYXIECQBuYW1lX2hhc2igp62HI+PuSwMKAG5ldHdvcmtfaWS9SGXLCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chiseled_quartz_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS4BAAACAQAbmFtZR8AbWluZWNyYWZ0OmNoaXNlbGVkX3F1YXJ0el9ibG9jawQJAG5hbWVfaGFzaAftJM9mCAvaAwoAbmV0d29ya19pZFwy0s0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:smooth_quartz", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS6BAAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9xdWFydHoECQBuYW1lX2hhc2hIVzzgiItGagMKAG5ldHdvcmtfaWTVWgU2CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:prismarine", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAAAACAQAbmFtZRQAbWluZWNyYWZ0OnByaXNtYXJpbmUECQBuYW1lX2hhc2jcnQCHi9CspQMKAG5ldHdvcmtfaWQnuuW1CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:prismarine_bricks", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSzBAAACAQAbmFtZRsAbWluZWNyYWZ0OnByaXNtYXJpbmVfYnJpY2tzBAkAbmFtZV9oYXNozeGe3/7s5fcDCgBuZXR3b3JrX2lkj/iBnAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dark_prismarine", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSyBAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfcHJpc21hcmluZQQJAG5hbWVfaGFzaK+rhxsgkzplAwoAbmV0d29ya19pZIdA0I0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:slime", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnNsaW1lBAkAbmFtZV9oYXNoHJiEEJx+JlkDCgBuZXR3b3JrX2lkfgfVzAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:honey_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAQAACAQAbmFtZRUAbWluZWNyYWZ0OmhvbmV5X2Jsb2NrBAkAbmFtZV9oYXNo9zLYSUlelywDCgBuZXR3b3JrX2lko+dyWgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:honeycomb_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAQAACAQAbmFtZRkAbWluZWNyYWZ0OmhvbmV5Y29tYl9ibG9jawQJAG5hbWVfaGFzaASIPuOCYd1oAwoAbmV0d29ya19pZKys4n4KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:resin_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT8BAAACAQAbmFtZRUAbWluZWNyYWZ0OnJlc2luX2Jsb2NrBAkAbmFtZV9oYXNo6SHuLxdB67QDCgBuZXR3b3JrX2lkcWO4EwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:hay_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAAAACAQAbmFtZRMAbWluZWNyYWZ0OmhheV9ibG9jawQJAG5hbWVfaGFzaIB2VxKxX8EpAwoAbmV0d29ya19pZKuQSloKBgBzdGF0ZXMDCgBkZXByZWNhdGVkAAAAAAgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:bone_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAAAACAQAbmFtZRQAbWluZWNyYWZ0OmJvbmVfYmxvY2sECQBuYW1lX2hhc2i4ZX576W9AWgMKAG5ldHdvcmtfaWTWGacQCgYAc3RhdGVzAwoAZGVwcmVjYXRlZAAAAAAICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:resin_bricks", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT0BAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlc2luX2JyaWNrcwQJAG5hbWVfaGFzaPQfo5PcOZSaAwoAbmV0d29ya19pZB24YHwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chiseled_resin_bricks", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT7BAAACAQAbmFtZR8AbWluZWNyYWZ0OmNoaXNlbGVkX3Jlc2luX2JyaWNrcwQJAG5hbWVfaGFzaNSCIvsamt6qAwoAbmV0d29ya19pZBY+3hYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:nether_brick", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAAAACAQAbmFtZRYAbWluZWNyYWZ0Om5ldGhlcl9icmljawQJAG5hbWVfaGFzaMxcRiheU+nXAwoAbmV0d29ya19pZMkmzloKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:red_nether_brick", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAAAACAQAbmFtZRoAbWluZWNyYWZ0OnJlZF9uZXRoZXJfYnJpY2sECQBuYW1lX2hhc2j8pRO4LfoECAMKAG5ldHdvcmtfaWRpdF0YCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:chiseled_nether_bricks", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNoaXNlbGVkX25ldGhlcl9icmlja3MECQBuYW1lX2hhc2g31SBPTcUK1QMKAG5ldHdvcmtfaWS8TJ+TCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cracked_nether_bricks", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAgAACAQAbmFtZR8AbWluZWNyYWZ0OmNyYWNrZWRfbmV0aGVyX2JyaWNrcwQJAG5hbWVfaGFzaAdC6eKzXT5tAwoAbmV0d29ya19pZIUSejwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:netherite_block", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcml0ZV9ibG9jawQJAG5hbWVfaGFzaMghh6Zib/ZKAwoAbmV0d29ya19pZIz0mq0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:lodestone", + "groupId": 17, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAQAACAQAbmFtZRMAbWluZWNyYWZ0OmxvZGVzdG9uZQQJAG5hbWVfaGFzaJ2gmHOTlXv8AwoAbmV0d29ya19pZEfgB4wKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:white_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAAAACAQAbmFtZRQAbWluZWNyYWZ0OndoaXRlX3dvb2wECQBuYW1lX2hhc2jRWB7vaIEDiQMKAG5ldHdvcmtfaWSO8paQCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:light_gray_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfd29vbAQJAG5hbWVfaGFzaOpdQ1a2v4b3AwoAbmV0d29ya19pZIqZCYEKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:gray_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAwAACAQAbmFtZRMAbWluZWNyYWZ0OmdyYXlfd29vbAQJAG5hbWVfaGFzaLsc1Lp1xdIOAwoAbmV0d29ya19pZFUs+HgKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:black_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrX3dvb2wECQBuYW1lX2hhc2hP2HC6o0X4HAMKAG5ldHdvcmtfaWRUbORcCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brown_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAwAACAQAbmFtZRQAbWluZWNyYWZ0OmJyb3duX3dvb2wECQBuYW1lX2hhc2ig5IW89PrREwMKAG5ldHdvcmtfaWRjT9j8CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAwAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF93b29sBAkAbmFtZV9oYXNoY4TBDq+mFgUDCgBuZXR3b3JrX2lktn9lcAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:orange_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAwAACAQAbmFtZRUAbWluZWNyYWZ0Om9yYW5nZV93b29sBAkAbmFtZV9oYXNoFstfrTZfSCgDCgBuZXR3b3JrX2lk+rqywwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:yellow_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtAwAACAQAbmFtZRUAbWluZWNyYWZ0OnllbGxvd193b29sBAkAbmFtZV9oYXNoTFyus2RHegcDCgBuZXR3b3JrX2lkkKBhXAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:lime_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAwAACAQAbmFtZRMAbWluZWNyYWZ0OmxpbWVfd29vbAQJAG5hbWVfaGFzaNVnnzKiMxmeAwoAbmV0d29ya19pZG9b32kKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:green_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAwAACAQAbmFtZRQAbWluZWNyYWZ0OmdyZWVuX3dvb2wECQBuYW1lX2hhc2i3mElRYHIcSQMKAG5ldHdvcmtfaWSssprwCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cyan_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwAwAACAQAbmFtZRMAbWluZWNyYWZ0OmN5YW5fd29vbAQJAG5hbWVfaGFzaBNDfvHn8dqFAwoAbmV0d29ya19pZK0hAbgKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:light_blue_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfd29vbAQJAG5hbWVfaGFzaLWFAUfyxFPNAwoAbmV0d29ya19pZL2oEugKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:blue_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAwAACAQAbmFtZRMAbWluZWNyYWZ0OmJsdWVfd29vbAQJAG5hbWVfaGFzaLjHyxxbTWCLAwoAbmV0d29ya19pZPaLdFQKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:purple_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAwAACAQAbmFtZRUAbWluZWNyYWZ0OnB1cnBsZV93b29sBAkAbmFtZV9oYXNojvFtqzjAf/4DCgBuZXR3b3JrX2lklqASNQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:magenta_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AwAACAQAbmFtZRYAbWluZWNyYWZ0Om1hZ2VudGFfd29vbAQJAG5hbWVfaGFzaGuOHvf+Pd4yAwoAbmV0d29ya19pZI4UoDQKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pink_wool", + "groupId": 18, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1AwAACAQAbmFtZRMAbWluZWNyYWZ0OnBpbmtfd29vbAQJAG5hbWVfaGFzaPiVA2pFeoFLAwoAbmV0d29ya19pZOZRO6oKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:white_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAAAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhcnBldAQJAG5hbWVfaGFzaNeMHTI1fWPXAwoAbmV0d29ya19pZEahDFcKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:light_gray_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FycGV0BAkAbmFtZV9oYXNoHPw6ArBAsP0DCgBuZXR3b3JrX2lkQoAeUAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:gray_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaAwAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FycGV0BAkAbmFtZV9oYXNoZVR0OI+1VRADCgBuZXR3b3JrX2lkETF4WwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:black_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhcnBldAQJAG5hbWVfaGFzaOk7LP9NptyhAwoAbmV0d29ya19pZFjmXtIKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:brown_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhcnBldAQJAG5hbWVfaGFzaNaXFyOsAvIvAwoAbmV0d29ya19pZHPjFuoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:red_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAwAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYXJwZXQECQBuYW1lX2hhc2i9eSKBf6SO3wMKAG5ldHdvcmtfaWQuhI/KCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:orange_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAwAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYXJwZXQECQBuYW1lX2hhc2hIUkO4HlAdygMKAG5ldHdvcmtfaWSyKV9OCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:yellow_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAwAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYXJwZXQECQBuYW1lX2hhc2hSDKX3scCamwMKAG5ldHdvcmtfaWT8nq+ECgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:lime_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAwAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FycGV0BAkAbmFtZV9oYXNo+6KFOpzsib4DCgBuZXR3b3JrX2lkT+DS4woGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:green_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgAwAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhcnBldAQJAG5hbWVfaGFzaCHPMP9ltqFJAwoAbmV0d29ya19pZBgwAvAKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cyan_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcAwAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FycGV0BAkAbmFtZV9oYXNobXf62dQBJj8DCgBuZXR3b3JrX2lkKVppLgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:light_blue_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAwAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FycGV0BAkAbmFtZV9oYXNo20l4oktdZ3sDCgBuZXR3b3JrX2lkjdeMiwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:blue_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWReAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FycGV0BAkAbmFtZV9oYXNo3p3lsW0eQwsDCgBuZXR3b3JrX2lkAovdPQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:purple_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdAwAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYXJwZXQECQBuYW1lX2hhc2jwIA9pW/qp7QMKAG5ldHdvcmtfaWTqJqhjCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:magenta_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVAwAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FycGV0BAkAbmFtZV9oYXNoFXT36YNNZhMDCgBuZXR3b3JrX2lk+tqsGAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:pink_carpet", + "groupId": 19, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FycGV0BAkAbmFtZV9oYXNoHll72oqk+OoDCgBuZXR3b3JrX2lkrnBYDwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:white_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTtAAAACAQAbmFtZR8AbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaFUk9iXVjwV8AwoAbmV0d29ya19pZJPZY8AKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:light_gray_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo7EUk30hmUtYDCgBuZXR3b3JrX2lkh8jVIwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:gray_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAwAACAQAbmFtZR4AbWluZWNyYWZ0OmdyYXlfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoW77af6WihdwDCgBuZXR3b3JrX2lkSsqC1woGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:black_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTSAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaAfWYp0xtgcfAwoAbmV0d29ya19pZMWTC8EKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:brown_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaB74EeiLO46XAwoAbmV0d29ya19pZEDHKqwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:red_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAwAACAQAbmFtZR0AbWluZWNyYWZ0OnJlZF9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gjFut6Z/VH1gMKAG5ldHdvcmtfaWSvcmwYCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:orange_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAwAACAQAbmFtZSAAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2gADDj2IJiw+gMKAG5ldHdvcmtfaWTHph0FCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:yellow_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAwAACAQAbmFtZSAAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iy6qKNn3ob5wMKAG5ldHdvcmtfaWQZAI39CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:lime_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAwAACAQAbmFtZR4AbWluZWNyYWZ0OmxpbWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNo4dYIPslbXPUDCgBuZXR3b3JrX2lk2O8X0AoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:green_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAwAACAQAbmFtZR8AbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlX3Bvd2RlcgQJAG5hbWVfaGFzaM/c9x2aJh3HAwoAbmV0d29ya19pZA0VfBMKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cyan_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAwAACAQAbmFtZR4AbWluZWNyYWZ0OmN5YW5fY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNok+xKAe7XXjoDCgBuZXR3b3JrX2lkmkn6uwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:light_blue_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAwAACAQAbmFtZSQAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNogScpIQceyAEDCgBuZXR3b3JrX2lkOmVSbgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:blue_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTOAwAACAQAbmFtZR4AbWluZWNyYWZ0OmJsdWVfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoFp7mmeL86r0DCgBuZXR3b3JrX2lkS3b3RQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:purple_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAwAACAQAbmFtZSAAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZV9wb3dkZXIECQBuYW1lX2hhc2iYcVU04hoStwMKAG5ldHdvcmtfaWQXimEjCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:magenta_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAwAACAQAbmFtZSEAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoy/70q6VPsWgDCgBuZXR3b3JrX2lkf9mxQwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:pink_concrete_powder", + "groupId": 20, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAwAACAQAbmFtZR4AbWluZWNyYWZ0OnBpbmtfY29uY3JldGVfcG93ZGVyBAkAbmFtZV9oYXNoVikSAf8DwV0DCgBuZXR3b3JrX2lku2MivwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:white_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsAAAACAQAbmFtZRgAbWluZWNyYWZ0OndoaXRlX2NvbmNyZXRlBAkAbmFtZV9oYXNo6zAp7lsLlvkDCgBuZXR3b3JrX2lk3MAYQAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:light_gray_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY29uY3JldGUECQBuYW1lX2hhc2hEtet5wuDIKAMKAG5ldHdvcmtfaWQISs02CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:gray_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AwAACAQAbmFtZRcAbWluZWNyYWZ0OmdyYXlfY29uY3JldGUECQBuYW1lX2hhc2j92INnb0a83AMKAG5ldHdvcmtfaWQj8RHwCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:black_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAwAACAQAbmFtZRgAbWluZWNyYWZ0OmJsYWNrX2NvbmNyZXRlBAkAbmFtZV9oYXNo2X7NDIQmZ70DCgBuZXR3b3JrX2lk2uiVDQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:brown_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AwAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX2NvbmNyZXRlBAkAbmFtZV9oYXNoeka02BwXf6oDCgBuZXR3b3JrX2lkYf+xDQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:red_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSAAwAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9jb25jcmV0ZQQJAG5hbWVfaGFzaPWmNowLGubqAwoAbmV0d29ya19pZKwyx58KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:orange_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRzAwAACAQAbmFtZRkAbWluZWNyYWZ0Om9yYW5nZV9jb25jcmV0ZQQJAG5hbWVfaGFzaAgE8XmaAi6+AwoAbmV0d29ya19pZMDQNz8KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:yellow_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR2AwAACAQAbmFtZRkAbWluZWNyYWZ0OnllbGxvd19jb25jcmV0ZQQJAG5hbWVfaGFzaE6ONfJPBd0+AwoAbmV0d29ya19pZMarutwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:lime_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR3AwAACAQAbmFtZRcAbWluZWNyYWZ0OmxpbWVfY29uY3JldGUECQBuYW1lX2hhc2gnd8JW6wmJcAMKAG5ldHdvcmtfaWTd47aoCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:green_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR/AwAACAQAbmFtZRgAbWluZWNyYWZ0OmdyZWVuX2NvbmNyZXRlBAkAbmFtZV9oYXNokbFxRKchQZkDCgBuZXR3b3JrX2lkmhZWUgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cyan_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AwAACAQAbmFtZRcAbWluZWNyYWZ0OmN5YW5fY29uY3JldGUECQBuYW1lX2hhc2hFRrWJ33qj1wMKAG5ldHdvcmtfaWQbi5b8CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:light_blue_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR1AwAACAQAbmFtZR0AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY29uY3JldGUECQBuYW1lX2hhc2gHAe0kl0SE4AMKAG5ldHdvcmtfaWRL/GbSCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:blue_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AwAACAQAbmFtZRcAbWluZWNyYWZ0OmJsdWVfY29uY3JldGUECQBuYW1lX2hhc2hiay301nnj1wMKAG5ldHdvcmtfaWRMvFXNCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:purple_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR8AwAACAQAbmFtZRkAbWluZWNyYWZ0OnB1cnBsZV9jb25jcmV0ZQQJAG5hbWVfaGFzaHBHflsPIwdXAwoAbmV0d29ya19pZCyKA5gKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:magenta_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AwAACAQAbmFtZRoAbWluZWNyYWZ0Om1hZ2VudGFfY29uY3JldGUECQBuYW1lX2hhc2gN7LuB/OvdZAMKAG5ldHdvcmtfaWTc6ZOdCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pink_concrete", + "groupId": 21, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpbmtfY29uY3JldGUECQBuYW1lX2hhc2ii2G5F0u3SOAMKAG5ldHdvcmtfaWSszGgrCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:hardened_clay", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSsAAAACAQAbmFtZRcAbWluZWNyYWZ0OmhhcmRlbmVkX2NsYXkECQBuYW1lX2hhc2jrnRwCJ0krJAMKAG5ldHdvcmtfaWRBCOrrCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:white_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAAAACAQAbmFtZRoAbWluZWNyYWZ0OndoaXRlX3RlcnJhY290dGEECQBuYW1lX2hhc2j3RSdgmnAIewMKAG5ldHdvcmtfaWSimKw+CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:light_gray_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2dyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAz1Ri3wIxomAwoAbmV0d29ya19pZH5qgOcKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:gray_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAwAACAQAbmFtZRkAbWluZWNyYWZ0OmdyYXlfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAXdSLAaNZ9vAwoAbmV0d29ya19pZM1QDV0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:black_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsYWNrX3RlcnJhY290dGEECQBuYW1lX2hhc2jxssdv5vlbpgMKAG5ldHdvcmtfaWRE3Ru/CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brown_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJyb3duX3RlcnJhY290dGEECQBuYW1lX2hhc2gG4kPenmOF9gMKAG5ldHdvcmtfaWQ/i0iNCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAwAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo7fX56HXFejEDCgBuZXR3b3JrX2lk8tTF8QoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:orange_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAwAACAQAbmFtZRsAbWluZWNyYWZ0Om9yYW5nZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNo0Hjmql3sruMDCgBuZXR3b3JrX2lklmqmkAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:yellow_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAwAACAQAbmFtZRsAbWluZWNyYWZ0OnllbGxvd190ZXJyYWNvdHRhBAkAbmFtZV9oYXNoqkyKKrmA3VcDCgBuZXR3b3JrX2lkaM/orAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:lime_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAwAACAQAbmFtZRkAbWluZWNyYWZ0OmxpbWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaANjADFOF9v7AwoAbmV0d29ya19pZJt0XsgKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:green_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyZWVuX3RlcnJhY290dGEECQBuYW1lX2hhc2j5Ybq36yYwRQMKAG5ldHdvcmtfaWQ8kGdHCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cyan_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAwAACAQAbmFtZRkAbWluZWNyYWZ0OmN5YW5fdGVycmFjb3R0YQQJAG5hbWVfaGFzaN09COzMuHwAAwoAbmV0d29ya19pZIWPCzoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:light_blue_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAwAACAQAbmFtZR8AbWluZWNyYWZ0OmxpZ2h0X2JsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaOMytez7cOZiAwoAbmV0d29ya19pZFHK1UsKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:blue_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAwAACAQAbmFtZRkAbWluZWNyYWZ0OmJsdWVfdGVycmFjb3R0YQQJAG5hbWVfaGFzaF6inyTK5RpAAwoAbmV0d29ya19pZF5mVZIKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:purple_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAwAACAQAbmFtZRsAbWluZWNyYWZ0OnB1cnBsZV90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoKF7YG61yTbEDCgBuZXR3b3JrX2lkhtRDlwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:magenta_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAwAACAQAbmFtZRwAbWluZWNyYWZ0Om1hZ2VudGFfdGVycmFjb3R0YQQJAG5hbWVfaGFzaLWvtpAVtztyAwoAbmV0d29ya19pZN5SoakKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pink_terracotta", + "groupId": 22, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAwAACAQAbmFtZRkAbWluZWNyYWZ0OnBpbmtfdGVycmFjb3R0YQQJAG5hbWVfaGFzaJ7mzvyzSQZTAwoAbmV0d29ya19pZDJWe4YKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:white_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAAAACAQAbmFtZSEAbWluZWNyYWZ0OndoaXRlX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoiVzCdoHAJo0DCgBuZXR3b3JrX2lkIlj9AAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:silver_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAAAACAQAbmFtZSIAbWluZWNyYWZ0OnNpbHZlcl9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaAVsA0CnhzA4AwoAbmV0d29ya19pZPnxtJEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:gray_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAAAACAQAbmFtZSAAbWluZWNyYWZ0OmdyYXlfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2jvLZt9u/lF/AMKAG5ldHdvcmtfaWQVU8eFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:black_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJsYWNrX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoe8I4xAXbO5UDCgBuZXR3b3JrX2lk2Icb9AoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brown_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAAAACAQAbmFtZSEAbWluZWNyYWZ0OmJyb3duX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNoSiNZOobbpjoDCgBuZXR3b3JrX2lkJy0jwgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAAAACAQAbmFtZR8AbWluZWNyYWZ0OnJlZF9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaBdWFGLmCLFVAwoAbmV0d29ya19pZMYBJSEKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:orange_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTdAAAACAQAbmFtZSIAbWluZWNyYWZ0Om9yYW5nZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaMyJMrnPr7szAwoAbmV0d29ya19pZN6+7TUKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:yellow_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAAAACAQAbmFtZSIAbWluZWNyYWZ0OnllbGxvd19nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaN6NaIhf6m0uAwoAbmV0d29ya19pZKRHXeoKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:lime_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAAAACAQAbmFtZSAAbWluZWNyYWZ0OmxpbWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2iF3E68/rB2EAMKAG5ldHdvcmtfaWSP7qQWCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:green_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAAAACAQAbmFtZSEAbWluZWNyYWZ0OmdyZWVuX2dsYXplZF90ZXJyYWNvdHRhBAkAbmFtZV9oYXNow5mo8aQDFboDCgBuZXR3b3JrX2lkoF11kgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:cyan_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAAAACAQAbmFtZSAAbWluZWNyYWZ0OmN5YW5fZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gnNB+cCFRJhwMKAG5ldHdvcmtfaWT9buMtCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:light_blue_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAAAACAQAbmFtZSYAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2gladnCDBKCigMKAG5ldHdvcmtfaWS5CszFCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:blue_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAAAACAQAbmFtZSAAbWluZWNyYWZ0OmJsdWVfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2giOZK+2nB1igMKAG5ldHdvcmtfaWR+e22CCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:purple_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTbAAAACAQAbmFtZSIAbWluZWNyYWZ0OnB1cnBsZV9nbGF6ZWRfdGVycmFjb3R0YQQJAG5hbWVfaGFzaIQU03txeAfHAwoAbmV0d29ya19pZLKbSE4KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:magenta_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAAAACAQAbmFtZSMAbWluZWNyYWZ0Om1hZ2VudGFfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2i/SNqDJbfjMgMKAG5ldHdvcmtfaWQKf9UvCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pink_glazed_terracotta", + "groupId": 23, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAAAACAQAbmFtZSAAbWluZWNyYWZ0OnBpbmtfZ2xhemVkX3RlcnJhY290dGEECQBuYW1lX2hhc2hik8DVt4g+twMKAG5ldHdvcmtfaWTKzav2CgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:purpur_block", + "groupId": 24, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnB1cnB1cl9ibG9jawQJAG5hbWVfaGFzaAgLwnUZGlzsAwoAbmV0d29ya19pZGCZ+4UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:purpur_pillar", + "groupId": 24, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS2BAAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnB1cl9waWxsYXIECQBuYW1lX2hhc2iFcSsdykO+jgMKAG5ldHdvcmtfaWQe0+geCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:packed_mud", + "groupId": 24, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcAgAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9tdWQECQBuYW1lX2hhc2gHOMa121h4FgMKAG5ldHdvcmtfaWTUb6LyCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:mud_bricks", + "groupId": 24, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAgAACAQAbmFtZRQAbWluZWNyYWZ0Om11ZF9icmlja3MECQBuYW1lX2hhc2iDL/SVl/PewQMKAG5ldHdvcmtfaWSkBjaDCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:nether_wart_block", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAAAACAQAbmFtZRsAbWluZWNyYWZ0Om5ldGhlcl93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9XGS4GNnlV4DCgBuZXR3b3JrX2lkh3apIgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_wart_block", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAQAACAQAbmFtZRsAbWluZWNyYWZ0OndhcnBlZF93YXJ0X2Jsb2NrBAkAbmFtZV9oYXNo9IqDS9yUPJoDCgBuZXR3b3JrX2lkMpKAbAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:shroomlight", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTlAQAACAQAbmFtZRUAbWluZWNyYWZ0OnNocm9vbWxpZ2h0BAkAbmFtZV9oYXNoZHCHcHX/HYADCgBuZXR3b3JrX2lkLG2JiwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:crimson_nylium", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTnAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fbnlsaXVtBAkAbmFtZV9oYXNoOr6DJYW2bFYDCgBuZXR3b3JrX2lkuWpRDgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_nylium", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWToAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9ueWxpdW0ECQBuYW1lX2hhc2g0Zf89cfr3rwMKAG5ldHdvcmtfaWSu/kekCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:netherrack", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXAAAACAQAbmFtZRQAbWluZWNyYWZ0Om5ldGhlcnJhY2sECQBuYW1lX2hhc2i/r5ZyRsvPyQMKAG5ldHdvcmtfaWTAiTOACgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:soul_soil", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAQAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc29pbAQJAG5hbWVfaGFzaC1/87ccutuTAwoAbmV0d29ya19pZKc63SMKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:grass_block", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXNzX2Jsb2NrBAkAbmFtZV9oYXNojPyGp3/CSZwDCgBuZXR3b3JrX2lktCgx3goGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:podzol", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTzAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBvZHpvbAQJAG5hbWVfaGFzaBzqokRjH4Z1AwoAbmV0d29ya19pZPPS/GUKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mycelium", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAAAACAQAbmFtZRIAbWluZWNyYWZ0Om15Y2VsaXVtBAkAbmFtZV9oYXNojTN09cKickIDCgBuZXR3b3JrX2lkLNPxXQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:grass_path", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGAAAACAQAbmFtZRQAbWluZWNyYWZ0OmdyYXNzX3BhdGgECQBuYW1lX2hhc2i0/KZV8Qsy+gMKAG5ldHdvcmtfaWT7CcdzCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dirt", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmRpcnQECQBuYW1lX2hhc2hXp6jnXAe+kQMKAG5ldHdvcmtfaWSG706CCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:coarse_dirt", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTBBAAACAQAbmFtZRUAbWluZWNyYWZ0OmNvYXJzZV9kaXJ0BAkAbmFtZV9oYXNosd+cah7WSmoDCgBuZXR3b3JrX2lkgS5RcAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dirt_with_roots", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRpcnRfd2l0aF9yb290cwQJAG5hbWVfaGFzaLCNDYPviDCIAwoAbmV0d29ya19pZNCkwzoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:farmland", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AAAACAQAbmFtZRIAbWluZWNyYWZ0OmZhcm1sYW5kBAkAbmFtZV9oYXNoxyQ5ag7LolADCgBuZXR3b3JrX2lkX618FQoGAHN0YXRlcwMSAG1vaXN0dXJpemVkX2Ftb3VudAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mud", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTYAgAACAQAbmFtZQ0AbWluZWNyYWZ0Om11ZAQJAG5hbWVfaGFzaPb/3P+uLy+9AwoAbmV0d29ya19pZPIUlUkKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:clay", + "groupId": 25, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAAAACAQAbmFtZQ4AbWluZWNyYWZ0OmNsYXkECQBuYW1lX2hhc2j/S6sKXRcpzwMKAG5ldHdvcmtfaWRmsb8nCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:iron_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAAAACAQAbmFtZRIAbWluZWNyYWZ0Omlyb25fb3JlBAkAbmFtZV9oYXNoS7BYtLnfx3gDCgBuZXR3b3JrX2lk3loneQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:gold_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAAAACAQAbmFtZRIAbWluZWNyYWZ0OmdvbGRfb3JlBAkAbmFtZV9oYXNoC5Y+DUGXLC4DCgBuZXR3b3JrX2lkNhvMfwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:diamond_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AAAACAQAbmFtZRUAbWluZWNyYWZ0OmRpYW1vbmRfb3JlBAkAbmFtZV9oYXNokUOJ2wZZrGQDCgBuZXR3b3JrX2lk/dChVAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:lapis_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQVAAAACAQAbmFtZRMAbWluZWNyYWZ0OmxhcGlzX29yZQQJAG5hbWVfaGFzaMrmrUrSzb7qAwoAbmV0d29ya19pZMg+qK4KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:redstone_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZHN0b25lX29yZQQJAG5hbWVfaGFzaFHVnp8Wc4JbAwoAbmV0d29ya19pZKDYvQoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:coal_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAAAACAQAbmFtZRIAbWluZWNyYWZ0OmNvYWxfb3JlBAkAbmFtZV9oYXNo1OjA+Iuy51oDCgBuZXR3b3JrX2lk+R/aKAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:copper_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AgAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcHBlcl9vcmUECQBuYW1lX2hhc2iSZduSntOzOwMKAG5ldHdvcmtfaWQtIuCnCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:emerald_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVtZXJhbGRfb3JlBAkAbmFtZV9oYXNoJTovr+VgINsDCgBuZXR3b3JrX2lknbkqCgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:quartz_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAAAACAQAbmFtZRQAbWluZWNyYWZ0OnF1YXJ0el9vcmUECQBuYW1lX2hhc2g0yNHLMK9TaQMKAG5ldHdvcmtfaWSzN7nzCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:nether_gold_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAgAACAQAbmFtZRkAbWluZWNyYWZ0Om5ldGhlcl9nb2xkX29yZQQJAG5hbWVfaGFzaEJZ7segIBgBAwoAbmV0d29ya19pZNI9pDgKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:ancient_debris", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFuY2llbnRfZGVicmlzBAkAbmFtZV9oYXNoNrbxMc9AwKcDCgBuZXR3b3JrX2lkrSNjEAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:deepslate_iron_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9pcm9uX29yZQQJAG5hbWVfaGFzaB/fDL9pgvXXAwoAbmV0d29ya19pZFA0bz4KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:deepslate_gold_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9nb2xkX29yZQQJAG5hbWVfaGFzaF9G7WYhKFinAwoAbmV0d29ya19pZHQTfBUKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:deepslate_diamond_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9kaWFtb25kX29yZQQJAG5hbWVfaGFzaEUH5USh+iD3AwoAbmV0d29ya19pZHP6VzAKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:deepslate_lapis_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAgAACAQAbmFtZR0AbWluZWNyYWZ0OmRlZXBzbGF0ZV9sYXBpc19vcmUECQBuYW1lX2hhc2j+yFxU/KZs1gMKAG5ldHdvcmtfaWRKINzICgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:deepslate_redstone_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAgAACAQAbmFtZSAAbWluZWNyYWZ0OmRlZXBzbGF0ZV9yZWRzdG9uZV9vcmUECQBuYW1lX2hhc2iVgM3wWWD6ugMKAG5ldHdvcmtfaWReBdYRCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:deepslate_emerald_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAgAACAQAbmFtZR8AbWluZWNyYWZ0OmRlZXBzbGF0ZV9lbWVyYWxkX29yZQQJAG5hbWVfaGFzaNlfo5HTwS6wAwoAbmV0d29ya19pZNeie6sKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:deepslate_coal_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAgAACAQAbmFtZRwAbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb2FsX29yZQQJAG5hbWVfaGFzaIjikmcbRrPPAwoAbmV0d29ya19pZD9TiygKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:deepslate_copper_ore", + "groupId": 26, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAgAACAQAbmFtZR4AbWluZWNyYWZ0OmRlZXBzbGF0ZV9jb3BwZXJfb3JlBAkAbmFtZV9oYXNottjV4Ev5LAQDCgBuZXR3b3JrX2lkP23rgQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stone", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnN0b25lBAkAbmFtZV9oYXNoE3mqhJxzJycDCgBuZXR3b3JrX2lkIQ4xgAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:granite", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAwAACAQAbmFtZREAbWluZWNyYWZ0OmdyYW5pdGUECQBuYW1lX2hhc2iq+Dur2pw4AwMKAG5ldHdvcmtfaWT2NMfJCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:diorite", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAwAACAQAbmFtZREAbWluZWNyYWZ0OmRpb3JpdGUECQBuYW1lX2hhc2iaFsq2iinZBQMKAG5ldHdvcmtfaWQqGE6XCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:andesite", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAwAACAQAbmFtZRIAbWluZWNyYWZ0OmFuZGVzaXRlBAkAbmFtZV9oYXNosaLIEnQQoSYDCgBuZXR3b3JrX2lkEApRZAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:blackstone", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAgAACAQAbmFtZRQAbWluZWNyYWZ0OmJsYWNrc3RvbmUECQBuYW1lX2hhc2iMFYziD80D6QMKAG5ldHdvcmtfaWSrUryHCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:deepslate", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AgAACAQAbmFtZRMAbWluZWNyYWZ0OmRlZXBzbGF0ZQQJAG5hbWVfaGFzaKX5pAblxz8TAwoAbmV0d29ya19pZOJoQjsKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:tuff", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAgAACAQAbmFtZQ4AbWluZWNyYWZ0OnR1ZmYECQBuYW1lX2hhc2h1Rwc1XYsBGwMKAG5ldHdvcmtfaWRwQGn0CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:basalt", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhc2FsdAQJAG5hbWVfaGFzaH+UQO2yWodiAwoAbmV0d29ya19pZBPNSV4KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_granite", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2dyYW5pdGUECQBuYW1lX2hhc2iLiEfys8pFIAMKAG5ldHdvcmtfaWTCxxcHCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_diorite", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBvbGlzaGVkX2Rpb3JpdGUECQBuYW1lX2hhc2hTxY4fKmNmlAMKAG5ldHdvcmtfaWTmtjdRCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_andesite", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSAwAACAQAbmFtZRsAbWluZWNyYWZ0OnBvbGlzaGVkX2FuZGVzaXRlBAkAbmFtZV9oYXNovl28uFk4HuQDCgBuZXR3b3JrX2lklFjuCwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:polished_blackstone", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAgAACAQAbmFtZR0AbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmUECQBuYW1lX2hhc2jT9fHCl6vWQQMKAG5ldHdvcmtfaWR/Ho6oCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_deepslate", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AgAACAQAbmFtZRwAbWluZWNyYWZ0OnBvbGlzaGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaHC1edoaWF3uAwoAbmV0d29ya19pZCPeQsEKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:polished_tuff", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBvbGlzaGVkX3R1ZmYECQBuYW1lX2hhc2hyaLe/KEVZ0gMKAG5ldHdvcmtfaWTcX3NrCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_basalt", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTqAQAACAQAbmFtZRkAbWluZWNyYWZ0OnBvbGlzaGVkX2Jhc2FsdAQJAG5hbWVfaGFzaMS+L0gMnRcBAwoAbmV0d29ya19pZF+/mHwKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:smooth_basalt", + "groupId": 27, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AgAACAQAbmFtZRcAbWluZWNyYWZ0OnNtb290aF9iYXNhbHQECQBuYW1lX2hhc2jKPUdz89kuNAMKAG5ldHdvcmtfaWTkb/oVCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:gravel", + "groupId": 28, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAAAACAQAbmFtZRAAbWluZWNyYWZ0OmdyYXZlbAQJAG5hbWVfaGFzaOFxz8XJd2r/AwoAbmV0d29ya19pZBpfI1sKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:sand", + "groupId": 28, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNhbmQECQBuYW1lX2hhc2i6lthXXbAyWAMKAG5ldHdvcmtfaWRjeUMICgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:red_sand", + "groupId": 28, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS0BAAACAQAbmFtZRIAbWluZWNyYWZ0OnJlZF9zYW5kBAkAbmFtZV9oYXNoCiarI69JQCkDCgBuZXR3b3JrX2lkU8UD/AoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cactus", + "groupId": 28, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAAAACAQAbmFtZRAAbWluZWNyYWZ0OmNhY3R1cwQJAG5hbWVfaGFzaCG9zL0N4wvGAwoAbmV0d29ya19pZDeCERAKBgBzdGF0ZXMDAwBhZ2UAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:oak_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAAAACAQAbmFtZREAbWluZWNyYWZ0Om9ha19sb2cECQBuYW1lX2hhc2ho6TS+K7PZFQMKAG5ldHdvcmtfaWQjfjoxCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_oak_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQJAQAACAQAbmFtZRoAbWluZWNyYWZ0OnN0cmlwcGVkX29ha19sb2cECQBuYW1lX2hhc2h8dqh+OOHU4wMKAG5ldHdvcmtfaWSYKjdrCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:spruce_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AwAACAQAbmFtZRQAbWluZWNyYWZ0OnNwcnVjZV9sb2cECQBuYW1lX2hhc2hZ03qaLoF3WgMKAG5ldHdvcmtfaWRlFD8eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_spruce_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV9sb2cECQBuYW1lX2hhc2iNrhKjS5IyrgMKAG5ldHdvcmtfaWRQcEC3CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:birch_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AwAACAQAbmFtZRMAbWluZWNyYWZ0OmJpcmNoX2xvZwQJAG5hbWVfaGFzaBUzT3NxsZAnAwoAbmV0d29ya19pZBKN3VQKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stripped_birch_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAQAACAQAbmFtZRwAbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX2xvZwQJAG5hbWVfaGFzaCFKS4AeuSidAwoAbmV0d29ya19pZN0IONIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:jungle_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AwAACAQAbmFtZRQAbWluZWNyYWZ0Omp1bmdsZV9sb2cECQBuYW1lX2hhc2gkwW0KNulqDgMKAG5ldHdvcmtfaWQaziU/CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_jungle_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV9sb2cECQBuYW1lX2hhc2hAwMsgOk02JAMKAG5ldHdvcmtfaWQvls0eCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:acacia_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAAAACAQAbmFtZRQAbWluZWNyYWZ0OmFjYWNpYV9sb2cECQBuYW1lX2hhc2iV48VpYhjoYQMKAG5ldHdvcmtfaWRxEqe0CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_acacia_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAQAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV9sb2cECQBuYW1lX2hhc2hJb0lQqnEqlgMKAG5ldHdvcmtfaWRg3IdRCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dark_oak_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AwAACAQAbmFtZRYAbWluZWNyYWZ0OmRhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaIWfVRd0XUo3AwoAbmV0d29ya19pZPMM7LYKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stripped_dark_oak_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQIAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX2xvZwQJAG5hbWVfaGFzaPFTdxRdPwkOAwoAbmV0d29ya19pZDIzenIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mangrove_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAgAACAQAbmFtZRYAbWluZWNyYWZ0Om1hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaHZe6DzPZBobAwoAbmV0d29ya19pZG6DuYkKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stripped_mangrove_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAgAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX2xvZwQJAG5hbWVfaGFzaLqIBo4hwA//AwoAbmV0d29ya19pZPtRn7UKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cherry_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAwAACAQAbmFtZRQAbWluZWNyYWZ0OmNoZXJyeV9sb2cECQBuYW1lX2hhc2hwFlaioppB1wMKAG5ldHdvcmtfaWS2sdXECgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_cherry_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQWAwAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV9sb2cECQBuYW1lX2hhc2i85H6G+WhXaAMKAG5ldHdvcmtfaWRjzoglCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pale_oak_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiBAAACAQAbmFtZRYAbWluZWNyYWZ0OnBhbGVfb2FrX2xvZwQJAG5hbWVfaGFzaIEcMMTin/ihAwoAbmV0d29ya19pZMtoEVwKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stripped_pale_oak_log", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWThBAAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX3BhbGVfb2FrX2xvZwQJAG5hbWVfaGFzaBVKFLV2TrFcAwoAbmV0d29ya19pZBY8/GAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:crimson_stem", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTgAQAACAQAbmFtZRYAbWluZWNyYWZ0OmNyaW1zb25fc3RlbQQJAG5hbWVfaGFzaM0FzfL0UTKZAwoAbmV0d29ya19pZKvzID0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stripped_crimson_stem", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvAQAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25fc3RlbQQJAG5hbWVfaGFzaDlA6nood57EAwoAbmV0d29ya19pZHrIqjIKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_stem", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAQAACAQAbmFtZRUAbWluZWNyYWZ0OndhcnBlZF9zdGVtBAkAbmFtZV9oYXNon7cKfPZxdrUDCgBuZXR3b3JrX2lkerWyMwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stripped_warped_stem", + "groupId": 29, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAQAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9zdGVtBAkAbmFtZV9oYXNoEw+y0dDPSd8DCgBuZXR3b3JrX2lkIQ9vBAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:oak_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAQAACAQAbmFtZRIAbWluZWNyYWZ0Om9ha193b29kBAkAbmFtZV9oYXNoqQIkuVPyJX0DCgBuZXR3b3JrX2lku2G1YAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stripped_oak_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyBAAACAQAbmFtZRsAbWluZWNyYWZ0OnN0cmlwcGVkX29ha193b29kBAkAbmFtZV9oYXNovW6KCv+VZnsDCgBuZXR3b3JrX2lkkhWGegoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:spruce_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQtBAAACAQAbmFtZRUAbWluZWNyYWZ0OnNwcnVjZV93b29kBAkAbmFtZV9oYXNoTrIJ5TAQ+OgDCgBuZXR3b3JrX2lkaXLxCwoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stripped_spruce_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzBAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX3NwcnVjZV93b29kBAkAbmFtZV9oYXNoMnuUk4Xo6icDCgBuZXR3b3JrX2lkes2ydAoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:birch_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuBAAACAQAbmFtZRQAbWluZWNyYWZ0OmJpcmNoX3dvb2QECQBuYW1lX2hhc2iqVjG4xt0cKQMKAG5ldHdvcmtfaWS06c5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_birch_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0BAAACAQAbmFtZR0AbWluZWNyYWZ0OnN0cmlwcGVkX2JpcmNoX3dvb2QECQBuYW1lX2hhc2hm88R604TKbAMKAG5ldHdvcmtfaWRleEMJCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:jungle_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvBAAACAQAbmFtZRUAbWluZWNyYWZ0Omp1bmdsZV93b29kBAkAbmFtZV9oYXNo9bYW29ORWCoDCgBuZXR3b3JrX2lkyFyKLQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stripped_jungle_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ1BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2p1bmdsZV93b29kBAkAbmFtZV9oYXNoUVs6KsZQRBoDCgBuZXR3b3JrX2lk92k8HQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:acacia_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQwBAAACAQAbmFtZRUAbWluZWNyYWZ0OmFjYWNpYV93b29kBAkAbmFtZV9oYXNoKkDfgzlJUcIDCgBuZXR3b3JrX2lkuTWlcgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stripped_acacia_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2BAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2FjYWNpYV93b29kBAkAbmFtZV9oYXNo/kOPN2bCJhUDCgBuZXR3b3JrX2lktl6LwQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dark_oak_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxBAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2jaKv4ORLadAAMKAG5ldHdvcmtfaWSDrNQ8CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_dark_oak_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3BAAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX2Rhcmtfb2FrX3dvb2QECQBuYW1lX2hhc2h2jFDfKVFgfAMKAG5ldHdvcmtfaWTgZQ5VCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mangrove_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAgAACAQAbmFtZRcAbWluZWNyYWZ0Om1hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2iXVxG0JG2fVAMKAG5ldHdvcmtfaWSkqJ4cCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_mangrove_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX21hbmdyb3ZlX3dvb2QECQBuYW1lX2hhc2h7CkbaBF7/WAMKAG5ldHdvcmtfaWQLAX88CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cherry_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAwAACAQAbmFtZRUAbWluZWNyYWZ0OmNoZXJyeV93b29kBAkAbmFtZV9oYXNoAW8srlmpBM8DCgBuZXR3b3JrX2lkLPsAwgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stripped_cherry_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAwAACAQAbmFtZR4AbWluZWNyYWZ0OnN0cmlwcGVkX2NoZXJyeV93b29kBAkAbmFtZV9oYXNo/e7KXv+CB38DCgBuZXR3b3JrX2lkg5aVtQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pale_oak_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTsBAAACAQAbmFtZRcAbWluZWNyYWZ0OnBhbGVfb2FrX3dvb2QECQBuYW1lX2hhc2hGlXnbUgRIggMKAG5ldHdvcmtfaWRPLx7LCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_pale_oak_wood", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTrBAAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3BhbGVfb2FrX3dvb2QECQBuYW1lX2hhc2iqaxd6ta2eNAMKAG5ldHdvcmtfaWQI+pz3CgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:crimson_hyphae", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQqAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNouRmKmfSqEWADCgBuZXR3b3JrX2lk+Tm5rQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stripped_crimson_hyphae", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQrAgAACAQAbmFtZSEAbWluZWNyYWZ0OnN0cmlwcGVkX2NyaW1zb25faHlwaGFlBAkAbmFtZV9oYXNoFffwmABq4LUDCgBuZXR3b3JrX2lkZAlUbgoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:warped_hyphae", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQpAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2hn8plQUr6pmQMKAG5ldHdvcmtfaWRU2AIBCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:stripped_warped_hyphae", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQsAgAACAQAbmFtZSAAbWluZWNyYWZ0OnN0cmlwcGVkX3dhcnBlZF9oeXBoYWUECQBuYW1lX2hhc2irKq+HYPSgjQMKAG5ldHdvcmtfaWSbrOPDCgYAc3RhdGVzCAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bamboo_block", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQOAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJhbWJvb19ibG9jawQJAG5hbWVfaGFzaAbDeur6stIBAwoAbmV0d29ya19pZCJAwn0KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:stripped_bamboo_block", + "groupId": 30, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAwAACAQAbmFtZR8AbWluZWNyYWZ0OnN0cmlwcGVkX2JhbWJvb19ibG9jawQJAG5hbWVfaGFzaJpwytpZOZM9AwoAbmV0d29ya19pZKuRbNEKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:oak_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQSAAAACAQAbmFtZRQAbWluZWNyYWZ0Om9ha19sZWF2ZXMECQBuYW1lX2hhc2h6O4xGqA2oKgMKAG5ldHdvcmtfaWT98c59CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:spruce_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfBAAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9sZWF2ZXMECQBuYW1lX2hhc2i9x1CtNAuqZwMKAG5ldHdvcmtfaWSzF7pTCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:birch_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgBAAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2xlYXZlcwQJAG5hbWVfaGFzaBlAGHaoaLZSAwoAbmV0d29ya19pZOjtvWcKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:jungle_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhBAAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9sZWF2ZXMECQBuYW1lX2hhc2iW1uAH07zGhgMKAG5ldHdvcmtfaWSA5KX0CgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:acacia_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAAAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9sZWF2ZXMECQBuYW1lX2hhc2iZJf8dAgDRNQMKAG5ldHdvcmtfaWQ/G7VuCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dark_oak_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiBAAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2xlYXZlcwQJAG5hbWVfaGFzaCk7rDipWFSjAwoAbmV0d29ya19pZJ2AkbYKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:mangrove_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2xlYXZlcwQJAG5hbWVfaGFzaKyI/dWvhEG8AwoAbmV0d29ya19pZPQxCZ8KBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cherry_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQjAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9sZWF2ZXMECQBuYW1lX2hhc2giTs9ChhYBlQMKAG5ldHdvcmtfaWR8bPpwCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pale_oak_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTuBAAACAQAbmFtZRkAbWluZWNyYWZ0OnBhbGVfb2FrX2xlYXZlcwQJAG5hbWVfaGFzaKVccFYyf0wbAwoAbmV0d29ya19pZNFNvgcKBgBzdGF0ZXMBDgBwZXJzaXN0ZW50X2JpdAABCgB1cGRhdGVfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:azalea_leaves", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAgAACAQAbmFtZRcAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXMECQBuYW1lX2hhc2iXFhD57wFS7AMKAG5ldHdvcmtfaWTNB/9ECgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:azalea_leaves_flowered", + "groupId": 31, + "block_state_b64": "CgAAAwgAYmxvY2tfaWREAgAACAQAbmFtZSAAbWluZWNyYWZ0OmF6YWxlYV9sZWF2ZXNfZmxvd2VyZWQECQBuYW1lX2hhc2gs8jxlS/pMrwMKAG5ldHdvcmtfaWQ7W4PyCgYAc3RhdGVzAQ4AcGVyc2lzdGVudF9iaXQAAQoAdXBkYXRlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:oak_sapling", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAAAACAQAbmFtZRUAbWluZWNyYWZ0Om9ha19zYXBsaW5nBAkAbmFtZV9oYXNoogXcT9QfjiUDCgBuZXR3b3JrX2lkG22C+AoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:spruce_sapling", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4BAAACAQAbmFtZRgAbWluZWNyYWZ0OnNwcnVjZV9zYXBsaW5nBAkAbmFtZV9oYXNoe8hz4uYP0FcDCgBuZXR3b3JrX2lkUQmhaQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:birch_sapling", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5BAAACAQAbmFtZRcAbWluZWNyYWZ0OmJpcmNoX3NhcGxpbmcECQBuYW1lX2hhc2h348iJQ/tK4wMKAG5ldHdvcmtfaWQ2Uh53CgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:jungle_sapling", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6BAAACAQAbmFtZRgAbWluZWNyYWZ0Omp1bmdsZV9zYXBsaW5nBAkAbmFtZV9oYXNo7tyTOdSrxaADCgBuZXR3b3JrX2lkXmBAdAoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:acacia_sapling", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7BAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjYWNpYV9zYXBsaW5nBAkAbmFtZV9oYXNo99sg15uoX7ADCgBuZXR3b3JrX2lkPXX1KgoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dark_oak_sapling", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8BAAACAQAbmFtZRoAbWluZWNyYWZ0OmRhcmtfb2FrX3NhcGxpbmcECQBuYW1lX2hhc2jnVzFplW7cHgMKAG5ldHdvcmtfaWTD4giHCgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mangrove_propagule", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAgAACAQAbmFtZRwAbWluZWNyYWZ0Om1hbmdyb3ZlX3Byb3BhZ3VsZQQJAG5hbWVfaGFzaJGeox6hkfLFAwoAbmV0d29ya19pZAIpvpYKBgBzdGF0ZXMBBwBoYW5naW5nAAMPAHByb3BhZ3VsZV9zdGFnZQAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cherry_sapling", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQiAwAACAQAbmFtZRgAbWluZWNyYWZ0OmNoZXJyeV9zYXBsaW5nBAkAbmFtZV9oYXNoGrPpNMf1LtcDCgBuZXR3b3JrX2lkypakXQoGAHN0YXRlcwEHAGFnZV9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pale_oak_sapling", + "groupId": 32, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTtBAAACAQAbmFtZRoAbWluZWNyYWZ0OnBhbGVfb2FrX3NhcGxpbmcECQBuYW1lX2hhc2gzvl+QbSfPHwMKAG5ldHdvcmtfaWSzav9sCgYAc3RhdGVzAQcAYWdlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bee_nest", + "groupId": 33, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTZAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJlZV9uZXN0BAkAbmFtZV9oYXNo2R2WBxUHEZIDCgBuZXR3b3JrX2lkiXWLEAoGAHN0YXRlcwMJAGRpcmVjdGlvbgAAAAADCwBob25leV9sZXZlbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:wheat_seeds", + "groupId": 34 + }, + { + "id": "minecraft:pumpkin_seeds", + "groupId": 34 + }, + { + "id": "minecraft:melon_seeds", + "groupId": 34 + }, + { + "id": "minecraft:beetroot_seeds", + "groupId": 34 + }, + { + "id": "minecraft:torchflower_seeds", + "groupId": 34 + }, + { + "id": "minecraft:pitcher_pod", + "groupId": 34 + }, + { + "id": "minecraft:wheat", + "groupId": 35 + }, + { + "id": "minecraft:beetroot", + "groupId": 35 + }, + { + "id": "minecraft:potato", + "groupId": 35 + }, + { + "id": "minecraft:poisonous_potato", + "groupId": 35 + }, + { + "id": "minecraft:carrot", + "groupId": 35 + }, + { + "id": "minecraft:golden_carrot", + "groupId": 35 + }, + { + "id": "minecraft:apple", + "groupId": 35 + }, + { + "id": "minecraft:golden_apple", + "groupId": 35 + }, + { + "id": "minecraft:enchanted_golden_apple", + "groupId": 35 + }, + { + "id": "minecraft:melon_block", + "groupId": 35, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAAAACAQAbmFtZRUAbWluZWNyYWZ0Om1lbG9uX2Jsb2NrBAkAbmFtZV9oYXNoXxSm0iYpAx8DCgBuZXR3b3JrX2lkC9rqygoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:melon_slice", + "groupId": 35 + }, + { + "id": "minecraft:glistering_melon_slice", + "groupId": 35 + }, + { + "id": "minecraft:sweet_berries", + "groupId": 35 + }, + { + "id": "minecraft:glow_berries", + "groupId": 35 + }, + { + "id": "minecraft:pumpkin", + "groupId": 35, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWAAAACAQAbmFtZREAbWluZWNyYWZ0OnB1bXBraW4ECQBuYW1lX2hhc2gc8A3jaSzWbgMKAG5ldHdvcmtfaWRFGA+xCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:carved_pumpkin", + "groupId": 36, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNhcnZlZF9wdW1wa2luBAkAbmFtZV9oYXNoPu1T0MJuG90DCgBuZXR3b3JrX2lkXNNn5QoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:lit_pumpkin", + "groupId": 36, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmxpdF9wdW1wa2luBAkAbmFtZV9oYXNo7gWtEm2uPL0DCgBuZXR3b3JrX2lki8sU4AoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:honeycomb", + "groupId": 36 + }, + { + "id": "minecraft:resin_clump", + "groupId": 36, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT9BAAACAQAbmFtZRUAbWluZWNyYWZ0OnJlc2luX2NsdW1wBAkAbmFtZV9oYXNok5dcTB5ZyioDCgBuZXR3b3JrX2lkFbHrwwoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHMAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:fern", + "groupId": 37, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPBAAACAQAbmFtZQ4AbWluZWNyYWZ0OmZlcm4ECQBuYW1lX2hhc2iHbj3yXFn4owMKAG5ldHdvcmtfaWQKC6u7CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:large_fern", + "groupId": 37, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRgBAAACAQAbmFtZRQAbWluZWNyYWZ0OmxhcmdlX2Zlcm4ECQBuYW1lX2hhc2gnE9sd0LzHtQMKAG5ldHdvcmtfaWTS9hG4CgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:short_grass", + "groupId": 37, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQfAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNob3J0X2dyYXNzBAkAbmFtZV9oYXNobWQghLH0bLcDCgBuZXR3b3JrX2lkJWOOqAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:tall_grass", + "groupId": 37, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRfBAAACAQAbmFtZRQAbWluZWNyYWZ0OnRhbGxfZ3Jhc3MECQBuYW1lX2hhc2ii5MyZJpv4sgMKAG5ldHdvcmtfaWRRfeH4CgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:nether_sprouts", + "groupId": 37 + }, + { + "id": "minecraft:fire_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAwAACAQAbmFtZRQAbWluZWNyYWZ0OmZpcmVfY29yYWwECQBuYW1lX2hhc2hOHyyECVQVJwMKAG5ldHdvcmtfaWS9vF0UCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brain_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWREAwAACAQAbmFtZRUAbWluZWNyYWZ0OmJyYWluX2NvcmFsBAkAbmFtZV9oYXNoRiWlLCwA2ycDCgBuZXR3b3JrX2lkrjAuhgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:bubble_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAwAACAQAbmFtZRYAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbAQJAG5hbWVfaGFzaJz6rWnl+v2qAwoAbmV0d29ya19pZImIWy0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:tube_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1YmVfY29yYWwECQBuYW1lX2hhc2iYa8oO/tgk7wMKAG5ldHdvcmtfaWRTfND5CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:horn_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAwAACAQAbmFtZRQAbWluZWNyYWZ0Omhvcm5fY29yYWwECQBuYW1lX2hhc2iZnRHjZbnLPgMKAG5ldHdvcmtfaWR+GGp8CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dead_fire_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbAQJAG5hbWVfaGFzaEPU6tFy/latAwoAbmV0d29ya19pZNMa7V4KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dead_brain_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAwAACAQAbmFtZRoAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWwECQBuYW1lX2hhc2j5L6QJCISvzwMKAG5ldHdvcmtfaWQkKzeiCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dead_bubble_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAwAACAQAbmFtZRsAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsBAkAbmFtZV9oYXNoSTOZ/8wpeNYDCgBuZXR3b3JrX2lka6w9DAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dead_tube_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbAQJAG5hbWVfaGFzaJGjNWhlaIJeAwoAbmV0d29ya19pZO3Z0ygKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dead_horn_coral", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAwAACAQAbmFtZRkAbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbAQJAG5hbWVfaGFzaJBkz3qt+g2cAwoAbmV0d29ya19pZBAN+eYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:fire_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJBAAACAQAbmFtZRgAbWluZWNyYWZ0OmZpcmVfY29yYWxfZmFuBAkAbmFtZV9oYXNosOTxYYxsDLgDCgBuZXR3b3JrX2lkFKxbEgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brain_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHBAAACAQAbmFtZRkAbWluZWNyYWZ0OmJyYWluX2NvcmFsX2ZhbgQJAG5hbWVfaGFzaAi5uHizSNcqAwoAbmV0d29ya19pZFtLjNwKBgBzdGF0ZXMDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:bubble_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIBAAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hy/rX2on17DgMKAG5ldHdvcmtfaWQof60VCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:tube_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSEAQAACAQAbmFtZRgAbWluZWNyYWZ0OnR1YmVfY29yYWxfZmFuBAkAbmFtZV9oYXNo9pbJbo+PphIDCgBuZXR3b3JrX2lkenDTYgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:horn_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKBAAACAQAbmFtZRgAbWluZWNyYWZ0Omhvcm5fY29yYWxfZmFuBAkAbmFtZV9oYXNoA+ri6NPDkbUDCgBuZXR3b3JrX2lkezoHNwoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dead_fire_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNBAAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hpQO02NDxPvwMKAG5ldHdvcmtfaWTaOJgLCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dead_brain_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLBAAACAQAbmFtZR4AbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWxfZmFuBAkAbmFtZV9oYXNoI9/+Z4YqMhIDCgBuZXR3b3JrX2lkqYXxYgoGAHN0YXRlcwMTAGNvcmFsX2Zhbl9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dead_bubble_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsX2ZhbgQJAG5hbWVfaGFzaBNECtIM6VIOAwoAbmV0d29ya19pZLrNtBEKBgBzdGF0ZXMDEwBjb3JhbF9mYW5fZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dead_tube_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSFAQAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbF9mYW4ECQBuYW1lX2hhc2hbBBM9jFKWvQMKAG5ldHdvcmtfaWSkJKUWCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dead_horn_coral_fan", + "groupId": 38, + "block_state_b64": "CgAAAwgAYmxvY2tfaWROBAAACAQAbmFtZR0AbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbF9mYW4ECQBuYW1lX2hhc2hObElFrHfPygMKAG5ldHdvcmtfaWQ1ZxvmCgYAc3RhdGVzAxMAY29yYWxfZmFuX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:crimson_roots", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTeAQAACAQAbmFtZRcAbWluZWNyYWZ0OmNyaW1zb25fcm9vdHMECQBuYW1lX2hhc2j1fWgQLViv5QMKAG5ldHdvcmtfaWRLh5DXCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:warped_roots", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTfAQAACAQAbmFtZRYAbWluZWNyYWZ0OndhcnBlZF9yb290cwQJAG5hbWVfaGFzaBc3WvbJOLlkAwoAbmV0d29ya19pZNLgDnAKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dandelion", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQlAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRhbmRlbGlvbgQJAG5hbWVfaGFzaBJ3bEUi+Nn/AwoAbmV0d29ya19pZBjjC44KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:poppy", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnBvcHB5BAkAbmFtZV9oYXNocMF8pITMbkcDCgBuZXR3b3JrX2lk8im6ywoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:blue_orchid", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9BAAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfb3JjaGlkBAkAbmFtZV9oYXNoBjz2MsgB21EDCgBuZXR3b3JrX2lk/iLsSwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:allium", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+BAAACAQAbmFtZRAAbWluZWNyYWZ0OmFsbGl1bQQJAG5hbWVfaGFzaDCGQBHNDTkcAwoAbmV0d29ya19pZD9Dgr0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:azure_bluet", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/BAAACAQAbmFtZRUAbWluZWNyYWZ0OmF6dXJlX2JsdWV0BAkAbmFtZV9oYXNo9N5egqMT2QcDCgBuZXR3b3JrX2lkwIgDnwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:red_tulip", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRABAAACAQAbmFtZRMAbWluZWNyYWZ0OnJlZF90dWxpcAQJAG5hbWVfaGFzaAjMi9Rd+6rhAwoAbmV0d29ya19pZAZCnt8KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:orange_tulip", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRBBAAACAQAbmFtZRYAbWluZWNyYWZ0Om9yYW5nZV90dWxpcAQJAG5hbWVfaGFzaP+NjxMBZ8vAAwoAbmV0d29ya19pZPYatsMKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:white_tulip", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCBAAACAQAbmFtZRUAbWluZWNyYWZ0OndoaXRlX3R1bGlwBAkAbmFtZV9oYXNo5vbU4VRPh3ADCgBuZXR3b3JrX2lkok+4rQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:pink_tulip", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDBAAACAQAbmFtZRQAbWluZWNyYWZ0OnBpbmtfdHVsaXAECQBuYW1lX2hhc2hxDHZa6OaNXAMKAG5ldHdvcmtfaWTiOT+VCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:oxeye_daisy", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWREBAAACAQAbmFtZRUAbWluZWNyYWZ0Om94ZXllX2RhaXN5BAkAbmFtZV9oYXNoXwxsqNQTN9gDCgBuZXR3b3JrX2lkw7R7dwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cornflower", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFBAAACAQAbmFtZRQAbWluZWNyYWZ0OmNvcm5mbG93ZXIECQBuYW1lX2hhc2gnhyC3EeqHgAMKAG5ldHdvcmtfaWR4VrvACgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:lily_of_the_valley", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGBAAACAQAbmFtZRwAbWluZWNyYWZ0OmxpbHlfb2ZfdGhlX3ZhbGxleQQJAG5hbWVfaGFzaI64TJSf9mgQAwoAbmV0d29ya19pZFE9+nwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:sunflower", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSvAAAACAQAbmFtZRMAbWluZWNyYWZ0OnN1bmZsb3dlcgQJAG5hbWVfaGFzaAMxYQLoqlZ0AwoAbmV0d29ya19pZA10iSoKBgBzdGF0ZXMBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:lilac", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWReBAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxpbGFjBAkAbmFtZV9oYXNoD3nrQJuo7NkDCgBuZXR3b3JrX2lk5W+uFAoGAHN0YXRlcwEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:rose_bush", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhBAAACAQAbmFtZRMAbWluZWNyYWZ0OnJvc2VfYnVzaAQJAG5hbWVfaGFzaLoiFk8LVpGKAwoAbmV0d29ya19pZMZPv48KBgBzdGF0ZXMBDwB1cHBlcl9ibG9ja19iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:peony", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRiBAAACAQAbmFtZQ8AbWluZWNyYWZ0OnBlb255BAkAbmFtZV9oYXNoR4dYc4QquPADCgBuZXR3b3JrX2lkrTe7RwoGAHN0YXRlcwEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pitcher_plant", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAwAACAQAbmFtZRcAbWluZWNyYWZ0OnBpdGNoZXJfcGxhbnQECQBuYW1lX2hhc2hRJHzsbDH+SQMKAG5ldHdvcmtfaWRnY76VCgYAc3RhdGVzAQ8AdXBwZXJfYmxvY2tfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:pink_petals", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQkAwAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfcGV0YWxzBAkAbmFtZV9oYXNo6DQwN9SwV3QDCgBuZXR3b3JrX2lkNWneGgoGAHN0YXRlcwMGAGdyb3d0aAAAAAAIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:wither_rose", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXAQAACAQAbmFtZRUAbWluZWNyYWZ0OndpdGhlcl9yb3NlBAkAbmFtZV9oYXNoaSKxl3I516gDCgBuZXR3b3JrX2lkATXLPwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:torchflower", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AwAACAQAbmFtZRUAbWluZWNyYWZ0OnRvcmNoZmxvd2VyBAkAbmFtZV9oYXNoL+mHtElwbqQDCgBuZXR3b3JrX2lkI34O+AoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:closed_eyeblossom", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT6BAAACAQAbmFtZRsAbWluZWNyYWZ0OmNsb3NlZF9leWVibG9zc29tBAkAbmFtZV9oYXNoYbeklHBkRL8DCgBuZXR3b3JrX2lku6xJeAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:open_eyeblossom", + "groupId": 39, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT5BAAACAQAbmFtZRkAbWluZWNyYWZ0Om9wZW5fZXllYmxvc3NvbQQJAG5hbWVfaGFzaHH2HXQ24l8fAwoAbmV0d29ya19pZP1bL4YKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:white_dye", + "groupId": 40 + }, + { + "id": "minecraft:light_gray_dye", + "groupId": 40 + }, + { + "id": "minecraft:gray_dye", + "groupId": 40 + }, + { + "id": "minecraft:black_dye", + "groupId": 40 + }, + { + "id": "minecraft:brown_dye", + "groupId": 40 + }, + { + "id": "minecraft:red_dye", + "groupId": 40 + }, + { + "id": "minecraft:orange_dye", + "groupId": 40 + }, + { + "id": "minecraft:yellow_dye", + "groupId": 40 + }, + { + "id": "minecraft:lime_dye", + "groupId": 40 + }, + { + "id": "minecraft:green_dye", + "groupId": 40 + }, + { + "id": "minecraft:cyan_dye", + "groupId": 40 + }, + { + "id": "minecraft:light_blue_dye", + "groupId": 40 + }, + { + "id": "minecraft:blue_dye", + "groupId": 40 + }, + { + "id": "minecraft:purple_dye", + "groupId": 40 + }, + { + "id": "minecraft:magenta_dye", + "groupId": 40 + }, + { + "id": "minecraft:pink_dye", + "groupId": 40 + }, + { + "id": "minecraft:ink_sac", + "groupId": 41 + }, + { + "id": "minecraft:glow_ink_sac", + "groupId": 41 + }, + { + "id": "minecraft:cocoa_beans", + "groupId": 41 + }, + { + "id": "minecraft:lapis_lazuli", + "groupId": 41 + }, + { + "id": "minecraft:bone_meal", + "groupId": 41 + }, + { + "id": "minecraft:vine", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnZpbmUECQBuYW1lX2hhc2j0Sj8/XeXOLAMKAG5ldHdvcmtfaWSUkDtbCgYAc3RhdGVzAxMAdmluZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:weeping_vines", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAQAACAQAbmFtZRcAbWluZWNyYWZ0OndlZXBpbmdfdmluZXMECQBuYW1lX2hhc2jrLgLHkQygiwMKAG5ldHdvcmtfaWQ8NHSJCgYAc3RhdGVzAxEAd2VlcGluZ192aW5lc19hZ2UAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:twisting_vines", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAgAACAQAbmFtZRgAbWluZWNyYWZ0OnR3aXN0aW5nX3ZpbmVzBAkAbmFtZV9oYXNoDYR5QgVUQJADCgBuZXR3b3JrX2lk5kYVIQoGAHN0YXRlcwMSAHR3aXN0aW5nX3ZpbmVzX2FnZQAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:waterlily", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAAAACAQAbmFtZRMAbWluZWNyYWZ0OndhdGVybGlseQQJAG5hbWVfaGFzaEHgC4c1SXg0AwoAbmV0d29ya19pZOOerp8KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:seagrass", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSBAQAACAQAbmFtZRIAbWluZWNyYWZ0OnNlYWdyYXNzBAkAbmFtZV9oYXNoHSBFtoHdWxIDCgBuZXR3b3JrX2lkd3lhEAoGAHN0YXRlcwgOAHNlYV9ncmFzc190eXBlBwBkZWZhdWx0AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:kelp", + "groupId": 41 + }, + { + "id": "minecraft:deadbush", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAAAACAQAbmFtZRIAbWluZWNyYWZ0OmRlYWRidXNoBAkAbmFtZV9oYXNoPFODe4IScnYDCgBuZXR3b3JrX2lkVfnl+goGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:bamboo", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhbWJvbwQJAG5hbWVfaGFzaBgpGmyzhedCAwoAbmV0d29ya19pZIZv1nYKBgBzdGF0ZXMBBwBhZ2VfYml0AAgQAGJhbWJvb19sZWFmX3NpemUJAG5vX2xlYXZlcwgWAGJhbWJvb19zdGFsa190aGlja25lc3MEAHRoaW4AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:snow", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnNub3cECQBuYW1lX2hhc2gVHr5XXdETWAMKAG5ldHdvcmtfaWQ0zCeHCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:ice", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAAAACAQAbmFtZQ0AbWluZWNyYWZ0OmljZQQJAG5hbWVfaGFzaNF26f+uUT29AwoAbmV0d29ya19pZOUMaQYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:packed_ice", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSuAAAACAQAbmFtZRQAbWluZWNyYWZ0OnBhY2tlZF9pY2UECQBuYW1lX2hhc2hk4bu123ZrFgMKAG5ldHdvcmtfaWTr/ooaCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:blue_ice", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQKAQAACAQAbmFtZRIAbWluZWNyYWZ0OmJsdWVfaWNlBAkAbmFtZV9oYXNo+EKxYgFhKcgDCgBuZXR3b3JrX2lkxfsA8goGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:snow_layer", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAAAACAQAbmFtZRQAbWluZWNyYWZ0OnNub3dfbGF5ZXIECQBuYW1lX2hhc2hXka6atMYUCQMKAG5ldHdvcmtfaWRCrIPcCgYAc3RhdGVzAQsAY292ZXJlZF9iaXQAAwYAaGVpZ2h0AAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:pointed_dripstone", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQzAgAACAQAbmFtZRsAbWluZWNyYWZ0OnBvaW50ZWRfZHJpcHN0b25lBAkAbmFtZV9oYXNoJMISzmHQgt8DCgBuZXR3b3JrX2lkbWrtYgoGAHN0YXRlcwgTAGRyaXBzdG9uZV90aGlja25lc3MDAHRpcAEHAGhhbmdpbmcBAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dripstone_block", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AgAACAQAbmFtZRkAbWluZWNyYWZ0OmRyaXBzdG9uZV9ibG9jawQJAG5hbWVfaGFzaIIXnEqY77YsAwoAbmV0d29ya19pZMZi2kwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:moss_carpet", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWROAgAACAQAbmFtZRUAbWluZWNyYWZ0Om1vc3NfY2FycGV0BAkAbmFtZV9oYXNo/NEDxRPTshYDCgBuZXR3b3JrX2lkaGG3QwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:moss_block", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ/AgAACAQAbmFtZRQAbWluZWNyYWZ0Om1vc3NfYmxvY2sECQBuYW1lX2hhc2iovcsPUYX2tgMKAG5ldHdvcmtfaWT3JSbfCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pale_moss_carpet", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTxBAAACAQAbmFtZRoAbWluZWNyYWZ0OnBhbGVfbW9zc19jYXJwZXQECQBuYW1lX2hhc2g5SFufsjDdpAMKAG5ldHdvcmtfaWSwu2O/CgYAc3RhdGVzCBoAcGFsZV9tb3NzX2NhcnBldF9zaWRlX2Vhc3QEAG5vbmUIGwBwYWxlX21vc3NfY2FycGV0X3NpZGVfbm9ydGgEAG5vbmUIGwBwYWxlX21vc3NfY2FycGV0X3NpZGVfc291dGgEAG5vbmUIGgBwYWxlX21vc3NfY2FycGV0X3NpZGVfd2VzdAQAbm9uZQEPAHVwcGVyX2Jsb2NrX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pale_moss_block", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwBAAACAQAbmFtZRkAbWluZWNyYWZ0OnBhbGVfbW9zc19ibG9jawQJAG5hbWVfaGFzaAv55craFDiRAwoAbmV0d29ya19pZNMKFzcKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:pale_hanging_moss", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTyBAAACAQAbmFtZRsAbWluZWNyYWZ0OnBhbGVfaGFuZ2luZ19tb3NzBAkAbmFtZV9oYXNoNjhSFL+E2aQDCgBuZXR3b3JrX2lkC5iPTgoGAHN0YXRlcwEDAHRpcAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:hanging_roots", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ+AgAACAQAbmFtZRcAbWluZWNyYWZ0Omhhbmdpbmdfcm9vdHMECQBuYW1lX2hhc2jaXn+Y5UZpDAMKAG5ldHdvcmtfaWRU4c2vCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:mangrove_roots", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWThAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNoa786PzQGZ6kDCgBuZXR3b3JrX2lklA0AHgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:muddy_mangrove_roots", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTiAgAACAQAbmFtZR4AbWluZWNyYWZ0Om11ZGR5X21hbmdyb3ZlX3Jvb3RzBAkAbmFtZV9oYXNo9YApdHpo1RkDCgBuZXR3b3JrX2lkH0Oc4woGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:big_dripleaf", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJpZ19kcmlwbGVhZgQJAG5hbWVfaGFzaGBEhXjo6qSdAwoAbmV0d29ya19pZMETsb8KBgBzdGF0ZXMBEQBiaWdfZHJpcGxlYWZfaGVhZAEIEQBiaWdfZHJpcGxlYWZfdGlsdAQAbm9uZQgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:small_dripleaf_block", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRPAgAACAQAbmFtZR4AbWluZWNyYWZ0OnNtYWxsX2RyaXBsZWFmX2Jsb2NrBAkAbmFtZV9oYXNojxRAgXP9uWADCgBuZXR3b3JrX2lkozbVPwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24EAGVhc3QBDwB1cHBlcl9ibG9ja19iaXQBAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:spore_blossom", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRAAgAACAQAbmFtZRcAbWluZWNyYWZ0OnNwb3JlX2Jsb3Nzb20ECQBuYW1lX2hhc2il3U72Gbco2gMKAG5ldHdvcmtfaWSbbbgcCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:azalea", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQAgAACAQAbmFtZRAAbWluZWNyYWZ0OmF6YWxlYQQJAG5hbWVfaGFzaNyUl+BW9JrBAwoAbmV0d29ya19pZO/XZtQKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:flowering_azalea", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRAgAACAQAbmFtZRoAbWluZWNyYWZ0OmZsb3dlcmluZ19hemFsZWEECQBuYW1lX2hhc2ie9r33wz8kiwMKAG5ldHdvcmtfaWQ3ij0VCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:glow_lichen", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSaAgAACAQAbmFtZRUAbWluZWNyYWZ0Omdsb3dfbGljaGVuBAkAbmFtZV9oYXNobyPUrIYlo44DCgBuZXR3b3JrX2lkvcbWHwoGAHN0YXRlcwMZAG11bHRpX2ZhY2VfZGlyZWN0aW9uX2JpdHMAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:amethyst_block", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAgAACAQAbmFtZRgAbWluZWNyYWZ0OmFtZXRoeXN0X2Jsb2NrBAkAbmFtZV9oYXNob+JK1iiAthcDCgBuZXR3b3JrX2lk8HtpzgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:budding_amethyst", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRHAgAACAQAbmFtZRoAbWluZWNyYWZ0OmJ1ZGRpbmdfYW1ldGh5c3QECQBuYW1lX2hhc2gJvAwfI14fxgMKAG5ldHdvcmtfaWTQYqfACgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:amethyst_cluster", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAgAACAQAbmFtZRoAbWluZWNyYWZ0OmFtZXRoeXN0X2NsdXN0ZXIECQBuYW1lX2hhc2jK82S88Jgm8wMKAG5ldHdvcmtfaWSCPMPGCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:large_amethyst_bud", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRJAgAACAQAbmFtZRwAbWluZWNyYWZ0OmxhcmdlX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaAHhdpWD+sd5AwoAbmV0d29ya19pZKkQxOcKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:medium_amethyst_bud", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRKAgAACAQAbmFtZR0AbWluZWNyYWZ0Om1lZGl1bV9hbWV0aHlzdF9idWQECQBuYW1lX2hhc2g5lBGtC0DzZQMKAG5ldHdvcmtfaWSYiP4gCgYAc3RhdGVzCBQAbWluZWNyYWZ0OmJsb2NrX2ZhY2UCAHVwAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:small_amethyst_bud", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRLAgAACAQAbmFtZRwAbWluZWNyYWZ0OnNtYWxsX2FtZXRoeXN0X2J1ZAQJAG5hbWVfaGFzaEnb4+q9PO4YAwoAbmV0d29ya19pZGWzxrQKBgBzdGF0ZXMIFABtaW5lY3JhZnQ6YmxvY2tfZmFjZQIAdXAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:calcite", + "groupId": 41, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAgAACAQAbmFtZREAbWluZWNyYWZ0OmNhbGNpdGUECQBuYW1lX2hhc2ixKLu8ZIdzDQMKAG5ldHdvcmtfaWQlSbJDCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:chicken", + "groupId": 42 + }, + { + "id": "minecraft:porkchop", + "groupId": 42 + }, + { + "id": "minecraft:beef", + "groupId": 42 + }, + { + "id": "minecraft:mutton", + "groupId": 42 + }, + { + "id": "minecraft:rabbit", + "groupId": 42 + }, + { + "id": "minecraft:cod", + "groupId": 42 + }, + { + "id": "minecraft:salmon", + "groupId": 42 + }, + { + "id": "minecraft:tropical_fish", + "groupId": 42 + }, + { + "id": "minecraft:pufferfish", + "groupId": 42 + }, + { + "id": "minecraft:brown_mushroom", + "groupId": 43, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAAAACAQAbmFtZRgAbWluZWNyYWZ0OmJyb3duX211c2hyb29tBAkAbmFtZV9oYXNonYw/FO78WDoDCgBuZXR3b3JrX2lkLh1OXAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:red_mushroom", + "groupId": 43, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQoAAAACAQAbmFtZRYAbWluZWNyYWZ0OnJlZF9tdXNocm9vbQQJAG5hbWVfaGFzaPpzJua7669xAwoAbmV0d29ya19pZCvWPYkKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:crimson_fungus", + "groupId": 43, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTjAQAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fZnVuZ3VzBAkAbmFtZV9oYXNolIcCUuFM2u0DCgBuZXR3b3JrX2lkD2NN0QoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_fungus", + "groupId": 43, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkAQAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9mdW5ndXMECQBuYW1lX2hhc2gq8bSnRVTAFgMKAG5ldHdvcmtfaWTkwS+rCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brown_mushroom_block", + "groupId": 43, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRjAAAACAQAbmFtZR4AbWluZWNyYWZ0OmJyb3duX211c2hyb29tX2Jsb2NrBAkAbmFtZV9oYXNoIyjnbI6xy9sDCgBuZXR3b3JrX2lkdOMhDAoGAHN0YXRlcwMSAGh1Z2VfbXVzaHJvb21fYml0cw4AAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:red_mushroom_block", + "groupId": 43, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAAAACAQAbmFtZRwAbWluZWNyYWZ0OnJlZF9tdXNocm9vbV9ibG9jawQJAG5hbWVfaGFzaJTTyJbth9M9AwoAbmV0d29ya19pZM+AyboKBgBzdGF0ZXMDEgBodWdlX211c2hyb29tX2JpdHMOAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:mushroom_stem", + "groupId": 43, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTvBAAACAQAbmFtZRcAbWluZWNyYWZ0Om11c2hyb29tX3N0ZW0ECQBuYW1lX2hhc2i2SozhK9NLpgMKAG5ldHdvcmtfaWTTVND+CgYAc3RhdGVzAxIAaHVnZV9tdXNocm9vbV9iaXRzDwAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:egg", + "groupId": 44 + }, + { + "id": "minecraft:sugar_cane", + "groupId": 44 + }, + { + "id": "minecraft:sugar", + "groupId": 44 + }, + { + "id": "minecraft:rotten_flesh", + "groupId": 44 + }, + { + "id": "minecraft:bone", + "groupId": 44 + }, + { + "id": "minecraft:web", + "groupId": 44, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQeAAAACAQAbmFtZQ0AbWluZWNyYWZ0OndlYgQJAG5hbWVfaGFzaA4GKQCvG4i9AwoAbmV0d29ya19pZApt+jgKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:spider_eye", + "groupId": 44 + }, + { + "id": "minecraft:mob_spawner", + "groupId": 44, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ0AAAACAQAbmFtZRUAbWluZWNyYWZ0Om1vYl9zcGF3bmVyBAkAbmFtZV9oYXNoNwGrCV/Fkh8DCgBuZXR3b3JrX2lkM1wTmgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:trial_spawner", + "groupId": 44, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AgAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaWFsX3NwYXduZXIECQBuYW1lX2hhc2iNLRPB4ACz+QMKAG5ldHdvcmtfaWTWFYHGCgYAc3RhdGVzAQcAb21pbm91cwADEwB0cmlhbF9zcGF3bmVyX3N0YXRlAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:vault", + "groupId": 44, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ5AgAACAQAbmFtZQ8AbWluZWNyYWZ0OnZhdWx0BAkAbmFtZV9oYXNoCAp9n3IAyqcDCgBuZXR3b3JrX2lk6/P+vwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAQcAb21pbm91cwAICwB2YXVsdF9zdGF0ZQgAaW5hY3RpdmUAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:creaking_heart", + "groupId": 44, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTzBAAACAQAbmFtZRgAbWluZWNyYWZ0OmNyZWFraW5nX2hlYXJ0BAkAbmFtZV9oYXNoQcOV0pmSMeADCgBuZXR3b3JrX2lk0dPBzwoGAHN0YXRlcwgUAGNyZWFraW5nX2hlYXJ0X3N0YXRlCAB1cHJvb3RlZAEHAG5hdHVyYWwACAsAcGlsbGFyX2F4aXMBAHkAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:end_portal_frame", + "groupId": 44, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR4AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuZF9wb3J0YWxfZnJhbWUECQBuYW1lX2hhc2gqofyUIjGOpQMKAG5ldHdvcmtfaWRbGHf8CgYAc3RhdGVzARIAZW5kX3BvcnRhbF9leWVfYml0AAgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:infested_stone", + "groupId": 45, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRhAAAACAQAbmFtZRgAbWluZWNyYWZ0OmluZmVzdGVkX3N0b25lBAkAbmFtZV9oYXNoxnRcHDu4zqQDCgBuZXR3b3JrX2lkpfcnsgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:infested_cobblestone", + "groupId": 45, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZBAAACAQAbmFtZR4AbWluZWNyYWZ0OmluZmVzdGVkX2NvYmJsZXN0b25lBAkAbmFtZV9oYXNoy+LVCKG2kVMDCgBuZXR3b3JrX2lkpn+icAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:infested_stone_bricks", + "groupId": 45, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRaBAAACAQAbmFtZR8AbWluZWNyYWZ0OmluZmVzdGVkX3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaBMnals7a32CAwoAbmV0d29ya19pZNHi2UYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:infested_mossy_stone_bricks", + "groupId": 45, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRbBAAACAQAbmFtZSUAbWluZWNyYWZ0OmluZmVzdGVkX21vc3N5X3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaAmJk+HmVq0rAwoAbmV0d29ya19pZAVH8/sKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:infested_cracked_stone_bricks", + "groupId": 45, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRcBAAACAQAbmFtZScAbWluZWNyYWZ0OmluZmVzdGVkX2NyYWNrZWRfc3RvbmVfYnJpY2tzBAkAbmFtZV9oYXNoMyc60XcfcyoDCgBuZXR3b3JrX2lkaW+kbQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:infested_chiseled_stone_bricks", + "groupId": 45, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRdBAAACAQAbmFtZSgAbWluZWNyYWZ0OmluZmVzdGVkX2NoaXNlbGVkX3N0b25lX2JyaWNrcwQJAG5hbWVfaGFzaNUvNIIg9dZbAwoAbmV0d29ya19pZCajGicKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:infested_deepslate", + "groupId": 45, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAgAACAQAbmFtZRwAbWluZWNyYWZ0OmluZmVzdGVkX2RlZXBzbGF0ZQQJAG5hbWVfaGFzaICF2VYccxF1AwoAbmV0d29ya19pZDa/624KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dragon_egg", + "groupId": 46, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR6AAAACAQAbmFtZRQAbWluZWNyYWZ0OmRyYWdvbl9lZ2cECQBuYW1lX2hhc2inMzXrV+/e1wMKAG5ldHdvcmtfaWTgO1yRCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:turtle_egg", + "groupId": 46, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAQAACAQAbmFtZRQAbWluZWNyYWZ0OnR1cnRsZV9lZ2cECQBuYW1lX2hhc2iwSRcxOJIJ9gMKAG5ldHdvcmtfaWSIRNUhCgYAc3RhdGVzCA0AY3JhY2tlZF9zdGF0ZQkAbm9fY3JhY2tzCBAAdHVydGxlX2VnZ19jb3VudAcAb25lX2VnZwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:sniffer_egg", + "groupId": 46, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTAwAACAQAbmFtZRUAbWluZWNyYWZ0OnNuaWZmZXJfZWdnBAkAbmFtZV9oYXNoY1lozc8lPcYDCgBuZXR3b3JrX2lk7yb/2QoGAHN0YXRlcwgNAGNyYWNrZWRfc3RhdGUJAG5vX2NyYWNrcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:frog_spawn", + "groupId": 46, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTTAgAACAQAbmFtZRQAbWluZWNyYWZ0OmZyb2dfc3Bhd24ECQBuYW1lX2hhc2iWmd7idp3ZZwMKAG5ldHdvcmtfaWRFzJudCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pearlescent_froglight", + "groupId": 46, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAgAACAQAbmFtZR8AbWluZWNyYWZ0OnBlYXJsZXNjZW50X2Zyb2dsaWdodAQJAG5hbWVfaGFzaKkcFRyycYGyAwoAbmV0d29ya19pZJqYakAKBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:verdant_froglight", + "groupId": 46, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAgAACAQAbmFtZRsAbWluZWNyYWZ0OnZlcmRhbnRfZnJvZ2xpZ2h0BAkAbmFtZV9oYXNoA+eXuTBohrQDCgBuZXR3b3JrX2lkDIVnsQoGAHN0YXRlcwgLAHBpbGxhcl9heGlzAQB5AAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:ochre_froglight", + "groupId": 46, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTWAgAACAQAbmFtZRkAbWluZWNyYWZ0Om9jaHJlX2Zyb2dsaWdodAQJAG5hbWVfaGFzaMY59kjPe+c3AwoAbmV0d29ya19pZO2TD50KBgBzdGF0ZXMICwBwaWxsYXJfYXhpcwEAeQADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:chicken_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:bee_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:cow_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:pig_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:sheep_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:wolf_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:polar_bear_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:ocelot_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:cat_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:mooshroom_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:bat_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:parrot_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:rabbit_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:llama_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:horse_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:donkey_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:mule_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:skeleton_horse_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:zombie_horse_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:tropical_fish_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:cod_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:pufferfish_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:salmon_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:dolphin_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:turtle_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:panda_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:fox_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:creeper_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:enderman_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:silverfish_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:skeleton_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:wither_skeleton_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:stray_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:slime_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:spider_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:zombie_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:zombie_pigman_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:husk_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:drowned_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:squid_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:glow_squid_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:cave_spider_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:witch_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:guardian_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:elder_guardian_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:endermite_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:magma_cube_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:strider_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:hoglin_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:piglin_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:zoglin_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:piglin_brute_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:goat_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:axolotl_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:warden_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:allay_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:frog_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:tadpole_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:trader_llama_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:camel_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:ghast_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:blaze_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:shulker_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:vindicator_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:evoker_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:vex_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:villager_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:wandering_trader_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:zombie_villager_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:phantom_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:pillager_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:ravager_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:iron_golem_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:snow_golem_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:sniffer_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:breeze_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:armadillo_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:bogged_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:creaking_spawn_egg", + "groupId": 47 + }, + { + "id": "minecraft:obsidian", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQxAAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2lkaWFuBAkAbmFtZV9oYXNoiz4qrb8QjyEDCgBuZXR3b3JrX2lkuqnPpQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:crying_obsidian", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQgAgAACAQAbmFtZRkAbWluZWNyYWZ0OmNyeWluZ19vYnNpZGlhbgQJAG5hbWVfaGFzaKT0JlA7Z1K+AwoAbmV0d29ya19pZCjbPV4KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bedrock", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQHAAAACAQAbmFtZREAbWluZWNyYWZ0OmJlZHJvY2sECQBuYW1lX2hhc2hWfFrh4LVtxwMKAG5ldHdvcmtfaWT7fKz1CgYAc3RhdGVzAQ4AaW5maW5pYnVybl9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:soul_sand", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYAAAACAQAbmFtZRMAbWluZWNyYWZ0OnNvdWxfc2FuZAQJAG5hbWVfaGFzaMaf+bccu+KTAwoAbmV0d29ya19pZBQSHrMKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:magma", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTVAAAACAQAbmFtZQ8AbWluZWNyYWZ0Om1hZ21hBAkAbmFtZV9oYXNoqyTjKaIsWfYDCgBuZXR3b3JrX2lkyfWAZgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:nether_wart", + "groupId": 48 + }, + { + "id": "minecraft:end_stone", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR5AAAACAQAbmFtZRMAbWluZWNyYWZ0OmVuZF9zdG9uZQQJAG5hbWVfaGFzaH1J9jA39GJNAwoAbmV0d29ya19pZFeFQ7UKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chorus_flower", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAAAACAQAbmFtZRcAbWluZWNyYWZ0OmNob3J1c19mbG93ZXIECQBuYW1lX2hhc2iMpSodli5uawMKAG5ldHdvcmtfaWRnd1ZWCgYAc3RhdGVzAwMAYWdlAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:chorus_plant", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTwAAAACAQAbmFtZRYAbWluZWNyYWZ0OmNob3J1c19wbGFudAQJAG5hbWVfaGFzaJhSrmNGKwaMAwoAbmV0d29ya19pZA3uVqMKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chorus_fruit", + "groupId": 48 + }, + { + "id": "minecraft:popped_chorus_fruit", + "groupId": 48 + }, + { + "id": "minecraft:sponge", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQTAAAACAQAbmFtZRAAbWluZWNyYWZ0OnNwb25nZQQJAG5hbWVfaGFzaLrd2ScYRDMiAwoAbmV0d29ya19pZNmQW/oKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:wet_sponge", + "groupId": 48, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTXBAAACAQAbmFtZRQAbWluZWNyYWZ0OndldF9zcG9uZ2UECQBuYW1lX2hhc2htp6nKpSHcAgMKAG5ldHdvcmtfaWQaW+fCCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:tube_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAQAACAQAbmFtZRoAbWluZWNyYWZ0OnR1YmVfY29yYWxfYmxvY2sECQBuYW1lX2hhc2iGkaiR7Eot4wMKAG5ldHdvcmtfaWQPNJ6sCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:brain_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRQBAAACAQAbmFtZRsAbWluZWNyYWZ0OmJyYWluX2NvcmFsX2Jsb2NrBAkAbmFtZV9oYXNoeDNAK18yUo4DCgBuZXR3b3JrX2lkloN1vgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:bubble_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRRBAAACAQAbmFtZRwAbWluZWNyYWZ0OmJ1YmJsZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaAI2mwMlvcNbAwoAbmV0d29ya19pZBlkxKIKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:fire_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRSBAAACAQAbmFtZRoAbWluZWNyYWZ0OmZpcmVfY29yYWxfYmxvY2sECQBuYW1lX2hhc2gg1gLeXLmKaAMKAG5ldHdvcmtfaWSp3W57CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:horn_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRTBAAACAQAbmFtZRoAbWluZWNyYWZ0Omhvcm5fY29yYWxfYmxvY2sECQBuYW1lX2hhc2hnZSLRWUwGhAMKAG5ldHdvcmtfaWRSK6ccCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dead_tube_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfdHViZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaB9+lY3hAkNNAwoAbmV0d29ya19pZF0hKKYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dead_brain_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRVBAAACAQAbmFtZSAAbWluZWNyYWZ0OmRlYWRfYnJhaW5fY29yYWxfYmxvY2sECQBuYW1lX2hhc2iHyDn52AO8uwMKAG5ldHdvcmtfaWQw7yCaCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dead_bubble_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRWBAAACAQAbmFtZSEAbWluZWNyYWZ0OmRlYWRfYnViYmxlX2NvcmFsX2Jsb2NrBAkAbmFtZV9oYXNotwkk/ITrsjADCgBuZXR3b3JrX2lk56mXUgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dead_fire_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRXBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfZmlyZV9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaG0qHxbIrBEyAwoAbmV0d29ya19pZFvnH88KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:dead_horn_coral_block", + "groupId": 49, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRYBAAACAQAbmFtZR8AbWluZWNyYWZ0OmRlYWRfaG9ybl9jb3JhbF9ibG9jawQJAG5hbWVfaGFzaL7D8bu4Fm+0AwoAbmV0d29ya19pZEALRLoKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:sculk", + "groupId": 50, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAgAACAQAbmFtZQ8AbWluZWNyYWZ0OnNjdWxrBAkAbmFtZV9oYXNo2Lq7T5yQF8kDCgBuZXR3b3JrX2lkyqUPPgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:sculk_vein", + "groupId": 50, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNjdWxrX3ZlaW4ECQBuYW1lX2hhc2gJUdhVooV4zwMKAG5ldHdvcmtfaWSUfn1XCgYAc3RhdGVzAxkAbXVsdGlfZmFjZV9kaXJlY3Rpb25fYml0cwAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:sculk_catalyst", + "groupId": 50, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX2NhdGFseXN0BAkAbmFtZV9oYXNo+gCpbrCHST4DCgBuZXR3b3JrX2lkMJ2n/woGAHN0YXRlcwEFAGJsb29tAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:sculk_shrieker", + "groupId": 50, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTMAgAACAQAbmFtZRgAbWluZWNyYWZ0OnNjdWxrX3Nocmlla2VyBAkAbmFtZV9oYXNo5OXtyObniQ4DCgBuZXR3b3JrX2lkxapoNAoGAHN0YXRlcwEGAGFjdGl2ZQABCgBjYW5fc3VtbW9uAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:sculk_sensor", + "groupId": 50, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNjdWxrX3NlbnNvcgQJAG5hbWVfaGFzaCkmHreeTgNnAwoAbmV0d29ya19pZLj2WPcKBgBzdGF0ZXMDEgBzY3Vsa19zZW5zb3JfcGhhc2UAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:calibrated_sculk_sensor", + "groupId": 50, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRDAwAACAQAbmFtZSEAbWluZWNyYWZ0OmNhbGlicmF0ZWRfc2N1bGtfc2Vuc29yBAkAbmFtZV9oYXNoffAcXXN/iJUDCgBuZXR3b3JrX2lkwOx3QQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAxIAc2N1bGtfc2Vuc29yX3BoYXNlAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:reinforced_deepslate", + "groupId": 51, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTRAgAACAQAbmFtZR4AbWluZWNyYWZ0OnJlaW5mb3JjZWRfZGVlcHNsYXRlBAkAbmFtZV9oYXNoldDmj91EapQDCgBuZXR3b3JrX2lkHIt+aQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:leather_helmet", + "groupId": 52 + }, + { + "id": "minecraft:chainmail_helmet", + "groupId": 52 + }, + { + "id": "minecraft:iron_helmet", + "groupId": 52 + }, + { + "id": "minecraft:golden_helmet", + "groupId": 52 + }, + { + "id": "minecraft:diamond_helmet", + "groupId": 52 + }, + { + "id": "minecraft:netherite_helmet", + "groupId": 52 + }, + { + "id": "minecraft:leather_chestplate", + "groupId": 53 + }, + { + "id": "minecraft:chainmail_chestplate", + "groupId": 53 + }, + { + "id": "minecraft:iron_chestplate", + "groupId": 53 + }, + { + "id": "minecraft:golden_chestplate", + "groupId": 53 + }, + { + "id": "minecraft:diamond_chestplate", + "groupId": 53 + }, + { + "id": "minecraft:netherite_chestplate", + "groupId": 53 + }, + { + "id": "minecraft:leather_leggings", + "groupId": 54 + }, + { + "id": "minecraft:chainmail_leggings", + "groupId": 54 + }, + { + "id": "minecraft:iron_leggings", + "groupId": 54 + }, + { + "id": "minecraft:golden_leggings", + "groupId": 54 + }, + { + "id": "minecraft:diamond_leggings", + "groupId": 54 + }, + { + "id": "minecraft:netherite_leggings", + "groupId": 54 + }, + { + "id": "minecraft:leather_boots", + "groupId": 55 + }, + { + "id": "minecraft:chainmail_boots", + "groupId": 55 + }, + { + "id": "minecraft:iron_boots", + "groupId": 55 + }, + { + "id": "minecraft:golden_boots", + "groupId": 55 + }, + { + "id": "minecraft:diamond_boots", + "groupId": 55 + }, + { + "id": "minecraft:netherite_boots", + "groupId": 55 + }, + { + "id": "minecraft:wooden_sword", + "groupId": 56 + }, + { + "id": "minecraft:stone_sword", + "groupId": 56 + }, + { + "id": "minecraft:iron_sword", + "groupId": 56 + }, + { + "id": "minecraft:golden_sword", + "groupId": 56 + }, + { + "id": "minecraft:diamond_sword", + "groupId": 56 + }, + { + "id": "minecraft:netherite_sword", + "groupId": 56 + }, + { + "id": "minecraft:wooden_axe", + "groupId": 57 + }, + { + "id": "minecraft:stone_axe", + "groupId": 57 + }, + { + "id": "minecraft:iron_axe", + "groupId": 57 + }, + { + "id": "minecraft:golden_axe", + "groupId": 57 + }, + { + "id": "minecraft:diamond_axe", + "groupId": 57 + }, + { + "id": "minecraft:netherite_axe", + "groupId": 57 + }, + { + "id": "minecraft:wooden_pickaxe", + "groupId": 58 + }, + { + "id": "minecraft:stone_pickaxe", + "groupId": 58 + }, + { + "id": "minecraft:iron_pickaxe", + "groupId": 58 + }, + { + "id": "minecraft:golden_pickaxe", + "groupId": 58 + }, + { + "id": "minecraft:diamond_pickaxe", + "groupId": 58 + }, + { + "id": "minecraft:netherite_pickaxe", + "groupId": 58 + }, + { + "id": "minecraft:wooden_shovel", + "groupId": 59 + }, + { + "id": "minecraft:stone_shovel", + "groupId": 59 + }, + { + "id": "minecraft:iron_shovel", + "groupId": 59 + }, + { + "id": "minecraft:golden_shovel", + "groupId": 59 + }, + { + "id": "minecraft:diamond_shovel", + "groupId": 59 + }, + { + "id": "minecraft:netherite_shovel", + "groupId": 59 + }, + { + "id": "minecraft:wooden_hoe", + "groupId": 60 + }, + { + "id": "minecraft:stone_hoe", + "groupId": 60 + }, + { + "id": "minecraft:iron_hoe", + "groupId": 60 + }, + { + "id": "minecraft:golden_hoe", + "groupId": 60 + }, + { + "id": "minecraft:diamond_hoe", + "groupId": 60 + }, + { + "id": "minecraft:netherite_hoe", + "groupId": 60 + }, + { + "id": "minecraft:bow", + "groupId": 61 + }, + { + "id": "minecraft:crossbow", + "groupId": 61 + }, + { + "id": "minecraft:mace", + "groupId": 61 + }, + { + "id": "minecraft:arrow", + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 6, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 7, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 8, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 9, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 10, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 11, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 12, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 13, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 14, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 15, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 16, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 17, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 18, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 19, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 20, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 21, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 22, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 23, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 24, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 25, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 26, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 27, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 28, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 29, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 30, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 31, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 32, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 33, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 34, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 35, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 36, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 37, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 38, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 39, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 40, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 41, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 42, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 43, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 44, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 45, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 46, + "groupId": 62 + }, + { + "id": "minecraft:arrow", + "damage": 47, + "groupId": 62 + }, + { + "id": "minecraft:shield", + "groupId": 63 + }, + { + "id": "minecraft:cooked_chicken", + "groupId": 64 + }, + { + "id": "minecraft:cooked_porkchop", + "groupId": 64 + }, + { + "id": "minecraft:cooked_beef", + "groupId": 64 + }, + { + "id": "minecraft:cooked_mutton", + "groupId": 64 + }, + { + "id": "minecraft:cooked_rabbit", + "groupId": 64 + }, + { + "id": "minecraft:cooked_cod", + "groupId": 64 + }, + { + "id": "minecraft:cooked_salmon", + "groupId": 64 + }, + { + "id": "minecraft:bread", + "groupId": 65 + }, + { + "id": "minecraft:mushroom_stew", + "groupId": 65 + }, + { + "id": "minecraft:beetroot_soup", + "groupId": 65 + }, + { + "id": "minecraft:rabbit_stew", + "groupId": 65 + }, + { + "id": "minecraft:baked_potato", + "groupId": 65 + }, + { + "id": "minecraft:cookie", + "groupId": 65 + }, + { + "id": "minecraft:pumpkin_pie", + "groupId": 65 + }, + { + "id": "minecraft:cake", + "groupId": 65 + }, + { + "id": "minecraft:dried_kelp", + "groupId": 65 + }, + { + "id": "minecraft:fishing_rod", + "groupId": 66 + }, + { + "id": "minecraft:carrot_on_a_stick", + "groupId": 66 + }, + { + "id": "minecraft:warped_fungus_on_a_stick", + "groupId": 66 + }, + { + "id": "minecraft:snowball", + "groupId": 66 + }, + { + "id": "minecraft:wind_charge", + "groupId": 66 + }, + { + "id": "minecraft:shears", + "groupId": 66 + }, + { + "id": "minecraft:flint_and_steel", + "groupId": 66 + }, + { + "id": "minecraft:lead", + "groupId": 66 + }, + { + "id": "minecraft:clock", + "groupId": 66 + }, + { + "id": "minecraft:compass", + "groupId": 66 + }, + { + "id": "minecraft:recovery_compass", + "groupId": 66 + }, + { + "id": "minecraft:goat_horn", + "groupId": 67 + }, + { + "id": "minecraft:goat_horn", + "damage": 1, + "groupId": 67 + }, + { + "id": "minecraft:goat_horn", + "damage": 2, + "groupId": 67 + }, + { + "id": "minecraft:goat_horn", + "damage": 3, + "groupId": 67 + }, + { + "id": "minecraft:goat_horn", + "damage": 4, + "groupId": 67 + }, + { + "id": "minecraft:goat_horn", + "damage": 5, + "groupId": 67 + }, + { + "id": "minecraft:goat_horn", + "damage": 6, + "groupId": 67 + }, + { + "id": "minecraft:goat_horn", + "damage": 7, + "groupId": 67 + }, + { + "id": "minecraft:empty_map", + "groupId": 68 + }, + { + "id": "minecraft:empty_map", + "damage": 2, + "groupId": 68 + }, + { + "id": "minecraft:saddle", + "groupId": 68 + }, + { + "id": "minecraft:bundle", + "groupId": 69 + }, + { + "id": "minecraft:white_bundle", + "groupId": 69 + }, + { + "id": "minecraft:light_gray_bundle", + "groupId": 69 + }, + { + "id": "minecraft:gray_bundle", + "groupId": 69 + }, + { + "id": "minecraft:black_bundle", + "groupId": 69 + }, + { + "id": "minecraft:brown_bundle", + "groupId": 69 + }, + { + "id": "minecraft:red_bundle", + "groupId": 69 + }, + { + "id": "minecraft:orange_bundle", + "groupId": 69 + }, + { + "id": "minecraft:yellow_bundle", + "groupId": 69 + }, + { + "id": "minecraft:lime_bundle", + "groupId": 69 + }, + { + "id": "minecraft:green_bundle", + "groupId": 69 + }, + { + "id": "minecraft:cyan_bundle", + "groupId": 69 + }, + { + "id": "minecraft:light_blue_bundle", + "groupId": 69 + }, + { + "id": "minecraft:blue_bundle", + "groupId": 69 + }, + { + "id": "minecraft:purple_bundle", + "groupId": 69 + }, + { + "id": "minecraft:magenta_bundle", + "groupId": 69 + }, + { + "id": "minecraft:pink_bundle", + "groupId": 69 + }, + { + "id": "minecraft:leather_horse_armor", + "groupId": 70 + }, + { + "id": "minecraft:iron_horse_armor", + "groupId": 70 + }, + { + "id": "minecraft:golden_horse_armor", + "groupId": 70 + }, + { + "id": "minecraft:diamond_horse_armor", + "groupId": 70 + }, + { + "id": "minecraft:wolf_armor", + "groupId": 71 + }, + { + "id": "minecraft:trident", + "groupId": 71 + }, + { + "id": "minecraft:turtle_helmet", + "groupId": 71 + }, + { + "id": "minecraft:elytra", + "groupId": 71 + }, + { + "id": "minecraft:totem_of_undying", + "groupId": 71 + }, + { + "id": "minecraft:glass_bottle", + "groupId": 71 + }, + { + "id": "minecraft:experience_bottle", + "groupId": 71 + }, + { + "id": "minecraft:potion", + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 1, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 2, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 3, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 4, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 5, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 6, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 7, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 8, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 9, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 10, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 11, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 12, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 13, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 14, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 15, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 16, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 17, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 18, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 19, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 20, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 21, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 22, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 23, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 24, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 25, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 26, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 27, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 28, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 29, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 30, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 31, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 32, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 33, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 34, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 35, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 36, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 37, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 38, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 39, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 40, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 41, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 42, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 43, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 44, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 45, + "groupId": 72 + }, + { + "id": "minecraft:potion", + "damage": 46, + "groupId": 72 + }, + { + "id": "minecraft:splash_potion", + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 1, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 2, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 3, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 4, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 5, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 6, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 7, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 8, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 9, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 10, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 11, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 12, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 13, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 14, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 15, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 16, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 17, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 18, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 19, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 20, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 21, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 22, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 23, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 24, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 25, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 26, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 27, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 28, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 29, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 30, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 31, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 32, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 33, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 34, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 35, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 36, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 37, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 38, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 39, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 40, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 41, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 42, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 43, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 44, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 45, + "groupId": 73 + }, + { + "id": "minecraft:splash_potion", + "damage": 46, + "groupId": 73 + }, + { + "id": "minecraft:lingering_potion", + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 1, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 2, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 3, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 4, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 5, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 6, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 7, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 8, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 9, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 10, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 11, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 12, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 13, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 14, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 15, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 16, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 17, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 18, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 19, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 20, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 21, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 22, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 23, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 24, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 25, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 26, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 27, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 28, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 29, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 30, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 31, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 32, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 33, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 34, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 35, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 36, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 37, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 38, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 39, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 40, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 41, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 42, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 43, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 44, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 45, + "groupId": 74 + }, + { + "id": "minecraft:lingering_potion", + "damage": 46, + "groupId": 74 + }, + { + "id": "minecraft:ominous_bottle", + "groupId": 75 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 1, + "groupId": 75 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 2, + "groupId": 75 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 3, + "groupId": 75 + }, + { + "id": "minecraft:ominous_bottle", + "damage": 4, + "groupId": 75 + }, + { + "id": "minecraft:spyglass", + "groupId": 76 + }, + { + "id": "minecraft:brush", + "groupId": 76 + }, + { + "id": "minecraft:stick", + "groupId": 77 + }, + { + "id": "minecraft:bed", + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 8, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 7, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 15, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 12, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 14, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 1, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 4, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 5, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 13, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 9, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 3, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 11, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 10, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 2, + "groupId": 78 + }, + { + "id": "minecraft:bed", + "damage": 6, + "groupId": 78 + }, + { + "id": "minecraft:torch", + "groupId": 79, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQyAAAACAQAbmFtZQ8AbWluZWNyYWZ0OnRvcmNoBAkAbmFtZV9oYXNoagn7rmDBzisDCgBuZXR3b3JrX2lk+BwwuQoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:soul_torch", + "groupId": 79, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQLAgAACAQAbmFtZRQAbWluZWNyYWZ0OnNvdWxfdG9yY2gECQBuYW1lX2hhc2huixOT04BRdQMKAG5ldHdvcmtfaWShbFILCgYAc3RhdGVzCBYAdG9yY2hfZmFjaW5nX2RpcmVjdGlvbgcAdW5rbm93bgADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:sea_pickle", + "groupId": 79, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAQAACAQAbmFtZRQAbWluZWNyYWZ0OnNlYV9waWNrbGUECQBuYW1lX2hhc2iONEfZJB+glgMKAG5ldHdvcmtfaWSINWQyCgYAc3RhdGVzAw0AY2x1c3Rlcl9jb3VudAAAAAABCABkZWFkX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:lantern", + "groupId": 79, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTPAQAACAQAbmFtZREAbWluZWNyYWZ0OmxhbnRlcm4ECQBuYW1lX2hhc2hMw44VI2HWygMKAG5ldHdvcmtfaWRkjQvzCgYAc3RhdGVzAQcAaGFuZ2luZwAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:soul_lantern", + "groupId": 79, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQMAgAACAQAbmFtZRYAbWluZWNyYWZ0OnNvdWxfbGFudGVybgQJAG5hbWVfaGFzaGjIpjxk9z+RAwoAbmV0d29ya19pZGfoP8cKBgBzdGF0ZXMBBwBoYW5naW5nAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSbAgAACAQAbmFtZRAAbWluZWNyYWZ0OmNhbmRsZQQJAG5hbWVfaGFzaHPd+MsNdWTfAwoAbmV0d29ya19pZHsBMA0KBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:white_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAgAACAQAbmFtZRYAbWluZWNyYWZ0OndoaXRlX2NhbmRsZQQJAG5hbWVfaGFzaN1EG5Q1mHiEAwoAbmV0d29ya19pZKN1mmgKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:orange_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSdAgAACAQAbmFtZRcAbWluZWNyYWZ0Om9yYW5nZV9jYW5kbGUECQBuYW1lX2hhc2jySEVWHgUIHQMKAG5ldHdvcmtfaWSfVz82CgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:magenta_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSeAgAACAQAbmFtZRgAbWluZWNyYWZ0Om1hZ2VudGFfY2FuZGxlBAkAbmFtZV9oYXNoG0u6YIOoBSEDCgBuZXR3b3JrX2lk9xGNkQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:light_blue_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSfAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfY2FuZGxlBAkAbmFtZV9oYXNocXGeK0zgrG0DCgBuZXR3b3JrX2lk2m1y8goGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:yellow_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSgAgAACAQAbmFtZRcAbWluZWNyYWZ0OnllbGxvd19jYW5kbGUECQBuYW1lX2hhc2i00dtusU3CqQMKAG5ldHdvcmtfaWR9LTmpCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:lime_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWShAgAACAQAbmFtZRUAbWluZWNyYWZ0OmxpbWVfY2FuZGxlBAkAbmFtZV9oYXNokcmrw5xvz7ADCgBuZXR3b3JrX2lkIAUu6QoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:pink_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSiAgAACAQAbmFtZRUAbWluZWNyYWZ0OnBpbmtfY2FuZGxlBAkAbmFtZV9oYXNoQJdEY4sZ0dwDCgBuZXR3b3JrX2lk23Rn5AoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:gray_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSjAgAACAQAbmFtZRUAbWluZWNyYWZ0OmdyYXlfY2FuZGxlBAkAbmFtZV9oYXNoS5poSo9wBDEDCgBuZXR3b3JrX2lk3trRCAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:light_gray_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSkAgAACAQAbmFtZRsAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfY2FuZGxlBAkAbmFtZV9oYXNo9ruTZLBNMasDCgBuZXR3b3JrX2lkb6DOegoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cyan_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSlAgAACAQAbmFtZRUAbWluZWNyYWZ0OmN5YW5fY2FuZGxlBAkAbmFtZV9oYXNoc/M8PNVcjOwDCgBuZXR3b3JrX2lkZoIQOQoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:purple_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSmAgAACAQAbmFtZRcAbWluZWNyYWZ0OnB1cnBsZV9jYW5kbGUECQBuYW1lX2hhc2jaI3xUW0/myQMKAG5ldHdvcmtfaWSnLI2BCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:blue_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSnAgAACAQAbmFtZRUAbWluZWNyYWZ0OmJsdWVfY2FuZGxlBAkAbmFtZV9oYXNoAASSPW6TgQADCgBuZXR3b3JrX2lkrxrjQAoGAHN0YXRlcwMHAGNhbmRsZXMAAAAAAQMAbGl0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:brown_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSoAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJyb3duX2NhbmRsZQQJAG5hbWVfaGFzaDia0l6s1+WYAwoAbmV0d29ya19pZKSkBXYKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:green_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAgAACAQAbmFtZRYAbWluZWNyYWZ0OmdyZWVuX2NhbmRsZQQJAG5hbWVfaGFzaLeFPO1l+fIoAwoAbmV0d29ya19pZBkznDsKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:red_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSqAgAACAQAbmFtZRQAbWluZWNyYWZ0OnJlZF9jYW5kbGUECQBuYW1lX2hhc2jjAQpGf59ZdwMKAG5ldHdvcmtfaWRbb88GCgYAc3RhdGVzAwcAY2FuZGxlcwAAAAABAwBsaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:black_candle", + "groupId": 80, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSrAgAACAQAbmFtZRYAbWluZWNyYWZ0OmJsYWNrX2NhbmRsZQQJAG5hbWVfaGFzaB+wRDpOqREKAwoAbmV0d29ya19pZNnOnuEKBgBzdGF0ZXMDBwBjYW5kbGVzAAAAAAEDAGxpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:crafting_table", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ6AAAACAQAbmFtZRgAbWluZWNyYWZ0OmNyYWZ0aW5nX3RhYmxlBAkAbmFtZV9oYXNoe76VAmjvbpYDCgBuZXR3b3JrX2lkwCxwaAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cartography_table", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHAQAACAQAbmFtZRsAbWluZWNyYWZ0OmNhcnRvZ3JhcGh5X3RhYmxlBAkAbmFtZV9oYXNomaWiiD/znP8DCgBuZXR3b3JrX2lkI6FzMwoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:fletching_table", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIAQAACAQAbmFtZRkAbWluZWNyYWZ0OmZsZXRjaGluZ190YWJsZQQJAG5hbWVfaGFzaPFibh8unKyUAwoAbmV0d29ya19pZJ2mW0oKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:smithing_table", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJAQAACAQAbmFtZRgAbWluZWNyYWZ0OnNtaXRoaW5nX3RhYmxlBAkAbmFtZV9oYXNo4tFES2xOXEYDCgBuZXR3b3JrX2lkXWMBzQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:beehive", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAQAACAQAbmFtZREAbWluZWNyYWZ0OmJlZWhpdmUECQBuYW1lX2hhc2hCcqn12UbNpwMKAG5ldHdvcmtfaWR/idcaCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAMLAGhvbmV5X2xldmVsAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:suspicious_sand", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQQAwAACAQAbmFtZRkAbWluZWNyYWZ0OnN1c3BpY2lvdXNfc2FuZAQJAG5hbWVfaGFzaL67QsuvLP00AwoAbmV0d29ya19pZKnkaIAKBgBzdGF0ZXMDEABicnVzaGVkX3Byb2dyZXNzAAAAAAEHAGhhbmdpbmcBAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:suspicious_gravel", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ8AwAACAQAbmFtZRsAbWluZWNyYWZ0OnN1c3BpY2lvdXNfZ3JhdmVsBAkAbmFtZV9oYXNoJSVbGNk7C3oDCgBuZXR3b3JrX2lkvIEJAAoGAHN0YXRlcwMQAGJydXNoZWRfcHJvZ3Jlc3MAAAAAAQcAaGFuZ2luZwEAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:campfire", + "groupId": 81 + }, + { + "id": "minecraft:soul_campfire", + "groupId": 81 + }, + { + "id": "minecraft:furnace", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ9AAAACAQAbmFtZREAbWluZWNyYWZ0OmZ1cm5hY2UECQBuYW1lX2hhc2ioOQrludYY8wMKAG5ldHdvcmtfaWRZxnDOCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:blast_furnace", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTDAQAACAQAbmFtZRcAbWluZWNyYWZ0OmJsYXN0X2Z1cm5hY2UECQBuYW1lX2hhc2ivDbnjkpGm5QMKAG5ldHdvcmtfaWTcEbV/CgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:smoker", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFAQAACAQAbmFtZRAAbWluZWNyYWZ0OnNtb2tlcgQJAG5hbWVfaGFzaJd1rDMkRWomAwoAbmV0d29ya19pZGWswMwKBgBzdGF0ZXMIHABtaW5lY3JhZnQ6Y2FyZGluYWxfZGlyZWN0aW9uBQBzb3V0aAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:respawn_anchor", + "groupId": 81, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQPAgAACAQAbmFtZRgAbWluZWNyYWZ0OnJlc3Bhd25fYW5jaG9yBAkAbmFtZV9oYXNoZOdcjW05qigDCgBuZXR3b3JrX2lkmhMcaQoGAHN0YXRlcwMVAHJlc3Bhd25fYW5jaG9yX2NoYXJnZQAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:brewing_stand", + "groupId": 81 + }, + { + "id": "minecraft:anvil", + "groupId": 82, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSRAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmFudmlsBAkAbmFtZV9oYXNoNqB3fgcUCbwDCgBuZXR3b3JrX2lkqXzNjwoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAHNvdXRoAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:chipped_anvil", + "groupId": 82, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS+BAAACAQAbmFtZRcAbWluZWNyYWZ0OmNoaXBwZWRfYW52aWwECQBuYW1lX2hhc2ge+QY3vlS/eQMKAG5ldHdvcmtfaWRJ15iUCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:damaged_anvil", + "groupId": 82, + "block_state_b64": "CgAAAwgAYmxvY2tfaWS/BAAACAQAbmFtZRcAbWluZWNyYWZ0OmRhbWFnZWRfYW52aWwECQBuYW1lX2hhc2imJ12Be2V8+AMKAG5ldHdvcmtfaWRh5SHkCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:grindstone", + "groupId": 83, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTCAQAACAQAbmFtZRQAbWluZWNyYWZ0OmdyaW5kc3RvbmUECQBuYW1lX2hhc2id56zc0nk99wMKAG5ldHdvcmtfaWS4Es07CgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:enchanting_table", + "groupId": 83, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR0AAAACAQAbmFtZRoAbWluZWNyYWZ0OmVuY2hhbnRpbmdfdGFibGUECQBuYW1lX2hhc2jgIx24VLvMvwMKAG5ldHdvcmtfaWRliFFJCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:bookshelf", + "groupId": 83, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQvAAAACAQAbmFtZRMAbWluZWNyYWZ0OmJvb2tzaGVsZgQJAG5hbWVfaGFzaDU04DrgJCS9AwoAbmV0d29ya19pZBcWwIwKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chiseled_bookshelf", + "groupId": 83, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQNAwAACAQAbmFtZRwAbWluZWNyYWZ0OmNoaXNlbGVkX2Jvb2tzaGVsZgQJAG5hbWVfaGFzaNXDBnsIsywYAwoAbmV0d29ya19pZIprt5IKBgBzdGF0ZXMDDABib29rc19zdG9yZWQAAAAAAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:lectern", + "groupId": 83, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTBAQAACAQAbmFtZREAbWluZWNyYWZ0OmxlY3Rlcm4ECQBuYW1lX2hhc2j5Z4Mmi/1QxAMKAG5ldHdvcmtfaWR4JfDHCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAc291dGgBCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cauldron", + "groupId": 83 + }, + { + "id": "minecraft:composter", + "groupId": 83, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTUAQAACAQAbmFtZRMAbWluZWNyYWZ0OmNvbXBvc3RlcgQJAG5hbWVfaGFzaPAADHptzeWJAwoAbmV0d29ya19pZHIL6i4KBgBzdGF0ZXMDFABjb21wb3N0ZXJfZmlsbF9sZXZlbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:chest", + "groupId": 84, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ2AAAACAQAbmFtZQ8AbWluZWNyYWZ0OmNoZXN0BAkAbmFtZV9oYXNog9ozMxlcA88DCgBuZXR3b3JrX2lkDkOFvAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:trapped_chest", + "groupId": 84, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSSAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyYXBwZWRfY2hlc3QECQBuYW1lX2hhc2g2qpF9stsEjgMKAG5ldHdvcmtfaWTjJWYxCgYAc3RhdGVzCBwAbWluZWNyYWZ0OmNhcmRpbmFsX2RpcmVjdGlvbgUAbm9ydGgAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:ender_chest", + "groupId": 84, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSCAAAACAQAbmFtZRUAbWluZWNyYWZ0OmVuZGVyX2NoZXN0BAkAbmFtZV9oYXNohEZzOFdg0WUDCgBuZXR3b3JrX2lkx4jiSQoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:barrel", + "groupId": 85, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTKAQAACAQAbmFtZRAAbWluZWNyYWZ0OmJhcnJlbAQJAG5hbWVfaGFzaHDkRPGymiRqAwoAbmV0d29ya19pZPnxzgsKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAEIAG9wZW5fYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:undyed_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAAAACAQAbmFtZRwAbWluZWNyYWZ0OnVuZHllZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaOC9mypm/MlBAwoAbmV0d29ya19pZJ8rxp0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:white_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTaAAAACAQAbmFtZRsAbWluZWNyYWZ0OndoaXRlX3NodWxrZXJfYm94BAkAbmFtZV9oYXNosK79m1rPUBwDCgBuZXR3b3JrX2lkjrET6goGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:light_gray_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRrAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2dyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iBe5zq7PxHmgMKAG5ldHdvcmtfaWSCVJv0CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:gray_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRqAwAACAQAbmFtZRoAbWluZWNyYWZ0OmdyYXlfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2ga2s8ctjHUhgMKAG5ldHdvcmtfaWS3WMsWCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:black_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRyAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJsYWNrX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoPm03OZphrp8DCgBuZXR3b3JrX2lkXHztNAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:brown_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRvAwAACAQAbmFtZRsAbWluZWNyYWZ0OmJyb3duX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoT3DD6qAL9cADCgBuZXR3b3JrX2lkaXxpYQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:red_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRxAwAACAQAbmFtZRkAbWluZWNyYWZ0OnJlZF9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaMIlKSCzqSZoAwoAbmV0d29ya19pZNrf+icKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:orange_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRkAwAACAQAbmFtZRwAbWluZWNyYWZ0Om9yYW5nZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaG2MAXU67wGrAwoAbmV0d29ya19pZGoO05gKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:yellow_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRnAwAACAQAbmFtZRwAbWluZWNyYWZ0OnllbGxvd19zaHVsa2VyX2JveAQJAG5hbWVfaGFzaIsLwQHYjcIEAwoAbmV0d29ya19pZBCBSiYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:lime_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRoAwAACAQAbmFtZRoAbWluZWNyYWZ0OmxpbWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hUwBkg+faUGAMKAG5ldHdvcmtfaWRJeKqqCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:green_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRwAwAACAQAbmFtZRsAbWluZWNyYWZ0OmdyZWVuX3NodWxrZXJfYm94BAkAbmFtZV9oYXNoZgUeT3LupLUDCgBuZXR3b3JrX2lkzJiohQoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:cyan_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRsAwAACAQAbmFtZRoAbWluZWNyYWZ0OmN5YW5fc2h1bGtlcl9ib3gECQBuYW1lX2hhc2gSfbjteXg5yAMKAG5ldHdvcmtfaWTHeliECgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:light_blue_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRmAwAACAQAbmFtZSAAbWluZWNyYWZ0OmxpZ2h0X2JsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2h0VFCX0qsRxQMKAG5ldHdvcmtfaWQXD8U0CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:blue_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRuAwAACAQAbmFtZRoAbWluZWNyYWZ0OmJsdWVfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2hn9gS0XIe6rAMKAG5ldHdvcmtfaWTO4PJaCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:purple_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRtAwAACAQAbmFtZRwAbWluZWNyYWZ0OnB1cnBsZV9zaHVsa2VyX2JveAQJAG5hbWVfaGFzaEV/lkNPxRDdAwoAbmV0d29ya19pZFK25GAKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:magenta_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRlAwAACAQAbmFtZR0AbWluZWNyYWZ0Om1hZ2VudGFfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2iqWM7IJHxcFgMKAG5ldHdvcmtfaWTyyudTCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pink_shulker_box", + "groupId": 86, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRpAwAACAQAbmFtZRoAbWluZWNyYWZ0OnBpbmtfc2h1bGtlcl9ib3gECQBuYW1lX2hhc2in1tkJ1GNcZgMKAG5ldHdvcmtfaWQOEGXjCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:armor_stand", + "groupId": 87 + }, + { + "id": "minecraft:noteblock", + "groupId": 87, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAAAACAQAbmFtZRMAbWluZWNyYWZ0Om5vdGVibG9jawQJAG5hbWVfaGFzaHPA8dBBH0UaAwoAbmV0d29ya19pZH1U5QkKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:jukebox", + "groupId": 87, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRUAAAACAQAbmFtZREAbWluZWNyYWZ0Omp1a2Vib3gECQBuYW1lX2hhc2ieAIPExf/ZfgMKAG5ldHdvcmtfaWSmR7JfCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:music_disc_13", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_cat", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_blocks", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_chirp", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_far", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_mall", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_mellohi", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_stal", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_strad", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_ward", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_11", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_wait", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_otherside", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_5", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_pigstep", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_relic", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_creator", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_creator_music_box", + "groupId": 88 + }, + { + "id": "minecraft:music_disc_precipice", + "groupId": 88 + }, + { + "id": "minecraft:disc_fragment_5", + "groupId": 89 + }, + { + "id": "minecraft:glowstone_dust", + "groupId": 89 + }, + { + "id": "minecraft:glowstone", + "groupId": 89, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRZAAAACAQAbmFtZRMAbWluZWNyYWZ0Omdsb3dzdG9uZQQJAG5hbWVfaGFzaFYqXNkefIlPAwoAbmV0d29ya19pZGT7WYYKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:redstone_lamp", + "groupId": 89, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR7AAAACAQAbmFtZRcAbWluZWNyYWZ0OnJlZHN0b25lX2xhbXAECQBuYW1lX2hhc2hJ9V80caPvEgMKAG5ldHdvcmtfaWRvNPwnCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:sea_lantern", + "groupId": 89, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSpAAAACAQAbmFtZRUAbWluZWNyYWZ0OnNlYV9sYW50ZXJuBAkAbmFtZV9oYXNoLPsv1TX9M+QDCgBuZXR3b3JrX2lk1PPVyAoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:oak_sign", + "groupId": 90 + }, + { + "id": "minecraft:spruce_sign", + "groupId": 90 + }, + { + "id": "minecraft:birch_sign", + "groupId": 90 + }, + { + "id": "minecraft:jungle_sign", + "groupId": 90 + }, + { + "id": "minecraft:acacia_sign", + "groupId": 90 + }, + { + "id": "minecraft:dark_oak_sign", + "groupId": 90 + }, + { + "id": "minecraft:mangrove_sign", + "groupId": 90 + }, + { + "id": "minecraft:cherry_sign", + "groupId": 90 + }, + { + "id": "minecraft:pale_oak_sign", + "groupId": 90 + }, + { + "id": "minecraft:bamboo_sign", + "groupId": 90 + }, + { + "id": "minecraft:crimson_sign", + "groupId": 90 + }, + { + "id": "minecraft:warped_sign", + "groupId": 90 + }, + { + "id": "minecraft:oak_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:spruce_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:birch_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:jungle_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:acacia_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:dark_oak_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:mangrove_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:cherry_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:pale_oak_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:bamboo_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:crimson_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:warped_hanging_sign", + "groupId": 91 + }, + { + "id": "minecraft:painting", + "groupId": 92 + }, + { + "id": "minecraft:frame", + "groupId": 92 + }, + { + "id": "minecraft:glow_frame", + "groupId": 92 + }, + { + "id": "minecraft:honey_bottle", + "groupId": 92 + }, + { + "id": "minecraft:flower_pot", + "groupId": 92 + }, + { + "id": "minecraft:bowl", + "groupId": 92 + }, + { + "id": "minecraft:bucket", + "groupId": 92 + }, + { + "id": "minecraft:milk_bucket", + "groupId": 92 + }, + { + "id": "minecraft:water_bucket", + "groupId": 92 + }, + { + "id": "minecraft:lava_bucket", + "groupId": 92 + }, + { + "id": "minecraft:cod_bucket", + "groupId": 92 + }, + { + "id": "minecraft:salmon_bucket", + "groupId": 92 + }, + { + "id": "minecraft:tropical_fish_bucket", + "groupId": 92 + }, + { + "id": "minecraft:pufferfish_bucket", + "groupId": 92 + }, + { + "id": "minecraft:powder_snow_bucket", + "groupId": 92 + }, + { + "id": "minecraft:axolotl_bucket", + "groupId": 92 + }, + { + "id": "minecraft:tadpole_bucket", + "groupId": 92 + }, + { + "id": "minecraft:player_head", + "groupId": 93, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTGBAAACAQAbmFtZRUAbWluZWNyYWZ0OnBsYXllcl9oZWFkBAkAbmFtZV9oYXNonFwZb7CL8EYDCgBuZXR3b3JrX2lkZeAXqAoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:zombie_head", + "groupId": 93, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTFBAAACAQAbmFtZRUAbWluZWNyYWZ0OnpvbWJpZV9oZWFkBAkAbmFtZV9oYXNoixuENYuaGgEDCgBuZXR3b3JrX2lk0NsHDgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:creeper_head", + "groupId": 93, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTHBAAACAQAbmFtZRYAbWluZWNyYWZ0OmNyZWVwZXJfaGVhZAQJAG5hbWVfaGFzaCvAGFMS/RqVAwoAbmV0d29ya19pZEfskXYKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dragon_head", + "groupId": 93, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTIBAAACAQAbmFtZRUAbWluZWNyYWZ0OmRyYWdvbl9oZWFkBAkAbmFtZV9oYXNozjh6bGRaa5UDCgBuZXR3b3JrX2lk/zjetgoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:skeleton_skull", + "groupId": 93, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSQAAAACAQAbmFtZRgAbWluZWNyYWZ0OnNrZWxldG9uX3NrdWxsBAkAbmFtZV9oYXNo3+kbzeMgg4kDCgBuZXR3b3JrX2lk/RqWbwoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:wither_skeleton_skull", + "groupId": 93, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEBAAACAQAbmFtZR8AbWluZWNyYWZ0OndpdGhlcl9za2VsZXRvbl9za3VsbAQJAG5hbWVfaGFzaEcZrUyy9cfRAwoAbmV0d29ya19pZJZ2G/oKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:piglin_head", + "groupId": 93, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTJBAAACAQAbmFtZRUAbWluZWNyYWZ0OnBpZ2xpbl9oZWFkBAkAbmFtZV9oYXNo+jUCKgb5DskDCgBuZXR3b3JrX2lkQ1ETVwoGAHN0YXRlcwMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:beacon", + "groupId": 94, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSKAAAACAQAbmFtZRAAbWluZWNyYWZ0OmJlYWNvbgQJAG5hbWVfaGFzaACwhhfSkdkHAwoAbmV0d29ya19pZF8jfiEKBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bell", + "groupId": 94, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTNAQAACAQAbmFtZQ4AbWluZWNyYWZ0OmJlbGwECQBuYW1lX2hhc2iPqsgDXRcsxAMKAG5ldHdvcmtfaWT7zhOoCgYAc3RhdGVzCAoAYXR0YWNobWVudAgAc3RhbmRpbmcDCQBkaXJlY3Rpb24AAAAAAQoAdG9nZ2xlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:conduit", + "groupId": 94, + "block_state_b64": "CgAAAwgAYmxvY2tfaWScAQAACAQAbmFtZREAbWluZWNyYWZ0OmNvbmR1aXQECQBuYW1lX2hhc2jqxKAxq2EaWQMKAG5ldHdvcmtfaWTWcBVnCgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stonecutter_block", + "groupId": 94, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTEAQAACAQAbmFtZRsAbWluZWNyYWZ0OnN0b25lY3V0dGVyX2Jsb2NrBAkAbmFtZV9oYXNoQAXTbAM3MeYDCgBuZXR3b3JrX2lkWS4RjAoGAHN0YXRlcwgcAG1pbmVjcmFmdDpjYXJkaW5hbF9kaXJlY3Rpb24FAG5vcnRoAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:coal", + "groupId": 94 + }, + { + "id": "minecraft:charcoal", + "groupId": 94 + }, + { + "id": "minecraft:diamond", + "groupId": 94 + }, + { + "id": "minecraft:iron_nugget", + "groupId": 94 + }, + { + "id": "minecraft:raw_iron", + "groupId": 94 + }, + { + "id": "minecraft:raw_gold", + "groupId": 94 + }, + { + "id": "minecraft:raw_copper", + "groupId": 94 + }, + { + "id": "minecraft:copper_ingot", + "groupId": 94 + }, + { + "id": "minecraft:iron_ingot", + "groupId": 94 + }, + { + "id": "minecraft:netherite_scrap", + "groupId": 94 + }, + { + "id": "minecraft:netherite_ingot", + "groupId": 94 + }, + { + "id": "minecraft:gold_nugget", + "groupId": 94 + }, + { + "id": "minecraft:gold_ingot", + "groupId": 94 + }, + { + "id": "minecraft:emerald", + "groupId": 94 + }, + { + "id": "minecraft:quartz", + "groupId": 94 + }, + { + "id": "minecraft:clay_ball", + "groupId": 94 + }, + { + "id": "minecraft:brick", + "groupId": 94 + }, + { + "id": "minecraft:netherbrick", + "groupId": 94 + }, + { + "id": "minecraft:resin_brick", + "groupId": 94 + }, + { + "id": "minecraft:prismarine_shard", + "groupId": 94 + }, + { + "id": "minecraft:amethyst_shard", + "groupId": 94 + }, + { + "id": "minecraft:prismarine_crystals", + "groupId": 94 + }, + { + "id": "minecraft:nautilus_shell", + "groupId": 94 + }, + { + "id": "minecraft:heart_of_the_sea", + "groupId": 94 + }, + { + "id": "minecraft:turtle_scute", + "groupId": 94 + }, + { + "id": "minecraft:armadillo_scute", + "groupId": 94 + }, + { + "id": "minecraft:phantom_membrane", + "groupId": 94 + }, + { + "id": "minecraft:string", + "groupId": 94 + }, + { + "id": "minecraft:feather", + "groupId": 94 + }, + { + "id": "minecraft:flint", + "groupId": 94 + }, + { + "id": "minecraft:gunpowder", + "groupId": 94 + }, + { + "id": "minecraft:leather", + "groupId": 94 + }, + { + "id": "minecraft:rabbit_hide", + "groupId": 94 + }, + { + "id": "minecraft:rabbit_foot", + "groupId": 94 + }, + { + "id": "minecraft:fire_charge", + "groupId": 94 + }, + { + "id": "minecraft:blaze_rod", + "groupId": 94 + }, + { + "id": "minecraft:breeze_rod", + "groupId": 94 + }, + { + "id": "minecraft:heavy_core", + "groupId": 94, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ7AgAACAQAbmFtZRQAbWluZWNyYWZ0OmhlYXZ5X2NvcmUECQBuYW1lX2hhc2hhz/uNCtrC2QMKAG5ldHdvcmtfaWRaFu+8CgYAc3RhdGVzAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:blaze_powder", + "groupId": 94 + }, + { + "id": "minecraft:magma_cream", + "groupId": 94 + }, + { + "id": "minecraft:fermented_spider_eye", + "groupId": 94 + }, + { + "id": "minecraft:echo_shard", + "groupId": 94 + }, + { + "id": "minecraft:dragon_breath", + "groupId": 94 + }, + { + "id": "minecraft:shulker_shell", + "groupId": 94 + }, + { + "id": "minecraft:ghast_tear", + "groupId": 94 + }, + { + "id": "minecraft:slime_ball", + "groupId": 94 + }, + { + "id": "minecraft:ender_pearl", + "groupId": 94 + }, + { + "id": "minecraft:ender_eye", + "groupId": 94 + }, + { + "id": "minecraft:nether_star", + "groupId": 94 + }, + { + "id": "minecraft:end_rod", + "groupId": 94, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTQAAAACAQAbmFtZREAbWluZWNyYWZ0OmVuZF9yb2QECQBuYW1lX2hhc2jx/q5cEA0hmQMKAG5ldHdvcmtfaWQ2eM8kCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:lightning_rod", + "groupId": 94, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ3AgAACAQAbmFtZRcAbWluZWNyYWZ0OmxpZ2h0bmluZ19yb2QECQBuYW1lX2hhc2ioXQF1xvfHNQMKAG5ldHdvcmtfaWRLuHyACgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:end_crystal", + "groupId": 94 + }, + { + "id": "minecraft:paper", + "groupId": 94 + }, + { + "id": "minecraft:book", + "groupId": 94 + }, + { + "id": "minecraft:writable_book", + "groupId": 94 + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQmAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQnAAIDAGx2bAUAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAEAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAIAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAMAAAA=" + }, + { + "id": "minecraft:enchanted_book", + "groupId": 95, + "nbt_b64": "CgAACQQAZW5jaAoBAAAAAgIAaWQoAAIDAGx2bAQAAAA=" + }, + { + "id": "minecraft:oak_boat", + "groupId": 96 + }, + { + "id": "minecraft:spruce_boat", + "groupId": 96 + }, + { + "id": "minecraft:birch_boat", + "groupId": 96 + }, + { + "id": "minecraft:jungle_boat", + "groupId": 96 + }, + { + "id": "minecraft:acacia_boat", + "groupId": 96 + }, + { + "id": "minecraft:dark_oak_boat", + "groupId": 96 + }, + { + "id": "minecraft:mangrove_boat", + "groupId": 96 + }, + { + "id": "minecraft:cherry_boat", + "groupId": 96 + }, + { + "id": "minecraft:pale_oak_boat", + "groupId": 96 + }, + { + "id": "minecraft:bamboo_raft", + "groupId": 96 + }, + { + "id": "minecraft:oak_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:spruce_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:birch_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:jungle_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:acacia_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:dark_oak_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:mangrove_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:cherry_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:pale_oak_chest_boat", + "groupId": 97 + }, + { + "id": "minecraft:bamboo_chest_raft", + "groupId": 97 + }, + { + "id": "minecraft:rail", + "groupId": 98, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRCAAAACAQAbmFtZQ4AbWluZWNyYWZ0OnJhaWwECQBuYW1lX2hhc2hUzmhUXYJDUQMKAG5ldHdvcmtfaWR+Sp6YCgYAc3RhdGVzAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:golden_rail", + "groupId": 98, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQbAAAACAQAbmFtZRUAbWluZWNyYWZ0OmdvbGRlbl9yYWlsBAkAbmFtZV9oYXNoOoV5MaKipoUDCgBuZXR3b3JrX2lkfAcxLwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:detector_rail", + "groupId": 98, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQcAAAACAQAbmFtZRcAbWluZWNyYWZ0OmRldGVjdG9yX3JhaWwECQBuYW1lX2hhc2gVUk31qOysUQMKAG5ldHdvcmtfaWRVW/aICgYAc3RhdGVzAQ0AcmFpbF9kYXRhX2JpdAADDgByYWlsX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:activator_rail", + "groupId": 98, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR+AAAACAQAbmFtZRgAbWluZWNyYWZ0OmFjdGl2YXRvcl9yYWlsBAkAbmFtZV9oYXNosIL91qriCRkDCgBuZXR3b3JrX2lkZfckmwoGAHN0YXRlcwENAHJhaWxfZGF0YV9iaXQAAw4AcmFpbF9kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:minecart", + "groupId": 99 + }, + { + "id": "minecraft:chest_minecart", + "groupId": 99 + }, + { + "id": "minecraft:hopper_minecart", + "groupId": 99 + }, + { + "id": "minecraft:tnt_minecart", + "groupId": 99 + }, + { + "id": "minecraft:redstone", + "groupId": 100 + }, + { + "id": "minecraft:redstone_block", + "groupId": 100, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX2Jsb2NrBAkAbmFtZV9oYXNoRhULL0r8o0sDCgBuZXR3b3JrX2lklayOHgoGAHN0YXRlcwADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:redstone_torch", + "groupId": 100, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRMAAAACAQAbmFtZRgAbWluZWNyYWZ0OnJlZHN0b25lX3RvcmNoBAkAbmFtZV9oYXNoizFRjpYMIDgDCgBuZXR3b3JrX2lkuHz7yAoGAHN0YXRlcwgWAHRvcmNoX2ZhY2luZ19kaXJlY3Rpb24HAHVua25vd24AAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:lever", + "groupId": 100, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRFAAAACAQAbmFtZQ8AbWluZWNyYWZ0OmxldmVyBAkAbmFtZV9oYXNoGMJeLJsUMLYDCgBuZXR3b3JrX2lkEF/GuAoGAHN0YXRlcwgPAGxldmVyX2RpcmVjdGlvbg4AZG93bl9lYXN0X3dlc3QBCABvcGVuX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:wooden_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAAAACAQAbmFtZRcAbWluZWNyYWZ0Ondvb2Rlbl9idXR0b24ECQBuYW1lX2hhc2hR7PgSTQt0sQMKAG5ldHdvcmtfaWSU07kYCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:spruce_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSPAQAACAQAbmFtZRcAbWluZWNyYWZ0OnNwcnVjZV9idXR0b24ECQBuYW1lX2hhc2jBW9Z8aYE7YQMKAG5ldHdvcmtfaWTkUIGuCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:birch_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSMAQAACAQAbmFtZRYAbWluZWNyYWZ0OmJpcmNoX2J1dHRvbgQJAG5hbWVfaGFzaJXYgGuSHbTwAwoAbmV0d29ya19pZGWp3yoKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:jungle_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSOAQAACAQAbmFtZRcAbWluZWNyYWZ0Omp1bmdsZV9idXR0b24ECQBuYW1lX2hhc2iCgNANcJs+BQMKAG5ldHdvcmtfaWT9fImWCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:acacia_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSLAQAACAQAbmFtZRcAbWluZWNyYWZ0OmFjYWNpYV9idXR0b24ECQBuYW1lX2hhc2gVvmcT7LTO0wMKAG5ldHdvcmtfaWRQnxIJCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dark_oak_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSNAQAACAQAbmFtZRkAbWluZWNyYWZ0OmRhcmtfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaIV10ZGGrCIEAwoAbmV0d29ya19pZN5vAmIKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mangrove_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTmAgAACAQAbmFtZRkAbWluZWNyYWZ0Om1hbmdyb3ZlX2J1dHRvbgQJAG5hbWVfaGFzaNzeYYKLgOzJAwoAbmV0d29ya19pZAFEGQ0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cherry_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQRAwAACAQAbmFtZRcAbWluZWNyYWZ0OmNoZXJyeV9idXR0b24ECQBuYW1lX2hhc2j2/IHjeAbUcwMKAG5ldHdvcmtfaWRJ1irQCgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pale_oak_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTcBAAACAQAbmFtZRkAbWluZWNyYWZ0OnBhbGVfb2FrX2J1dHRvbgQJAG5hbWVfaGFzaLk54s7RtGHgAwoAbmV0d29ya19pZNLO6ZwKBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bamboo_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT+AgAACAQAbmFtZRcAbWluZWNyYWZ0OmJhbWJvb19idXR0b24ECQBuYW1lX2hhc2j7AddMi+6nsgMKAG5ldHdvcmtfaWSa9w4/CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stone_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRNAAAACAQAbmFtZRYAbWluZWNyYWZ0OnN0b25lX2J1dHRvbgQJAG5hbWVfaGFzaM4ejMctmvohAwoAbmV0d29ya19pZMw+aC0KBgBzdGF0ZXMBEgBidXR0b25fcHJlc3NlZF9iaXQAAxAAZmFjaW5nX2RpcmVjdGlvbgAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:crimson_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQDAgAACAQAbmFtZRgAbWluZWNyYWZ0OmNyaW1zb25fYnV0dG9uBAkAbmFtZV9oYXNofnjYHaYIeWgDCgBuZXR3b3JrX2lk+n1vyQoGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQEAgAACAQAbmFtZRcAbWluZWNyYWZ0OndhcnBlZF9idXR0b24ECQBuYW1lX2hhc2jwkV2EU6Cn1QMKAG5ldHdvcmtfaWTnHnk1CgYAc3RhdGVzARIAYnV0dG9uX3ByZXNzZWRfYml0AAMQAGZhY2luZ19kaXJlY3Rpb24AAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:polished_blackstone_button", + "groupId": 101, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQnAgAACAQAbmFtZSQAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfYnV0dG9uBAkAbmFtZV9oYXNojmxzQKS0S/EDCgBuZXR3b3JrX2lkDtQ95woGAHN0YXRlcwESAGJ1dHRvbl9wcmVzc2VkX2JpdAADEABmYWNpbmdfZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:tripwire_hook", + "groupId": 102, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSDAAAACAQAbmFtZRcAbWluZWNyYWZ0OnRyaXB3aXJlX2hvb2sECQBuYW1lX2hhc2gQdp+oGZLNnAMKAG5ldHdvcmtfaWSy+1KJCgYAc3RhdGVzAQwAYXR0YWNoZWRfYml0AAMJAGRpcmVjdGlvbgAAAAABCwBwb3dlcmVkX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:wooden_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRIAAAACAQAbmFtZR8AbWluZWNyYWZ0Ondvb2Rlbl9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaGkGs5kCuA74AwoAbmV0d29ya19pZDRzPNwKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:spruce_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSZAQAACAQAbmFtZR8AbWluZWNyYWZ0OnNwcnVjZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNmwuq549fJKAwoAbmV0d29ya19pZLQMCw0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:birch_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSWAQAACAQAbmFtZR4AbWluZWNyYWZ0OmJpcmNoX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNorQkT9kDdlTwDCgBuZXR3b3JrX2lkH0G97AoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:jungle_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSYAQAACAQAbmFtZR8AbWluZWNyYWZ0Omp1bmdsZV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaJ7DcteCkb8/AwoAbmV0d29ya19pZLdPBSAKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:acacia_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSVAQAACAQAbmFtZR8AbWluZWNyYWZ0OmFjYWNpYV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaC2frZtfoYqCAwoAbmV0d29ya19pZIDdI18KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:dark_oak_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAQAACAQAbmFtZSEAbWluZWNyYWZ0OmRhcmtfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoHUCJsTy52pwDCgBuZXR3b3JrX2lkKpi8rAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:mangrove_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTpAgAACAQAbmFtZSEAbWluZWNyYWZ0Om1hbmdyb3ZlX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoiDsTfJaX100DCgBuZXR3b3JrX2lkuwWDyQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:cherry_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQZAwAACAQAbmFtZR8AbWluZWNyYWZ0OmNoZXJyeV9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaALMqYEZDUQHAwoAbmV0d29ya19pZPNT+r0KBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:pale_oak_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTkBAAACAQAbmFtZSEAbWluZWNyYWZ0OnBhbGVfb2FrX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNo8cvY7evY5xkDCgBuZXR3b3JrX2lkDmW0uAoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:bamboo_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQBAwAACAQAbmFtZR8AbWluZWNyYWZ0OmJhbWJvb19wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaNvxJ7NIAaqlAwoAbmV0d29ya19pZIZ8XnYKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:crimson_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQFAgAACAQAbmFtZSAAbWluZWNyYWZ0OmNyaW1zb25fcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2hqBDVDAd31/gMKAG5ldHdvcmtfaWRmV18LCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:warped_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQGAgAACAQAbmFtZR8AbWluZWNyYWZ0OndhcnBlZF9wcmVzc3VyZV9wbGF0ZQQJAG5hbWVfaGFzaBxFoQksWtYUAwoAbmV0d29ya19pZJVRoIcKBgBzdGF0ZXMDDwByZWRzdG9uZV9zaWduYWwAAAAAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:stone_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWRGAAAACAQAbmFtZR4AbWluZWNyYWZ0OnN0b25lX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNounJuTBUTrU8DCgBuZXR3b3JrX2lkjDydwQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:light_weighted_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSTAAAACAQAbmFtZScAbWluZWNyYWZ0OmxpZ2h0X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoOyOJkNxLtkEDCgBuZXR3b3JrX2lkrr2AjgoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:heavy_weighted_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSUAAAACAQAbmFtZScAbWluZWNyYWZ0OmhlYXZ5X3dlaWdodGVkX3ByZXNzdXJlX3BsYXRlBAkAbmFtZV9oYXNoltgDmDvTajUDCgBuZXR3b3JrX2lkFxVKuQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:polished_blackstone_pressure_plate", + "groupId": 103, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAgAACAQAbmFtZSwAbWluZWNyYWZ0OnBvbGlzaGVkX2JsYWNrc3RvbmVfcHJlc3N1cmVfcGxhdGUECQBuYW1lX2hhc2h65Ci6/CeGqwMKAG5ldHdvcmtfaWTaSW5xCgYAc3RhdGVzAw8AcmVkc3RvbmVfc2lnbmFsAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:observer", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWT7AAAACAQAbmFtZRIAbWluZWNyYWZ0Om9ic2VydmVyBAkAbmFtZV9oYXNoYhlh1lpmHTgDCgBuZXR3b3JrX2lkQEh55goGAHN0YXRlcwgaAG1pbmVjcmFmdDpmYWNpbmdfZGlyZWN0aW9uBABkb3duAQsAcG93ZXJlZF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:daylight_detector", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWSXAAAACAQAbmFtZRsAbWluZWNyYWZ0OmRheWxpZ2h0X2RldGVjdG9yBAkAbmFtZV9oYXNoV0F0s7B7PVgDCgBuZXR3b3JrX2lkri5afQoGAHN0YXRlcwMPAHJlZHN0b25lX3NpZ25hbAAAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:repeater", + "groupId": 104 + }, + { + "id": "minecraft:comparator", + "groupId": 104 + }, + { + "id": "minecraft:hopper", + "groupId": 104 + }, + { + "id": "minecraft:dropper", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWR9AAAACAQAbmFtZREAbWluZWNyYWZ0OmRyb3BwZXIECQBuYW1lX2hhc2joXP7XqU0l3QMKAG5ldHdvcmtfaWQfQN6zCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgMAAAABDQB0cmlnZ2VyZWRfYml0AAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:dispenser", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQXAAAACAQAbmFtZRMAbWluZWNyYWZ0OmRpc3BlbnNlcgQJAG5hbWVfaGFzaP1RR+zAbYP2AwoAbmV0d29ya19pZGAayD0KBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAwAAAAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:crafter", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQ4AgAACAQAbmFtZREAbWluZWNyYWZ0OmNyYWZ0ZXIECQBuYW1lX2hhc2iLCT/rJmRN8QMKAG5ldHdvcmtfaWTPTbvrCgYAc3RhdGVzAQgAY3JhZnRpbmcACAsAb3JpZW50YXRpb24JAGRvd25fZWFzdAENAHRyaWdnZXJlZF9iaXQAAAMHAHZlcnNpb24hPBUBAA==" + }, + { + "id": "minecraft:piston", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQhAAAACAQAbmFtZRAAbWluZWNyYWZ0OnBpc3RvbgQJAG5hbWVfaGFzaDs3AFh1fL0uAwoAbmV0d29ya19pZLD/5XQKBgBzdGF0ZXMDEABmYWNpbmdfZGlyZWN0aW9uAQAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:sticky_piston", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQdAAAACAQAbmFtZRcAbWluZWNyYWZ0OnN0aWNreV9waXN0b24ECQBuYW1lX2hhc2hPFJFJSiJ0ZQMKAG5ldHdvcmtfaWT/MzCJCgYAc3RhdGVzAxAAZmFjaW5nX2RpcmVjdGlvbgEAAAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:tnt", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQuAAAACAQAbmFtZQ0AbWluZWNyYWZ0OnRudAQJAG5hbWVfaGFzaEYOHwCvJH29AwoAbmV0d29ya19pZAXzHyUKBgBzdGF0ZXMBCwBleHBsb2RlX2JpdAAAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:name_tag", + "groupId": 104 + }, + { + "id": "minecraft:loom", + "groupId": 104, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTLAQAACAQAbmFtZQ4AbWluZWNyYWZ0Omxvb20ECQBuYW1lX2hhc2i7DKjAXNq8TAMKAG5ldHdvcmtfaWR/49HXCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:banner", + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 8, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 7, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 15, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 12, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 14, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 1, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 4, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 5, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 13, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 9, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 3, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 11, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 10, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 2, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 6, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQAAAAAA" + }, + { + "id": "minecraft:banner", + "damage": 15, + "groupId": 105, + "nbt_b64": "CgAAAwQAVHlwZQEAAAAA" + }, + { + "id": "minecraft:creeper_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:skull_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:flower_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:mojang_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:field_masoned_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:bordure_indented_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:piglin_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:globe_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:flow_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:guster_banner_pattern", + "groupId": 106 + }, + { + "id": "minecraft:angler_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:archer_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:arms_up_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:blade_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:brewer_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:burn_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:danger_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:explorer_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:flow_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:friend_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:guster_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:heart_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:heartbreak_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:howl_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:miner_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:mourner_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:plenty_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:prize_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:scrape_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:sheaf_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:shelter_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:skull_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:snort_pottery_sherd", + "groupId": 107 + }, + { + "id": "minecraft:netherite_upgrade_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:sentry_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:vex_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:wild_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:coast_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:dune_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:wayfinder_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:shaper_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:raiser_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:host_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:ward_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:silence_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:tide_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:snout_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:rib_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:eye_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:spire_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:flow_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:bolt_armor_trim_smithing_template", + "groupId": 108 + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_rocket", + "groupId": 109, + "nbt_b64": "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id": "minecraft:firework_star", + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 8, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 7, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 15, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 12, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 14, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 1, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 4, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 5, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 13, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 9, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 3, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 11, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 10, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 2, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" + }, + { + "id": "minecraft:firework_star", + "damage": 6, + "groupId": 110, + "nbt_b64": "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" + }, + { + "id": "minecraft:chain", + "groupId": 111 + }, + { + "id": "minecraft:target", + "groupId": 111, + "block_state_b64": "CgAAAwgAYmxvY2tfaWTuAQAACAQAbmFtZRAAbWluZWNyYWZ0OnRhcmdldAQJAG5hbWVfaGFzaJc66SVbYlaxAwoAbmV0d29ya19pZPBozs0KBgBzdGF0ZXMAAwcAdmVyc2lvbiE8FQEA" + }, + { + "id": "minecraft:decorated_pot", + "groupId": 111, + "block_state_b64": "CgAAAwgAYmxvY2tfaWQmAwAACAQAbmFtZRcAbWluZWNyYWZ0OmRlY29yYXRlZF9wb3QECQBuYW1lX2hhc2jjQgckn8VTvwMKAG5ldHdvcmtfaWRwvkUUCgYAc3RhdGVzAwkAZGlyZWN0aW9uAAAAAAADBwB2ZXJzaW9uITwVAQA=" + }, + { + "id": "minecraft:trial_key", + "groupId": 111 + }, + { + "id": "minecraft:ominous_trial_key", + "groupId": 111 + } + ] +} diff --git a/core/src/main/resources/bedrock/item_components.nbt b/core/src/main/resources/bedrock/item_components.nbt new file mode 100644 index 0000000000000000000000000000000000000000..34d2ac7f0ca1bf5fafda5891c7666b562aa6922f GIT binary patch literal 12649 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 Xkr#9y(Pfc{?&ALgn8T(o6b}Ia*2(6l literal 0 HcmV?d00001 diff --git a/core/src/main/resources/bedrock/item_tags.1_21_60.json b/core/src/main/resources/bedrock/item_tags.1_21_60.json new file mode 100644 index 000000000..b8b94d6f3 --- /dev/null +++ b/core/src/main/resources/bedrock/item_tags.1_21_60.json @@ -0,0 +1,829 @@ +{ + "minecraft:arrow": [ + "minecraft:arrow" + ], + "minecraft:banner": [ + "minecraft:banner" + ], + "minecraft:boat": [ + "minecraft:pale_oak_chest_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:pale_oak_boat" + ], + "minecraft:boats": [ + "minecraft:pale_oak_chest_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:pale_oak_boat" + ], + "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:pale_oak_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:pale_oak_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_shears": [ + "minecraft:shears" + ], + "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: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:pale_oak_wood", + "minecraft:stripped_warped_hyphae", + "minecraft:acacia_log", + "minecraft:stripped_warped_stem", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:stripped_pale_oak_wood", + "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_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_pale_oak_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:pale_oak_log", + "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: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:pale_oak_wood", + "minecraft:acacia_log", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:stripped_pale_oak_wood", + "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_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_pale_oak_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:pale_oak_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:pale_oak_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:pale_oak_hanging_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:pale_oak_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:creaking_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:resin_brick", + "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:green_carpet", + "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: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:pale_oak_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/bedrock/runtime_item_states.1_21_60.json b/core/src/main/resources/bedrock/runtime_item_states.1_21_60.json new file mode 100644 index 000000000..9f8bf5cdb --- /dev/null +++ b/core/src/main/resources/bedrock/runtime_item_states.1_21_60.json @@ -0,0 +1,10730 @@ +[ + { + "name": "minecraft:acacia_boat", + "id": 405, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_button", + "id": -140, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_chest_boat", + "id": 679, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_door", + "id": 589, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_double_slab", + "id": -812, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_fence", + "id": -575, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_fence_gate", + "id": 187, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_hanging_sign", + "id": -504, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_leaves", + "id": 161, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_log", + "id": 162, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_planks", + "id": -742, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_pressure_plate", + "id": -150, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_sapling", + "id": -828, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_sign", + "id": 612, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_slab", + "id": -807, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_stairs", + "id": 163, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_standing_sign", + "id": -190, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_trapdoor", + "id": -145, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_wall_sign", + "id": -191, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:acacia_wood", + "id": -817, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:activator_rail", + "id": 126, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:agent_spawn_egg", + "id": 515, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:air", + "id": -158, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:allay_spawn_egg", + "id": 668, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:allium", + "id": -831, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:allow", + "id": 210, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:amethyst_block", + "id": -327, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:amethyst_cluster", + "id": -329, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:amethyst_shard", + "id": 661, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ancient_debris", + "id": -271, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:andesite", + "id": -594, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:andesite_double_slab", + "id": -920, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:andesite_slab", + "id": -893, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:andesite_stairs", + "id": -171, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:andesite_wall", + "id": -974, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:angler_pottery_sherd", + "id": 693, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:anvil", + "id": 145, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:apple", + "id": 278, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:archer_pottery_sherd", + "id": 694, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:armadillo_scute", + "id": 740, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:armadillo_spawn_egg", + "id": 739, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:armor_stand", + "id": 585, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:arms_up_pottery_sherd", + "id": 695, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:arrow", + "id": 325, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:axolotl_bucket", + "id": 394, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:axolotl_spawn_egg", + "id": 530, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:azalea", + "id": -337, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:azalea_leaves", + "id": -324, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:azalea_leaves_flowered", + "id": -325, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:azure_bluet", + "id": -832, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:baked_potato", + "id": 303, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:balloon", + "id": 635, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo", + "id": -163, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_block", + "id": -527, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_button", + "id": -511, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_chest_raft", + "id": 691, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_door", + "id": -517, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_double_slab", + "id": -521, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_fence", + "id": -515, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_fence_gate", + "id": -516, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_hanging_sign", + "id": -522, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_mosaic", + "id": -509, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_mosaic_double_slab", + "id": -525, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_mosaic_slab", + "id": -524, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_mosaic_stairs", + "id": -523, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_planks", + "id": -510, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_pressure_plate", + "id": -514, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_raft", + "id": 690, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_sapling", + "id": -164, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_sign", + "id": 689, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_slab", + "id": -513, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_stairs", + "id": -512, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_standing_sign", + "id": -518, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_trapdoor", + "id": -520, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bamboo_wall_sign", + "id": -519, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:banner", + "id": 600, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:banner_pattern", + "id": 793, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:barrel", + "id": -203, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:barrier", + "id": -161, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:basalt", + "id": -234, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bat_spawn_egg", + "id": 480, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:beacon", + "id": 138, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bed", + "id": 444, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bedrock", + "id": 7, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bee_nest", + "id": -218, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bee_spawn_egg", + "id": 522, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:beef", + "id": 295, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:beehive", + "id": -219, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:beetroot", + "id": 307, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:beetroot_seeds", + "id": 317, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:beetroot_soup", + "id": 308, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:bell", + "id": -206, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:big_dripleaf", + "id": -323, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_boat", + "id": 402, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_button", + "id": -141, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_chest_boat", + "id": 676, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_door", + "id": 587, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_double_slab", + "id": -810, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_fence", + "id": -576, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_fence_gate", + "id": 184, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_hanging_sign", + "id": -502, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_leaves", + "id": -801, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_log", + "id": -570, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_planks", + "id": -740, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_pressure_plate", + "id": -151, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_sapling", + "id": -826, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_sign", + "id": 610, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_slab", + "id": -805, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_stairs", + "id": 135, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_standing_sign", + "id": -186, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_trapdoor", + "id": -146, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_wall_sign", + "id": -187, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:birch_wood", + "id": -815, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_bundle", + "id": 257, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:black_candle", + "id": -428, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_candle_cake", + "id": -445, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_carpet", + "id": -611, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_concrete", + "id": -642, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_concrete_powder", + "id": -723, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_dye", + "id": 421, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_glazed_terracotta", + "id": 235, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_shulker_box", + "id": -627, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_stained_glass", + "id": -687, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_stained_glass_pane", + "id": -657, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_terracotta", + "id": -738, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:black_wool", + "id": -554, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blackstone", + "id": -273, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blackstone_double_slab", + "id": -283, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blackstone_slab", + "id": -282, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blackstone_stairs", + "id": -276, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blackstone_wall", + "id": -277, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blade_pottery_sherd", + "id": 696, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blast_furnace", + "id": -196, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blaze_powder", + "id": 456, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blaze_rod", + "id": 449, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blaze_spawn_egg", + "id": 483, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bleach", + "id": 633, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_bundle", + "id": 258, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:blue_candle", + "id": -424, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_candle_cake", + "id": -441, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_carpet", + "id": -607, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_concrete", + "id": -638, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_concrete_powder", + "id": -719, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_dye", + "id": 425, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_glazed_terracotta", + "id": 231, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_ice", + "id": -11, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_orchid", + "id": -830, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_shulker_box", + "id": -623, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_stained_glass", + "id": -683, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_stained_glass_pane", + "id": -653, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_terracotta", + "id": -734, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:blue_wool", + "id": -563, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:board", + "id": 629, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:boat", + "id": 791, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bogged_spawn_egg", + "id": 490, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bolt_armor_trim_smithing_template", + "id": 735, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bone", + "id": 441, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bone_block", + "id": 216, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bone_meal", + "id": 437, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:book", + "id": 413, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bookshelf", + "id": 47, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:border_block", + "id": 212, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bordure_indented_banner_pattern", + "id": 619, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bow", + "id": 324, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bowl", + "id": 346, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brain_coral", + "id": -581, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brain_coral_block", + "id": -849, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brain_coral_fan", + "id": -840, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brain_coral_wall_fan", + "id": -904, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bread", + "id": 283, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:breeze_rod", + "id": 274, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:breeze_spawn_egg", + "id": 529, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brewer_pottery_sherd", + "id": 697, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brewing_stand", + "id": 458, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:brick", + "id": 409, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brick_block", + "id": 45, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brick_double_slab", + "id": -880, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brick_slab", + "id": -874, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brick_stairs", + "id": 108, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brick_wall", + "id": -976, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_bundle", + "id": 259, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:brown_candle", + "id": -425, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_candle_cake", + "id": -442, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_carpet", + "id": -608, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_concrete", + "id": -639, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_concrete_powder", + "id": -720, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_dye", + "id": 424, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_glazed_terracotta", + "id": 232, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_mushroom", + "id": 39, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_mushroom_block", + "id": 99, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_shulker_box", + "id": -624, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_stained_glass", + "id": -684, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_stained_glass_pane", + "id": -654, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_terracotta", + "id": -735, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brown_wool", + "id": -555, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:brush", + "id": 716, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bubble_column", + "id": -160, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bubble_coral", + "id": -582, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bubble_coral_block", + "id": -850, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bubble_coral_fan", + "id": -841, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bubble_coral_wall_fan", + "id": -136, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bucket", + "id": 385, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:budding_amethyst", + "id": -328, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:bundle", + "id": 260, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:burn_pottery_sherd", + "id": 698, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cactus", + "id": 81, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cake", + "id": 443, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:calcite", + "id": -326, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:calibrated_sculk_sensor", + "id": -580, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:camel_spawn_egg", + "id": 692, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:camera", + "id": 630, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:campfire", + "id": 624, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:candle", + "id": -412, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:candle_cake", + "id": -429, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:carpet", + "id": 750, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:carrot", + "id": 301, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:carrot_on_a_stick", + "id": 550, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:carrots", + "id": 141, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cartography_table", + "id": -200, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:carved_pumpkin", + "id": -155, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cat_spawn_egg", + "id": 516, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cauldron", + "id": 459, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:cave_spider_spawn_egg", + "id": 484, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cave_vines", + "id": -322, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cave_vines_body_with_berries", + "id": -375, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cave_vines_head_with_berries", + "id": -376, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chain", + "id": 656, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:chain_command_block", + "id": 189, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chainmail_boots", + "id": 367, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chainmail_chestplate", + "id": 365, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chainmail_helmet", + "id": 364, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chainmail_leggings", + "id": 366, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chalkboard", + "id": 230, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:charcoal", + "id": 327, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:chemical_heat", + "id": 192, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chemistry_table", + "id": 785, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_boat", + "id": 686, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_button", + "id": -530, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_chest_boat", + "id": 687, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_door", + "id": -531, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_double_slab", + "id": -540, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_fence", + "id": -532, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_fence_gate", + "id": -533, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_hanging_sign", + "id": -534, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_leaves", + "id": -548, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_log", + "id": -536, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_planks", + "id": -537, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_pressure_plate", + "id": -538, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_sapling", + "id": -547, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_sign", + "id": 688, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_slab", + "id": -539, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_stairs", + "id": -541, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_standing_sign", + "id": -542, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_trapdoor", + "id": -543, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_wall_sign", + "id": -544, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cherry_wood", + "id": -546, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chest", + "id": 54, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chest_boat", + "id": 682, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chest_minecart", + "id": 415, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chicken", + "id": 297, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:chicken_spawn_egg", + "id": 462, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chipped_anvil", + "id": -959, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_bookshelf", + "id": -526, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_copper", + "id": -760, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_deepslate", + "id": -395, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_nether_bricks", + "id": -302, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_polished_blackstone", + "id": -279, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_quartz_block", + "id": -953, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_red_sandstone", + "id": -956, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_resin_bricks", + "id": -1020, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_sandstone", + "id": -944, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_stone_bricks", + "id": -870, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_tuff", + "id": -753, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chiseled_tuff_bricks", + "id": -759, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chorus_flower", + "id": 200, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:chorus_fruit", + "id": 591, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:chorus_plant", + "id": 240, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:clay", + "id": 82, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:clay_ball", + "id": 410, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:client_request_placeholder_block", + "id": -465, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:clock", + "id": 419, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:closed_eyeblossom", + "id": -1019, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:coal", + "id": 326, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:coal_block", + "id": 173, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:coal_ore", + "id": 16, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:coarse_dirt", + "id": -962, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:coast_armor_trim_smithing_template", + "id": 720, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobbled_deepslate", + "id": -379, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobbled_deepslate_double_slab", + "id": -396, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobbled_deepslate_slab", + "id": -380, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobbled_deepslate_stairs", + "id": -381, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobbled_deepslate_wall", + "id": -382, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobblestone", + "id": 4, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobblestone_double_slab", + "id": -879, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobblestone_slab", + "id": -873, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cobblestone_wall", + "id": 139, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cocoa", + "id": 127, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cocoa_beans", + "id": 438, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cod", + "id": 286, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:cod_bucket", + "id": 389, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cod_spawn_egg", + "id": 508, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:colored_torch_blue", + "id": 204, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:colored_torch_bp", + "id": 789, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:colored_torch_green", + "id": -963, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:colored_torch_purple", + "id": -964, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:colored_torch_red", + "id": 202, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:colored_torch_rg", + "id": 788, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:command_block", + "id": 137, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:command_block_minecart", + "id": 596, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:comparator", + "id": 555, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:compass", + "id": 417, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:composter", + "id": -213, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:compound", + "id": 631, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:compound_creator", + "id": 238, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:concrete", + "id": 776, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:concrete_powder", + "id": 777, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:conduit", + "id": -157, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cooked_beef", + "id": 296, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:cooked_chicken", + "id": 298, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:cooked_cod", + "id": 290, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:cooked_mutton", + "id": 584, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:cooked_porkchop", + "id": 285, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:cooked_rabbit", + "id": 311, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:cooked_salmon", + "id": 291, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:cookie", + "id": 293, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:copper_block", + "id": -340, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:copper_bulb", + "id": -776, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:copper_door", + "id": -784, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:copper_grate", + "id": -768, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:copper_ingot", + "id": 538, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:copper_ore", + "id": -311, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:copper_trapdoor", + "id": -792, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:coral", + "id": 772, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:coral_block", + "id": 754, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:coral_fan", + "id": 763, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:coral_fan_dead", + "id": 764, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cornflower", + "id": -838, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cow_spawn_egg", + "id": 463, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cracked_deepslate_bricks", + "id": -410, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cracked_deepslate_tiles", + "id": -409, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cracked_nether_bricks", + "id": -303, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cracked_polished_blackstone_bricks", + "id": -280, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cracked_stone_bricks", + "id": -869, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crafter", + "id": -313, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crafting_table", + "id": 58, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:creaking_heart", + "id": -1012, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:creaking_spawn_egg", + "id": 747, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:creeper_banner_pattern", + "id": 615, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:creeper_head", + "id": -968, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:creeper_spawn_egg", + "id": 468, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_button", + "id": -260, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_door", + "id": 653, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_double_slab", + "id": -266, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_fence", + "id": -256, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_fence_gate", + "id": -258, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_fungus", + "id": -228, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_hanging_sign", + "id": -506, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_hyphae", + "id": -299, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_nylium", + "id": -232, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_planks", + "id": -242, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_pressure_plate", + "id": -262, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_roots", + "id": -223, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_sign", + "id": 651, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_slab", + "id": -264, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_stairs", + "id": -254, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_standing_sign", + "id": -250, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_stem", + "id": -225, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_trapdoor", + "id": -246, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crimson_wall_sign", + "id": -252, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crossbow", + "id": 608, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:crying_obsidian", + "id": -289, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_copper", + "id": -347, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_copper_slab", + "id": -361, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_copper_stairs", + "id": -354, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_red_sandstone", + "id": -957, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_red_sandstone_double_slab", + "id": -928, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_red_sandstone_slab", + "id": -901, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_sandstone", + "id": -945, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_sandstone_double_slab", + "id": -927, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cut_sandstone_slab", + "id": -900, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_bundle", + "id": 261, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:cyan_candle", + "id": -422, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_candle_cake", + "id": -439, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_carpet", + "id": -605, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_concrete", + "id": -636, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_concrete_powder", + "id": -717, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_dye", + "id": 427, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_glazed_terracotta", + "id": 229, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_shulker_box", + "id": -621, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_stained_glass", + "id": -681, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_stained_glass_pane", + "id": -651, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_terracotta", + "id": -732, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:cyan_wool", + "id": -561, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:damaged_anvil", + "id": -960, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dandelion", + "id": 37, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:danger_pottery_sherd", + "id": 699, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_boat", + "id": 406, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_button", + "id": -142, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_chest_boat", + "id": 680, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_door", + "id": 590, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_double_slab", + "id": -813, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_fence", + "id": -577, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_fence_gate", + "id": 186, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_hanging_sign", + "id": -505, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_leaves", + "id": -803, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_log", + "id": -572, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_planks", + "id": -743, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_pressure_plate", + "id": -152, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_sapling", + "id": -829, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_sign", + "id": 613, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_slab", + "id": -808, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_stairs", + "id": 164, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_trapdoor", + "id": -147, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_oak_wood", + "id": -818, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_prismarine", + "id": -947, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_prismarine_double_slab", + "id": -913, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_prismarine_slab", + "id": -886, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dark_prismarine_stairs", + "id": -3, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:darkoak_standing_sign", + "id": -192, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:darkoak_wall_sign", + "id": -193, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:daylight_detector", + "id": 151, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:daylight_detector_inverted", + "id": 178, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_brain_coral", + "id": -586, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_brain_coral_block", + "id": -854, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_brain_coral_fan", + "id": -844, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_brain_coral_wall_fan", + "id": -906, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_bubble_coral", + "id": -587, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_bubble_coral_block", + "id": -855, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_bubble_coral_fan", + "id": -845, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_bubble_coral_wall_fan", + "id": -908, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_fire_coral", + "id": -588, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_fire_coral_block", + "id": -856, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_fire_coral_fan", + "id": -846, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_fire_coral_wall_fan", + "id": -909, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_horn_coral", + "id": -589, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_horn_coral_block", + "id": -857, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_horn_coral_fan", + "id": -847, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_horn_coral_wall_fan", + "id": -910, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_tube_coral", + "id": -585, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_tube_coral_block", + "id": -853, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_tube_coral_fan", + "id": -134, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dead_tube_coral_wall_fan", + "id": -905, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deadbush", + "id": 32, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:decorated_pot", + "id": -551, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate", + "id": -378, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_brick_double_slab", + "id": -399, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_brick_slab", + "id": -392, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_brick_stairs", + "id": -393, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_brick_wall", + "id": -394, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_bricks", + "id": -391, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_coal_ore", + "id": -406, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_copper_ore", + "id": -408, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_diamond_ore", + "id": -405, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_emerald_ore", + "id": -407, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_gold_ore", + "id": -402, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_iron_ore", + "id": -401, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_lapis_ore", + "id": -400, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_redstone_ore", + "id": -403, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_tile_double_slab", + "id": -398, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_tile_slab", + "id": -388, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_tile_stairs", + "id": -389, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_tile_wall", + "id": -390, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deepslate_tiles", + "id": -387, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deny", + "id": 211, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deprecated_anvil", + "id": -961, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deprecated_purpur_block_1", + "id": -950, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:deprecated_purpur_block_2", + "id": -952, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:detector_rail", + "id": 28, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond", + "id": 328, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_axe", + "id": 343, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_block", + "id": 57, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_boots", + "id": 375, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_chestplate", + "id": 373, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_helmet", + "id": 372, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_hoe", + "id": 357, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_horse_armor", + "id": 566, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_leggings", + "id": 374, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_ore", + "id": 56, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_pickaxe", + "id": 342, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_shovel", + "id": 341, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diamond_sword", + "id": 340, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diorite", + "id": -592, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diorite_double_slab", + "id": -921, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diorite_slab", + "id": -894, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diorite_stairs", + "id": -170, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:diorite_wall", + "id": -973, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dirt", + "id": 3, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dirt_with_roots", + "id": -318, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:disc_fragment_5", + "id": 674, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dispenser", + "id": 23, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dolphin_spawn_egg", + "id": 512, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:donkey_spawn_egg", + "id": 493, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:double_cut_copper_slab", + "id": -368, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:double_plant", + "id": 770, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:double_stone_block_slab", + "id": 759, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:double_stone_block_slab2", + "id": 760, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:double_stone_block_slab3", + "id": 761, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:double_stone_block_slab4", + "id": 762, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dragon_breath", + "id": 593, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dragon_egg", + "id": 122, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dragon_head", + "id": -969, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dried_kelp", + "id": 292, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:dried_kelp_block", + "id": -139, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dripstone_block", + "id": -317, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dropper", + "id": 125, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:drowned_spawn_egg", + "id": 511, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dune_armor_trim_smithing_template", + "id": 719, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:dye", + "id": 792, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:echo_shard", + "id": 684, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:egg", + "id": 416, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:elder_guardian_spawn_egg", + "id": 499, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_0", + "id": 36, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_1", + "id": -12, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_10", + "id": -21, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_100", + "id": -111, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_101", + "id": -112, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_102", + "id": -113, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_103", + "id": -114, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_104", + "id": -115, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_105", + "id": -116, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_106", + "id": -117, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_107", + "id": -118, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_108", + "id": -119, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_109", + "id": -120, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_11", + "id": -22, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_110", + "id": -121, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_111", + "id": -122, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_112", + "id": -123, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_113", + "id": -124, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_114", + "id": -125, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_115", + "id": -126, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_116", + "id": -127, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_117", + "id": -128, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_118", + "id": -129, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_12", + "id": -23, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_13", + "id": -24, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_14", + "id": -25, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_15", + "id": -26, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_16", + "id": -27, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_17", + "id": -28, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_18", + "id": -29, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_19", + "id": -30, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_2", + "id": -13, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_20", + "id": -31, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_21", + "id": -32, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_22", + "id": -33, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_23", + "id": -34, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_24", + "id": -35, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_25", + "id": -36, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_26", + "id": -37, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_27", + "id": -38, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_28", + "id": -39, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_29", + "id": -40, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_3", + "id": -14, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_30", + "id": -41, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_31", + "id": -42, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_32", + "id": -43, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_33", + "id": -44, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_34", + "id": -45, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_35", + "id": -46, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_36", + "id": -47, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_37", + "id": -48, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_38", + "id": -49, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_39", + "id": -50, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_4", + "id": -15, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_40", + "id": -51, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_41", + "id": -52, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_42", + "id": -53, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_43", + "id": -54, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_44", + "id": -55, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_45", + "id": -56, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_46", + "id": -57, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_47", + "id": -58, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_48", + "id": -59, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_49", + "id": -60, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_5", + "id": -16, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_50", + "id": -61, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_51", + "id": -62, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_52", + "id": -63, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_53", + "id": -64, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_54", + "id": -65, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_55", + "id": -66, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_56", + "id": -67, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_57", + "id": -68, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_58", + "id": -69, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_59", + "id": -70, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_6", + "id": -17, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_60", + "id": -71, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_61", + "id": -72, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_62", + "id": -73, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_63", + "id": -74, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_64", + "id": -75, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_65", + "id": -76, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_66", + "id": -77, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_67", + "id": -78, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_68", + "id": -79, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_69", + "id": -80, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_7", + "id": -18, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_70", + "id": -81, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_71", + "id": -82, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_72", + "id": -83, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_73", + "id": -84, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_74", + "id": -85, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_75", + "id": -86, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_76", + "id": -87, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_77", + "id": -88, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_78", + "id": -89, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_79", + "id": -90, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_8", + "id": -19, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_80", + "id": -91, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_81", + "id": -92, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_82", + "id": -93, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_83", + "id": -94, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_84", + "id": -95, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_85", + "id": -96, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_86", + "id": -97, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_87", + "id": -98, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_88", + "id": -99, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_89", + "id": -100, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_9", + "id": -20, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_90", + "id": -101, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_91", + "id": -102, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_92", + "id": -103, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_93", + "id": -104, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_94", + "id": -105, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_95", + "id": -106, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_96", + "id": -107, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_97", + "id": -108, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_98", + "id": -109, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_99", + "id": -110, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:element_constructor", + "id": -987, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:elytra", + "id": 597, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:emerald", + "id": 546, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:emerald_block", + "id": 133, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:emerald_ore", + "id": 129, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:empty_map", + "id": 549, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:enchanted_book", + "id": 554, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:enchanted_golden_apple", + "id": 281, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:enchanting_table", + "id": 116, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_brick_stairs", + "id": -178, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_bricks", + "id": 206, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_crystal", + "id": 795, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_gateway", + "id": 209, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_portal", + "id": 119, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_portal_frame", + "id": 120, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_rod", + "id": 208, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_stone", + "id": 121, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_stone_brick_double_slab", + "id": -167, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_stone_brick_slab", + "id": -162, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:end_stone_brick_wall", + "id": -980, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ender_chest", + "id": 130, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ender_dragon_spawn_egg", + "id": 535, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ender_eye", + "id": 460, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ender_pearl", + "id": 448, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:enderman_spawn_egg", + "id": 469, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:endermite_spawn_egg", + "id": 487, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:evoker_spawn_egg", + "id": 503, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:experience_bottle", + "id": 542, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:explorer_pottery_sherd", + "id": 700, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_chiseled_copper", + "id": -761, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_copper", + "id": -341, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_copper_bulb", + "id": -777, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_copper_door", + "id": -785, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_copper_grate", + "id": -769, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_copper_trapdoor", + "id": -793, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_cut_copper", + "id": -348, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_cut_copper_slab", + "id": -362, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_cut_copper_stairs", + "id": -355, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:exposed_double_cut_copper_slab", + "id": -369, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:eye_armor_trim_smithing_template", + "id": 723, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:farmland", + "id": 60, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:feather", + "id": 352, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fence", + "id": 752, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fence_gate", + "id": 107, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fermented_spider_eye", + "id": 455, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fern", + "id": -848, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:field_masoned_banner_pattern", + "id": 618, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:filled_map", + "id": 446, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fire", + "id": 51, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fire_charge", + "id": 543, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fire_coral", + "id": -583, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fire_coral_block", + "id": -851, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fire_coral_fan", + "id": -842, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fire_coral_wall_fan", + "id": -907, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:firework_rocket", + "id": 552, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:firework_star", + "id": 553, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fishing_rod", + "id": 418, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:fletching_table", + "id": -201, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flint", + "id": 381, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flint_and_steel", + "id": 323, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flow_armor_trim_smithing_template", + "id": 734, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flow_banner_pattern", + "id": 622, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flow_pottery_sherd", + "id": 701, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flower_banner_pattern", + "id": 614, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flower_pot", + "id": 548, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:flowering_azalea", + "id": -338, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flowing_lava", + "id": 10, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:flowing_water", + "id": 8, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:fox_spawn_egg", + "id": 518, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:frame", + "id": 547, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:friend_pottery_sherd", + "id": 702, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:frog_spawn", + "id": -468, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:frog_spawn_egg", + "id": 665, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:frosted_ice", + "id": 207, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:furnace", + "id": 61, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ghast_spawn_egg", + "id": 481, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ghast_tear", + "id": 451, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gilded_blackstone", + "id": -281, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glass", + "id": 20, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glass_bottle", + "id": 454, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glass_pane", + "id": 102, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glistering_melon_slice", + "id": 461, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:globe_banner_pattern", + "id": 621, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glow_berries", + "id": 796, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:glow_frame", + "id": 660, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:glow_ink_sac", + "id": 537, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glow_lichen", + "id": -411, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glow_squid_spawn_egg", + "id": 532, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glow_stick", + "id": 638, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glowingobsidian", + "id": 246, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glowstone", + "id": 89, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:glowstone_dust", + "id": 420, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:goat_horn", + "id": 664, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:goat_spawn_egg", + "id": 531, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gold_block", + "id": 41, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gold_ingot", + "id": 330, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gold_nugget", + "id": 452, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gold_ore", + "id": 14, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_apple", + "id": 280, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:golden_axe", + "id": 350, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_boots", + "id": 379, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_carrot", + "id": 305, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:golden_chestplate", + "id": 377, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_helmet", + "id": 376, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_hoe", + "id": 358, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_horse_armor", + "id": 565, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_leggings", + "id": 378, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_pickaxe", + "id": 349, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_rail", + "id": 27, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_shovel", + "id": 348, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:golden_sword", + "id": 347, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:granite", + "id": -590, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:granite_double_slab", + "id": -923, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:granite_slab", + "id": -896, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:granite_stairs", + "id": -169, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:granite_wall", + "id": -972, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:grass_block", + "id": 2, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:grass_path", + "id": 198, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gravel", + "id": 13, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_bundle", + "id": 262, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:gray_candle", + "id": -420, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_candle_cake", + "id": -437, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_carpet", + "id": -603, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_concrete", + "id": -634, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_concrete_powder", + "id": -715, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_dye", + "id": 429, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_glazed_terracotta", + "id": 227, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_shulker_box", + "id": -619, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_stained_glass", + "id": -679, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_stained_glass_pane", + "id": -649, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_terracotta", + "id": -730, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gray_wool", + "id": -553, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_bundle", + "id": 263, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:green_candle", + "id": -426, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_candle_cake", + "id": -443, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_carpet", + "id": -609, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_concrete", + "id": -640, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_concrete_powder", + "id": -721, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_dye", + "id": 423, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_glazed_terracotta", + "id": 233, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_shulker_box", + "id": -625, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_stained_glass", + "id": -685, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_stained_glass_pane", + "id": -655, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_terracotta", + "id": -736, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:green_wool", + "id": -560, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:grindstone", + "id": -195, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:guardian_spawn_egg", + "id": 488, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:gunpowder", + "id": 353, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:guster_banner_pattern", + "id": 623, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:guster_pottery_sherd", + "id": 703, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hanging_roots", + "id": -319, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_black_stained_glass", + "id": -702, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_black_stained_glass_pane", + "id": -672, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_blue_stained_glass", + "id": -698, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_blue_stained_glass_pane", + "id": -668, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_brown_stained_glass", + "id": -699, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_brown_stained_glass_pane", + "id": -669, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_cyan_stained_glass", + "id": -696, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_cyan_stained_glass_pane", + "id": -666, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_glass", + "id": 253, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_glass_pane", + "id": 190, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_gray_stained_glass", + "id": -694, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_gray_stained_glass_pane", + "id": -664, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_green_stained_glass", + "id": -700, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_green_stained_glass_pane", + "id": -670, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_light_blue_stained_glass", + "id": -690, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_light_blue_stained_glass_pane", + "id": -660, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_light_gray_stained_glass", + "id": -695, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_light_gray_stained_glass_pane", + "id": -665, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_lime_stained_glass", + "id": -692, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_lime_stained_glass_pane", + "id": -662, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_magenta_stained_glass", + "id": -689, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_magenta_stained_glass_pane", + "id": -659, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_orange_stained_glass", + "id": -688, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_orange_stained_glass_pane", + "id": -658, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_pink_stained_glass", + "id": -693, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_pink_stained_glass_pane", + "id": -663, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_purple_stained_glass", + "id": -697, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_purple_stained_glass_pane", + "id": -667, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_red_stained_glass", + "id": -701, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_red_stained_glass_pane", + "id": -671, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_stained_glass", + "id": 786, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_stained_glass_pane", + "id": 787, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_white_stained_glass", + "id": 254, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_white_stained_glass_pane", + "id": 191, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_yellow_stained_glass", + "id": -691, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hard_yellow_stained_glass_pane", + "id": -661, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hardened_clay", + "id": 172, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hay_block", + "id": 170, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:heart_of_the_sea", + "id": 604, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:heart_pottery_sherd", + "id": 704, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:heartbreak_pottery_sherd", + "id": 705, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:heavy_core", + "id": -316, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:heavy_weighted_pressure_plate", + "id": 148, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hoglin_spawn_egg", + "id": 524, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:honey_block", + "id": -220, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:honey_bottle", + "id": 627, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:honeycomb", + "id": 626, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:honeycomb_block", + "id": -221, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:hopper", + "id": 560, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:hopper_minecart", + "id": 559, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:horn_coral", + "id": -584, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:horn_coral_block", + "id": -852, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:horn_coral_fan", + "id": -843, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:horn_coral_wall_fan", + "id": -137, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:horse_spawn_egg", + "id": 485, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:host_armor_trim_smithing_template", + "id": 733, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:howl_pottery_sherd", + "id": 706, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:husk_spawn_egg", + "id": 491, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ice", + "id": 79, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ice_bomb", + "id": 632, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:infested_chiseled_stone_bricks", + "id": -862, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:infested_cobblestone", + "id": -858, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:infested_cracked_stone_bricks", + "id": -861, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:infested_deepslate", + "id": -454, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:infested_mossy_stone_bricks", + "id": -860, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:infested_stone", + "id": 97, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:infested_stone_bricks", + "id": -859, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:info_update", + "id": 248, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:info_update2", + "id": 249, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ink_sac", + "id": 439, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:invisible_bedrock", + "id": 95, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_axe", + "id": 322, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_bars", + "id": 101, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_block", + "id": 42, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_boots", + "id": 371, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_chestplate", + "id": 369, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_door", + "id": 397, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_golem_spawn_egg", + "id": 533, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_helmet", + "id": 368, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_hoe", + "id": 356, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_horse_armor", + "id": 564, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_ingot", + "id": 329, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_leggings", + "id": 370, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_nugget", + "id": 602, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_ore", + "id": 15, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_pickaxe", + "id": 321, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_shovel", + "id": 320, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_sword", + "id": 331, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:iron_trapdoor", + "id": 167, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.acacia_door", + "id": 196, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.bed", + "id": 26, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.beetroot", + "id": 244, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.birch_door", + "id": 194, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.brewing_stand", + "id": 117, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.cake", + "id": 92, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.camera", + "id": 242, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.campfire", + "id": -209, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.cauldron", + "id": 118, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.chain", + "id": -286, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.crimson_door", + "id": -244, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.dark_oak_door", + "id": 197, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.flower_pot", + "id": 140, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.frame", + "id": 199, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.glow_frame", + "id": -339, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.hopper", + "id": 154, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.iron_door", + "id": 71, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.jungle_door", + "id": 195, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.kelp", + "id": -138, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.mangrove_door", + "id": -493, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.nether_sprouts", + "id": -238, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.nether_wart", + "id": 115, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.reeds", + "id": 83, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.soul_campfire", + "id": -290, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.spruce_door", + "id": 193, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.warped_door", + "id": -245, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.wheat", + "id": 59, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:item.wooden_door", + "id": 64, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jigsaw", + "id": -211, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jukebox", + "id": 84, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_boat", + "id": 403, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_button", + "id": -143, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_chest_boat", + "id": 677, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_door", + "id": 588, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_double_slab", + "id": -811, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_fence", + "id": -578, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_fence_gate", + "id": 185, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_hanging_sign", + "id": -503, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_leaves", + "id": -802, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_log", + "id": -571, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_planks", + "id": -741, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_pressure_plate", + "id": -153, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_sapling", + "id": -827, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_sign", + "id": 611, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_slab", + "id": -806, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_stairs", + "id": 136, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_standing_sign", + "id": -188, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_trapdoor", + "id": -148, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_wall_sign", + "id": -189, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:jungle_wood", + "id": -816, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:kelp", + "id": 408, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:lab_table", + "id": -988, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ladder", + "id": 65, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lantern", + "id": -208, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lapis_block", + "id": 22, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lapis_lazuli", + "id": 440, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lapis_ore", + "id": 21, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:large_amethyst_bud", + "id": -330, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:large_fern", + "id": -865, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lava", + "id": 11, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lava_bucket", + "id": 388, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lead", + "id": 580, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:leather", + "id": 407, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:leather_boots", + "id": 363, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:leather_chestplate", + "id": 361, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:leather_helmet", + "id": 360, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:leather_horse_armor", + "id": 563, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:leather_leggings", + "id": 362, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:leaves", + "id": 766, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:leaves2", + "id": 767, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lectern", + "id": -194, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lever", + "id": 69, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block", + "id": 790, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_0", + "id": -215, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_1", + "id": -929, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_10", + "id": -938, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_11", + "id": -939, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_12", + "id": -940, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_13", + "id": -941, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_14", + "id": -942, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_15", + "id": -943, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_2", + "id": -930, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_3", + "id": -931, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_4", + "id": -932, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_5", + "id": -933, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_6", + "id": -934, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_7", + "id": -935, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_8", + "id": -936, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_block_9", + "id": -937, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_bundle", + "id": 264, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:light_blue_candle", + "id": -416, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_candle_cake", + "id": -433, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_carpet", + "id": -599, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_concrete", + "id": -630, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_concrete_powder", + "id": -711, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_dye", + "id": 433, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_glazed_terracotta", + "id": 223, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_shulker_box", + "id": -615, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_stained_glass", + "id": -675, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_stained_glass_pane", + "id": -645, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_terracotta", + "id": -726, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_blue_wool", + "id": -562, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_bundle", + "id": 265, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:light_gray_candle", + "id": -421, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_candle_cake", + "id": -438, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_carpet", + "id": -604, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_concrete", + "id": -635, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_concrete_powder", + "id": -716, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_dye", + "id": 428, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_shulker_box", + "id": -620, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_stained_glass", + "id": -680, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_stained_glass_pane", + "id": -650, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_terracotta", + "id": -731, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_gray_wool", + "id": -552, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:light_weighted_pressure_plate", + "id": 147, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lightning_rod", + "id": -312, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lilac", + "id": -863, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lily_of_the_valley", + "id": -839, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_bundle", + "id": 266, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:lime_candle", + "id": -418, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_candle_cake", + "id": -435, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_carpet", + "id": -601, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_concrete", + "id": -632, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_concrete_powder", + "id": -713, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_dye", + "id": 431, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_glazed_terracotta", + "id": 225, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_shulker_box", + "id": -617, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_stained_glass", + "id": -677, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_stained_glass_pane", + "id": -647, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_terracotta", + "id": -728, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lime_wool", + "id": -559, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lingering_potion", + "id": 595, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lit_blast_furnace", + "id": -214, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lit_deepslate_redstone_ore", + "id": -404, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lit_furnace", + "id": 62, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lit_pumpkin", + "id": 91, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lit_redstone_lamp", + "id": 124, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lit_redstone_ore", + "id": 74, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lit_smoker", + "id": -199, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:llama_spawn_egg", + "id": 501, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lodestone", + "id": -222, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:lodestone_compass", + "id": 639, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:log", + "id": 751, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:log2", + "id": 774, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:loom", + "id": -204, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mace", + "id": 344, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_bundle", + "id": 267, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:magenta_candle", + "id": -415, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_candle_cake", + "id": -432, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_carpet", + "id": -598, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_concrete", + "id": -629, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_concrete_powder", + "id": -710, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_dye", + "id": 434, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_glazed_terracotta", + "id": 222, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_shulker_box", + "id": -614, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_stained_glass", + "id": -674, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_stained_glass_pane", + "id": -644, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_terracotta", + "id": -725, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magenta_wool", + "id": -565, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magma", + "id": 213, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magma_cream", + "id": 457, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:magma_cube_spawn_egg", + "id": 482, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_boat", + "id": 672, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_button", + "id": -487, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_chest_boat", + "id": 681, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_door", + "id": 670, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_double_slab", + "id": -499, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_fence", + "id": -491, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_fence_gate", + "id": -492, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_hanging_sign", + "id": -508, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_leaves", + "id": -472, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_log", + "id": -484, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_planks", + "id": -486, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_pressure_plate", + "id": -490, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_propagule", + "id": -474, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_roots", + "id": -482, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_sign", + "id": 671, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_slab", + "id": -489, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_stairs", + "id": -488, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_standing_sign", + "id": -494, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_trapdoor", + "id": -496, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_wall_sign", + "id": -495, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mangrove_wood", + "id": -497, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:material_reducer", + "id": -986, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:medicine", + "id": 636, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:medium_amethyst_bud", + "id": -331, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:melon_block", + "id": 103, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:melon_seeds", + "id": 315, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:melon_slice", + "id": 294, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:melon_stem", + "id": 105, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:milk_bucket", + "id": 386, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:minecart", + "id": 395, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:miner_pottery_sherd", + "id": 707, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mob_spawner", + "id": 52, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mojang_banner_pattern", + "id": 617, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:monster_egg", + "id": 775, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mooshroom_spawn_egg", + "id": 467, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:moss_block", + "id": -320, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:moss_carpet", + "id": -335, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_cobblestone", + "id": 48, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_cobblestone_double_slab", + "id": -915, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_cobblestone_slab", + "id": -888, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_cobblestone_stairs", + "id": -179, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_cobblestone_wall", + "id": -971, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_stone_brick_double_slab", + "id": -168, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_stone_brick_slab", + "id": -166, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_stone_brick_stairs", + "id": -175, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_stone_brick_wall", + "id": -978, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mossy_stone_bricks", + "id": -868, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mourner_pottery_sherd", + "id": 708, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:moving_block", + "id": 250, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mud", + "id": -473, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mud_brick_double_slab", + "id": -479, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mud_brick_slab", + "id": -478, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mud_brick_stairs", + "id": -480, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mud_brick_wall", + "id": -481, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mud_bricks", + "id": -475, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:muddy_mangrove_roots", + "id": -483, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mule_spawn_egg", + "id": 494, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mushroom_stem", + "id": -1008, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:mushroom_stew", + "id": 282, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:music_disc_11", + "id": 577, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_13", + "id": 567, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_5", + "id": 673, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_blocks", + "id": 569, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_cat", + "id": 568, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_chirp", + "id": 570, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_creator", + "id": 782, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_creator_music_box", + "id": 783, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_far", + "id": 571, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_mall", + "id": 572, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_mellohi", + "id": 573, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_otherside", + "id": 663, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_pigstep", + "id": 657, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_precipice", + "id": 784, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_relic", + "id": 736, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_stal", + "id": 574, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_strad", + "id": 575, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_wait", + "id": 578, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:music_disc_ward", + "id": 576, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:mutton", + "id": 583, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:mycelium", + "id": 110, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:name_tag", + "id": 581, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nautilus_shell", + "id": 603, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_brick", + "id": 112, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_brick_double_slab", + "id": -883, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_brick_fence", + "id": 113, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_brick_slab", + "id": -877, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_brick_stairs", + "id": 114, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_brick_wall", + "id": -979, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_gold_ore", + "id": -288, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_sprouts", + "id": 658, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:nether_star", + "id": 551, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:nether_wart", + "id": 316, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:nether_wart_block", + "id": 214, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherbrick", + "id": 556, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_axe", + "id": 643, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_block", + "id": -270, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_boots", + "id": 649, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_chestplate", + "id": 647, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_helmet", + "id": 646, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_hoe", + "id": 644, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_ingot", + "id": 645, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_leggings", + "id": 648, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_pickaxe", + "id": 642, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_scrap", + "id": 650, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_shovel", + "id": 641, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_sword", + "id": 640, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherite_upgrade_smithing_template", + "id": 717, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherrack", + "id": 87, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:netherreactor", + "id": 247, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:normal_stone_double_slab", + "id": -926, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:normal_stone_slab", + "id": -899, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:normal_stone_stairs", + "id": -180, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:noteblock", + "id": 25, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:npc_spawn_egg", + "id": 498, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_boat", + "id": 401, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_chest_boat", + "id": 675, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_double_slab", + "id": 157, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_fence", + "id": 85, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_hanging_sign", + "id": -500, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_leaves", + "id": 18, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_log", + "id": 17, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_planks", + "id": 5, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_sapling", + "id": 6, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_sign", + "id": 383, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_slab", + "id": 158, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_stairs", + "id": 53, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oak_wood", + "id": -212, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:observer", + "id": 251, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:obsidian", + "id": 49, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ocelot_spawn_egg", + "id": 478, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ochre_froglight", + "id": -471, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ominous_bottle", + "id": 628, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ominous_trial_key", + "id": 275, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:open_eyeblossom", + "id": -1018, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_bundle", + "id": 268, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:orange_candle", + "id": -414, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_candle_cake", + "id": -431, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_carpet", + "id": -597, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_concrete", + "id": -628, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_concrete_powder", + "id": -709, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_dye", + "id": 435, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_glazed_terracotta", + "id": 221, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_shulker_box", + "id": -613, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_stained_glass", + "id": -673, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_stained_glass_pane", + "id": -643, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_terracotta", + "id": -724, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_tulip", + "id": -834, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:orange_wool", + "id": -557, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxeye_daisy", + "id": -837, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_chiseled_copper", + "id": -763, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_copper", + "id": -343, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_copper_bulb", + "id": -779, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_copper_door", + "id": -787, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_copper_grate", + "id": -771, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_copper_trapdoor", + "id": -795, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_cut_copper", + "id": -350, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_cut_copper_slab", + "id": -364, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_cut_copper_stairs", + "id": -357, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:oxidized_double_cut_copper_slab", + "id": -371, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:packed_ice", + "id": 174, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:packed_mud", + "id": -477, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:painting", + "id": 382, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_hanging_moss", + "id": -1011, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_moss_block", + "id": -1009, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_moss_carpet", + "id": -1010, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_boat", + "id": 744, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_button", + "id": -989, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_chest_boat", + "id": 745, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_door", + "id": -990, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_double_slab", + "id": -999, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_fence", + "id": -991, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_fence_gate", + "id": -992, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_hanging_sign", + "id": -993, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_leaves", + "id": -1007, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_log", + "id": -995, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_planks", + "id": -996, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_pressure_plate", + "id": -997, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_sapling", + "id": -1006, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_sign", + "id": 746, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_slab", + "id": -998, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_stairs", + "id": -1000, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_standing_sign", + "id": -1001, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_trapdoor", + "id": -1002, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_wall_sign", + "id": -1003, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pale_oak_wood", + "id": -1005, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:panda_spawn_egg", + "id": 517, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:paper", + "id": 412, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:parrot_spawn_egg", + "id": 506, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pearlescent_froglight", + "id": -469, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:peony", + "id": -867, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:petrified_oak_double_slab", + "id": -903, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:petrified_oak_slab", + "id": -902, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:phantom_membrane", + "id": 607, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:phantom_spawn_egg", + "id": 514, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pig_spawn_egg", + "id": 464, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:piglin_banner_pattern", + "id": 620, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:piglin_brute_spawn_egg", + "id": 527, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:piglin_head", + "id": -970, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:piglin_spawn_egg", + "id": 525, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pillager_spawn_egg", + "id": 519, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_bundle", + "id": 269, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:pink_candle", + "id": -419, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_candle_cake", + "id": -436, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_carpet", + "id": -602, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_concrete", + "id": -633, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_concrete_powder", + "id": -714, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_dye", + "id": 430, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_glazed_terracotta", + "id": 226, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_petals", + "id": -549, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_shulker_box", + "id": -618, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_stained_glass", + "id": -678, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_stained_glass_pane", + "id": -648, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_terracotta", + "id": -729, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_tulip", + "id": -836, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pink_wool", + "id": -566, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:piston", + "id": 33, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:piston_arm_collision", + "id": 34, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pitcher_crop", + "id": -574, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pitcher_plant", + "id": -612, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pitcher_pod", + "id": 319, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:planks", + "id": 771, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:player_head", + "id": -967, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:plenty_pottery_sherd", + "id": 709, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:podzol", + "id": 243, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pointed_dripstone", + "id": -308, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:poisonous_potato", + "id": 304, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:polar_bear_spawn_egg", + "id": 500, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_andesite", + "id": -595, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_andesite_double_slab", + "id": -919, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_andesite_slab", + "id": -892, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_andesite_stairs", + "id": -174, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_basalt", + "id": -235, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone", + "id": -291, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_brick_double_slab", + "id": -285, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_brick_slab", + "id": -284, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_brick_stairs", + "id": -275, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_brick_wall", + "id": -278, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_bricks", + "id": -274, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_button", + "id": -296, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_double_slab", + "id": -294, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_pressure_plate", + "id": -295, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_slab", + "id": -293, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_stairs", + "id": -292, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_blackstone_wall", + "id": -297, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_deepslate", + "id": -383, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_deepslate_double_slab", + "id": -397, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_deepslate_slab", + "id": -384, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_deepslate_stairs", + "id": -385, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_deepslate_wall", + "id": -386, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_diorite", + "id": -593, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_diorite_double_slab", + "id": -922, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_diorite_slab", + "id": -895, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_diorite_stairs", + "id": -173, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_granite", + "id": -591, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_granite_double_slab", + "id": -924, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_granite_slab", + "id": -897, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_granite_stairs", + "id": -172, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_tuff", + "id": -748, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_tuff_double_slab", + "id": -750, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_tuff_slab", + "id": -749, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_tuff_stairs", + "id": -751, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:polished_tuff_wall", + "id": -752, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:popped_chorus_fruit", + "id": 592, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:poppy", + "id": 38, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:porkchop", + "id": 284, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:portal", + "id": 90, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:potato", + "id": 302, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:potatoes", + "id": 142, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:potion", + "id": 453, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:powder_snow", + "id": -306, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:powder_snow_bucket", + "id": 393, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:powered_comparator", + "id": 150, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:powered_repeater", + "id": 94, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine", + "id": 168, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_brick_double_slab", + "id": -914, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_brick_slab", + "id": -887, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_bricks", + "id": -948, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_bricks_stairs", + "id": -4, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_crystals", + "id": 582, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_double_slab", + "id": -912, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_shard", + "id": 598, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_slab", + "id": -885, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_stairs", + "id": -2, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prismarine_wall", + "id": -981, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:prize_pottery_sherd", + "id": 710, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pufferfish", + "id": 289, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:pufferfish_bucket", + "id": 392, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pufferfish_spawn_egg", + "id": 509, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pumpkin", + "id": 86, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:pumpkin_pie", + "id": 306, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:pumpkin_seeds", + "id": 314, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:pumpkin_stem", + "id": 104, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_bundle", + "id": 270, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:purple_candle", + "id": -423, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_candle_cake", + "id": -440, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_carpet", + "id": -606, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_concrete", + "id": -637, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_concrete_powder", + "id": -718, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_dye", + "id": 426, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_glazed_terracotta", + "id": 219, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_shulker_box", + "id": -622, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_stained_glass", + "id": -682, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_stained_glass_pane", + "id": -652, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_terracotta", + "id": -733, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purple_wool", + "id": -564, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purpur_block", + "id": 201, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purpur_double_slab", + "id": -911, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purpur_pillar", + "id": -951, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purpur_slab", + "id": -884, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:purpur_stairs", + "id": 203, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:quartz", + "id": 557, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:quartz_block", + "id": 155, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:quartz_bricks", + "id": -304, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:quartz_double_slab", + "id": -882, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:quartz_ore", + "id": 153, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:quartz_pillar", + "id": -954, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:quartz_slab", + "id": -876, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:quartz_stairs", + "id": 156, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:rabbit", + "id": 310, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:rabbit_foot", + "id": 561, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:rabbit_hide", + "id": 562, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:rabbit_spawn_egg", + "id": 486, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:rabbit_stew", + "id": 312, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:rail", + "id": 66, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:raiser_armor_trim_smithing_template", + "id": 731, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:rapid_fertilizer", + "id": 634, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ravager_spawn_egg", + "id": 521, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:raw_copper", + "id": 541, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:raw_copper_block", + "id": -452, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:raw_gold", + "id": 540, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:raw_gold_block", + "id": -453, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:raw_iron", + "id": 539, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:raw_iron_block", + "id": -451, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:recovery_compass", + "id": 683, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_bundle", + "id": 271, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:red_candle", + "id": -427, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_candle_cake", + "id": -444, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_carpet", + "id": -610, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_concrete", + "id": -641, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_concrete_powder", + "id": -722, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_dye", + "id": 422, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_flower", + "id": 769, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_glazed_terracotta", + "id": 234, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_mushroom", + "id": 40, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_mushroom_block", + "id": 100, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_nether_brick", + "id": 215, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_nether_brick_double_slab", + "id": -917, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_nether_brick_slab", + "id": -890, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_nether_brick_stairs", + "id": -184, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_nether_brick_wall", + "id": -983, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_sand", + "id": -949, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_sandstone", + "id": 179, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_sandstone_double_slab", + "id": 181, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_sandstone_slab", + "id": 182, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_sandstone_stairs", + "id": 180, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_sandstone_wall", + "id": -982, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_shulker_box", + "id": -626, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_stained_glass", + "id": -686, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_stained_glass_pane", + "id": -656, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_terracotta", + "id": -737, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_tulip", + "id": -833, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:red_wool", + "id": -556, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:redstone", + "id": 398, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:redstone_block", + "id": 152, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:redstone_lamp", + "id": 123, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:redstone_ore", + "id": 73, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:redstone_torch", + "id": 76, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:redstone_wire", + "id": 55, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:reinforced_deepslate", + "id": -466, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:repeater", + "id": 445, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:repeating_command_block", + "id": 188, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:reserved6", + "id": 255, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:resin_block", + "id": -1021, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:resin_brick", + "id": 748, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:resin_brick_double_slab", + "id": -1015, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:resin_brick_slab", + "id": -1014, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:resin_brick_stairs", + "id": -1016, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:resin_brick_wall", + "id": -1017, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:resin_bricks", + "id": -1013, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:resin_clump", + "id": -1022, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:respawn_anchor", + "id": -272, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:rib_armor_trim_smithing_template", + "id": 727, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:rose_bush", + "id": -866, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:rotten_flesh", + "id": 299, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:saddle", + "id": 396, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:salmon", + "id": 287, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:salmon_bucket", + "id": 390, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:salmon_spawn_egg", + "id": 510, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sand", + "id": 12, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sandstone", + "id": 24, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sandstone_double_slab", + "id": -878, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sandstone_slab", + "id": -872, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sandstone_stairs", + "id": 128, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sandstone_wall", + "id": -975, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sapling", + "id": 765, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:scaffolding", + "id": -165, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:scrape_pottery_sherd", + "id": 711, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sculk", + "id": -458, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sculk_catalyst", + "id": -460, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sculk_sensor", + "id": -307, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sculk_shrieker", + "id": -461, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sculk_vein", + "id": -459, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sea_lantern", + "id": 169, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sea_pickle", + "id": -156, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:seagrass", + "id": -130, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sentry_armor_trim_smithing_template", + "id": 718, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:shaper_armor_trim_smithing_template", + "id": 732, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sheaf_pottery_sherd", + "id": 712, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:shears", + "id": 447, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sheep_spawn_egg", + "id": 465, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:shelter_pottery_sherd", + "id": 713, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:shield", + "id": 380, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:short_grass", + "id": 31, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:shroomlight", + "id": -230, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:shulker_box", + "id": 780, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:shulker_shell", + "id": 599, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:shulker_spawn_egg", + "id": 497, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:silence_armor_trim_smithing_template", + "id": 729, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:silver_glazed_terracotta", + "id": 228, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:silverfish_spawn_egg", + "id": 470, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:skeleton_horse_spawn_egg", + "id": 495, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:skeleton_skull", + "id": 144, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:skeleton_spawn_egg", + "id": 471, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:skull", + "id": 737, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:skull_banner_pattern", + "id": 616, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:skull_pottery_sherd", + "id": 714, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:slime", + "id": 165, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:slime_ball", + "id": 414, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:slime_spawn_egg", + "id": 472, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:small_amethyst_bud", + "id": -332, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:small_dripleaf_block", + "id": -336, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smithing_table", + "id": -202, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smoker", + "id": -198, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_basalt", + "id": -377, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_quartz", + "id": -955, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_quartz_double_slab", + "id": -925, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_quartz_slab", + "id": -898, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_quartz_stairs", + "id": -185, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_red_sandstone", + "id": -958, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_red_sandstone_double_slab", + "id": -918, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_red_sandstone_slab", + "id": -891, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_red_sandstone_stairs", + "id": -176, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_sandstone", + "id": -946, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_sandstone_double_slab", + "id": -916, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_sandstone_slab", + "id": -889, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_sandstone_stairs", + "id": -177, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_stone", + "id": -183, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_stone_double_slab", + "id": 43, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:smooth_stone_slab", + "id": 44, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sniffer_egg", + "id": -596, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sniffer_spawn_egg", + "id": 528, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:snort_pottery_sherd", + "id": 715, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:snout_armor_trim_smithing_template", + "id": 726, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:snow", + "id": 80, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:snow_golem_spawn_egg", + "id": 534, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:snow_layer", + "id": 78, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:snowball", + "id": 399, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:soul_campfire", + "id": 659, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:soul_fire", + "id": -237, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:soul_lantern", + "id": -269, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:soul_sand", + "id": 88, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:soul_soil", + "id": -236, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:soul_torch", + "id": -268, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sparkler", + "id": 637, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spawn_egg", + "id": 794, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spider_eye", + "id": 300, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:spider_spawn_egg", + "id": 473, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spire_armor_trim_smithing_template", + "id": 728, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:splash_potion", + "id": 594, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sponge", + "id": 19, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spore_blossom", + "id": -321, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_boat", + "id": 404, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_button", + "id": -144, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_chest_boat", + "id": 678, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_door", + "id": 586, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_double_slab", + "id": -809, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_fence", + "id": -579, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_fence_gate", + "id": 183, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_hanging_sign", + "id": -501, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_leaves", + "id": -800, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_log", + "id": -569, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_planks", + "id": -739, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_pressure_plate", + "id": -154, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_sapling", + "id": -825, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_sign", + "id": 609, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_slab", + "id": -804, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_stairs", + "id": 134, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_standing_sign", + "id": -181, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_trapdoor", + "id": -149, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_wall_sign", + "id": -182, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spruce_wood", + "id": -814, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:spyglass", + "id": 662, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:squid_spawn_egg", + "id": 477, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stained_glass", + "id": 778, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stained_glass_pane", + "id": 779, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stained_hardened_clay", + "id": 738, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:standing_banner", + "id": 176, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:standing_sign", + "id": 63, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stick", + "id": 345, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sticky_piston", + "id": 29, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sticky_piston_arm_collision", + "id": -217, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone", + "id": 1, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_axe", + "id": 339, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_block_slab", + "id": 755, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_block_slab2", + "id": 756, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_block_slab3", + "id": 757, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_block_slab4", + "id": 758, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_brick_double_slab", + "id": -881, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_brick_slab", + "id": -875, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_brick_stairs", + "id": 109, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_brick_wall", + "id": -977, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_bricks", + "id": 98, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_button", + "id": 77, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_hoe", + "id": 355, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_pickaxe", + "id": 338, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_pressure_plate", + "id": 70, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_shovel", + "id": 337, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_stairs", + "id": 67, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stone_sword", + "id": 336, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stonebrick", + "id": 753, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stonecutter", + "id": 245, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stonecutter_block", + "id": -197, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stray_spawn_egg", + "id": 489, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:strider_spawn_egg", + "id": 523, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:string", + "id": 351, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:stripped_acacia_log", + "id": -8, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_acacia_wood", + "id": -823, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_bamboo_block", + "id": -528, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_birch_log", + "id": -6, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_birch_wood", + "id": -821, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_cherry_log", + "id": -535, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_cherry_wood", + "id": -545, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_crimson_hyphae", + "id": -300, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_crimson_stem", + "id": -240, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_dark_oak_log", + "id": -9, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_dark_oak_wood", + "id": -824, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_jungle_log", + "id": -7, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_jungle_wood", + "id": -822, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_mangrove_log", + "id": -485, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_mangrove_wood", + "id": -498, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_oak_log", + "id": -10, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_oak_wood", + "id": -819, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_pale_oak_log", + "id": -994, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_pale_oak_wood", + "id": -1004, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_spruce_log", + "id": -5, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_spruce_wood", + "id": -820, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_warped_hyphae", + "id": -301, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:stripped_warped_stem", + "id": -241, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:structure_block", + "id": 252, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:structure_void", + "id": 217, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sugar", + "id": 442, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:sugar_cane", + "id": 411, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:sunflower", + "id": 175, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:suspicious_gravel", + "id": -573, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:suspicious_sand", + "id": -529, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:suspicious_stew", + "id": 625, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:sweet_berries", + "id": 309, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:sweet_berry_bush", + "id": -207, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tadpole_bucket", + "id": 667, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tadpole_spawn_egg", + "id": 666, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tall_grass", + "id": -864, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tallgrass", + "id": 773, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:target", + "id": -239, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tide_armor_trim_smithing_template", + "id": 725, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tinted_glass", + "id": -334, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tnt", + "id": 46, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tnt_minecart", + "id": 558, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:torch", + "id": 50, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:torchflower", + "id": -568, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:torchflower_crop", + "id": -567, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:torchflower_seeds", + "id": 318, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:totem_of_undying", + "id": 601, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:trader_llama_spawn_egg", + "id": 685, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:trapdoor", + "id": 96, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:trapped_chest", + "id": 146, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:trial_key", + "id": 276, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:trial_spawner", + "id": -315, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:trident", + "id": 579, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:trip_wire", + "id": 132, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tripwire_hook", + "id": 131, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tropical_fish", + "id": 288, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:tropical_fish_bucket", + "id": 391, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tropical_fish_spawn_egg", + "id": 507, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tube_coral", + "id": -131, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tube_coral_block", + "id": -132, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tube_coral_fan", + "id": -133, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tube_coral_wall_fan", + "id": -135, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff", + "id": -333, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_brick_double_slab", + "id": -756, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_brick_slab", + "id": -755, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_brick_stairs", + "id": -757, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_brick_wall", + "id": -758, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_bricks", + "id": -754, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_double_slab", + "id": -745, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_slab", + "id": -744, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_stairs", + "id": -746, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:tuff_wall", + "id": -747, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:turtle_egg", + "id": -159, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:turtle_helmet", + "id": 606, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:turtle_scute", + "id": 605, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:turtle_spawn_egg", + "id": 513, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:twisting_vines", + "id": -287, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:underwater_tnt", + "id": -985, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:underwater_torch", + "id": 239, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:undyed_shulker_box", + "id": 205, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:unknown", + "id": -305, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:unlit_redstone_torch", + "id": 75, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:unpowered_comparator", + "id": 149, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:unpowered_repeater", + "id": 93, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:vault", + "id": -314, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:verdant_froglight", + "id": -470, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:vex_armor_trim_smithing_template", + "id": 724, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:vex_spawn_egg", + "id": 504, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:villager_spawn_egg", + "id": 476, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:vindicator_spawn_egg", + "id": 502, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:vine", + "id": 106, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wall_banner", + "id": 177, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wall_sign", + "id": 68, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wandering_trader_spawn_egg", + "id": 520, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:ward_armor_trim_smithing_template", + "id": 722, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warden_spawn_egg", + "id": 669, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_button", + "id": -261, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_door", + "id": 654, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_double_slab", + "id": -267, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_fence", + "id": -257, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_fence_gate", + "id": -259, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_fungus", + "id": -229, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_fungus_on_a_stick", + "id": 655, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:warped_hanging_sign", + "id": -507, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_hyphae", + "id": -298, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_nylium", + "id": -233, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_planks", + "id": -243, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_pressure_plate", + "id": -263, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_roots", + "id": -224, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_sign", + "id": 652, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_slab", + "id": -265, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_stairs", + "id": -255, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_standing_sign", + "id": -251, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_stem", + "id": -226, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_trapdoor", + "id": -247, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_wall_sign", + "id": -253, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:warped_wart_block", + "id": -227, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:water", + "id": 9, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:water_bucket", + "id": 387, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waterlily", + "id": 111, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_chiseled_copper", + "id": -764, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_copper", + "id": -344, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_copper_bulb", + "id": -780, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_copper_door", + "id": -788, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_copper_grate", + "id": -772, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_copper_trapdoor", + "id": -796, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_cut_copper", + "id": -351, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_cut_copper_slab", + "id": -365, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_cut_copper_stairs", + "id": -358, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_double_cut_copper_slab", + "id": -372, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_chiseled_copper", + "id": -765, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_copper", + "id": -345, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_copper_bulb", + "id": -781, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_copper_door", + "id": -789, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_copper_grate", + "id": -773, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_copper_trapdoor", + "id": -797, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_cut_copper", + "id": -352, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_cut_copper_slab", + "id": -366, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_cut_copper_stairs", + "id": -359, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_exposed_double_cut_copper_slab", + "id": -373, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_chiseled_copper", + "id": -766, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_copper", + "id": -446, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_copper_bulb", + "id": -783, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_copper_door", + "id": -791, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_copper_grate", + "id": -775, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_copper_trapdoor", + "id": -799, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_cut_copper", + "id": -447, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_cut_copper_slab", + "id": -449, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_cut_copper_stairs", + "id": -448, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_oxidized_double_cut_copper_slab", + "id": -450, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_chiseled_copper", + "id": -767, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_copper", + "id": -346, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_copper_bulb", + "id": -782, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_copper_door", + "id": -790, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_copper_grate", + "id": -774, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_copper_trapdoor", + "id": -798, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_cut_copper", + "id": -353, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_cut_copper_slab", + "id": -367, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_cut_copper_stairs", + "id": -360, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:waxed_weathered_double_cut_copper_slab", + "id": -374, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wayfinder_armor_trim_smithing_template", + "id": 730, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_chiseled_copper", + "id": -762, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_copper", + "id": -342, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_copper_bulb", + "id": -778, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_copper_door", + "id": -786, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_copper_grate", + "id": -770, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_copper_trapdoor", + "id": -794, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_cut_copper", + "id": -349, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_cut_copper_slab", + "id": -363, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_cut_copper_stairs", + "id": -356, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weathered_double_cut_copper_slab", + "id": -370, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:web", + "id": 30, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:weeping_vines", + "id": -231, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wet_sponge", + "id": -984, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wheat", + "id": 359, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wheat_seeds", + "id": 313, + "version": 0, + "componentBased": false + }, + { + "name": "minecraft:white_bundle", + "id": 272, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:white_candle", + "id": -413, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_candle_cake", + "id": -430, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_carpet", + "id": 171, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_concrete", + "id": 236, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_concrete_powder", + "id": 237, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_dye", + "id": 436, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_glazed_terracotta", + "id": 220, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_shulker_box", + "id": 218, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_stained_glass", + "id": 241, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_stained_glass_pane", + "id": 160, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_terracotta", + "id": 159, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_tulip", + "id": -835, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:white_wool", + "id": 35, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wild_armor_trim_smithing_template", + "id": 721, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wind_charge", + "id": 277, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:witch_spawn_egg", + "id": 479, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wither_rose", + "id": -216, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wither_skeleton_skull", + "id": -965, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wither_skeleton_spawn_egg", + "id": 492, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wither_spawn_egg", + "id": 536, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wolf_armor", + "id": 741, + "version": 2, + "componentBased": true + }, + { + "name": "minecraft:wolf_spawn_egg", + "id": 466, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wood", + "id": 781, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_axe", + "id": 335, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_button", + "id": 143, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_door", + "id": 384, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_hoe", + "id": 354, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_pickaxe", + "id": 334, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_pressure_plate", + "id": 72, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_shovel", + "id": 333, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_slab", + "id": 768, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wooden_sword", + "id": 332, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:wool", + "id": 749, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:writable_book", + "id": 544, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:written_book", + "id": 545, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_bundle", + "id": 273, + "version": 1, + "componentBased": true + }, + { + "name": "minecraft:yellow_candle", + "id": -417, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_candle_cake", + "id": -434, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_carpet", + "id": -600, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_concrete", + "id": -631, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_concrete_powder", + "id": -712, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_dye", + "id": 432, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_glazed_terracotta", + "id": 224, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_shulker_box", + "id": -616, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_stained_glass", + "id": -676, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_stained_glass_pane", + "id": -646, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_terracotta", + "id": -727, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:yellow_wool", + "id": -558, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:zoglin_spawn_egg", + "id": 526, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:zombie_head", + "id": -966, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:zombie_horse_spawn_egg", + "id": 496, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:zombie_pigman_spawn_egg", + "id": 475, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:zombie_spawn_egg", + "id": 474, + "version": 2, + "componentBased": false + }, + { + "name": "minecraft:zombie_villager_spawn_egg", + "id": 505, + "version": 2, + "componentBased": false + } +] diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 7499daf71..61642604b 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 7499daf712ad6de70a07fba471b51b4ad92315c5 +Subproject commit 61642604b8af1673f714087837f0c4287bfdc492 diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 6808d0e16..2281e339f 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 6808d0e16a85e5e569d9d7f89ace59c73196c1f4 +Subproject commit 2281e339fc4aa11d606345f109bd96d4fc6781f8 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2943521e0..4616ab96d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,9 +10,9 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol-connection = "3.0.0.Beta5-20241213.160944-20" -protocol-common = "3.0.0.Beta5-20241213.160944-20" -protocol-codec = "3.0.0.Beta5-20241213.160944-20" +protocol-connection = "3.0.0.Beta6-20250203.121006-1" +protocol-common = "3.0.0.Beta6-20250203.121006-1" +protocol-codec = "3.0.0.Beta6-20250203.121006-1" raknet = "1.0.0.CR3-20250128.101054-17" minecraftauth = "4.1.1" mcprotocollib = "1.21.4-20250121.131208-18" From 04586a453296de1dbf3b3f8c5241e0401a622d2c Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 11 Feb 2025 19:49:23 +0100 Subject: [PATCH 538/897] Update API version to 2.6.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index c380ec371..5557e53ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,5 +8,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.6.0-SNAPSHOT +version=2.6.1-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From bb6ff4ddb9324978dd076a2f928f5910a5b853b9 Mon Sep 17 00:00:00 2001 From: valaphee <32491319+valaphee@users.noreply.github.com> Date: Tue, 11 Feb 2025 23:47:51 +0100 Subject: [PATCH 539/897] Update boss event packet serializer in codec processor --- .../geyser/network/CodecProcessor.java | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) 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 b3f3af5ff..f2ed792c7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -29,7 +29,6 @@ import io.netty.buffer.ByteBuf; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; 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; @@ -42,6 +41,7 @@ import org.cloudburstmc.protocol.bedrock.codec.v662.serializer.SetEntityMotionSe import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.MobArmorEquipmentSerializer_v712; import org.cloudburstmc.protocol.bedrock.codec.v748.serializer.InventoryContentSerializer_v748; import org.cloudburstmc.protocol.bedrock.codec.v748.serializer.InventorySlotSerializer_v748; +import org.cloudburstmc.protocol.bedrock.codec.v776.serializer.BossEventSerializer_v776; import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.cloudburstmc.protocol.bedrock.packet.BossEventPacket; @@ -87,6 +87,8 @@ import org.cloudburstmc.protocol.common.util.VarInts; /** * Processes the Bedrock codec to remove or modify unused or unsafe packets and fields. + * + * TODO: Keep serializers up-to-date! */ @SuppressWarnings("deprecation") class CodecProcessor { @@ -157,7 +159,16 @@ class CodecProcessor { /** * Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client. */ - private static final BedrockPacketSerializer BOSS_EVENT_SERIALIZER = new BossEventSerializer_v486() { + private static final BedrockPacketSerializer BOSS_EVENT_SERIALIZER_486 = new BossEventSerializer_v486() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BossEventPacket packet) { + } + }; + + /** + * Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client. + */ + private static final BedrockPacketSerializer BOSS_EVENT_SERIALIZER_776 = new BossEventSerializer_v776() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, BossEventPacket packet) { } @@ -166,16 +177,7 @@ class CodecProcessor { /** * Serializer that does nothing when trying to deserialize MobArmorEquipmentPacket since it is not used from the client. */ - private static final BedrockPacketSerializer MOB_ARMOR_EQUIPMENT_SERIALIZER_V291 = new MobArmorEquipmentSerializer_v291() { - @Override - public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobArmorEquipmentPacket packet) { - } - }; - - /** - * Serializer that does nothing when trying to deserialize MobArmorEquipmentPacket since it is not used from the client. - */ - private static final BedrockPacketSerializer MOB_ARMOR_EQUIPMENT_SERIALIZER_V712 = new MobArmorEquipmentSerializer_v712() { + private static final BedrockPacketSerializer MOB_ARMOR_EQUIPMENT_SERIALIZER = new MobArmorEquipmentSerializer_v712() { @Override public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MobArmorEquipmentPacket packet) { } @@ -242,6 +244,13 @@ class CodecProcessor { @SuppressWarnings("unchecked") static BedrockCodec processCodec(BedrockCodec codec) { + BedrockPacketSerializer bossEventSerializer; + if (codec.getProtocolVersion() >= 776) { + bossEventSerializer = BOSS_EVENT_SERIALIZER_776; + } else { + bossEventSerializer = BOSS_EVENT_SERIALIZER_486; + } + BedrockCodec.Builder codecBuilder = codec.toBuilder() // Illegal unused serverbound EDU packets .updateSerializer(PhotoTransferPacket.class, ILLEGAL_SERIALIZER) @@ -276,8 +285,8 @@ class CodecProcessor { .updateSerializer(RiderJumpPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(PlayerInputPacket.class, ILLEGAL_SERIALIZER) // Ignored only when serverbound - .updateSerializer(BossEventPacket.class, BOSS_EVENT_SERIALIZER) - .updateSerializer(MobArmorEquipmentPacket.class, MOB_ARMOR_EQUIPMENT_SERIALIZER_V712) + .updateSerializer(BossEventPacket.class, bossEventSerializer) + .updateSerializer(MobArmorEquipmentPacket.class, MOB_ARMOR_EQUIPMENT_SERIALIZER) .updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER) .updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER) .updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER) From 6c59a821c97d91befd03e2868ccaedb061f87099 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 12 Feb 2025 14:57:26 +0100 Subject: [PATCH 540/897] Fix eating animations not showing --- .../CustomItemRegistryPopulator.java | 5 +++-- .../DataComponentRegistryPopulator.java | 3 +++ .../populator/ItemRegistryPopulator.java | 19 +++++++++--------- .../resources/bedrock/item_components.nbt | Bin 12649 -> 14202 bytes gradle/libs.versions.toml | 6 +++--- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index cd19ab147..d1cec3231 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -33,6 +33,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemVersion; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomRenderOffsets; @@ -106,7 +107,7 @@ public class CustomItemRegistryPopulator { public static GeyserCustomMappingData registerCustomItem(String customItemName, Item javaItem, GeyserMappingItem mapping, CustomItemData customItemData, int bedrockId, int protocolVersion) { NbtMapBuilder builder = createComponentNbt(customItemData, javaItem, mapping, customItemName, bedrockId, protocolVersion); - ItemDefinition itemDefinition = new SimpleItemDefinition(customItemName, bedrockId, 1, true, builder.build()); + ItemDefinition itemDefinition = new SimpleItemDefinition(customItemName, bedrockId, ItemVersion.DATA_DRIVEN, true, builder.build()); return new GeyserCustomMappingData(itemDefinition, customItemName, bedrockId); } @@ -143,7 +144,7 @@ public class CustomItemRegistryPopulator { customItemData.isHat(), customItemData.displayHandheld(), protocolVersion); ItemMapping customItemMapping = ItemMapping.builder() .bedrockIdentifier(customIdentifier) - .bedrockDefinition(new SimpleItemDefinition(customIdentifier, customItemId, 1, true, builder.build())) + .bedrockDefinition(new SimpleItemDefinition(customIdentifier, customItemId, ItemVersion.DATA_DRIVEN, true, builder.build())) .bedrockData(0) .bedrockBlockDefinition(null) .toolType(customItemData.toolType()) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java index 742564a39..829e8719e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java @@ -48,6 +48,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +/** + * Loads default item components for all Java items. + */ public final class DataComponentRegistryPopulator { public static void populate() { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 6e269b5a3..08f3226f9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -54,6 +54,7 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemGroup; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemVersion; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; @@ -212,15 +213,13 @@ public class ItemRegistryPopulator { nextFreeBedrockId = id + 1; } - NbtMap components = null; - if (entry.isComponentBased()) { - components = vanillaComponents.getCompound(entry.getName()); - if (components == null) { - throw new RuntimeException("Could not find vanilla components for vanilla component based item! " + entry.getName()); - } + // Some items, e.g. food, are not component based but still have components + NbtMap components = vanillaComponents.getCompound(entry.getName()); + if (components == null && entry.isComponentBased()) { + throw new RuntimeException("Could not find vanilla components for vanilla component based item! " + entry.getName()); } - ItemDefinition definition = new SimpleItemDefinition(entry.getName().intern(), id, entry.getVersion(), entry.isComponentBased(), components); + ItemDefinition definition = new SimpleItemDefinition(entry.getName().intern(), id, ItemVersion.from(entry.getVersion()), entry.isComponentBased(), components); definitions.put(entry.getName(), definition); registry.put(definition.getRuntimeId(), definition); } @@ -453,7 +452,7 @@ public class ItemRegistryPopulator { int customProtocolId = nextFreeBedrockId++; mappingItem = mappingItem.withBedrockData(customProtocolId); bedrockIdentifier = customBlockData.identifier(); - definition = new SimpleItemDefinition(bedrockIdentifier, customProtocolId, 1, false, null); + definition = new SimpleItemDefinition(bedrockIdentifier, customProtocolId, ItemVersion.DATA_DRIVEN, true, NbtMap.EMPTY); registry.put(customProtocolId, definition); customBlockItemDefinitions.put(customBlockData, definition); customIdMappings.put(customProtocolId, bedrockIdentifier); @@ -593,7 +592,7 @@ public class ItemRegistryPopulator { if (customItemsAllowed) { // Add furnace minecart int furnaceMinecartId = nextFreeBedrockId++; - ItemDefinition definition = new SimpleItemDefinition("geysermc:furnace_minecart", furnaceMinecartId, 1, true, registerFurnaceMinecart(furnaceMinecartId)); + ItemDefinition definition = new SimpleItemDefinition("geysermc:furnace_minecart", furnaceMinecartId, ItemVersion.DATA_DRIVEN, true, registerFurnaceMinecart(furnaceMinecartId)); definitions.put("geysermc:furnace_minecart", definition); registry.put(definition.getRuntimeId(), definition); componentItemData.add(definition); @@ -667,7 +666,7 @@ public class ItemRegistryPopulator { String identifier = customBlock.identifier(); // TODO verify - final ItemDefinition definition = new SimpleItemDefinition(identifier, customProtocolId, 1, false, null); + final ItemDefinition definition = new SimpleItemDefinition(identifier, customProtocolId, ItemVersion.DATA_DRIVEN, false, null); registry.put(customProtocolId, definition); customBlockItemDefinitions.put(customBlock, definition); customIdMappings.put(customProtocolId, identifier); diff --git a/core/src/main/resources/bedrock/item_components.nbt b/core/src/main/resources/bedrock/item_components.nbt index 34d2ac7f0ca1bf5fafda5891c7666b562aa6922f..b34ebf881463170f79c3bde3343aa0761bc4d1e7 100644 GIT binary patch literal 14202 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 Xkr#9y(Pfc{?&ALgn8T(o6b}Ia*2(6l diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4616ab96d..1d993bf60 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,9 +10,9 @@ netty-io-uring = "0.0.25.Final-SNAPSHOT" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol-connection = "3.0.0.Beta6-20250203.121006-1" -protocol-common = "3.0.0.Beta6-20250203.121006-1" -protocol-codec = "3.0.0.Beta6-20250203.121006-1" +protocol-connection = "3.0.0.Beta6-20250212.131009-3" +protocol-common = "3.0.0.Beta6-20250212.131009-3" +protocol-codec = "3.0.0.Beta6-20250212.131009-3" raknet = "1.0.0.CR3-20250128.101054-17" minecraftauth = "4.1.1" mcprotocollib = "1.21.4-20250121.131208-18" From 4d36524d05aec6637eeb5d20a6246e6ca7500cf8 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 12 Feb 2025 15:21:47 +0100 Subject: [PATCH 541/897] Fix https://github.com/GeyserMC/Geyser/issues/5280, update supported Bedrock version in the README.md The "tracking" property seems to only be used server-side, so we should not rely on it client-side --- README.md | 2 +- .../geysermc/geyser/session/cache/LodestoneCache.java | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9f5c9d8d5..57aaaf6fe 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.21.40 - 1.21.50 and Minecraft Java 1.21.4. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.21.40 - 1.21.60 and Minecraft Java 1.21.4. 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/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java index ee8ebb13f..98aace480 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java @@ -53,13 +53,8 @@ public final class LodestoneCache { private int id = 1; public void cacheInventoryItem(GeyserItemStack itemStack, LodestoneTracker tracker) { - if (!tracker.isTracked()) { - return; - } - GlobalPos position = tracker.getPos(); if (position == null) { - // As of 1.20.6, position can still be null even if tracking is enabled. return; } int x = position.getX(); @@ -86,13 +81,9 @@ public final class LodestoneCache { } public int store(LodestoneTracker tracker) { - if (!tracker.isTracked()) { - // No coordinates; nothing to convert - return 0; - } - GlobalPos position = tracker.getPos(); if (position == null) { + // No coordinates; nothing to convert return 0; } From b0bf867581a45ca6c337120bab18702c3b9886b9 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Wed, 12 Feb 2025 15:32:55 +0000 Subject: [PATCH 542/897] Add basic support for the 1.21.2 minecart experiment (#5134) * Add simple translator for move minecart packet * Cleanup code * This could be cleaned up even more * Implement minecart lerping * Use ClientboundUpdateEnabledFeaturesPacket to set experimental minecart behavior * Move experiment checking to a per-session check --------- Co-authored-by: onebeastchris --- .../geyser/entity/type/MinecartEntity.java | 162 +++++++++++++++++- .../geyser/session/GeyserSession.java | 6 + .../java/JavaUpdateEnabledFeaturesPacket.java | 45 +++++ .../entity/JavaMoveMinecartTranslator.java | 47 +++++ 4 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateEnabledFeaturesPacket.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveMinecartTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java index 9096d8bd6..6faecb389 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java @@ -25,20 +25,40 @@ package org.geysermc.geyser.entity.type; +import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.MinecartStep; 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.clientbound.entity.ClientboundMoveMinecartPacket; +import java.util.LinkedList; +import java.util.List; import java.util.UUID; -public class MinecartEntity extends Entity { +public class MinecartEntity extends Entity implements Tickable { + private static final int POS_ROT_LERP_TICKS = 3; + + private final List lerpSteps = new LinkedList<>(); + private final List currentLerpSteps = new LinkedList<>(); + + private MinecartStep lastCompletedStep = new MinecartStep(Vector3d.ZERO, Vector3d. ZERO, 0.0F, 0.0F, 0.0F); + private float currentStepsTotalWeight = 0.0F; + private int lerpDelay = 0; + + private PartialStep cachedPartialStep; + private int cachedStepDelay; + private float cachedDelta; public MinecartEntity(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.add(0d, definition.offset(), 0d), motion, yaw, pitch, headYaw); @@ -58,6 +78,131 @@ public class MinecartEntity extends Entity { dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0)); } + @Override + public void tick() { + if (!session.isUsingExperimentalMinecartLogic()) { + return; + } + + // All minecart lerp code here and in the methods below has been based off of the code in the Java NewMinecartBehavior class + lerpDelay--; + if (lerpDelay <= 0) { + updateCompletedStep(); + currentLerpSteps.clear(); + if (!lerpSteps.isEmpty()) { + currentLerpSteps.addAll(lerpSteps); + lerpSteps.clear(); + currentStepsTotalWeight = 0.0F; + + for (MinecartStep step : currentLerpSteps) { + currentStepsTotalWeight += step.weight(); + } + + lerpDelay = currentStepsTotalWeight == 0.0F ? 0 : POS_ROT_LERP_TICKS; + } + } + + if (isLerping()) { + float delta = 1.0F; // This is always 1, maybe it should be removed + + Vector3f position = getCurrentLerpPosition(delta).toFloat(); + Vector3f movement = getCurrentLerpMovement(delta).toFloat(); + setPosition(position); + setMotion(movement); + + setYaw(180.0F - getCurrentLerpYaw(delta)); + setPitch(getCurrentLerpPitch(delta)); + + MoveEntityDeltaPacket moveEntityPacket = new MoveEntityDeltaPacket(); + moveEntityPacket.setRuntimeEntityId(geyserId); + + moveEntityPacket.setX(position.getX()); + moveEntityPacket.setY(position.getY() + definition.offset()); + moveEntityPacket.setZ(position.getZ()); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_X); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Y); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Z); + + moveEntityPacket.setYaw(getYaw()); + moveEntityPacket.setPitch(getPitch()); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_YAW); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_PITCH); + + SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket(); + entityMotionPacket.setRuntimeEntityId(geyserId); + entityMotionPacket.setMotion(movement); + + session.sendUpstreamPacket(moveEntityPacket); + session.sendUpstreamPacket(entityMotionPacket); + } + } + + public void handleMinecartMovePacket(ClientboundMoveMinecartPacket packet) { + lerpSteps.addAll(packet.getLerpSteps()); + } + + private boolean isLerping() { + return !currentLerpSteps.isEmpty(); + } + + private float getCurrentLerpPitch(float delta) { + PartialStep partialStep = getCurrentLerpStep(delta); + return lerpRotation(partialStep.delta, partialStep.previousStep.xRot(), partialStep.currentStep.xRot()); + } + + private float getCurrentLerpYaw(float delta) { + PartialStep partialStep = getCurrentLerpStep(delta); + return lerpRotation(partialStep.delta, partialStep.previousStep.yRot(), partialStep.currentStep.yRot()); + } + + private Vector3d getCurrentLerpPosition(float delta) { + PartialStep partialStep = getCurrentLerpStep(delta); + return lerp(partialStep.delta, partialStep.previousStep.position(), partialStep.currentStep.position()); + } + + private Vector3d getCurrentLerpMovement(float delta) { + PartialStep partialStep = getCurrentLerpStep(delta); + return lerp(partialStep.delta, partialStep.previousStep.movement(), partialStep.currentStep.movement()); + } + + private PartialStep getCurrentLerpStep(float delta) { + if (cachedDelta != delta || lerpDelay != cachedStepDelay || cachedPartialStep == null) { + float g = ((POS_ROT_LERP_TICKS - lerpDelay) + delta) / POS_ROT_LERP_TICKS; + float totalWeight = 0.0F; + float stepDelta = 1.0F; + boolean foundStep = false; + + int step; + for (step = 0; step < currentLerpSteps.size(); step++) { + float currentWeight = currentLerpSteps.get(step).weight(); + if (!(currentWeight <= 0.0F)) { + totalWeight += currentWeight; + if ((double) totalWeight >= currentStepsTotalWeight * (double) g) { + float h = totalWeight - currentWeight; + stepDelta = (g * currentStepsTotalWeight - h) / currentWeight; + foundStep = true; + break; + } + } + } + + if (!foundStep) { + step = currentLerpSteps.size() - 1; + } + + MinecartStep currentStep = currentLerpSteps.get(step); + MinecartStep previousStep = step > 0 ? currentLerpSteps.get(step - 1) : lastCompletedStep; + cachedPartialStep = new PartialStep(stepDelta, currentStep, previousStep); + cachedStepDelay = lerpDelay; + cachedDelta = delta; + } + return cachedPartialStep; + } + + private void updateCompletedStep() { + lastCompletedStep = new MinecartStep(position.toDouble(), motion.toDouble(), yaw, pitch, 0.0F); + } + @Override public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) { super.moveAbsolute(position.add(0d, this.definition.offset(), 0d), yaw, pitch, headYaw, isOnGround, teleported); @@ -103,4 +248,19 @@ public class MinecartEntity extends Entity { } } } + + private static Vector3d lerp(double delta, Vector3d start, Vector3d end) { + return Vector3d.from(lerp(delta, start.getX(), end.getX()), lerp(delta, start.getY(), end.getY()), lerp(delta, start.getZ(), end.getZ())); + } + + public static double lerp(double delta, double start, double end) { + return start + delta * (end - start); + } + + private static float lerpRotation(float delta, float start, float end) { + return start + delta * MathUtils.wrapDegrees(end - start); + } + + private record PartialStep(float delta, MinecartStep currentStep, MinecartStep previousStep) { + } } 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 14a7f42a9..f9802fe52 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -477,6 +477,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private boolean oldSmithingTable = false; + /** + * Whether to use the minecart_improvements experiment + */ + @Setter + private boolean isUsingExperimentalMinecartLogic = false; + /** * The current attack speed of the player. Used for sending proper cooldown timings. * Setting a default fixes cooldowns not showing up on a fresh world. diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateEnabledFeaturesPacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateEnabledFeaturesPacket.java new file mode 100644 index 000000000..15ea7c684 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateEnabledFeaturesPacket.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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 net.kyori.adventure.key.Key; +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.configuration.clientbound.ClientboundUpdateEnabledFeaturesPacket; + +import java.util.Arrays; + +@Translator(packet = ClientboundUpdateEnabledFeaturesPacket.class) +public class JavaUpdateEnabledFeaturesPacket extends PacketTranslator { + + private final static Key MINECART_EXPERIMENT = Key.key("minecart_improvements"); + + @Override + public void translate(GeyserSession session, ClientboundUpdateEnabledFeaturesPacket packet) { + session.setUsingExperimentalMinecartLogic(Arrays.asList(packet.getFeatures()).contains(MINECART_EXPERIMENT)); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveMinecartTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveMinecartTranslator.java new file mode 100644 index 000000000..dc004ffba --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaMoveMinecartTranslator.java @@ -0,0 +1,47 @@ +/* + * 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.entity; + +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.entity.type.MinecartEntity; +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.ClientboundMoveMinecartPacket; + +@Translator(packet = ClientboundMoveMinecartPacket.class) +public class JavaMoveMinecartTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundMoveMinecartPacket packet) { + if (!packet.getLerpSteps().isEmpty()) { + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); + if (entity instanceof MinecartEntity minecart) { + minecart.handleMinecartMovePacket(packet); + } + } + } +} From d5b5712e60107175ccaed7fab21deca09c0f15cf Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 12 Feb 2025 20:40:05 +0100 Subject: [PATCH 543/897] Fix custom skulls (#5338) --- .../geyser/item/components/Rarity.java | 4 +-- .../org/geysermc/geyser/item/type/Item.java | 5 --- .../geyser/item/type/PlayerHeadItem.java | 36 +++++++++---------- .../populator/ItemRegistryPopulator.java | 7 ++-- .../geyser/session/cache/SkullCache.java | 2 -- .../translator/item/ItemTranslator.java | 3 +- 6 files changed, 23 insertions(+), 34 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java b/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java index 6fa74ea35..437fc5391 100644 --- a/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java +++ b/core/src/main/java/org/geysermc/geyser/item/components/Rarity.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.components; import lombok.Getter; +import org.checkerframework.checker.nullness.qual.NonNull; @Getter public enum Rarity { @@ -44,8 +45,7 @@ public enum Rarity { private static final Rarity[] VALUES = values(); - public static Rarity fromId(int id) { + public static @NonNull Rarity fromId(Integer id) { return VALUES.length > id ? VALUES[id] : VALUES[0]; } - } 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 738d57788..056e8b48a 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 @@ -37,7 +37,6 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.Registries; @@ -95,10 +94,6 @@ public class Item { return baseComponents.getOrDefault(DataComponentType.MAX_STACK_SIZE, 1); } - public Rarity defaultRarity() { - return Rarity.fromId(baseComponents.getOrDefault(DataComponentType.RARITY, 0)); - } - /** * Returns an unmodifiable {@link DataComponents} view containing known data components. * Optionally, additional components can be provided to replace (or add to) diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index d4999c80d..003aa0a73 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -25,13 +25,14 @@ package org.geysermc.geyser.item.type; -import org.geysermc.mcprotocollib.auth.GameProfile; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -44,24 +45,21 @@ public class PlayerHeadItem extends BlockItem { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - // TODO verify - // Also - ChatColor.YELLOW + ChatColor.ITALIC + MessageTranslator.convertMessageLenient(nameTag.getValue(), session.locale())) this code existed if a custom name was already present. - // But I think we would always overwrite that because translateDisplayProperties runs after this method. - String customName = builder.getCustomName(); - if (customName == null) { - GameProfile profile = components.get(DataComponentType.PROFILE); - if (profile != null) { - String name = profile.getName(); - if (name != null) { - // Add correct name of player skull - String displayName = ChatColor.RESET + ChatColor.YELLOW + - MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.locale()).replace("%s", name); - builder.setCustomName(displayName); - } else { - // No name found so default to "Player Head" - builder.setCustomName(ChatColor.RESET + ChatColor.YELLOW + - MinecraftLocale.getLocaleString("block.minecraft.player_head", session.locale())); - } + // Use the correct color, determined by the rarity of the item + char rarity = Rarity.fromId(components.get(DataComponentType.RARITY)).getColor(); + + GameProfile profile = components.get(DataComponentType.PROFILE); + if (profile != null) { + String name = profile.getName(); + if (name != null) { + // Add correct name of player skull + String displayName = ChatColor.RESET + ChatColor.ESCAPE + rarity + + MinecraftLocale.getLocaleString("block.minecraft.player_head.named", session.locale()).replace("%s", name); + builder.setCustomName(displayName); + } else { + // No name found so default to "Player Head" + builder.setCustomName(ChatColor.RESET + ChatColor.ESCAPE + rarity + + MinecraftLocale.getLocaleString("block.minecraft.player_head", session.locale())); } } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 08f3226f9..c0c006549 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -67,7 +67,6 @@ import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.property.Properties; @@ -491,9 +490,8 @@ public class ItemRegistryPopulator { mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType().intern()); } - if (javaOnlyItems.contains(javaItem) || javaItem.defaultRarity() != Rarity.COMMON) { + if (javaOnlyItems.contains(javaItem)) { // These items don't exist on Bedrock, so set up a variable that indicates they should have custom names - // Or, ensure that we are translating these at all times to account for rarity colouring mappingBuilder = mappingBuilder.translationString((javaItem instanceof BlockItem ? "block." : "item.") + entry.getKey().replace(":", ".")); GeyserImpl.getInstance().getLogger().debug("Adding " + entry.getKey() + " as an item that needs to be translated."); } @@ -665,8 +663,7 @@ public class ItemRegistryPopulator { int customProtocolId = nextFreeBedrockId++; String identifier = customBlock.identifier(); - // TODO verify - final ItemDefinition definition = new SimpleItemDefinition(identifier, customProtocolId, ItemVersion.DATA_DRIVEN, false, null); + final ItemDefinition definition = new SimpleItemDefinition(identifier, customProtocolId, ItemVersion.NONE, false, null); registry.put(customProtocolId, definition); customBlockItemDefinitions.put(customBlock, definition); customIdMappings.put(customProtocolId, identifier); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java index a3cf1247f..08f73a381 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java @@ -64,8 +64,6 @@ public class SkullCache { private Vector3f lastPlayerPosition; - private long lastCleanup = System.currentTimeMillis(); - public SkullCache(GeyserSession session) { this.session = session; this.maxVisibleSkulls = session.getGeyser().getConfig().getMaxVisibleCustomSkulls(); 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 3f9bf7446..a41c4ee84 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 @@ -174,7 +174,7 @@ public final class ItemTranslator { // Translate item-specific components javaItem.translateComponentsToBedrock(session, components, nbtBuilder); - Rarity rarity = Rarity.fromId(components.getOrDefault(DataComponentType.RARITY, 0)); + Rarity rarity = Rarity.fromId(components.get(DataComponentType.RARITY)); String customName = getCustomName(session, customComponents, bedrockItem, rarity.getColor(), false, false); if (customName != null) { PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); @@ -611,6 +611,7 @@ public final class ItemTranslator { } if (textures == null || textures.isEmpty()) { + // TODO the java client looks up the texture properties here and updates the item return null; } From 3e6172642d4e894c4b76414ddd6228ee5497fe97 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 16 Feb 2025 16:58:44 +0100 Subject: [PATCH 544/897] Update MCPL, resolves issues with the ClientboundPlayerInfoUpdatePacket --- .../java/org/geysermc/geyser/session/GeyserSessionAdapter.java | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java index 9e17e9cd3..812456644 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java @@ -232,7 +232,7 @@ public class GeyserSessionAdapter extends SessionAdapter { @Override public void packetError(PacketErrorEvent event) { geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.downstream_error", - (event.getPacketClass() != null ? "(" + event.getPacketClass().getSimpleName() + ")" : "") + + (event.getPacketClass() != null ? "(" + event.getPacketClass().getSimpleName() + ") " : "") + event.getCause().getMessage()) ); if (geyser.getConfig().isDebugMode()) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1d993bf60..c4fc04bf7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta6-20250212.131009-3" protocol-codec = "3.0.0.Beta6-20250212.131009-3" raknet = "1.0.0.CR3-20250128.101054-17" minecraftauth = "4.1.1" -mcprotocollib = "1.21.4-20250121.131208-18" +mcprotocollib = "1.21.4-20250216.154737-20" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From ecc10d656093d03720b708498741b29729d324e8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 16 Feb 2025 15:18:55 -0500 Subject: [PATCH 545/897] Update direct connection/compression disabler for newest BungeeCord Fixes #5348 --- .../GeyserBungeeCompressionDisabler.java | 6 ++++-- .../platform/bungeecord/GeyserBungeeInjector.java | 10 +++++++++- .../bungeecord/GeyserBungeePingPassthrough.java | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeCompressionDisabler.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeCompressionDisabler.java index 485079a05..23ab36363 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeCompressionDisabler.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeCompressionDisabler.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.platform.bungeecord; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; +import net.md_5.bungee.netty.LengthPrependerAndCompressor; import net.md_5.bungee.protocol.packet.LoginSuccess; import net.md_5.bungee.protocol.packet.SetCompression; @@ -40,8 +41,9 @@ public class GeyserBungeeCompressionDisabler extends ChannelOutboundHandlerAdapt // Fixes https://github.com/GeyserMC/Geyser/issues/4281 // The server may send a LoginDisconnect packet after compression is set. if (!compressionDisabled) { - if (ctx.pipeline().get("compress") != null) { - ctx.pipeline().remove("compress"); + LengthPrependerAndCompressor compressor = ctx.pipeline().get(LengthPrependerAndCompressor.class); + if (compressor.isCompress()) { + compressor.setCompress(false); compressionDisabled = true; } if (ctx.pipeline().get("decompress") != null) { diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeInjector.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeInjector.java index 7c60ba95d..459bde3af 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeInjector.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeInjector.java @@ -73,6 +73,14 @@ public class GeyserBungeeInjector extends GeyserInjector implements Listener { throw new UnsupportedOperationException("Geyser does not currently support multiple listeners with injection! " + "Please reach out to us on our Discord at https://discord.gg/GeyserMC so we can hear feedback on your setup."); } + + // TODO remove + try { + ProxyServer.class.getMethod("unsafe"); + } catch (NoSuchMethodException e) { + throw new UnsupportedOperationException("You're using an outdated version of BungeeCord - please update. Thank you!"); + } + ListenerInfo listenerInfo = proxy.getConfig().getListeners().stream().findFirst().orElseThrow(IllegalStateException::new); Class proxyClass = proxy.getClass(); @@ -138,7 +146,7 @@ public class GeyserBungeeInjector extends GeyserInjector implements Listener { if (channelInitializer == null) { // Proxy has finished initializing; we can safely grab this variable without fear of plugins modifying it // (Older versions of ViaVersion replace this to inject) - channelInitializer = PipelineUtils.SERVER_CHILD; + channelInitializer = proxy.unsafe().getFrontendChannelInitializer().getChannelInitializer(); } initChannel.invoke(channelInitializer, ch); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java index 1193a52b3..472c5f10a 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java @@ -186,6 +186,21 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List return false; } + @Override + public boolean isTransferred() { + return false; + } + + @Override + public CompletableFuture retrieveCookie(String s) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture sendData(String s, byte[] bytes) { + throw new UnsupportedOperationException(); + } + @Override public Unsafe unsafe() { throw new UnsupportedOperationException(); From 778c0819ef76abb51eab191d0e6250c2a2e2618e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 16 Feb 2025 15:35:07 -0500 Subject: [PATCH 546/897] Add the Gradle versions file, too... --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c4fc04bf7..f9bfd758e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ cloud = "2.0.0-rc.2" cloud-minecraft = "2.0.0-beta.9" cloud-minecraft-modded = "2.0.0-beta.10" commodore = "2.2" -bungeecord = "a7c6ede" +bungeecord = "1.21-R0.1-20250215.224541-54" velocity = "3.3.0-SNAPSHOT" viaproxy = "3.3.2-SNAPSHOT" fabric-loader = "0.16.9" @@ -116,7 +116,7 @@ neoforge-minecraft = { group = "net.neoforged", name = "neoforge", version.ref = adapters-spigot = { group = "org.geysermc.geyser.adapters", name = "spigot-all", version.ref = "adapters" } adapters-paper = { group = "org.geysermc.geyser.adapters", name = "paper-all", version.ref = "adapters" } -bungeecord-proxy = { group = "com.github.SpigotMC.BungeeCord", name = "bungeecord-proxy", version.ref = "bungeecord" } +bungeecord-proxy = { group = "net.md-5", name = "bungeecord-proxy", version.ref = "bungeecord" } checker-qual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerframework" } commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" } guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } From 7448a994ad2b4edc2bd4617035cd277834575f83 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 18 Feb 2025 15:12:38 +0100 Subject: [PATCH 547/897] Fix: Server-side requested container closing (#5346) * Work on closing inventories * Test more container types, add very hacky player container close workaround * Only send close container packet to Java edition when needed * Adjust warning to hopefully find where desync issues occur * don't crash when closing lecterns * remove debug logging * Don't send container close packet to the Java server when not needed, mainly for fake lecterns --- .../geysermc/geyser/inventory/Container.java | 4 +- .../geysermc/geyser/inventory/Inventory.java | 8 +++ .../geyser/inventory/LecternContainer.java | 11 ++-- .../holder/BlockInventoryHolder.java | 52 ++++++++++++------- .../inventory/holder/InventoryHolder.java | 3 +- .../populator/BlockRegistryPopulator.java | 10 ++++ .../geyser/registry/type/BlockMappings.java | 3 +- .../geyser/session/GeyserSession.java | 8 +++ .../AbstractBlockInventoryTranslator.java | 10 +++- .../inventory/AnvilInventoryTranslator.java | 6 +++ .../inventory/BeaconInventoryTranslator.java | 5 ++ .../inventory/BrewingInventoryTranslator.java | 6 +++ .../CartographyInventoryTranslator.java | 6 +++ .../inventory/CrafterInventoryTranslator.java | 5 ++ .../CraftingInventoryTranslator.java | 6 +++ .../EnchantingInventoryTranslator.java | 6 +++ .../Generic3X3InventoryTranslator.java | 6 +++ .../GrindstoneInventoryTranslator.java | 6 +++ .../inventory/HopperInventoryTranslator.java | 7 +++ .../inventory/LecternInventoryTranslator.java | 11 ++-- .../inventory/LoomInventoryTranslator.java | 6 +++ .../inventory/OldSmithingTableTranslator.java | 6 +++ .../inventory/PlayerInventoryTranslator.java | 30 ++++++++--- .../inventory/ShulkerInventoryTranslator.java | 6 +++ .../SmithingInventoryTranslator.java | 6 +++ .../StonecutterInventoryTranslator.java | 6 +++ .../chest/DoubleChestInventoryTranslator.java | 18 ++++++- .../chest/SingleChestInventoryTranslator.java | 2 +- .../BlastFurnaceInventoryTranslator.java | 7 +++ .../furnace/FurnaceInventoryTranslator.java | 7 +++ .../furnace/SmokerInventoryTranslator.java | 7 +++ .../AbstractHorseInventoryTranslator.java | 2 + .../BedrockContainerCloseTranslator.java | 4 +- .../BedrockLecternUpdateTranslator.java | 4 +- .../JavaContainerCloseTranslator.java | 1 + .../inventory/JavaOpenBookTranslator.java | 4 +- .../geysermc/geyser/util/InventoryUtils.java | 10 +++- 37 files changed, 255 insertions(+), 50 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Container.java index e78a4d2c6..f2db415c0 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Container.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Container.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.inventory; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.jetbrains.annotations.Range; /** diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index c960ed1a2..4639e0151 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -171,4 +171,12 @@ public abstract class Inventory { public void resetNextStateId() { nextStateId = -1; } + + /** + * Whether we should be sending a {@link org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket} + * when closing the inventory. + */ + public boolean shouldConfirmContainerClose() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java index ff21f561e..9988188f1 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java @@ -43,7 +43,7 @@ public class LecternContainer extends Container { @Setter private Vector3i position; - private boolean isFakeLectern = false; + private boolean isBookInPlayerInventory = false; public LecternContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) { super(title, id, size, containerType, playerInventory); @@ -55,7 +55,7 @@ public class LecternContainer extends Container { */ @Override public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { - if (isFakeLectern) { + if (isBookInPlayerInventory) { session.getPlayerInventory().setItem(slot, newItem, session); } else { super.setItem(slot, newItem, session); @@ -67,7 +67,12 @@ public class LecternContainer extends Container { * See {@link LecternContainer#setItem(int, GeyserItemStack, GeyserSession)} as for why this is separate. */ public void setFakeLecternBook(GeyserItemStack book, GeyserSession session) { - this.isFakeLectern = true; + this.isBookInPlayerInventory = true; super.setItem(0, book, session); } + + @Override + public boolean shouldConfirmContainerClose() { + return !isBookInPlayerInventory; + } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index 385a1e2bd..1bf30bc7e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -155,32 +155,46 @@ public class BlockInventoryHolder extends InventoryHolder { } @Override - public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { - if (inventory instanceof Container container) { - if (container.isUsingRealBlock() && !(container instanceof LecternContainer)) { - // No need to reset a block since we didn't change any blocks - // But send a container close packet because we aren't destroying the original. - ContainerClosePacket packet = new ContainerClosePacket(); - packet.setId((byte) inventory.getBedrockId()); - packet.setServerInitiated(true); - packet.setType(ContainerType.CONTAINER); - session.sendUpstreamPacket(packet); - return; - } - } else { - GeyserImpl.getInstance().getLogger().warning("Tried to close a non-container inventory in a block inventory holder! "); - if (GeyserImpl.getInstance().getLogger().isDebug()) { - GeyserImpl.getInstance().getLogger().debug("Current inventory: " + inventory); - GeyserImpl.getInstance().getLogger().debug("Open inventory: " + session.getOpenInventory()); - } + public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory, ContainerType type) { + if (!(inventory instanceof Container container)) { + GeyserImpl.getInstance().getLogger().warning("Tried to close a non-container inventory in a block inventory holder! Please report this error on discord."); + GeyserImpl.getInstance().getLogger().warning("Current inventory translator: " + translator.getClass().getSimpleName()); + GeyserImpl.getInstance().getLogger().warning("Current inventory: " + inventory.getClass().getSimpleName()); // Try to save ourselves? maybe? // https://github.com/GeyserMC/Geyser/issues/4141 - // TODO: improve once this issue is pinned down properly + // TODO: improve once this issue is pinned down session.setOpenInventory(null); session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR); return; } + // Bedrock broke inventory closing. I wish i was kidding. + // "type" is explicitly passed to keep track of which inventory types can be closed without + // ""workarounds"". yippie. + // Further, Lecterns cannot be closed with any of the two methods below. + if (container.isUsingRealBlock() && !(container instanceof LecternContainer)) { + if (type != null) { + // No need to reset a block since we didn't change any blocks + // But send a container close packet because we aren't destroying the original. + ContainerClosePacket packet = new ContainerClosePacket(); + packet.setId((byte) inventory.getBedrockId()); + packet.setServerInitiated(true); + packet.setType(type); + session.sendUpstreamPacket(packet); + return; + } + + // Destroy the block. There's no inventory to view => it gets closed! + Vector3i holderPos = inventory.getHolderPosition(); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setDataLayer(0); + blockPacket.setBlockPosition(holderPos); + blockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); + blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); + session.sendUpstreamPacket(blockPacket); + } + + // Reset to correct block Vector3i holderPos = inventory.getHolderPosition(); int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos.getX(), holderPos.getY(), holderPos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java index 986df53db..d61193c7a 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.inventory.holder; +import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; @@ -32,5 +33,5 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator; public abstract class InventoryHolder { public abstract boolean prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); public abstract void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); - public abstract void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); + public abstract void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory, ContainerType containerType); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 29591ce9e..59cdd52c4 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -245,6 +245,7 @@ public final class BlockRegistryPopulator { GeyserBedrockBlock airDefinition = null; BlockDefinition commandBlockDefinition = null; BlockDefinition mobSpawnerBlockDefinition = null; + BlockDefinition netherPortalBlockDefinition = null; BlockDefinition waterDefinition = null; BlockDefinition movingBlockDefinition = null; Iterator blocksIterator = BLOCKS_NBT.iterator(); @@ -330,6 +331,10 @@ public final class BlockRegistryPopulator { structureBlockDefinitions.put(mode.toUpperCase(Locale.ROOT), bedrockDefinition); } + if (block == Blocks.NETHER_PORTAL) { + netherPortalBlockDefinition = bedrockDefinition; + } + boolean waterlogged = blockState.getValue(Properties.WATERLOGGED, false) || block == Blocks.BUBBLE_COLUMN || block == Blocks.KELP || block == Blocks.KELP_PLANT || block == Blocks.SEAGRASS || block == Blocks.TALL_SEAGRASS; @@ -358,6 +363,11 @@ public final class BlockRegistryPopulator { } builder.mobSpawnerBlock(mobSpawnerBlockDefinition); + if (netherPortalBlockDefinition == null) { + throw new AssertionError("Unable to find nether portal block in palette"); + } + builder.netherPortalBlock(netherPortalBlockDefinition); + if (waterDefinition == null) { throw new AssertionError("Unable to find water in palette"); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index be96fec0e..c783aee56 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -64,6 +64,7 @@ public class BlockMappings implements DefinitionRegistry { BlockDefinition commandBlock; BlockDefinition mobSpawnerBlock; + BlockDefinition netherPortalBlock; Map itemFrames; Map flowerPotBlocks; @@ -137,4 +138,4 @@ public class BlockMappings implements DefinitionRegistry { public boolean isRegistered(BlockDefinition bedrockBlock) { return getDefinition(bedrockBlock.getRuntimeId()) == bedrockBlock; } -} \ No newline at end of file +} 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 f9802fe52..4a2863b9e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -526,6 +526,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private boolean placedBucket; + /** + * Stores whether the Java server requested the player inventory to be closed. + * Used to prevent our hacky player inventory closing workaround in {@link org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator#closeInventory(GeyserSession, Inventory)} + * to run when the closing is initated by the Bedrock client. + */ + @Setter + private boolean serverRequestedClosePlayerInventory; + /** * 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. diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java index 4476391c8..0cd60987d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; @@ -86,7 +87,7 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran @Override public void closeInventory(GeyserSession session, Inventory inventory) { - holder.closeInventory(this, session, inventory); + holder.closeInventory(this, session, inventory, closeContainerType(inventory)); } @Override @@ -98,4 +99,11 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran public void updateSlot(GeyserSession session, Inventory inventory, int slot) { updater.updateSlot(this, session, inventory, slot); } + + /* + So. Sometime in 1.21, Bedrock just broke the ContainerClosePacket. As in: Geyser sends it, the player ignores it. + But only for some blocks! And some blocks only respond to specific container types (dispensers/droppers now require the specific type...) + When this returns null, we just... break the block, and replace it. Primitive. But if that works... fine. + */ + public abstract @Nullable ContainerType closeContainerType(Inventory inventory); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java index cbc8ce7bd..f43d1301b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; @@ -115,4 +116,9 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { anvilContainer.setUseJavaLevelCost(true); updateSlot(session, anvilContainer, 1); } + + @Override + public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java index 6edbd925e..2b731000d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java @@ -147,4 +147,9 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator public Inventory createInventory(String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) { return new BeaconContainer(name, windowId, this.size, containerType, playerInventory); } + + @Override + public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java index 5147fb75d..d3b5299eb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; @@ -106,4 +107,9 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator default -> super.javaSlotToBedrockContainer(slot); }; } + + @Override + public @Nullable ContainerType closeContainerType(Inventory inventory) { + return ContainerType.BREWING_STAND; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java index 65fc7b35c..2cb4d0f14 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.geysermc.geyser.inventory.*; @@ -88,4 +89,9 @@ public class CartographyInventoryTranslator extends AbstractBlockInventoryTransl public Inventory createInventory(String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) { return new CartographyContainer(name, windowId, this.size, containerType, playerInventory); } + + @Override + public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java index 83076640a..390c0d6e6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CrafterInventoryTranslator.java @@ -162,4 +162,9 @@ public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator BlockEntityUtils.updateBlockEntity(session, tag.build(), container.getHolderPosition()); } + + @Override + public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java index 577d87fe5..6c9dad5f3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java @@ -29,6 +29,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.level.block.Blocks; @@ -86,4 +87,9 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato public static boolean isCraftingGrid(int slot) { return slot >= 1 && slot <= 9; } + + @Override + public ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java index eb0e351e1..10386c23e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.translator.inventory; import it.unimi.dsi.fastutil.ints.IntSets; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; @@ -170,4 +171,9 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla public Inventory createInventory(String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) { return new EnchantingContainer(name, windowId, this.size, containerType, playerInventory); } + + @Override + public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java index 80040e375..0f90240d1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java @@ -68,4 +68,10 @@ public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTransla } return super.javaSlotToBedrockContainer(javaSlot); } + + @Override + public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(Inventory inventory) { + return ((Generic3X3Container) inventory).isDropper() ? org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DROPPER : + org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java index d3283de40..2c4430ac3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java @@ -29,6 +29,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.level.block.Blocks; @@ -66,4 +67,9 @@ public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTransla default -> super.javaSlotToBedrock(slot); }; } + + @Override + public ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java index fdcd7bf57..37cb4a813 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java @@ -25,9 +25,11 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.level.block.Blocks; @@ -46,4 +48,9 @@ public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator } return super.javaSlotToBedrockContainer(javaSlot); } + + @Override + public @Nullable ContainerType closeContainerType(Inventory inventory) { + return ContainerType.HOPPER; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 414ab655a..c5814e336 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -62,7 +63,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator @Override public boolean prepareInventory(GeyserSession session, Inventory inventory) { super.prepareInventory(session, inventory); - if (((LecternContainer) inventory).isFakeLectern()) { + if (((LecternContainer) inventory).isBookInPlayerInventory()) { // See JavaOpenBookTranslator; this isn't a lectern but a book in the player inventory updateBook(session, inventory, inventory.getItem(0)); receivedBook = true; @@ -98,7 +99,6 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator // Now: Restore the lectern, if it actually exists if (lecternContainer.isUsingRealBlock()) { boolean hasBook = session.getGeyser().getWorldManager().blockAt(session, position).getValue(Properties.HAS_BOOK, false); - NbtMap map = LecternBlock.getBaseLecternTag(position, hasBook); BlockEntityUtils.updateBlockEntity(session, map, position); } @@ -131,7 +131,7 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator @Override public void updateSlot(GeyserSession session, Inventory inventory, int slot) { // If we're not in a real lectern, the Java server thinks we are still in the player inventory. - if (((LecternContainer) inventory).isFakeLectern()) { + if (((LecternContainer) inventory).isBookInPlayerInventory()) { InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), slot); return; } @@ -141,6 +141,11 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator } } + @Override + public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) { + return null; + } + /** * Translate the data of the book in the lectern into a block entity tag. */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 998108154..9fb407336 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.inventory; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; @@ -207,4 +208,9 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { } return super.getSlotType(javaSlot); } + + @Override + public @Nullable ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java index fc9c4f587..1ee8b18eb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/OldSmithingTableTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; @@ -145,4 +146,9 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator slotPacket.setItem(UPGRADE_TEMPLATE.apply(session.getUpstream().getProtocolVersion())); session.sendUpstreamPacket(slotPacket); } + + @Override + public @Nullable ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index c69293717..45deacaad 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -28,6 +28,8 @@ package org.geysermc.geyser.translator.inventory; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.CreativeItemData; @@ -41,10 +43,10 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action 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.packet.ContainerClosePacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; @@ -65,6 +67,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.function.IntFunction; public class PlayerInventoryTranslator extends InventoryTranslator { @@ -577,11 +580,26 @@ public class PlayerInventoryTranslator extends InventoryTranslator { @Override public void closeInventory(GeyserSession session, Inventory inventory) { - ContainerClosePacket packet = new ContainerClosePacket(); - packet.setServerInitiated(true); - packet.setId((byte) ContainerId.INVENTORY); - packet.setType(org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.INVENTORY); - session.sendUpstreamPacket(packet); + if (session.isServerRequestedClosePlayerInventory()) { + Vector3i pos = session.getPlayerEntity().getPosition().toInt(); + + UpdateBlockPacket packet = new UpdateBlockPacket(); + packet.setBlockPosition(pos); + packet.setDefinition(session.getBlockMappings().getNetherPortalBlock()); + packet.setDataLayer(0); + packet.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + session.sendUpstreamPacket(packet); + + session.scheduleInEventLoop(() -> { + BlockDefinition definition = session.getBlockMappings().getBedrockBlock(session.getGeyser().getWorldManager().blockAt(session, pos)); + + packet.setBlockPosition(pos); + packet.setDefinition(definition); + packet.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + packet.setDataLayer(0); + session.sendUpstreamPacket(packet); + }, 50, TimeUnit.MILLISECONDS); + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java index 464bf07f7..ccf0d32be 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -80,4 +81,9 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator } return super.javaSlotToBedrockContainer(javaSlot); } + + @Override + public @Nullable ContainerType closeContainerType(Inventory inventory) { + return ContainerType.CONTAINER; + } } 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 2a9e974f3..8067585d3 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 @@ -29,6 +29,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.level.block.Blocks; @@ -74,4 +75,9 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato default -> super.javaSlotToBedrock(slot); }; } + + @Override + public ContainerType closeContainerType(Inventory inventory) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java index df7e15fef..90ef13fd5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.inventory; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; @@ -125,4 +126,9 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl public Inventory createInventory(String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) { return new StonecutterContainer(name, windowId, this.size, containerType, playerInventory); } + + @Override + public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) { + return org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.STONECUTTER; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index 856cc1876..93b9d8e04 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -34,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.level.block.Blocks; @@ -43,6 +44,7 @@ import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.DoubleChestBlockEntityTranslator; import org.geysermc.geyser.util.InventoryUtils; @@ -146,13 +148,25 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { @Override public void closeInventory(GeyserSession session, Inventory inventory) { - if (((Container) inventory).isUsingRealBlock()) { + if (!(inventory instanceof Container container)) { + GeyserImpl.getInstance().getLogger().warning("Tried to close a non-container inventory in a block inventory holder! Please report this error on discord."); + GeyserImpl.getInstance().getLogger().warning("Current inventory translator: " + session.getInventoryTranslator().getClass().getSimpleName()); + GeyserImpl.getInstance().getLogger().warning("Current inventory: " + inventory.getClass().getSimpleName()); + // Try to save ourselves? maybe? + // https://github.com/GeyserMC/Geyser/issues/4141 + // TODO: improve once this issue is pinned down + session.setOpenInventory(null); + session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR); + return; + } + + if (container.isUsingRealBlock()) { // No need to reset a block since we didn't change any blocks // But send a container close packet because we aren't destroying the original. ContainerClosePacket packet = new ContainerClosePacket(); packet.setId((byte) inventory.getBedrockId()); packet.setServerInitiated(true); - packet.setType(ContainerType.MINECART_CHEST); + packet.setType(ContainerType.CONTAINER); session.sendUpstreamPacket(packet); return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java index 94bdeb281..30a9ff8d6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java @@ -67,6 +67,6 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator { @Override public void closeInventory(GeyserSession session, Inventory inventory) { - holder.closeInventory(this, session, inventory); + holder.closeInventory(this, session, inventory, ContainerType.CONTAINER); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java index 185cafc51..5f2721ae3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java @@ -25,9 +25,11 @@ package org.geysermc.geyser.translator.inventory.furnace; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.level.block.Blocks; public class BlastFurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator { @@ -42,4 +44,9 @@ public class BlastFurnaceInventoryTranslator extends AbstractFurnaceInventoryTra } return super.javaSlotToBedrockContainer(slot); } + + @Override + public @Nullable ContainerType closeContainerType(Inventory inventory) { + return ContainerType.BLAST_FURNACE; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java index bc96f7105..8a520dde2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java @@ -25,9 +25,11 @@ package org.geysermc.geyser.translator.inventory.furnace; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.level.block.Blocks; public class FurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator { @@ -42,4 +44,9 @@ public class FurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslat } return super.javaSlotToBedrockContainer(slot); } + + @Override + public @Nullable ContainerType closeContainerType(Inventory inventory) { + return ContainerType.FURNACE; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java index 380446f09..2b676c424 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java @@ -25,9 +25,11 @@ package org.geysermc.geyser.translator.inventory.furnace; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.level.block.Blocks; public class SmokerInventoryTranslator extends AbstractFurnaceInventoryTranslator { @@ -42,4 +44,9 @@ public class SmokerInventoryTranslator extends AbstractFurnaceInventoryTranslato } return super.javaSlotToBedrockContainer(slot); } + + @Override + public @Nullable ContainerType closeContainerType(Inventory inventory) { + return ContainerType.SMOKER; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java index 538133e0e..06d62fadf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java @@ -50,6 +50,8 @@ public abstract class AbstractHorseInventoryTranslator extends BaseInventoryTran @Override public void closeInventory(GeyserSession session, Inventory inventory) { + // TODO find a way to implement + // Can cause inventory de-sync if the Java server requests an inventory close } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java index d675a07e9..4554bbe38 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.MerchantContainer; @@ -54,8 +53,7 @@ public class BedrockContainerCloseTranslator extends PacketTranslator Date: Wed, 19 Feb 2025 14:27:22 +0100 Subject: [PATCH 548/897] Update to latest MCPL changes, fix issues with the force-player-inventory workaround --- .../geyser/entity/EntityDefinition.java | 7 +- .../geyser/entity/EntityDefinitions.java | 314 +++++++++--------- .../geyser/entity/type/FireworkEntity.java | 2 +- .../geyser/entity/type/ItemFrameEntity.java | 2 +- .../geyser/entity/type/LivingEntity.java | 4 +- .../entity/type/ThrownPotionEntity.java | 6 +- .../living/animal/tameable/WolfEntity.java | 4 +- .../geyser/inventory/AnvilContainer.java | 4 +- .../geyser/inventory/GeyserItemStack.java | 7 +- .../geysermc/geyser/inventory/Inventory.java | 4 +- .../updater/AnvilInventoryUpdater.java | 20 +- .../geysermc/geyser/item/type/ArmorItem.java | 4 +- .../geysermc/geyser/item/type/ArrowItem.java | 4 +- .../geysermc/geyser/item/type/BannerItem.java | 10 +- .../geyser/item/type/CompassItem.java | 6 +- .../geyser/item/type/CrossbowItem.java | 4 +- .../geyser/item/type/DecoratedPotItem.java | 4 +- .../geyser/item/type/EnchantedBookItem.java | 6 +- .../geyser/item/type/FilledMapItem.java | 4 +- .../geyser/item/type/FireworkRocketItem.java | 6 +- .../geyser/item/type/FireworkStarItem.java | 6 +- .../geyser/item/type/GoatHornItem.java | 12 +- .../org/geysermc/geyser/item/type/Item.java | 19 +- .../geysermc/geyser/item/type/LightItem.java | 4 +- .../geysermc/geyser/item/type/MapItem.java | 4 +- .../geyser/item/type/OminousBottleItem.java | 6 +- .../geyser/item/type/PlayerHeadItem.java | 6 +- .../geysermc/geyser/item/type/PotionItem.java | 6 +- .../geysermc/geyser/item/type/ShieldItem.java | 6 +- .../geyser/item/type/ShulkerBoxItem.java | 8 +- .../geyser/item/type/TippedArrowItem.java | 4 +- .../item/type/TropicalFishBucketItem.java | 4 +- .../geyser/item/type/WritableBookItem.java | 4 +- .../geyser/item/type/WrittenBookItem.java | 4 +- .../geysermc/geyser/level/WorldManager.java | 3 +- .../geyser/level/block/type/SkullBlock.java | 6 +- .../CustomItemRegistryPopulator.java | 7 +- .../DataComponentRegistryPopulator.java | 3 +- .../geyser/session/GeyserSession.java | 2 +- .../geyser/session/cache/BundleCache.java | 4 +- .../geyser/session/cache/WorldCache.java | 4 +- .../entity/EntityMetadataTranslator.java | 2 +- .../inventory/BundleInventoryTranslator.java | 6 +- .../inventory/InventoryTranslator.java | 7 +- .../inventory/LecternInventoryTranslator.java | 6 +- .../inventory/LoomInventoryTranslator.java | 6 +- .../inventory/PlayerInventoryTranslator.java | 14 +- .../translator/item/CustomItemTranslator.java | 8 +- .../translator/item/ItemTranslator.java | 36 +- .../entity/VaultBlockEntityTranslator.java | 6 +- .../bedrock/BedrockBookEditTranslator.java | 6 +- ...BedrockInventoryTransactionTranslator.java | 4 +- .../java/JavaRecipeBookAddTranslator.java | 2 +- .../entity/JavaSetEquipmentTranslator.java | 6 +- .../JavaContainerCloseTranslator.java | 3 +- .../BlockSoundInteractionTranslator.java | 4 +- .../org/geysermc/geyser/util/BlockUtils.java | 6 +- .../geysermc/geyser/util/InventoryUtils.java | 2 +- .../org/geysermc/geyser/util/ItemUtils.java | 8 +- .../network/ScoreboardIssueTests.java | 8 +- gradle/libs.versions.toml | 2 +- 61 files changed, 346 insertions(+), 340 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java index 5b4dc0969..d26a25d2c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java @@ -26,9 +26,6 @@ package org.geysermc.geyser.entity; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import java.util.List; -import java.util.Locale; -import java.util.function.BiConsumer; import lombok.Setter; import lombok.experimental.Accessors; import org.geysermc.geyser.GeyserImpl; @@ -41,6 +38,10 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetad import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import java.util.List; +import java.util.Locale; +import java.util.function.BiConsumer; + /** * Represents data for an entity. This includes properties such as height and width, as well as the list of entity * metadata translators needed to translate the properties sent from the server. The translators are structured in such 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 b17e3d21d..c8488238d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -147,7 +147,7 @@ import org.geysermc.geyser.entity.type.living.monster.raid.VindicatorEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataTypes; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; @@ -310,14 +310,14 @@ public final class EntityDefinitions { static { EntityDefinition entityBase = EntityDefinition.builder(Entity::new) - .addTranslator(MetadataType.BYTE, Entity::setFlags) - .addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles - .addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName) - .addTranslator(MetadataType.BOOLEAN, Entity::setDisplayNameVisible) - .addTranslator(MetadataType.BOOLEAN, Entity::setSilent) - .addTranslator(MetadataType.BOOLEAN, Entity::setGravity) - .addTranslator(MetadataType.POSE, (entity, entityMetadata) -> entity.setPose(entityMetadata.getValue())) - .addTranslator(MetadataType.INT, Entity::setFreezing) + .addTranslator(MetadataTypes.BYTE, Entity::setFlags) + .addTranslator(MetadataTypes.INT, Entity::setAir) // Air/bubbles + .addTranslator(MetadataTypes.OPTIONAL_CHAT, Entity::setDisplayName) + .addTranslator(MetadataTypes.BOOLEAN, Entity::setDisplayNameVisible) + .addTranslator(MetadataTypes.BOOLEAN, Entity::setSilent) + .addTranslator(MetadataTypes.BOOLEAN, Entity::setGravity) + .addTranslator(MetadataTypes.POSE, (entity, entityMetadata) -> entity.setPose(entityMetadata.getValue())) + .addTranslator(MetadataTypes.INT, Entity::setFreezing) .build(); // Extends entity @@ -325,9 +325,9 @@ public final class EntityDefinitions { AREA_EFFECT_CLOUD = EntityDefinition.inherited(AreaEffectCloudEntity::new, entityBase) .type(EntityType.AREA_EFFECT_CLOUD) .height(0.5f).width(1.0f) - .addTranslator(MetadataType.FLOAT, AreaEffectCloudEntity::setRadius) + .addTranslator(MetadataTypes.FLOAT, AreaEffectCloudEntity::setRadius) .addTranslator(null) // Waiting - .addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle) + .addTranslator(MetadataTypes.PARTICLE, AreaEffectCloudEntity::setParticle) .build(); DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase) .type(EntityType.DRAGON_FIREBALL) @@ -337,8 +337,8 @@ public final class EntityDefinitions { .type(EntityType.END_CRYSTAL) .heightAndWidth(2.0f) .identifier("minecraft:ender_crystal") - .addTranslator(MetadataType.OPTIONAL_POSITION, EnderCrystalEntity::setBlockTarget) - .addTranslator(MetadataType.BOOLEAN, + .addTranslator(MetadataTypes.OPTIONAL_POSITION, EnderCrystalEntity::setBlockTarget) + .addTranslator(MetadataTypes.BOOLEAN, (enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal .build(); EXPERIENCE_ORB = EntityDefinition.inherited(ExpOrbEntity::new, entityBase) @@ -365,21 +365,21 @@ public final class EntityDefinitions { .type(EntityType.FIREWORK_ROCKET) .heightAndWidth(0.25f) .identifier("minecraft:fireworks_rocket") - .addTranslator(MetadataType.ITEM, FireworkEntity::setFireworkItem) - .addTranslator(MetadataType.OPTIONAL_VARINT, FireworkEntity::setPlayerGliding) + .addTranslator(MetadataTypes.ITEM, FireworkEntity::setFireworkItem) + .addTranslator(MetadataTypes.OPTIONAL_VARINT, FireworkEntity::setPlayerGliding) .addTranslator(null) // Shot at angle .build(); FISHING_BOBBER = EntityDefinition.inherited(null, entityBase) .type(EntityType.FISHING_BOBBER) .identifier("minecraft:fishing_hook") - .addTranslator(MetadataType.INT, FishingHookEntity::setHookedEntity) + .addTranslator(MetadataTypes.INT, FishingHookEntity::setHookedEntity) .addTranslator(null) // Biting TODO check .build(); ITEM = EntityDefinition.inherited(ItemEntity::new, entityBase) .type(EntityType.ITEM) .heightAndWidth(0.25f) .offset(0.125f) - .addTranslator(MetadataType.ITEM, ItemEntity::setItem) + .addTranslator(MetadataTypes.ITEM, ItemEntity::setItem) .build(); LEASH_KNOT = EntityDefinition.inherited(LeashKnotEntity::new, entityBase) .type(EntityType.LEASH_KNOT) @@ -394,7 +394,7 @@ public final class EntityDefinitions { .build(); PAINTING = EntityDefinition.inherited(null, entityBase) .type(EntityType.PAINTING) - .addTranslator(MetadataType.PAINTING_VARIANT, PaintingEntity::setPaintingType) + .addTranslator(MetadataTypes.PAINTING_VARIANT, PaintingEntity::setPaintingType) .build(); SHULKER_BULLET = EntityDefinition.inherited(ThrowableEntity::new, entityBase) .type(EntityType.SHULKER_BULLET) @@ -404,14 +404,14 @@ public final class EntityDefinitions { .type(EntityType.TNT) .heightAndWidth(0.98f) .offset(0.49f) - .addTranslator(MetadataType.INT, TNTEntity::setFuseLength) + .addTranslator(MetadataTypes.INT, TNTEntity::setFuseLength) .build(); EntityDefinition displayBase = EntityDefinition.inherited(DisplayBaseEntity::new, entityBase) .addTranslator(null) // Interpolation delay .addTranslator(null) // Transformation interpolation duration .addTranslator(null) // Position/Rotation interpolation duration - .addTranslator(MetadataType.VECTOR3, DisplayBaseEntity::setTranslation) // Translation + .addTranslator(MetadataTypes.VECTOR3, DisplayBaseEntity::setTranslation) // Translation .addTranslator(null) // Scale .addTranslator(null) // Left rotation .addTranslator(null) // Right rotation @@ -428,7 +428,7 @@ public final class EntityDefinitions { .type(EntityType.TEXT_DISPLAY) .identifier("minecraft:armor_stand") .offset(-0.5f) - .addTranslator(MetadataType.CHAT, TextDisplayEntity::setText) + .addTranslator(MetadataTypes.CHAT, TextDisplayEntity::setText) .addTranslator(null) // Line width .addTranslator(null) // Background color .addTranslator(null) // Text opacity @@ -439,9 +439,9 @@ public final class EntityDefinitions { .type(EntityType.INTERACTION) .heightAndWidth(1.0f) // default size until server specifies otherwise .identifier("minecraft:armor_stand") - .addTranslator(MetadataType.FLOAT, InteractionEntity::setWidth) - .addTranslator(MetadataType.FLOAT, InteractionEntity::setHeight) - .addTranslator(MetadataType.BOOLEAN, InteractionEntity::setResponse) + .addTranslator(MetadataTypes.FLOAT, InteractionEntity::setWidth) + .addTranslator(MetadataTypes.FLOAT, InteractionEntity::setHeight) + .addTranslator(MetadataTypes.BOOLEAN, InteractionEntity::setResponse) .build(); EntityDefinition fireballBase = EntityDefinition.inherited(FireballEntity::new, entityBase) @@ -457,7 +457,7 @@ public final class EntityDefinitions { .build(); EntityDefinition throwableItemBase = EntityDefinition.inherited(ThrowableItemEntity::new, entityBase) - .addTranslator(MetadataType.ITEM, ThrowableItemEntity::setItem) + .addTranslator(MetadataTypes.ITEM, ThrowableItemEntity::setItem) .build(); EGG = EntityDefinition.inherited(ThrowableItemEntity::new, throwableItemBase) .type(EntityType.EGG) @@ -495,14 +495,14 @@ public final class EntityDefinitions { .build(); EntityDefinition abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase) - .addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags) + .addTranslator(MetadataTypes.BYTE, AbstractArrowEntity::setArrowFlags) .addTranslator(null) // "Piercing level" .addTranslator(null) // If the arrow is in the ground .build(); ARROW = EntityDefinition.inherited(ArrowEntity::new, abstractArrowBase) .type(EntityType.ARROW) .heightAndWidth(0.25f) - .addTranslator(MetadataType.INT, ArrowEntity::setPotionEffectColor) + .addTranslator(MetadataTypes.INT, ArrowEntity::setPotionEffectColor) .build(); SPECTRAL_ARROW = EntityDefinition.inherited(abstractArrowBase.factory(), abstractArrowBase) .type(EntityType.SPECTRAL_ARROW) @@ -513,14 +513,14 @@ public final class EntityDefinitions { .type(EntityType.TRIDENT) .identifier("minecraft:thrown_trident") .addTranslator(null) // Loyalty - .addTranslator(MetadataType.BOOLEAN, (tridentEntity, entityMetadata) -> tridentEntity.setFlag(EntityFlag.ENCHANTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataTypes.BOOLEAN, (tridentEntity, entityMetadata) -> tridentEntity.setFlag(EntityFlag.ENCHANTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .build(); // Item frames are handled differently as they are blocks, not items, in Bedrock ITEM_FRAME = EntityDefinition.inherited(null, entityBase) .type(EntityType.ITEM_FRAME) - .addTranslator(MetadataType.ITEM, ItemFrameEntity::setItemInFrame) - .addTranslator(MetadataType.INT, ItemFrameEntity::setItemRotation) + .addTranslator(MetadataTypes.ITEM, ItemFrameEntity::setItemInFrame) + .addTranslator(MetadataTypes.INT, ItemFrameEntity::setItemRotation) .build(); GLOW_ITEM_FRAME = EntityDefinition.inherited(ITEM_FRAME.factory(), ITEM_FRAME) .type(EntityType.GLOW_ITEM_FRAME) @@ -530,27 +530,27 @@ public final class EntityDefinitions { .type(EntityType.MINECART) .height(0.7f).width(0.98f) .offset(0.35f) - .addTranslator(MetadataType.INT, (minecartEntity, entityMetadata) -> minecartEntity.getDirtyMetadata().put(EntityDataTypes.STRUCTURAL_INTEGRITY, entityMetadata.getValue())) - .addTranslator(MetadataType.INT, (minecartEntity, entityMetadata) -> minecartEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Direction in which the minecart is shaking - .addTranslator(MetadataType.FLOAT, (minecartEntity, entityMetadata) -> + .addTranslator(MetadataTypes.INT, (minecartEntity, entityMetadata) -> minecartEntity.getDirtyMetadata().put(EntityDataTypes.STRUCTURAL_INTEGRITY, entityMetadata.getValue())) + .addTranslator(MetadataTypes.INT, (minecartEntity, entityMetadata) -> minecartEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Direction in which the minecart is shaking + .addTranslator(MetadataTypes.FLOAT, (minecartEntity, entityMetadata) -> // Power in Java, hurt ticks in Bedrock minecartEntity.getDirtyMetadata().put(EntityDataTypes.HURT_TICKS, Math.min((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue(), 15))) - .addTranslator(MetadataType.INT, MinecartEntity::setCustomBlock) - .addTranslator(MetadataType.INT, MinecartEntity::setCustomBlockOffset) - .addTranslator(MetadataType.BOOLEAN, MinecartEntity::setShowCustomBlock) + .addTranslator(MetadataTypes.INT, MinecartEntity::setCustomBlock) + .addTranslator(MetadataTypes.INT, MinecartEntity::setCustomBlockOffset) + .addTranslator(MetadataTypes.BOOLEAN, MinecartEntity::setShowCustomBlock) .build(); CHEST_MINECART = EntityDefinition.inherited(MINECART.factory(), MINECART) .type(EntityType.CHEST_MINECART) .build(); COMMAND_BLOCK_MINECART = EntityDefinition.inherited(CommandBlockMinecartEntity::new, MINECART) .type(EntityType.COMMAND_BLOCK_MINECART) - .addTranslator(MetadataType.STRING, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.COMMAND_BLOCK_NAME, entityMetadata.getValue())) - .addTranslator(MetadataType.CHAT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage(entityMetadata.getValue()))) + .addTranslator(MetadataTypes.STRING, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.COMMAND_BLOCK_NAME, entityMetadata.getValue())) + .addTranslator(MetadataTypes.CHAT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage(entityMetadata.getValue()))) .build(); FURNACE_MINECART = EntityDefinition.inherited(FurnaceMinecartEntity::new, MINECART) .type(EntityType.FURNACE_MINECART) .identifier("minecraft:minecart") - .addTranslator(MetadataType.BOOLEAN, FurnaceMinecartEntity::setHasFuel) + .addTranslator(MetadataTypes.BOOLEAN, FurnaceMinecartEntity::setHasFuel) .build(); HOPPER_MINECART = EntityDefinition.inherited(MINECART.factory(), MINECART) .type(EntityType.HOPPER_MINECART) @@ -566,7 +566,7 @@ public final class EntityDefinitions { WITHER_SKULL = EntityDefinition.inherited(WitherSkullEntity::new, entityBase) .type(EntityType.WITHER_SKULL) .heightAndWidth(0.3125f) - .addTranslator(MetadataType.BOOLEAN, WitherSkullEntity::setDangerous) + .addTranslator(MetadataTypes.BOOLEAN, WitherSkullEntity::setDangerous) .build(); WITHER_SKULL_DANGEROUS = EntityDefinition.inherited(WITHER_SKULL.factory(), WITHER_SKULL) .build(false); @@ -577,14 +577,14 @@ public final class EntityDefinitions { 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) -> + .addTranslator(MetadataTypes.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_TICKS, entityMetadata.getValue())) // Time since last hit + .addTranslator(MetadataTypes.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Rocking direction + .addTranslator(MetadataTypes.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 + .addTranslator(MetadataTypes.BOOLEAN, BoatEntity::setPaddlingLeft) + .addTranslator(MetadataTypes.BOOLEAN, BoatEntity::setPaddlingRight) + .addTranslator(MetadataTypes.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); @@ -614,41 +614,41 @@ public final class EntityDefinitions { } EntityDefinition livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase) - .addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags) - .addTranslator(MetadataType.FLOAT, LivingEntity::setHealth) - .addTranslator(MetadataType.PARTICLES, LivingEntity::setParticles) - .addTranslator(MetadataType.BOOLEAN, + .addTranslator(MetadataTypes.BYTE, LivingEntity::setLivingEntityFlags) + .addTranslator(MetadataTypes.FLOAT, LivingEntity::setHealth) + .addTranslator(MetadataTypes.PARTICLES, LivingEntity::setParticles) + .addTranslator(MetadataTypes.BOOLEAN, (livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityDataTypes.EFFECT_AMBIENCE, (byte) (((BooleanEntityMetadata) entityMetadata).getPrimitiveValue() ? 1 : 0))) .addTranslator(null) // Arrow count .addTranslator(null) // Stinger count - .addTranslator(MetadataType.OPTIONAL_POSITION, LivingEntity::setBedPosition) + .addTranslator(MetadataTypes.OPTIONAL_POSITION, LivingEntity::setBedPosition) .build(); ARMOR_STAND = EntityDefinition.inherited(ArmorStandEntity::new, livingEntityBase) .type(EntityType.ARMOR_STAND) .height(1.975f).width(0.5f) - .addTranslator(MetadataType.BYTE, ArmorStandEntity::setArmorStandFlags) - .addTranslator(MetadataType.ROTATION, ArmorStandEntity::setHeadRotation) - .addTranslator(MetadataType.ROTATION, ArmorStandEntity::setBodyRotation) - .addTranslator(MetadataType.ROTATION, ArmorStandEntity::setLeftArmRotation) - .addTranslator(MetadataType.ROTATION, ArmorStandEntity::setRightArmRotation) - .addTranslator(MetadataType.ROTATION, ArmorStandEntity::setLeftLegRotation) - .addTranslator(MetadataType.ROTATION, ArmorStandEntity::setRightLegRotation) + .addTranslator(MetadataTypes.BYTE, ArmorStandEntity::setArmorStandFlags) + .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setHeadRotation) + .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setBodyRotation) + .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setLeftArmRotation) + .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setRightArmRotation) + .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setLeftLegRotation) + .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setRightLegRotation) .build(); PLAYER = EntityDefinition.inherited(null, livingEntityBase) .type(EntityType.PLAYER) .height(1.8f).width(0.6f) .offset(1.62f) - .addTranslator(MetadataType.FLOAT, PlayerEntity::setAbsorptionHearts) + .addTranslator(MetadataTypes.FLOAT, PlayerEntity::setAbsorptionHearts) .addTranslator(null) // Player score - .addTranslator(MetadataType.BYTE, PlayerEntity::setSkinVisibility) + .addTranslator(MetadataTypes.BYTE, PlayerEntity::setSkinVisibility) .addTranslator(null) // Player main hand - .addTranslator(MetadataType.NBT_TAG, PlayerEntity::setLeftParrot) - .addTranslator(MetadataType.NBT_TAG, PlayerEntity::setRightParrot) + .addTranslator(MetadataTypes.NBT_TAG, PlayerEntity::setLeftParrot) + .addTranslator(MetadataTypes.NBT_TAG, PlayerEntity::setRightParrot) .build(); EntityDefinition mobEntityBase = EntityDefinition.inherited(MobEntity::new, livingEntityBase) - .addTranslator(MetadataType.BYTE, MobEntity::setMobFlags) + .addTranslator(MetadataTypes.BYTE, MobEntity::setMobFlags) .build(); // Extends mob @@ -656,23 +656,23 @@ public final class EntityDefinitions { ALLAY = EntityDefinition.inherited(AllayEntity::new, mobEntityBase) .type(EntityType.ALLAY) .height(0.6f).width(0.35f) - .addTranslator(MetadataType.BOOLEAN, AllayEntity::setDancing) - .addTranslator(MetadataType.BOOLEAN, AllayEntity::setCanDuplicate) + .addTranslator(MetadataTypes.BOOLEAN, AllayEntity::setDancing) + .addTranslator(MetadataTypes.BOOLEAN, AllayEntity::setCanDuplicate) .build(); BAT = EntityDefinition.inherited(BatEntity::new, mobEntityBase) .type(EntityType.BAT) .height(0.9f).width(0.5f) - .addTranslator(MetadataType.BYTE, BatEntity::setBatFlags) + .addTranslator(MetadataTypes.BYTE, BatEntity::setBatFlags) .build(); BOGGED = EntityDefinition.inherited(BoggedEntity::new, mobEntityBase) .type(EntityType.BOGGED) .height(1.99f).width(0.6f) - .addTranslator(MetadataType.BOOLEAN, BoggedEntity::setSheared) + .addTranslator(MetadataTypes.BOOLEAN, BoggedEntity::setSheared) .build(); BLAZE = EntityDefinition.inherited(BlazeEntity::new, mobEntityBase) .type(EntityType.BLAZE) .height(1.8f).width(0.6f) - .addTranslator(MetadataType.BYTE, BlazeEntity::setBlazeFlags) + .addTranslator(MetadataTypes.BYTE, BlazeEntity::setBlazeFlags) .build(); BREEZE = EntityDefinition.inherited(BreezeEntity::new, mobEntityBase) .type(EntityType.BREEZE) @@ -681,10 +681,10 @@ public final class EntityDefinitions { CREAKING = EntityDefinition.inherited(CreakingEntity::new, mobEntityBase) .type(EntityType.CREAKING) .height(2.7f).width(0.9f) - .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setCanMove) - .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setActive) - .addTranslator(MetadataType.BOOLEAN, CreakingEntity::setIsTearingDown) - .addTranslator(MetadataType.OPTIONAL_POSITION, CreakingEntity::setHomePos) + .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setCanMove) + .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setActive) + .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setIsTearingDown) + .addTranslator(MetadataTypes.OPTIONAL_POSITION, CreakingEntity::setHomePos) .properties(new GeyserEntityProperties.Builder() .addEnum(CreakingEntity.CREAKING_STATE, "neutral", @@ -699,16 +699,16 @@ public final class EntityDefinitions { .type(EntityType.CREEPER) .height(1.7f).width(0.6f) .offset(1.62f) - .addTranslator(MetadataType.INT, CreeperEntity::setSwelling) - .addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.POWERED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) - .addTranslator(MetadataType.BOOLEAN, CreeperEntity::setIgnited) + .addTranslator(MetadataTypes.INT, CreeperEntity::setSwelling) + .addTranslator(MetadataTypes.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.POWERED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataTypes.BOOLEAN, CreeperEntity::setIgnited) .build(); ENDERMAN = EntityDefinition.inherited(EndermanEntity::new, mobEntityBase) .type(EntityType.ENDERMAN) .height(2.9f).width(0.6f) - .addTranslator(MetadataType.OPTIONAL_BLOCK_STATE, EndermanEntity::setCarriedBlock) - .addTranslator(MetadataType.BOOLEAN, EndermanEntity::setScreaming) - .addTranslator(MetadataType.BOOLEAN, EndermanEntity::setAngry) + .addTranslator(MetadataTypes.OPTIONAL_BLOCK_STATE, EndermanEntity::setCarriedBlock) + .addTranslator(MetadataTypes.BOOLEAN, EndermanEntity::setScreaming) + .addTranslator(MetadataTypes.BOOLEAN, EndermanEntity::setAngry) .build(); ENDERMITE = EntityDefinition.inherited(MonsterEntity::new, mobEntityBase) .type(EntityType.ENDERMITE) @@ -716,12 +716,12 @@ public final class EntityDefinitions { .build(); ENDER_DRAGON = EntityDefinition.inherited(EnderDragonEntity::new, mobEntityBase) .type(EntityType.ENDER_DRAGON) - .addTranslator(MetadataType.INT, EnderDragonEntity::setPhase) + .addTranslator(MetadataTypes.INT, EnderDragonEntity::setPhase) .build(); GHAST = EntityDefinition.inherited(GhastEntity::new, mobEntityBase) .type(EntityType.GHAST) .heightAndWidth(4.0f) - .addTranslator(MetadataType.BOOLEAN, GhastEntity::setGhastAttacking) + .addTranslator(MetadataTypes.BOOLEAN, GhastEntity::setGhastAttacking) .build(); GIANT = EntityDefinition.inherited(GiantEntity::new, mobEntityBase) .type(EntityType.GIANT) @@ -738,7 +738,7 @@ public final class EntityDefinitions { .type(EntityType.PHANTOM) .height(0.5f).width(0.9f) .offset(0.6f) - .addTranslator(MetadataType.INT, PhantomEntity::setPhantomScale) + .addTranslator(MetadataTypes.INT, PhantomEntity::setPhantomScale) .build(); SILVERFISH = EntityDefinition.inherited(MonsterEntity::new, mobEntityBase) .type(EntityType.SILVERFISH) @@ -747,26 +747,26 @@ public final class EntityDefinitions { SHULKER = EntityDefinition.inherited(ShulkerEntity::new, mobEntityBase) .type(EntityType.SHULKER) .heightAndWidth(1f) - .addTranslator(MetadataType.DIRECTION, ShulkerEntity::setAttachedFace) - .addTranslator(MetadataType.BYTE, ShulkerEntity::setShulkerHeight) - .addTranslator(MetadataType.BYTE, ShulkerEntity::setShulkerColor) + .addTranslator(MetadataTypes.DIRECTION, ShulkerEntity::setAttachedFace) + .addTranslator(MetadataTypes.BYTE, ShulkerEntity::setShulkerHeight) + .addTranslator(MetadataTypes.BYTE, ShulkerEntity::setShulkerColor) .build(); SKELETON = EntityDefinition.inherited(SkeletonEntity::new, mobEntityBase) .type(EntityType.SKELETON) .height(1.8f).width(0.6f) .offset(1.62f) - .addTranslator(MetadataType.BOOLEAN, SkeletonEntity::setConvertingToStray) + .addTranslator(MetadataTypes.BOOLEAN, SkeletonEntity::setConvertingToStray) .build(); SNOW_GOLEM = EntityDefinition.inherited(SnowGolemEntity::new, mobEntityBase) .type(EntityType.SNOW_GOLEM) .height(1.9f).width(0.7f) - .addTranslator(MetadataType.BYTE, SnowGolemEntity::setSnowGolemFlags) + .addTranslator(MetadataTypes.BYTE, SnowGolemEntity::setSnowGolemFlags) .build(); SPIDER = EntityDefinition.inherited(SpiderEntity::new, mobEntityBase) .type(EntityType.SPIDER) .height(0.9f).width(1.4f) .offset(1f) - .addTranslator(MetadataType.BYTE, SpiderEntity::setSpiderFlags) + .addTranslator(MetadataTypes.BYTE, SpiderEntity::setSpiderFlags) .build(); CAVE_SPIDER = EntityDefinition.inherited(SpiderEntity::new, SPIDER) .type(EntityType.CAVE_SPIDER) @@ -780,20 +780,20 @@ public final class EntityDefinitions { VEX = EntityDefinition.inherited(VexEntity::new, mobEntityBase) .type(EntityType.VEX) .height(0.8f).width(0.4f) - .addTranslator(MetadataType.BYTE, VexEntity::setVexFlags) + .addTranslator(MetadataTypes.BYTE, VexEntity::setVexFlags) .build(); WARDEN = EntityDefinition.inherited(WardenEntity::new, mobEntityBase) .type(EntityType.WARDEN) .height(2.9f).width(0.9f) - .addTranslator(MetadataType.INT, WardenEntity::setAngerLevel) + .addTranslator(MetadataTypes.INT, WardenEntity::setAngerLevel) .build(); WITHER = EntityDefinition.inherited(WitherEntity::new, mobEntityBase) .type(EntityType.WITHER) .height(3.5f).width(0.9f) - .addTranslator(MetadataType.INT, WitherEntity::setTarget1) - .addTranslator(MetadataType.INT, WitherEntity::setTarget2) - .addTranslator(MetadataType.INT, WitherEntity::setTarget3) - .addTranslator(MetadataType.INT, WitherEntity::setInvulnerableTicks) + .addTranslator(MetadataTypes.INT, WitherEntity::setTarget1) + .addTranslator(MetadataTypes.INT, WitherEntity::setTarget2) + .addTranslator(MetadataTypes.INT, WitherEntity::setTarget3) + .addTranslator(MetadataTypes.INT, WitherEntity::setInvulnerableTicks) .build(); WITHER_SKELETON = EntityDefinition.inherited(AbstractSkeletonEntity::new, mobEntityBase) .type(EntityType.WITHER_SKELETON) @@ -802,23 +802,23 @@ public final class EntityDefinitions { ZOGLIN = EntityDefinition.inherited(ZoglinEntity::new, mobEntityBase) .type(EntityType.ZOGLIN) .height(1.4f).width(1.3965f) - .addTranslator(MetadataType.BOOLEAN, ZoglinEntity::setBaby) + .addTranslator(MetadataTypes.BOOLEAN, ZoglinEntity::setBaby) .build(); ZOMBIE = EntityDefinition.inherited(ZombieEntity::new, mobEntityBase) .type(EntityType.ZOMBIE) .height(1.8f).width(0.6f) .offset(1.62f) - .addTranslator(MetadataType.BOOLEAN, ZombieEntity::setZombieBaby) + .addTranslator(MetadataTypes.BOOLEAN, ZombieEntity::setZombieBaby) .addTranslator(null) // "set special type", doesn't do anything - .addTranslator(MetadataType.BOOLEAN, ZombieEntity::setConvertingToDrowned) + .addTranslator(MetadataTypes.BOOLEAN, ZombieEntity::setConvertingToDrowned) .build(); ZOMBIE_VILLAGER = EntityDefinition.inherited(ZombieVillagerEntity::new, ZOMBIE) .type(EntityType.ZOMBIE_VILLAGER) .height(1.8f).width(0.6f) .offset(1.62f) .identifier("minecraft:zombie_villager_v2") - .addTranslator(MetadataType.BOOLEAN, ZombieVillagerEntity::setTransforming) - .addTranslator(MetadataType.VILLAGER_DATA, ZombieVillagerEntity::setZombieVillagerData) + .addTranslator(MetadataTypes.BOOLEAN, ZombieVillagerEntity::setTransforming) + .addTranslator(MetadataTypes.VILLAGER_DATA, ZombieVillagerEntity::setZombieVillagerData) .build(); ZOMBIFIED_PIGLIN = EntityDefinition.inherited(ZombifiedPiglinEntity::new, ZOMBIE) //TODO test how zombie entity metadata is handled? .type(EntityType.ZOMBIFIED_PIGLIN) @@ -839,7 +839,7 @@ public final class EntityDefinitions { .type(EntityType.GUARDIAN) .heightAndWidth(0.85f) .addTranslator(null) // Moving //TODO - .addTranslator(MetadataType.INT, GuardianEntity::setGuardianTarget) + .addTranslator(MetadataTypes.INT, GuardianEntity::setGuardianTarget) .build(); ELDER_GUARDIAN = EntityDefinition.inherited(ElderGuardianEntity::new, GUARDIAN) .type(EntityType.ELDER_GUARDIAN) @@ -849,7 +849,7 @@ public final class EntityDefinitions { SLIME = EntityDefinition.inherited(SlimeEntity::new, mobEntityBase) .type(EntityType.SLIME) .heightAndWidth(0.51f) - .addTranslator(MetadataType.INT, SlimeEntity::setSlimeScale) + .addTranslator(MetadataTypes.INT, SlimeEntity::setSlimeScale) .build(); MAGMA_CUBE = EntityDefinition.inherited(MagmaCubeEntity::new, SLIME) .type(EntityType.MAGMA_CUBE) @@ -865,7 +865,7 @@ public final class EntityDefinitions { PUFFERFISH = EntityDefinition.inherited(PufferFishEntity::new, abstractFishEntityBase) .type(EntityType.PUFFERFISH) .heightAndWidth(0.7f) - .addTranslator(MetadataType.INT, PufferFishEntity::setPufferfishSize) + .addTranslator(MetadataTypes.INT, PufferFishEntity::setPufferfishSize) .build(); SALMON = EntityDefinition.inherited(abstractFishEntityBase.factory(), abstractFishEntityBase) .type(EntityType.SALMON) @@ -880,18 +880,18 @@ public final class EntityDefinitions { .type(EntityType.TROPICAL_FISH) .heightAndWidth(0.6f) .identifier("minecraft:tropicalfish") - .addTranslator(MetadataType.INT, TropicalFishEntity::setFishVariant) + .addTranslator(MetadataTypes.INT, TropicalFishEntity::setFishVariant) .build(); EntityDefinition abstractPiglinEntityBase = EntityDefinition.inherited(BasePiglinEntity::new, mobEntityBase) - .addTranslator(MetadataType.BOOLEAN, BasePiglinEntity::setImmuneToZombification) + .addTranslator(MetadataTypes.BOOLEAN, BasePiglinEntity::setImmuneToZombification) .build(); PIGLIN = EntityDefinition.inherited(PiglinEntity::new, abstractPiglinEntityBase) .type(EntityType.PIGLIN) .height(1.95f).width(0.6f) - .addTranslator(MetadataType.BOOLEAN, PiglinEntity::setBaby) - .addTranslator(MetadataType.BOOLEAN, PiglinEntity::setChargingCrossbow) - .addTranslator(MetadataType.BOOLEAN, PiglinEntity::setDancing) + .addTranslator(MetadataTypes.BOOLEAN, PiglinEntity::setBaby) + .addTranslator(MetadataTypes.BOOLEAN, PiglinEntity::setChargingCrossbow) + .addTranslator(MetadataTypes.BOOLEAN, PiglinEntity::setDancing) .build(); PIGLIN_BRUTE = EntityDefinition.inherited(abstractPiglinEntityBase.factory(), abstractPiglinEntityBase) .type(EntityType.PIGLIN_BRUTE) @@ -902,7 +902,7 @@ public final class EntityDefinitions { .addTranslator(null) // Celebrating //TODO .build(); EntityDefinition spellcasterEntityBase = EntityDefinition.inherited(SpellcasterIllagerEntity::new, raidParticipantEntityBase) - .addTranslator(MetadataType.BYTE, SpellcasterIllagerEntity::setSpellType) + .addTranslator(MetadataTypes.BYTE, SpellcasterIllagerEntity::setSpellType) .build(); EVOKER = EntityDefinition.inherited(spellcasterEntityBase.factory(), spellcasterEntityBase) .type(EntityType.EVOKER) @@ -918,7 +918,7 @@ public final class EntityDefinitions { .type(EntityType.PILLAGER) .height(1.8f).width(0.6f) .offset(1.62f) - .addTranslator(MetadataType.BOOLEAN, PillagerEntity::setChargingCrossbow) + .addTranslator(MetadataTypes.BOOLEAN, PillagerEntity::setChargingCrossbow) .build(); RAVAGER = EntityDefinition.inherited(RavagerEntity::new, raidParticipantEntityBase) .type(EntityType.RAVAGER) @@ -938,7 +938,7 @@ public final class EntityDefinitions { } EntityDefinition ageableEntityBase = EntityDefinition.inherited(AgeableEntity::new, mobEntityBase) - .addTranslator(MetadataType.BOOLEAN, AgeableEntity::setBaby) + .addTranslator(MetadataTypes.BOOLEAN, AgeableEntity::setBaby) .build(); // Extends ageable @@ -955,13 +955,13 @@ public final class EntityDefinitions { "rolled_up_relaxing", "rolled_up_unrolling") .build()) - .addTranslator(MetadataType.ARMADILLO_STATE, ArmadilloEntity::setArmadilloState) + .addTranslator(MetadataTypes.ARMADILLO_STATE, ArmadilloEntity::setArmadilloState) .build(); AXOLOTL = EntityDefinition.inherited(AxolotlEntity::new, ageableEntityBase) .type(EntityType.AXOLOTL) .height(0.42f).width(0.7f) - .addTranslator(MetadataType.INT, AxolotlEntity::setVariant) - .addTranslator(MetadataType.BOOLEAN, AxolotlEntity::setPlayingDead) + .addTranslator(MetadataTypes.INT, AxolotlEntity::setVariant) + .addTranslator(MetadataTypes.BOOLEAN, AxolotlEntity::setPlayingDead) .addTranslator(null) // From bucket .build(); BEE = EntityDefinition.inherited(BeeEntity::new, ageableEntityBase) @@ -970,8 +970,8 @@ public final class EntityDefinitions { .properties(new GeyserEntityProperties.Builder() .addBoolean("minecraft:has_nectar") .build()) - .addTranslator(MetadataType.BYTE, BeeEntity::setBeeFlags) - .addTranslator(MetadataType.INT, BeeEntity::setAngerTime) + .addTranslator(MetadataTypes.BYTE, BeeEntity::setBeeFlags) + .addTranslator(MetadataTypes.INT, BeeEntity::setAngerTime) .build(); CHICKEN = EntityDefinition.inherited(ChickenEntity::new, ageableEntityBase) .type(EntityType.CHICKEN) @@ -984,89 +984,89 @@ public final class EntityDefinitions { FOX = EntityDefinition.inherited(FoxEntity::new, ageableEntityBase) .type(EntityType.FOX) .height(0.7f).width(0.6f) - .addTranslator(MetadataType.INT, FoxEntity::setFoxVariant) - .addTranslator(MetadataType.BYTE, FoxEntity::setFoxFlags) + .addTranslator(MetadataTypes.INT, FoxEntity::setFoxVariant) + .addTranslator(MetadataTypes.BYTE, FoxEntity::setFoxFlags) .addTranslator(null) // Trusted player 1 .addTranslator(null) // Trusted player 2 .build(); FROG = EntityDefinition.inherited(FrogEntity::new, ageableEntityBase) .type(EntityType.FROG) .heightAndWidth(0.5f) - .addTranslator(MetadataType.FROG_VARIANT, FrogEntity::setFrogVariant) - .addTranslator(MetadataType.OPTIONAL_VARINT, FrogEntity::setTongueTarget) + .addTranslator(MetadataTypes.FROG_VARIANT, FrogEntity::setFrogVariant) + .addTranslator(MetadataTypes.OPTIONAL_VARINT, FrogEntity::setTongueTarget) .build(); HOGLIN = EntityDefinition.inherited(HoglinEntity::new, ageableEntityBase) .type(EntityType.HOGLIN) .height(1.4f).width(1.3965f) - .addTranslator(MetadataType.BOOLEAN, HoglinEntity::setImmuneToZombification) + .addTranslator(MetadataTypes.BOOLEAN, HoglinEntity::setImmuneToZombification) .build(); GOAT = EntityDefinition.inherited(GoatEntity::new, ageableEntityBase) .type(EntityType.GOAT) .height(1.3f).width(0.9f) - .addTranslator(MetadataType.BOOLEAN, GoatEntity::setScreamer) - .addTranslator(MetadataType.BOOLEAN, GoatEntity::setHasLeftHorn) - .addTranslator(MetadataType.BOOLEAN, GoatEntity::setHasRightHorn) + .addTranslator(MetadataTypes.BOOLEAN, GoatEntity::setScreamer) + .addTranslator(MetadataTypes.BOOLEAN, GoatEntity::setHasLeftHorn) + .addTranslator(MetadataTypes.BOOLEAN, GoatEntity::setHasRightHorn) .build(); MOOSHROOM = EntityDefinition.inherited(MooshroomEntity::new, ageableEntityBase) .type(EntityType.MOOSHROOM) .height(1.4f).width(0.9f) - .addTranslator(MetadataType.STRING, MooshroomEntity::setVariant) + .addTranslator(MetadataTypes.STRING, MooshroomEntity::setVariant) .build(); OCELOT = EntityDefinition.inherited(OcelotEntity::new, ageableEntityBase) .type(EntityType.OCELOT) .height(0.7f).width(0.6f) - .addTranslator(MetadataType.BOOLEAN, (ocelotEntity, entityMetadata) -> ocelotEntity.setFlag(EntityFlag.TRUSTING, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataTypes.BOOLEAN, (ocelotEntity, entityMetadata) -> ocelotEntity.setFlag(EntityFlag.TRUSTING, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .build(); PANDA = EntityDefinition.inherited(PandaEntity::new, ageableEntityBase) .type(EntityType.PANDA) .height(1.25f).width(1.125f) .addTranslator(null) // Unhappy counter .addTranslator(null) // Sneeze counter - .addTranslator(MetadataType.INT, PandaEntity::setEatingCounter) - .addTranslator(MetadataType.BYTE, PandaEntity::setMainGene) - .addTranslator(MetadataType.BYTE, PandaEntity::setHiddenGene) - .addTranslator(MetadataType.BYTE, PandaEntity::setPandaFlags) + .addTranslator(MetadataTypes.INT, PandaEntity::setEatingCounter) + .addTranslator(MetadataTypes.BYTE, PandaEntity::setMainGene) + .addTranslator(MetadataTypes.BYTE, PandaEntity::setHiddenGene) + .addTranslator(MetadataTypes.BYTE, PandaEntity::setPandaFlags) .build(); PIG = EntityDefinition.inherited(PigEntity::new, ageableEntityBase) .type(EntityType.PIG) .heightAndWidth(0.9f) - .addTranslator(MetadataType.BOOLEAN, (pigEntity, entityMetadata) -> pigEntity.setFlag(EntityFlag.SADDLED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) - .addTranslator(MetadataType.INT, PigEntity::setBoost) + .addTranslator(MetadataTypes.BOOLEAN, (pigEntity, entityMetadata) -> pigEntity.setFlag(EntityFlag.SADDLED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataTypes.INT, PigEntity::setBoost) .build(); POLAR_BEAR = EntityDefinition.inherited(PolarBearEntity::new, ageableEntityBase) .type(EntityType.POLAR_BEAR) .height(1.4f).width(1.3f) - .addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.STANDING, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataTypes.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.STANDING, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .build(); RABBIT = EntityDefinition.inherited(RabbitEntity::new, ageableEntityBase) .type(EntityType.RABBIT) .height(0.5f).width(0.4f) - .addTranslator(MetadataType.INT, RabbitEntity::setRabbitVariant) + .addTranslator(MetadataTypes.INT, RabbitEntity::setRabbitVariant) .build(); SHEEP = EntityDefinition.inherited(SheepEntity::new, ageableEntityBase) .type(EntityType.SHEEP) .height(1.3f).width(0.9f) - .addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags) + .addTranslator(MetadataTypes.BYTE, SheepEntity::setSheepFlags) .build(); SNIFFER = EntityDefinition.inherited(SnifferEntity::new, ageableEntityBase) .type(EntityType.SNIFFER) .height(1.75f).width(1.9f) - .addTranslator(MetadataType.SNIFFER_STATE, SnifferEntity::setSnifferState) + .addTranslator(MetadataTypes.SNIFFER_STATE, SnifferEntity::setSnifferState) .addTranslator(null) // Integer, drop seed at tick .build(); STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase) .type(EntityType.STRIDER) .height(1.7f).width(0.9f) - .addTranslator(MetadataType.INT, StriderEntity::setBoost) - .addTranslator(MetadataType.BOOLEAN, StriderEntity::setCold) - .addTranslator(MetadataType.BOOLEAN, StriderEntity::setSaddled) + .addTranslator(MetadataTypes.INT, StriderEntity::setBoost) + .addTranslator(MetadataTypes.BOOLEAN, StriderEntity::setCold) + .addTranslator(MetadataTypes.BOOLEAN, StriderEntity::setSaddled) .build(); TURTLE = EntityDefinition.inherited(TurtleEntity::new, ageableEntityBase) .type(EntityType.TURTLE) .height(0.4f).width(1.2f) .addTranslator(null) // Home position - .addTranslator(MetadataType.BOOLEAN, TurtleEntity::setPregnant) - .addTranslator(MetadataType.BOOLEAN, TurtleEntity::setLayingEgg) + .addTranslator(MetadataTypes.BOOLEAN, TurtleEntity::setPregnant) + .addTranslator(MetadataTypes.BOOLEAN, TurtleEntity::setLayingEgg) .addTranslator(null) // Travel position .addTranslator(null) // Going home .addTranslator(null) // Travelling @@ -1080,7 +1080,7 @@ public final class EntityDefinitions { .height(1.8f).width(0.6f) .offset(1.62f) .identifier("minecraft:villager_v2") - .addTranslator(MetadataType.VILLAGER_DATA, VillagerEntity::setVillagerData) + .addTranslator(MetadataTypes.VILLAGER_DATA, VillagerEntity::setVillagerData) .build(); WANDERING_TRADER = EntityDefinition.inherited(abstractVillagerEntityBase.factory(), abstractVillagerEntityBase) .type(EntityType.WANDERING_TRADER) @@ -1112,18 +1112,18 @@ public final class EntityDefinitions { // Horses { EntityDefinition abstractHorseEntityBase = EntityDefinition.inherited(AbstractHorseEntity::new, ageableEntityBase) - .addTranslator(MetadataType.BYTE, AbstractHorseEntity::setHorseFlags) + .addTranslator(MetadataTypes.BYTE, AbstractHorseEntity::setHorseFlags) .build(); CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase) .type(EntityType.CAMEL) .height(2.375f).width(1.7f) - .addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing) - .addTranslator(MetadataType.LONG, CamelEntity::setLastPoseTick) + .addTranslator(MetadataTypes.BOOLEAN, CamelEntity::setDashing) + .addTranslator(MetadataTypes.LONG, CamelEntity::setLastPoseTick) .build(); HORSE = EntityDefinition.inherited(HorseEntity::new, abstractHorseEntityBase) .type(EntityType.HORSE) .height(1.6f).width(1.3965f) - .addTranslator(MetadataType.INT, HorseEntity::setHorseVariant) + .addTranslator(MetadataTypes.INT, HorseEntity::setHorseVariant) .build(); SKELETON_HORSE = EntityDefinition.inherited(SkeletonHorseEntity::new, abstractHorseEntityBase) .type(EntityType.SKELETON_HORSE) @@ -1134,7 +1134,7 @@ public final class EntityDefinitions { .height(1.6f).width(1.3965f) .build(); EntityDefinition chestedHorseEntityBase = EntityDefinition.inherited(ChestedHorseEntity::new, abstractHorseEntityBase) - .addTranslator(MetadataType.BOOLEAN, (horseEntity, entityMetadata) -> horseEntity.setFlag(EntityFlag.CHESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataTypes.BOOLEAN, (horseEntity, entityMetadata) -> horseEntity.setFlag(EntityFlag.CHESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .build(); DONKEY = EntityDefinition.inherited(chestedHorseEntityBase.factory(), chestedHorseEntityBase) .type(EntityType.DONKEY) @@ -1147,8 +1147,8 @@ public final class EntityDefinitions { LLAMA = EntityDefinition.inherited(LlamaEntity::new, chestedHorseEntityBase) .type(EntityType.LLAMA) .height(1.87f).width(0.9f) - .addTranslator(MetadataType.INT, LlamaEntity::setStrength) - .addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.VARIANT, entityMetadata.getValue())) + .addTranslator(MetadataTypes.INT, LlamaEntity::setStrength) + .addTranslator(MetadataTypes.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.VARIANT, entityMetadata.getValue())) .build(); TRADER_LLAMA = EntityDefinition.inherited(TraderLlamaEntity::new, LLAMA) .type(EntityType.TRADER_LLAMA) @@ -1157,30 +1157,30 @@ public final class EntityDefinitions { } EntityDefinition tameableEntityBase = EntityDefinition.inherited(null, ageableEntityBase) // No factory, is abstract - .addTranslator(MetadataType.BYTE, TameableEntity::setTameableFlags) - .addTranslator(MetadataType.OPTIONAL_UUID, TameableEntity::setOwner) + .addTranslator(MetadataTypes.BYTE, TameableEntity::setTameableFlags) + .addTranslator(MetadataTypes.OPTIONAL_UUID, TameableEntity::setOwner) .build(); CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase) .type(EntityType.CAT) .height(0.35f).width(0.3f) - .addTranslator(MetadataType.CAT_VARIANT, CatEntity::setCatVariant) - .addTranslator(MetadataType.BOOLEAN, CatEntity::setResting) + .addTranslator(MetadataTypes.CAT_VARIANT, CatEntity::setCatVariant) + .addTranslator(MetadataTypes.BOOLEAN, CatEntity::setResting) .addTranslator(null) // "resting state one" //TODO - .addTranslator(MetadataType.INT, CatEntity::setCollarColor) + .addTranslator(MetadataTypes.INT, CatEntity::setCollarColor) .build(); PARROT = EntityDefinition.inherited(ParrotEntity::new, tameableEntityBase) .type(EntityType.PARROT) .height(0.9f).width(0.5f) - .addTranslator(MetadataType.INT, (parrotEntity, entityMetadata) -> parrotEntity.getDirtyMetadata().put(EntityDataTypes.VARIANT, entityMetadata.getValue())) // Parrot color + .addTranslator(MetadataTypes.INT, (parrotEntity, entityMetadata) -> parrotEntity.getDirtyMetadata().put(EntityDataTypes.VARIANT, entityMetadata.getValue())) // Parrot color .build(); WOLF = EntityDefinition.inherited(WolfEntity::new, tameableEntityBase) .type(EntityType.WOLF) .height(0.85f).width(0.6f) // "Begging" on wiki.vg, "Interested" in Nukkit - the tilt of the head - .addTranslator(MetadataType.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) - .addTranslator(MetadataType.INT, WolfEntity::setCollarColor) - .addTranslator(MetadataType.INT, WolfEntity::setWolfAngerTime) - .addTranslator(MetadataType.WOLF_VARIANT, WolfEntity::setWolfVariant) + .addTranslator(MetadataTypes.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataTypes.INT, WolfEntity::setCollarColor) + .addTranslator(MetadataTypes.INT, WolfEntity::setWolfAngerTime) + .addTranslator(MetadataTypes.WOLF_VARIANT, WolfEntity::setWolfVariant) .build(); // As of 1.18 these don't track entity data at all diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java index f0739abb3..ebe35320e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java @@ -51,7 +51,7 @@ public class FireworkEntity extends Entity { if (item == null) { return; } - DataComponents components = item.getDataComponents(); + DataComponents components = item.getDataComponentsPatch(); if (components == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java index afe0dcdc6..680bdecd8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java @@ -120,7 +120,7 @@ public class ItemFrameEntity extends Entity { NbtMap itemDataTag = itemData.getTag(); if (itemDataTag != null) { // Remove custom name that Geyser sets for items due to translating non-"custom_name" components - String customName = ItemTranslator.getCustomName(session, heldItem.getDataComponents(), + String customName = ItemTranslator.getCustomName(session, heldItem.getDataComponentsPatch(), session.getItemMappings().getMapping(heldItem), 'f', true, false); if (customName == null) { // No custom name found, must modify tag if custom name exists 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 33064edfe..ca9dca6e0 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 @@ -61,7 +61,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEnt import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; @@ -344,7 +344,7 @@ public class LivingEntity extends Entity { */ // Implementation note for 1.20.5: this code was moved to the NameTag item. protected final InteractionResult checkInteractWithNameTag(GeyserItemStack itemStack) { - if (itemStack.getComponent(DataComponentType.CUSTOM_NAME) != null) { + if (itemStack.getComponent(DataComponentTypes.CUSTOM_NAME) != null) { // The mob shall be named return InteractionResult.SUCCESS; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java index 88cf4f8b9..e940b074e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java @@ -36,7 +36,7 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; @@ -59,9 +59,9 @@ public class ThrownPotionEntity extends ThrowableItemEntity { setFlag(EntityFlag.LINGERING, false); } else { // As of Java 1.19.3, the server/client doesn't seem to care of the item is actually a potion? - DataComponents components = itemStack.getDataComponents(); + DataComponents components = itemStack.getDataComponentsPatch(); if (components != null) { - PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); if (potionContents != null) { Potion potion = Potion.getByJavaId(potionContents.getPotionId()); if (potion != 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 b108c9fbe..c8b6a6f58 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 @@ -51,7 +51,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Object 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.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.Collections; @@ -129,7 +129,7 @@ public class WolfEntity extends TameableEntity { super.setBody(stack); isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); // Not using ItemStack#getDataComponents as that wouldn't include default item components - repairableItems = GeyserItemStack.from(stack).getComponent(DataComponentType.REPAIRABLE); + repairableItems = GeyserItemStack.from(stack).getComponent(DataComponentTypes.REPAIRABLE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index f5969efbb..fe760c75a 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -32,7 +32,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; /** @@ -73,7 +73,7 @@ public class AnvilContainer extends Container { String correctRename; newName = rename; - Component originalName = getInput().getComponent(DataComponentType.CUSTOM_NAME); + Component originalName = getInput().getComponent(DataComponentTypes.CUSTOM_NAME); String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.locale()); String plainNewName = MessageTranslator.convertToPlainText(rename); 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 c4a3542d1..a66b07598 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -43,6 +43,7 @@ import org.geysermc.geyser.session.cache.BundleCache; 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.DataComponentTypes; 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; @@ -89,7 +90,7 @@ public class GeyserItemStack { } public static @NonNull GeyserItemStack from(@Nullable ItemStack itemStack) { - return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponents()); + return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponentsPatch()); } public static @NonNull GeyserItemStack from(@NonNull SlotDisplay slotDisplay) { @@ -217,11 +218,11 @@ public class GeyserItemStack { // Not fresh from server? Then we have changes to apply!~ if (bundleData != null && !bundleData.freshFromServer()) { if (!bundleData.contents().isEmpty()) { - getOrCreateComponents().put(DataComponentType.BUNDLE_CONTENTS, bundleData.toComponent()); + getOrCreateComponents().put(DataComponentTypes.BUNDLE_CONTENTS, bundleData.toComponent()); } else { if (components != null) { // Empty list = no component = should delete - components.getDataComponents().remove(DataComponentType.BUNDLE_CONTENTS); + components.getDataComponents().remove(DataComponentTypes.BUNDLE_CONTENTS); } } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index 4639e0151..2c0c2798d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -36,7 +36,7 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.jetbrains.annotations.Range; import java.util.Arrays; @@ -135,7 +135,7 @@ public abstract class Inventory { // Lodestone caching if (newItem.asItem() == Items.COMPASS) { - var tracker = newItem.getComponent(DataComponentType.LODESTONE_TRACKER); + var tracker = newItem.getComponent(DataComponentTypes.LODESTONE_TRACKER); if (tracker != null) { session.getLodestoneCache().cacheInventoryItem(newItem, tracker); } 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 8282607af..ac9e35909 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 @@ -44,7 +44,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; 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.DataComponentTypes; 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; @@ -117,7 +117,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // Changing the item in the input slot resets the name field on Bedrock, but // does not result in a FilterTextPacket - String originalName = MessageTranslator.convertToPlainText(input.getComponent(DataComponentType.CUSTOM_NAME), session.locale()); + String originalName = MessageTranslator.convertToPlainText(input.getComponent(DataComponentTypes.CUSTOM_NAME), session.locale()); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName); session.sendDownstreamGamePacket(renameItemPacket); @@ -367,9 +367,9 @@ public class AnvilInventoryUpdater extends InventoryUpdater { private Object2IntMap getEnchantments(GeyserSession session, GeyserItemStack itemStack) { ItemEnchantments enchantmentComponent; if (isEnchantedBook(itemStack)) { - enchantmentComponent = itemStack.getComponent(DataComponentType.STORED_ENCHANTMENTS); + enchantmentComponent = itemStack.getComponent(DataComponentTypes.STORED_ENCHANTMENTS); } else { - enchantmentComponent = itemStack.getComponent(DataComponentType.ENCHANTMENTS); + enchantmentComponent = itemStack.getComponent(DataComponentTypes.ENCHANTMENTS); } if (enchantmentComponent != null) { Object2IntMap enchantments = new Object2IntOpenHashMap<>(); @@ -395,7 +395,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } private boolean isRepairing(GeyserItemStack input, GeyserItemStack material, GeyserSession session) { - HolderSet repairable = input.getComponent(DataComponentType.REPAIRABLE); + HolderSet repairable = input.getComponent(DataComponentTypes.REPAIRABLE); if (repairable == null) { return false; } @@ -409,27 +409,27 @@ public class AnvilInventoryUpdater extends InventoryUpdater { } // This should really check the name field in all cases, but that requires the localized name // of the item which can change depending on NBT and Minecraft Edition - Component originalName = anvilContainer.getInput().getComponent(DataComponentType.CUSTOM_NAME); + Component originalName = anvilContainer.getInput().getComponent(DataComponentTypes.CUSTOM_NAME); if (bedrock && originalName != null && anvilContainer.getNewName() != null) { // Check text and formatting String legacyOriginalName = MessageTranslator.convertMessage(originalName, session.locale()); return !legacyOriginalName.equals(anvilContainer.getNewName()); } - return !Objects.equals(originalName, anvilContainer.getResult().getComponent(DataComponentType.CUSTOM_NAME)); + return !Objects.equals(originalName, anvilContainer.getResult().getComponent(DataComponentTypes.CUSTOM_NAME)); } private int getRepairCost(GeyserItemStack itemStack) { - return itemStack.getComponentElseGet(DataComponentType.REPAIR_COST, () -> 0); + return itemStack.getComponentElseGet(DataComponentTypes.REPAIR_COST, () -> 0); } private boolean hasDurability(GeyserItemStack itemStack) { if (itemStack.asItem().defaultMaxDamage() > 0) { - return itemStack.getComponent(DataComponentType.UNBREAKABLE) != null; + return itemStack.getComponent(DataComponentTypes.UNBREAKABLE) != null; } return false; } private int getDamage(GeyserItemStack itemStack) { - return itemStack.getComponentElseGet(DataComponentType.DAMAGE, () -> 0); + return itemStack.getComponentElseGet(DataComponentTypes.DAMAGE, () -> 0); } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index ec87728a9..c20cc490e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -33,7 +33,7 @@ import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ArmorTrim; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class ArmorItem extends Item { @@ -46,7 +46,7 @@ public class ArmorItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - ArmorTrim trim = components.get(DataComponentType.TRIM); + ArmorTrim trim = components.get(DataComponentTypes.TRIM); if (trim != null) { TrimMaterial material = session.getRegistryCache().trimMaterials().byId(trim.material().id()); TrimPattern pattern = session.getRegistryCache().trimPatterns().byId(trim.pattern().id()); 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 b2d3737d8..8aaf389f6 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 @@ -33,7 +33,7 @@ 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; public class ArrowItem extends Item { @@ -48,7 +48,7 @@ public class ArrowItem extends Item { if (potion != null) { itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents()); PotionContents contents = potion.toComponent(); - itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, contents); + itemStack.getOrCreateComponents().put(DataComponentTypes.POTION_CONTENTS, contents); } return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 6ec0da8ed..2a5f76c33 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -44,7 +44,7 @@ import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; @@ -206,7 +206,7 @@ public class BannerItem extends BlockItem { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - List patterns = components.get(DataComponentType.BANNER_PATTERNS); + List patterns = components.get(DataComponentTypes.BANNER_PATTERNS); if (patterns != null) { convertBannerPattern(session, patterns, builder); } @@ -225,9 +225,9 @@ public class BannerItem extends BlockItem { pair.right().ordinal())); } - components.put(DataComponentType.BANNER_PATTERNS, patternLayers); - components.put(DataComponentType.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE); - components.put(DataComponentType.ITEM_NAME, Component + components.put(DataComponentTypes.BANNER_PATTERNS, patternLayers); + components.put(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE); + components.put(DataComponentTypes.ITEM_NAME, Component .translatable("block.minecraft.ominous_banner") .style(Style.style(TextColor.color(16755200))) ); 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 1c0ec0d5f..d6403a8c3 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 @@ -33,7 +33,7 @@ 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.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.LodestoneTracker; @@ -62,7 +62,7 @@ public class CompassItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - LodestoneTracker tracker = components.get(DataComponentType.LODESTONE_TRACKER); + LodestoneTracker tracker = components.get(DataComponentTypes.LODESTONE_TRACKER); if (tracker != null) { int trackId = session.getLodestoneCache().store(tracker); // Set the bedrock tracking id - will return 0 if invalid @@ -72,7 +72,7 @@ public class CompassItem extends Item { private boolean isLodestoneCompass(@Nullable DataComponents components) { if (components != null) { - return components.getDataComponents().containsKey(DataComponentType.LODESTONE_TRACKER); + return components.getDataComponents().containsKey(DataComponentTypes.LODESTONE_TRACKER); } return false; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java index 7e1181c4e..13e79958e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java @@ -33,7 +33,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.List; @@ -47,7 +47,7 @@ public class CrossbowItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - List chargedProjectiles = components.get(DataComponentType.CHARGED_PROJECTILES); + List chargedProjectiles = components.get(DataComponentTypes.CHARGED_PROJECTILES); if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { ItemStack javaProjectile = chargedProjectiles.get(0); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index 578ba4063..fa08bd7ec 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -31,7 +31,7 @@ import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.ArrayList; @@ -47,7 +47,7 @@ public class DecoratedPotItem extends BlockItem { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - List decorations = components.get(DataComponentType.POT_DECORATIONS); // TODO maybe unbox in MCProtocolLib + List decorations = components.get(DataComponentTypes.POT_DECORATIONS); // TODO maybe unbox in MCProtocolLib if (decorations != null) { List sherds = new ArrayList<>(decorations.size()); for (Integer decoration : decorations) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index 8b0f3e22e..f5ddb698b 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -36,7 +36,7 @@ import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; @@ -54,7 +54,7 @@ public class EnchantedBookItem extends Item { super.translateComponentsToBedrock(session, components, builder); List bedrockEnchants = new ArrayList<>(); - ItemEnchantments enchantments = components.get(DataComponentType.STORED_ENCHANTMENTS); + ItemEnchantments enchantments = components.get(DataComponentTypes.STORED_ENCHANTMENTS); if (enchantments != null) { // TODO don't duplicate code? for (Map.Entry enchantment : enchantments.getEnchantments().entrySet()) { NbtMap bedrockTag = remapEnchantment(session, enchantment.getKey(), enchantment.getValue(), builder); @@ -94,7 +94,7 @@ public class EnchantedBookItem extends Item { } } if (!javaEnchantments.isEmpty()) { - components.put(DataComponentType.STORED_ENCHANTMENTS, new ItemEnchantments(javaEnchantments, true)); + components.put(DataComponentTypes.STORED_ENCHANTMENTS, new ItemEnchantments(javaEnchantments, true)); } } } 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 07a0ad133..82c45ff31 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 @@ -29,7 +29,7 @@ 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class FilledMapItem extends MapItem { @@ -45,7 +45,7 @@ public class FilledMapItem extends MapItem { //return builder.tag(NbtMap.builder().putInt("map", 0).build()); TODO if this is *still* broken, let's move it to translateComponentsToBedrock return builder; } else { - Integer mapColor = components.get(DataComponentType.MAP_COLOR); + Integer mapColor = components.get(DataComponentTypes.MAP_COLOR); if (mapColor != null) { // Note: damage 5 treasure map, 6 ??? // Java Edition allows any color; Bedrock only allows some. So let's take what colors we can get diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index 862325a90..265d3aad7 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -35,7 +35,7 @@ import org.geysermc.geyser.level.FireworkColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Fireworks; @@ -51,7 +51,7 @@ public class FireworkRocketItem extends Item implements BedrockRequiresTagItem { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - Fireworks fireworks = components.get(DataComponentType.FIREWORKS); + Fireworks fireworks = components.get(DataComponentTypes.FIREWORKS); if (fireworks == null) { return; } @@ -87,7 +87,7 @@ public class FireworkRocketItem extends Item implements BedrockRequiresTagItem { javaExplosions.add(javaExplosion); } } - components.put(DataComponentType.FIREWORKS, new Fireworks(1, javaExplosions)); + components.put(DataComponentTypes.FIREWORKS, new Fireworks(1, javaExplosions)); } } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 5ac0f475c..170d386fd 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -30,7 +30,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Fireworks; @@ -43,7 +43,7 @@ public class FireworkStarItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - Fireworks.FireworkExplosion explosion = components.get(DataComponentType.FIREWORK_EXPLOSION); + Fireworks.FireworkExplosion explosion = components.get(DataComponentTypes.FIREWORK_EXPLOSION); if (explosion != null) { NbtMap newExplosion = FireworkRocketItem.translateExplosionToBedrock(explosion); builder.putCompound("FireworksItem", newExplosion); @@ -87,7 +87,7 @@ public class FireworkStarItem extends Item { if (newExplosion == null) { return; } - components.put(DataComponentType.FIREWORK_EXPLOSION, newExplosion); + components.put(DataComponentTypes.FIREWORK_EXPLOSION, newExplosion); } } 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 9af07a40e..bd1ac0724 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 @@ -34,7 +34,7 @@ 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument; @@ -50,7 +50,7 @@ public class GoatHornItem extends Item { return builder; } - Holder holder = components.get(DataComponentType.INSTRUMENT); + Holder holder = components.get(DataComponentTypes.INSTRUMENT); if (holder != null) { GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder); int bedrockId = instrument.bedrockId(); @@ -66,9 +66,9 @@ public class GoatHornItem extends Item { 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) { + Holder holder = components.get(DataComponentTypes.INSTRUMENT); + if (holder != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null + && components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) { GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder); if (instrument.bedrockInstrument() == null) { builder.getOrCreateLore().add(instrument.description()); @@ -82,7 +82,7 @@ public class GoatHornItem extends Item { int damage = itemData.getDamage(); // 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))); + itemStack.getOrCreateComponents().put(DataComponentTypes.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 056e8b48a..f0ae57018 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 @@ -49,6 +49,7 @@ import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DyedItemColor; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; @@ -83,7 +84,7 @@ public class Item { } public int defaultMaxDamage() { - return baseComponents.getOrDefault(DataComponentType.MAX_DAMAGE, 0); + return baseComponents.getOrDefault(DataComponentTypes.MAX_DAMAGE, 0); } public int defaultAttackDamage() { @@ -91,7 +92,7 @@ public class Item { } public int defaultMaxStackSize() { - return baseComponents.getOrDefault(DataComponentType.MAX_STACK_SIZE, 1); + return baseComponents.getOrDefault(DataComponentTypes.MAX_STACK_SIZE, 1); } /** @@ -157,21 +158,21 @@ public class Item { * Takes components from Java Edition and map them into Bedrock. */ public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - List loreComponents = components.get(DataComponentType.LORE); - if (loreComponents != null && components.get(DataComponentType.HIDE_TOOLTIP) == null) { + List loreComponents = components.get(DataComponentTypes.LORE); + if (loreComponents != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null) { List lore = builder.getOrCreateLore(); for (Component loreComponent : loreComponents) { lore.add(MessageTranslator.convertMessage(loreComponent, session.locale())); } } - Integer damage = components.get(DataComponentType.DAMAGE); + Integer damage = components.get(DataComponentTypes.DAMAGE); if (damage != null) { builder.setDamage(damage); } List enchantNbtList = new ArrayList<>(); - ItemEnchantments enchantments = components.get(DataComponentType.ENCHANTMENTS); + ItemEnchantments enchantments = components.get(DataComponentTypes.ENCHANTMENTS); if (enchantments != null) { for (Map.Entry enchantment : enchantments.getEnchantments().entrySet()) { NbtMap enchantNbt = remapEnchantment(session, enchantment.getKey(), enchantment.getValue(), builder); @@ -185,7 +186,7 @@ public class Item { builder.putList("ench", NbtType.COMPOUND, enchantNbtList); } - Integer repairCost = components.get(DataComponentType.REPAIR_COST); + Integer repairCost = components.get(DataComponentTypes.REPAIR_COST); // Java sets repair cost to 0 on all items via default components, that trips up Bedrock crafting. // See https://github.com/GeyserMC/Geyser/issues/5220 for more details if (repairCost != null && repairCost != 0) { @@ -193,7 +194,7 @@ public class Item { } // If the tag exists, it's unbreakable; the value is just weather to show the tooltip. As of Java 1.21 - if (components.getDataComponents().containsKey(DataComponentType.UNBREAKABLE)) { + if (components.getDataComponents().containsKey(DataComponentTypes.UNBREAKABLE)) { builder.putByte("Unbreakable", (byte) 1); } @@ -265,7 +266,7 @@ public class Item { } protected final void translateDyedColor(DataComponents components, BedrockItemBuilder builder) { - DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR); + DyedItemColor dyedItemColor = components.get(DataComponentTypes.DYED_COLOR); if (dyedItemColor != null) { builder.putInt("customColor", dyedItemColor.getRgb()); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java b/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java index d176ff367..36509f042 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/LightItem.java @@ -33,7 +33,7 @@ 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.BlockStateProperties; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class LightItem extends BlockItem { @@ -63,7 +63,7 @@ public class LightItem extends BlockItem { private static ItemMapping getLightLevelMapping(DataComponents components, ItemMappings mappings) { String lightLevel = "15"; if (components != null) { - BlockStateProperties blockStateProperties = components.get(DataComponentType.BLOCK_STATE); + BlockStateProperties blockStateProperties = components.get(DataComponentTypes.BLOCK_STATE); if (blockStateProperties != null) { lightLevel = blockStateProperties.getProperties().get(Properties.LEVEL.name()); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java index 5d8a1667d..f19da5968 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class MapItem extends Item { @@ -40,7 +40,7 @@ public class MapItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - Integer mapValue = components.get(DataComponentType.MAP_ID); + Integer mapValue = components.get(DataComponentTypes.MAP_ID); if (mapValue == null) { return; } 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 92a8d726d..0579e1c5b 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 @@ -32,7 +32,7 @@ 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class OminousBottleItem extends Item { @@ -47,7 +47,7 @@ public class OminousBottleItem extends Item { // Level 1 ominous bottle is null components - Java 1.21. return builder; } - Integer amplifier = components.get(DataComponentType.OMINOUS_BOTTLE_AMPLIFIER); + Integer amplifier = components.get(DataComponentTypes.OMINOUS_BOTTLE_AMPLIFIER); if (amplifier != null) { builder.damage(amplifier); } @@ -62,7 +62,7 @@ public class OminousBottleItem extends Item { if (damage == 0) { return itemStack; } - itemStack.getOrCreateComponents().put(DataComponentType.OMINOUS_BOTTLE_AMPLIFIER, damage); + itemStack.getOrCreateComponents().put(DataComponentTypes.OMINOUS_BOTTLE_AMPLIFIER, damage); return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index 003aa0a73..502d9be0d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -33,7 +33,7 @@ import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.auth.GameProfile; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; public class PlayerHeadItem extends BlockItem { @@ -46,9 +46,9 @@ public class PlayerHeadItem extends BlockItem { super.translateComponentsToBedrock(session, components, builder); // Use the correct color, determined by the rarity of the item - char rarity = Rarity.fromId(components.get(DataComponentType.RARITY)).getColor(); + char rarity = Rarity.fromId(components.get(DataComponentTypes.RARITY)).getColor(); - GameProfile profile = components.get(DataComponentType.PROFILE); + GameProfile profile = components.get(DataComponentTypes.PROFILE); if (profile != null) { String name = profile.getName(); if (name != null) { 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 89e60b325..2cdd6e4c1 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 @@ -35,7 +35,7 @@ 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; @@ -47,7 +47,7 @@ public class PotionItem extends Item { @Override 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); + PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); if (potionContents != null) { ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(components, mapping); if (customItemDefinition == null) { @@ -73,7 +73,7 @@ public class PotionItem extends Item { Potion potion = Potion.getByBedrockId(itemData.getDamage()); GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings); if (potion != null) { - itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, potion.toComponent()); + itemStack.getOrCreateComponents().put(DataComponentTypes.POTION_CONTENTS, potion.toComponent()); } return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index 98ef80d95..01cea9c17 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -29,7 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.List; @@ -43,12 +43,12 @@ public class ShieldItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - List patterns = components.get(DataComponentType.BANNER_PATTERNS); + List patterns = components.get(DataComponentTypes.BANNER_PATTERNS); if (patterns != null) { BannerItem.convertBannerPattern(session, patterns, builder); } // Shield pattern backing color - Integer baseColor = components.get(DataComponentType.BASE_COLOR); + Integer baseColor = components.get(DataComponentTypes.BASE_COLOR); if (baseColor != null) { builder.putInt("Base", 15 - baseColor); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index 5d14f748c..a53a9b7bc 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -40,7 +40,7 @@ import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.CustomItemTranslator; 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; @@ -56,7 +56,7 @@ public class ShulkerBoxItem extends BlockItem { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - List contents = components.get(DataComponentType.CONTAINER); + List contents = components.get(DataComponentTypes.CONTAINER); if (contents == null || contents.isEmpty()) { // Empty shulker box return; @@ -71,7 +71,7 @@ public class ShulkerBoxItem extends BlockItem { int bedrockData = boxMapping.getBedrockData(); String bedrockIdentifier = boxMapping.getBedrockIdentifier(); - DataComponents boxComponents = item.getDataComponents(); + DataComponents boxComponents = item.getDataComponentsPatch(); if (boxComponents != null) { // Check for custom items @@ -82,7 +82,7 @@ public class ShulkerBoxItem extends BlockItem { } else { // Manual checks for potions/tipped arrows if (boxMapping.getJavaItem() instanceof PotionItem || boxMapping.getJavaItem() instanceof ArrowItem) { - PotionContents potionContents = boxComponents.get(DataComponentType.POTION_CONTENTS); + PotionContents potionContents = boxComponents.get(DataComponentTypes.POTION_CONTENTS); if (potionContents != null) { Potion potion = Potion.getByJavaId(potionContents.getPotionId()); if (potion != null) { 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 09e4ee21f..ae77be643 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 @@ -31,7 +31,7 @@ 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; @@ -43,7 +43,7 @@ public class TippedArrowItem extends ArrowItem { @Override public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { if (components != null) { - PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); if (potionContents != null) { Potion potion = Potion.getByJavaId(potionContents.getPotionId()); if (potion != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index 7c5ad26f6..a93cc5934 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -36,7 +36,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.List; @@ -57,7 +57,7 @@ public class TropicalFishBucketItem extends Item { builder.putString("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale())); // Add Java's client side lore tag // Do you know how frequently Java NBT used to be before 1.20.5? It was a lot. And now it's just this lowly check. - NbtMap entityTag = components.get(DataComponentType.BUCKET_ENTITY_DATA); + NbtMap entityTag = components.get(DataComponentTypes.BUCKET_ENTITY_DATA); if (entityTag != null && !entityTag.isEmpty()) { //TODO test int bucketVariant = entityTag.getInt("BucketVariantTag"); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java index 55ad16b20..177ca0b2a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java @@ -32,7 +32,7 @@ import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Filterable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBookContent; @@ -49,7 +49,7 @@ public class WritableBookItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - WritableBookContent bookContent = components.get(DataComponentType.WRITABLE_BOOK_CONTENT); + WritableBookContent bookContent = components.get(DataComponentTypes.WRITABLE_BOOK_CONTENT); if (bookContent == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index dd41a5e89..9cb661e70 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -33,7 +33,7 @@ import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Filterable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent; @@ -54,7 +54,7 @@ public class WrittenBookItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - WrittenBookContent bookContent = components.get(DataComponentType.WRITTEN_BOOK_CONTENT); + WrittenBookContent bookContent = components.get(DataComponentTypes.WRITTEN_BOOK_CONTENT); if (bookContent == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index c33fc7665..b0422913d 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -38,6 +38,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; @@ -202,7 +203,7 @@ public abstract class WorldManager { try { Map, DataComponent> components = new HashMap<>(); Int2ObjectMaps.fastForEach(map, entry -> { - DataComponentType type = DataComponentType.from(entry.getIntKey()); + DataComponentType type = DataComponentTypes.from(entry.getIntKey()); ByteBuf buf = Unpooled.wrappedBuffer(entry.getValue()); DataComponent value = type.readDataComponent(buf); components.put(type, value); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java index 6e791d674..d41d160f8 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java @@ -34,7 +34,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.SkullCache; 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.Collections; @@ -79,7 +79,7 @@ public class SkullBlock extends Block { .putInt("y", position.getY()) .putInt("z", position.getZ()); DataComponents components = itemStack.getOrCreateComponents(); - components.put(DataComponentType.BLOCK_ENTITY_DATA, builder.build()); + components.put(DataComponentTypes.BLOCK_ENTITY_DATA, builder.build()); UUID uuid = skull.getUuid(); String texturesProperty = skull.getTexturesProperty(); @@ -87,7 +87,7 @@ public class SkullBlock extends Block { if (texturesProperty != null) { profile.setProperties(Collections.singletonList(new GameProfile.Property("textures", texturesProperty))); } - components.put(DataComponentType.PROFILE, profile); + components.put(DataComponentTypes.PROFILE, profile); return itemStack.getItemStack(); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index d1cec3231..4b92c6250 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -48,7 +48,8 @@ import org.geysermc.geyser.registry.mappings.MappingsConfigReader; import org.geysermc.geyser.registry.type.GeyserMappingItem; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.NonVanillaItemRegistration; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.ArrayList; @@ -134,8 +135,8 @@ public class CustomItemRegistryPopulator { String customIdentifier = customItemData.identifier(); DataComponents components = new DataComponents(new HashMap<>()); - components.put(DataComponentType.MAX_STACK_SIZE, customItemData.stackSize()); - components.put(DataComponentType.MAX_DAMAGE, customItemData.maxDamage()); + components.put(DataComponentTypes.MAX_STACK_SIZE, customItemData.stackSize()); + components.put(DataComponentTypes.MAX_DAMAGE, customItemData.maxDamage()); Item item = new Item(customIdentifier, Item.builder().components(components)); Items.register(item, customItemData.javaId()); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java index 829e8719e..ef3168f41 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java @@ -39,6 +39,7 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.mcprotocollib.protocol.codec.MinecraftTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.io.InputStream; @@ -74,7 +75,7 @@ public final class DataComponentRegistryPopulator { byte[] bytes = Base64.getDecoder().decode(encodedValue); ByteBuf buf = Unpooled.wrappedBuffer(bytes); int varInt = MinecraftTypes.readVarInt(buf); - DataComponentType dataComponentType = DataComponentType.from(varInt); + DataComponentType dataComponentType = DataComponentTypes.from(varInt); DataComponent dataComponent = dataComponentType.readDataComponent(buf); map.put(dataComponentType, dataComponent); 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 4a2863b9e..3e18a2829 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -291,7 +291,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final PlayerInventory playerInventory; @Setter - private Inventory openInventory; + private @Nullable Inventory openInventory; @Setter private boolean closingInventory; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/BundleCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/BundleCache.java index 8ad31949b..3338a11fc 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/BundleCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/BundleCache.java @@ -41,7 +41,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InventoryUtils; 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.DataComponentTypes; import java.util.ArrayList; import java.util.Arrays; @@ -75,7 +75,7 @@ public final class BundleCache { } BundleData bundleData; - List rawContents = itemStack.getComponent(DataComponentType.BUNDLE_CONTENTS); + List rawContents = itemStack.getComponent(DataComponentTypes.BUNDLE_CONTENTS); if (rawContents != null) { // Use existing list and transform it to support net IDs bundleData = new BundleData(session, rawContents); 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 eb57e0214..6108c6432 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 @@ -41,7 +41,7 @@ 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseCooldown; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; @@ -221,7 +221,7 @@ public final class WorldCache { } public boolean hasCooldown(GeyserItemStack item) { - UseCooldown cooldown = item.getComponent(DataComponentType.USE_COOLDOWN); + UseCooldown cooldown = item.getComponent(DataComponentTypes.USE_COOLDOWN); String cooldownGroup; if (cooldown != null && cooldown.cooldownGroup() != null) { cooldownGroup = cooldown.cooldownGroup().asString(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java index 194194501..1c9f7e8fa 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.entity; +import org.geysermc.geyser.entity.type.Entity; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; -import org.geysermc.geyser.entity.type.Entity; import java.util.function.BiConsumer; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java index bbe94ba95..333304f61 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BundleInventoryTranslator.java @@ -44,7 +44,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.BundleCache; import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.thirdparty.Fraction; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.List; @@ -308,13 +308,13 @@ public final class BundleInventoryTranslator { if (components != null) { // NOTE: this seems to be Java-only, so it can technically cause a bundle weight desync, // but it'll be so rare we can probably ignore it. - List bees = components.get(DataComponentType.BEES); + List bees = components.get(DataComponentTypes.BEES); if (bees != null && !bees.isEmpty()) { // Bees be heavy, I guess. return Fraction.ONE; } } - return Fraction.getFraction(1, itemStack.getComponentElseGet(DataComponentType.MAX_STACK_SIZE, () -> itemStack.asItem().defaultMaxStackSize())); + return Fraction.getFraction(1, itemStack.getComponentElseGet(DataComponentTypes.MAX_STACK_SIZE, () -> itemStack.asItem().defaultMaxStackSize())); } public static int capacityForItemStack(Fraction bundleWeight, GeyserItemStack itemStack) { 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 e6c670eea..21ffdfa96 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 @@ -75,7 +75,8 @@ 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.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; @@ -261,7 +262,7 @@ public abstract class InventoryTranslator { GeyserItemStack javaItem = inventory.getItem(sourceSlot); if (javaItem.asItem() == Items.PLAYER_HEAD && javaItem.hasNonBaseComponents()) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentType.PROFILE)); + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); } } else if (sourceSlot == 5) { //we are probably removing the head, so restore the original skin @@ -1040,7 +1041,7 @@ public abstract class InventoryTranslator { // As of 1.16.210: Bedrock needs confirmation on what the current item durability is. // If 0 is sent, then Bedrock thinks the item is not damaged int durability = 0; - Integer damage = itemStack.getComponent(DataComponentType.DAMAGE); + Integer damage = itemStack.getComponent(DataComponentTypes.DAMAGE); if (damage != null) { durability = ItemUtils.getCorrectBedrockDurability(itemStack.asItem(), damage); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index c5814e336..f62bfbc7c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -43,7 +43,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBookContent; import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; @@ -164,11 +164,11 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator NbtMap blockEntityTag; if (book.hasNonBaseComponents()) { int pages = 0; - WrittenBookContent writtenBookComponents = book.getComponent(DataComponentType.WRITTEN_BOOK_CONTENT); + WrittenBookContent writtenBookComponents = book.getComponent(DataComponentTypes.WRITTEN_BOOK_CONTENT); if (writtenBookComponents != null) { pages = writtenBookComponents.getPages().size(); } else { - WritableBookContent writableBookComponents = book.getComponent(DataComponentType.WRITABLE_BOOK_CONTENT); + WritableBookContent writableBookComponents = book.getComponent(DataComponentTypes.WRITABLE_BOOK_CONTENT); if (writableBookComponents != null) { pages = writableBookComponents.getPages().size(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 9fb407336..d75228f9b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -49,7 +49,7 @@ import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import java.util.ArrayList; @@ -157,9 +157,9 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { inputCopy.setNetId(session.getNextItemNetId()); BannerPatternLayer bannerPatternLayer = BannerItem.getJavaBannerPattern(session, pattern); // TODO if (bannerPatternLayer != null) { - List patternsList = new ArrayList<>(inputCopy.getComponentElseGet(DataComponentType.BANNER_PATTERNS, ArrayList::new)); + List patternsList = new ArrayList<>(inputCopy.getComponentElseGet(DataComponentTypes.BANNER_PATTERNS, ArrayList::new)); patternsList.add(bannerPatternLayer); - inputCopy.getOrCreateComponents().put(DataComponentType.BANNER_PATTERNS, patternsList); + inputCopy.getOrCreateComponents().put(DataComponentTypes.BANNER_PATTERNS, patternsList); } // Set the new item as the output diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 45deacaad..f95bbb7c4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -61,7 +61,7 @@ import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import java.util.Arrays; @@ -110,7 +110,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (i == 5 && item.asItem() == Items.PLAYER_HEAD && item.hasNonBaseComponents()) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponent(DataComponentType.PROFILE)); + FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponent(DataComponentTypes.PROFILE)); } } armorContentPacket.setContents(Arrays.asList(contents)); @@ -154,7 +154,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { // Check for custom skull if (javaItem.asItem() == Items.PLAYER_HEAD && javaItem.hasNonBaseComponents()) { - FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentType.PROFILE)); + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); } else { FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity()); } @@ -523,7 +523,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { dropStack = javaCreativeItem; } else { // Specify custom count - dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getDataComponents()); + dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getDataComponentsPatch()); } ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket((short)-1, dropStack); session.sendDownstreamGamePacket(creativeDropPacket); @@ -581,22 +581,20 @@ public class PlayerInventoryTranslator extends InventoryTranslator { @Override public void closeInventory(GeyserSession session, Inventory inventory) { if (session.isServerRequestedClosePlayerInventory()) { + session.setServerRequestedClosePlayerInventory(false); Vector3i pos = session.getPlayerEntity().getPosition().toInt(); UpdateBlockPacket packet = new UpdateBlockPacket(); packet.setBlockPosition(pos); packet.setDefinition(session.getBlockMappings().getNetherPortalBlock()); packet.setDataLayer(0); - packet.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + packet.getFlags().add(UpdateBlockPacket.Flag.NETWORK); session.sendUpstreamPacket(packet); session.scheduleInEventLoop(() -> { BlockDefinition definition = session.getBlockMappings().getBedrockBlock(session.getGeyser().getWorldManager().blockAt(session, pos)); - - packet.setBlockPosition(pos); packet.setDefinition(definition); packet.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - packet.setDataLayer(0); session.sendUpstreamPacket(packet); }, 50, TimeUnit.MILLISECONDS); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java index c6318c461..d1a265039 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.item; import org.geysermc.mcprotocollib.protocol.data.game.item.component.CustomModelData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import it.unimi.dsi.fastutil.Pair; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -55,7 +55,7 @@ public final class CustomItemTranslator { // TODO 1.21.4 float customModelDataInt = 0; - CustomModelData customModelData = components.get(DataComponentType.CUSTOM_MODEL_DATA); + CustomModelData customModelData = components.get(DataComponentTypes.CUSTOM_MODEL_DATA); if (customModelData != null) { if (!customModelData.floats().isEmpty()) { customModelDataInt = customModelData.floats().get(0); @@ -63,7 +63,7 @@ public final class CustomItemTranslator { } boolean checkDamage = mapping.getJavaItem().defaultMaxDamage() > 0; - int damage = !checkDamage ? 0 : components.getOrDefault(DataComponentType.DAMAGE, 0); + int damage = !checkDamage ? 0 : components.getOrDefault(DataComponentTypes.DAMAGE, 0); boolean unbreakable = checkDamage && !isDamaged(components, damage); for (Pair mappingTypes : customMappings) { @@ -119,7 +119,7 @@ public final class CustomItemTranslator { private static boolean isDamagableItem(DataComponents components) { // mapping.getMaxDamage > 0 should also be checked (return false if not true) but we already check prior to this function - return components.get(DataComponentType.UNBREAKABLE) == null; + return components.get(DataComponentTypes.UNBREAKABLE) == null; } private CustomItemTranslator() { 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 a41c4ee84..f2213bd07 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 @@ -64,7 +64,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeT import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.ModifierOperation; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.AdventureModePredicate; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttributeModifiers; @@ -161,7 +161,7 @@ public final class ItemTranslator { return ItemData.AIR; } // Java item needs to be loaded separately. The mapping for tipped arrow would - return translateToBedrock(session, Registries.JAVA_ITEMS.get().get(stack.getId()), bedrockItem, stack.getAmount(), stack.getDataComponents()) + return translateToBedrock(session, Registries.JAVA_ITEMS.get().get(stack.getId()), bedrockItem, stack.getAmount(), stack.getDataComponentsPatch()) .build(); } @@ -174,22 +174,22 @@ public final class ItemTranslator { // Translate item-specific components javaItem.translateComponentsToBedrock(session, components, nbtBuilder); - Rarity rarity = Rarity.fromId(components.get(DataComponentType.RARITY)); + Rarity rarity = Rarity.fromId(components.get(DataComponentTypes.RARITY)); String customName = getCustomName(session, customComponents, bedrockItem, rarity.getColor(), false, false); if (customName != null) { - PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); // Make custom effect information visible // Ignore when item have "hide_additional_tooltip" component - if (potionContents != null && components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) == null) { + if (potionContents != null && components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) { customName += getPotionEffectInfo(potionContents, session.locale()); } nbtBuilder.setCustomName(customName); } - boolean hideTooltips = components.get(DataComponentType.HIDE_TOOLTIP) != null; + boolean hideTooltips = components.get(DataComponentTypes.HIDE_TOOLTIP) != null; - ItemAttributeModifiers attributeModifiers = components.get(DataComponentType.ATTRIBUTE_MODIFIERS); + ItemAttributeModifiers attributeModifiers = components.get(DataComponentTypes.ATTRIBUTE_MODIFIERS); if (attributeModifiers != null && attributeModifiers.isShowInTooltip() && !hideTooltips) { // only add if attribute modifiers do not indicate to hide them addAttributeLore(session, attributeModifiers, nbtBuilder, session.locale()); @@ -200,7 +200,7 @@ public final class ItemTranslator { } // Add enchantment override. We can't remove it - enchantments would stop showing - but we can add it. - if (components.getOrDefault(DataComponentType.ENCHANTMENT_GLINT_OVERRIDE, false) && !GLINT_PRESENT.contains(javaItem)) { + if (components.getOrDefault(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, false) && !GLINT_PRESENT.contains(javaItem)) { NbtMapBuilder nbtMapBuilder = nbtBuilder.getOrCreateNbt(); nbtMapBuilder.putIfAbsent("ench", NbtList.EMPTY); } @@ -219,14 +219,14 @@ public final class ItemTranslator { } if (bedrockItem.getJavaItem().equals(Items.PLAYER_HEAD)) { - translatePlayerHead(session, components.get(DataComponentType.PROFILE), builder); + translatePlayerHead(session, components.get(DataComponentTypes.PROFILE), builder); } translateCustomItem(components, builder, bedrockItem); // Translate the canDestroy and canPlaceOn Java components - AdventureModePredicate canDestroy = components.get(DataComponentType.CAN_BREAK); - AdventureModePredicate canPlaceOn = components.get(DataComponentType.CAN_PLACE_ON); + AdventureModePredicate canDestroy = components.get(DataComponentTypes.CAN_BREAK); + AdventureModePredicate canPlaceOn = components.get(DataComponentTypes.CAN_PLACE_ON); String[] canBreak = getCanModify(session, canDestroy); String[] canPlace = getCanModify(session, canPlaceOn); if (canBreak != null) { @@ -422,7 +422,7 @@ public final class ItemTranslator { int maxDurability = item.defaultMaxDamage(); if (maxDurability != 0 && components != null) { - Integer durabilityComponent = components.get(DataComponentType.DAMAGE); + Integer durabilityComponent = components.get(DataComponentTypes.DAMAGE); if (durabilityComponent != null) { int durability = maxDurability - durabilityComponent; if (durability != maxDurability) { @@ -516,7 +516,7 @@ public final class ItemTranslator { } if (mapping.getJavaItem().equals(Items.PLAYER_HEAD)) { - CustomSkull customSkull = getCustomSkull(itemStack.getComponent(DataComponentType.PROFILE)); + CustomSkull customSkull = getCustomSkull(itemStack.getComponent(DataComponentTypes.PROFILE)); if (customSkull != null) { itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customSkull.getCustomBlockData()); } @@ -538,26 +538,26 @@ public final class ItemTranslator { public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor, boolean customNameOnly, boolean includeAll) { if (components != null) { // ItemStack#getHoverName as of 1.20.5 - Component customName = components.get(DataComponentType.CUSTOM_NAME); + Component customName = components.get(DataComponentTypes.CUSTOM_NAME); if (customName != null) { return MessageTranslator.convertMessage(customName, session.locale()); } if (!customNameOnly) { - PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); + PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); if (potionContents != null) { - String potionName = getPotionName(potionContents, mapping, components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) != null, session.locale()); + String potionName = getPotionName(potionContents, mapping, components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) != null, session.locale()); if (potionName != null) { return ChatColor.RESET + ChatColor.ESCAPE + translationColor + potionName; } } if (includeAll) { // Fix book title display in tooltips of shulker box - WrittenBookContent bookContent = components.get(DataComponentType.WRITTEN_BOOK_CONTENT); + WrittenBookContent bookContent = components.get(DataComponentTypes.WRITTEN_BOOK_CONTENT); if (bookContent != null) { return ChatColor.RESET + ChatColor.ESCAPE + translationColor + bookContent.getTitle().getRaw(); } } - customName = components.get(DataComponentType.ITEM_NAME); + customName = components.get(DataComponentTypes.ITEM_NAME); if (customName != null) { // Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition // behavior as of 1.21 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java index 81be5b33a..46a4b78bf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java @@ -43,7 +43,7 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.ItemTranslator; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -132,7 +132,7 @@ public class VaultBlockEntityTranslator extends BlockEntityTranslator { "minecraft:potion_contents", (session, tag, components) -> { String potionId = tag.getString("potion"); Potion potion = Potion.getByJavaIdentifier(potionId); - components.put(DataComponentType.POTION_CONTENTS, potion.toComponent()); + components.put(DataComponentTypes.POTION_CONTENTS, potion.toComponent()); }, "minecraft:enchantments", (session, tag, components) -> { // Enchanted books already have glint. Translating them doesn't matter. NbtMap levels = tag.getCompound("levels"); @@ -145,6 +145,6 @@ public class VaultBlockEntityTranslator extends BlockEntityTranslator { } } } - components.put(DataComponentType.ENCHANTMENTS, new ItemEnchantments(enchantments, true)); + components.put(DataComponentTypes.ENCHANTMENTS, new ItemEnchantments(enchantments, true)); }); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java index 700ba0532..e1ab6d242 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBookEditTranslator.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Filterable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBookContent; @@ -57,7 +57,7 @@ public class BedrockBookEditTranslator extends PacketTranslator ItemStack bookItem = new ItemStack(itemStack.getJavaId(), itemStack.getAmount(), components); List pages = new LinkedList<>(); - WritableBookContent writableBookContent = components.get(DataComponentType.WRITABLE_BOOK_CONTENT); + WritableBookContent writableBookContent = components.get(DataComponentTypes.WRITABLE_BOOK_CONTENT); if (writableBookContent != null) { for (Filterable page : writableBookContent.getPages()) { pages.add(page.getRaw()); @@ -125,7 +125,7 @@ public class BedrockBookEditTranslator extends PacketTranslator for (String raw : pages) { filterablePages.add(new Filterable<>(raw, null)); } - components.put(DataComponentType.WRITABLE_BOOK_CONTENT, new WritableBookContent(filterablePages)); + components.put(DataComponentTypes.WRITABLE_BOOK_CONTENT, new WritableBookContent(filterablePages)); // Update local copy session.getPlayerInventory().setItem(36 + session.getPlayerInventory().getHeldItemSlot(), GeyserItemStack.from(bookItem), session); 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 db1a05011..2a3d1eb57 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 @@ -85,7 +85,7 @@ 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.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; @@ -385,7 +385,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator holder = session.getPlayerInventory() .getItemInHand() - .getComponent(DataComponentType.INSTRUMENT); + .getComponent(DataComponentTypes.INSTRUMENT); if (holder != null) { GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder); if (instrument.bedrockInstrument() != null) { 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 index 8e83c9f55..332ef32db 100644 --- 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 @@ -225,7 +225,7 @@ public class JavaRecipeBookAddTranslator extends PacketTranslator= other.getAmount() - && Objects.equals(itemStack.getComponents(), other.getDataComponents()); + && Objects.equals(itemStack.getComponents(), other.getDataComponentsPatch()); } if (slotDisplay instanceof TagSlotDisplay tagSlotDisplay) { return session.getTagCache().is(new Tag<>(JavaRegistries.ITEM, tagSlotDisplay.tag()), itemStack.asItem()); diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index eca9756e6..6206da048 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -34,7 +34,7 @@ import org.geysermc.geyser.item.type.FishingRodItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; 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.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; @@ -51,7 +51,7 @@ public final class ItemUtils { return 0; } - ItemEnchantments enchantmentData = components.get(DataComponentType.ENCHANTMENTS); + ItemEnchantments enchantmentData = components.get(DataComponentTypes.ENCHANTMENTS); if (enchantmentData == null) { return 0; } @@ -69,12 +69,12 @@ public final class ItemUtils { if (itemStack == null) { return false; } - DataComponents components = itemStack.getDataComponents(); + DataComponents components = itemStack.getDataComponentsPatch(); if (components == null) { return false; } - ItemEnchantments enchantmentData = components.get(DataComponentType.ENCHANTMENTS); + ItemEnchantments enchantmentData = components.get(DataComponentTypes.ENCHANTMENTS); if (enchantmentData == null) { return false; } 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 e01ea7cd3..2ad0ca8ad 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 @@ -45,7 +45,7 @@ import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntryAction; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataTypes; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; @@ -213,9 +213,9 @@ public class ScoreboardIssueTests { // metadata set: invisible, custom name, custom name visible context.translate(setEntityDataTranslator, new ClientboundSetEntityDataPacket(1298, new EntityMetadata[]{ - new ByteEntityMetadata(0, MetadataType.BYTE, (byte) 0x20), - new ObjectEntityMetadata<>(2, MetadataType.OPTIONAL_CHAT, Optional.of(Component.text("tesss"))), - new BooleanEntityMetadata(3, MetadataType.BOOLEAN, true) + new ByteEntityMetadata(0, MetaDataTypes.BYTE, (byte) 0x20), + new ObjectEntityMetadata<>(2, MetaDataTypes.OPTIONAL_CHAT, Optional.of(Component.text("tesss"))), + new BooleanEntityMetadata(3, MetaDataTypes.BOOLEAN, true) })); assertNextPacketMatch(context, SetEntityDataPacket.class, packet -> { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f9bfd758e..3ab475829 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta6-20250212.131009-3" protocol-codec = "3.0.0.Beta6-20250212.131009-3" raknet = "1.0.0.CR3-20250128.101054-17" minecraftauth = "4.1.1" -mcprotocollib = "1.21.4-20250216.154737-20" +mcprotocollib = "1.21.4-20250218.175633-22" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From ebaaed7542e681955330696985bd4326a4d15b45 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Wed, 19 Feb 2025 14:46:46 +0100 Subject: [PATCH 549/897] fix test --- .../geyser/scoreboard/network/ScoreboardIssueTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 2ad0ca8ad..2239c9819 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 @@ -213,9 +213,9 @@ public class ScoreboardIssueTests { // metadata set: invisible, custom name, custom name visible context.translate(setEntityDataTranslator, new ClientboundSetEntityDataPacket(1298, new EntityMetadata[]{ - new ByteEntityMetadata(0, MetaDataTypes.BYTE, (byte) 0x20), - new ObjectEntityMetadata<>(2, MetaDataTypes.OPTIONAL_CHAT, Optional.of(Component.text("tesss"))), - new BooleanEntityMetadata(3, MetaDataTypes.BOOLEAN, true) + new ByteEntityMetadata(0, MetadataTypes.BYTE, (byte) 0x20), + new ObjectEntityMetadata<>(2, MetadataTypes.OPTIONAL_CHAT, Optional.of(Component.text("tesss"))), + new BooleanEntityMetadata(3, MetadataTypes.BOOLEAN, true) })); assertNextPacketMatch(context, SetEntityDataPacket.class, packet -> { From fd4c80598ed40c2069b2ccc83c39e3fe1cc46aef Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 20 Feb 2025 17:01:39 +0100 Subject: [PATCH 550/897] Fix skins not showing on 1.21.60 --- .../geyser/session/GeyserSession.java | 10 +++++-- .../geyser/skin/FakeHeadProvider.java | 30 ++++++++++++------- .../org/geysermc/geyser/skin/SkinManager.java | 25 +++++++++------- .../geyser/skin/SkullSkinManager.java | 22 ++++++++------ .../inventory/InventoryTranslator.java | 5 ++-- .../inventory/PlayerInventoryTranslator.java | 18 ++++++++--- 6 files changed, 70 insertions(+), 40 deletions(-) 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 3e18a2829..261e57aed 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -35,7 +35,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -94,6 +93,7 @@ import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetCommandsEnabledPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket; import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket; import org.cloudburstmc.protocol.bedrock.packet.SyncEntityPropertyPacket; @@ -331,10 +331,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final Map itemFrameCache = new Object2ObjectOpenHashMap<>(); /** - * A list of all players that have a player head on with a custom texture. + * A map of all players (and their heads) that are wearing a player head with a custom texture. * Our workaround for these players is to give them a custom skin and geometry to emulate wearing a custom skull. */ - private final Set playerWithCustomHeads = new ObjectOpenHashSet<>(); + private final Map playerWithCustomHeads = new Object2ObjectOpenHashMap<>(); @Setter private boolean droppingLecternBook; @@ -787,6 +787,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); upstream.sendPacket(playStatusPacket); + SetCommandsEnabledPacket setCommandsEnabledPacket = new SetCommandsEnabledPacket(); + setCommandsEnabledPacket.setCommandsEnabled(!geyser.getConfig().isXboxAchievementsEnabled()); + upstream.sendPacket(setCommandsEnabledPacket); + UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); attributesPacket.setRuntimeEntityId(getPlayerEntity().getGeyserId()); // Default move speed diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index 2434d6d91..12f002025 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java @@ -109,6 +109,12 @@ public class FakeHeadProvider { return; } + GameProfile current = session.getPlayerWithCustomHeads().get(entity.getUuid()); + if (profile.equals(current)) { + // We already did this, no need to re-compute + return; + } + Map textures; try { textures = profile.getTextures(false); @@ -118,7 +124,7 @@ public class FakeHeadProvider { } if (textures == null || textures.isEmpty()) { - loadHead(session, entity, profile.getName()); + loadHeadFromProfile(session, entity, profile); return; } @@ -133,16 +139,18 @@ public class FakeHeadProvider { boolean isAlex = skinTexture.getModel() == TextureModel.SLIM; - loadHead(session, entity, new GameProfileData(skinTexture.getURL(), capeUrl, isAlex)); + loadHeadFromProfile(session, entity, new GameProfileData(skinTexture.getURL(), capeUrl, isAlex), profile); } - public static void loadHead(GeyserSession session, PlayerEntity entity, String owner) { - if (owner == null || owner.isEmpty()) { - return; + public static void loadHeadFromProfile(GeyserSession session, PlayerEntity entity, GameProfile profile) { + CompletableFuture texturesFuture; + if (profile.getId() != null) { + texturesFuture = SkinProvider.requestTexturesFromUUID(profile.getId().toString()); + } else { + texturesFuture = SkinProvider.requestTexturesFromUsername(profile.getName()); } - CompletableFuture completableFuture = SkinProvider.requestTexturesFromUsername(owner); - completableFuture.whenCompleteAsync((encodedJson, throwable) -> { + texturesFuture.whenCompleteAsync((encodedJson, throwable) -> { if (throwable != null) { GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), throwable); return; @@ -152,17 +160,17 @@ public class FakeHeadProvider { if (gameProfileData == null) { return; } - loadHead(session, entity, gameProfileData); + loadHeadFromProfile(session, entity, gameProfileData, profile); } catch (IOException e) { GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.skin.fail", entity.getUuid(), e.getMessage())); } }); } - public static void loadHead(GeyserSession session, PlayerEntity entity, SkinManager.GameProfileData gameProfileData) { + public static void loadHeadFromProfile(GeyserSession session, PlayerEntity entity, SkinManager.GameProfileData gameProfileData, GameProfile profile) { String fakeHeadSkinUrl = gameProfileData.skinUrl(); - session.getPlayerWithCustomHeads().add(entity.getUuid()); + session.getPlayerWithCustomHeads().put(entity.getUuid(), profile); String texturesProperty = entity.getTexturesProperty(); SkinProvider.getExecutorService().execute(() -> { try { @@ -179,7 +187,7 @@ public class FakeHeadProvider { return; } - if (!session.getPlayerWithCustomHeads().remove(entity.getUuid())) { + if (session.getPlayerWithCustomHeads().remove(entity.getUuid()) == null) { return; } diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java index 4c3db7504..8d4090ee4 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java @@ -47,7 +47,6 @@ import org.geysermc.geyser.text.GeyserLocale; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Base64; -import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.function.Consumer; @@ -102,7 +101,7 @@ public class SkinManager { Skin skin, Cape cape, SkinGeometry geometry) { - SerializedSkin serializedSkin = getSkin(skin.textureUrl(), skin, cape, geometry); + SerializedSkin serializedSkin = getSkin(session, skin.textureUrl(), skin, cape, geometry); // This attempts to find the XUID of the player so profile images show up for Xbox accounts String xuid = ""; @@ -138,7 +137,6 @@ public class SkinManager { SkinGeometry geometry = skinData.geometry(); if (entity.getUuid().equals(session.getPlayerEntity().getUuid())) { - // TODO is this special behavior needed? PlayerListPacket.Entry updatedEntry = buildEntryManually( session, entity.getUuid(), @@ -158,17 +156,24 @@ public class SkinManager { packet.setUuid(entity.getUuid()); packet.setOldSkinName(""); packet.setNewSkinName(skin.textureUrl()); - packet.setSkin(getSkin(skin.textureUrl(), skin, cape, geometry)); + packet.setSkin(getSkin(session, skin.textureUrl(), skin, cape, geometry)); packet.setTrustedSkin(true); session.sendUpstreamPacket(packet); } } - private static SerializedSkin getSkin(String skinId, Skin skin, Cape cape, SkinGeometry geometry) { - return SerializedSkin.of(skinId, "", geometry.geometryName(), - ImageData.of(skin.skinData()), Collections.emptyList(), - ImageData.of(cape.capeData()), geometry.geometryData(), - "", true, false, false, cape.capeId(), skinId); + private static SerializedSkin getSkin(GeyserSession session, String skinId, Skin skin, Cape cape, SkinGeometry geometry) { + return SerializedSkin.builder() + .skinId(skinId) + .skinResourcePatch(geometry.geometryName()) + .skinData(ImageData.of(skin.skinData())) + .capeData(ImageData.of(cape.capeData())) + .geometryData(geometry.geometryData()) + .premium(true) + .capeId(cape.capeId()) + .fullSkinId(skinId) + .geometryDataEngineVersion(session.getClientData().getGameVersion()) + .build(); } public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSession session, @@ -334,4 +339,4 @@ public class SkinManager { private static final String DEFAULT_FLOODGATE_STEVE = "https://textures.minecraft.net/texture/31f477eb1a7beee631c2ca64d06f8f68fa93a3386d04452ab27f43acdf1b60cb"; } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java index e3f00d3b7..41e4025f1 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java @@ -35,20 +35,24 @@ import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; -import java.util.Collections; import java.util.function.BiConsumer; import java.util.function.Consumer; public class SkullSkinManager extends SkinManager { - public static SerializedSkin buildSkullEntryManually(String skinId, byte[] skinData) { - // Prevents https://cdn.discordapp.com/attachments/613194828359925800/779458146191147008/unknown.png + public static SerializedSkin buildSkullEntryManually(GeyserSession session, String skinId, byte[] skinData) { skinId = skinId + "_skull"; - return SerializedSkin.of( - skinId, "", SkinProvider.SKULL_GEOMETRY.geometryName(), ImageData.of(skinData), Collections.emptyList(), - ImageData.of(SkinProvider.EMPTY_CAPE.capeData()), SkinProvider.SKULL_GEOMETRY.geometryData(), - "", true, false, false, SkinProvider.EMPTY_CAPE.capeId(), skinId - ); + return SerializedSkin.builder() + .skinId(skinId) + .skinResourcePatch(SkinProvider.SKULL_GEOMETRY.geometryName()) + .skinData(ImageData.of(skinData)) + .capeData(ImageData.of(SkinProvider.EMPTY_CAPE.capeData())) + .geometryData(SkinProvider.SKULL_GEOMETRY.geometryData()) + .premium(true) + .capeId(SkinProvider.EMPTY_CAPE.capeId()) + .fullSkinId(skinId) + .geometryDataEngineVersion(session.getClientData().getGameVersion()) + .build(); } public static void requestAndHandleSkin(SkullPlayerEntity entity, GeyserSession session, @@ -59,7 +63,7 @@ public class SkullSkinManager extends SkinManager { packet.setUuid(entity.getUuid()); packet.setOldSkinName(""); packet.setNewSkinName(skin.textureUrl()); - packet.setSkin(buildSkullEntryManually(skin.textureUrl(), skin.skinData())); + packet.setSkin(buildSkullEntryManually(session, skin.textureUrl(), skin.skinData())); packet.setTrustedSkin(true); session.sendUpstreamPacket(packet); } catch (Exception e) { 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 21ffdfa96..6394c5312 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 @@ -76,7 +76,6 @@ 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.component.DataComponentTypes; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; @@ -258,14 +257,14 @@ public abstract class InventoryTranslator { if (this instanceof PlayerInventoryTranslator) { if (destSlot == 5) { - //only set the head if the destination is the head slot + // only set the head if the destination is the head slot GeyserItemStack javaItem = inventory.getItem(sourceSlot); if (javaItem.asItem() == Items.PLAYER_HEAD && javaItem.hasNonBaseComponents()) { FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); } } else if (sourceSlot == 5) { - //we are probably removing the head, so restore the original skin + // we are probably removing the head, so restore the original skin FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index f95bbb7c4..7064f1169 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -279,9 +279,22 @@ public class PlayerInventoryTranslator extends InventoryTranslator { return bundleResponse; } + int sourceSlot = bedrockSlotToJava(transferAction.getSource()); + int destSlot = bedrockSlotToJava(transferAction.getDestination()); + if (destSlot == 5) { + // only set the head if the destination is the head slot + GeyserItemStack javaItem = inventory.getItem(sourceSlot); + if (javaItem.asItem() == Items.PLAYER_HEAD + && javaItem.hasNonBaseComponents()) { + FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); + } + } else if (sourceSlot == 5) { + // we are probably removing the head, so restore the original skin + FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity()); + } + int transferAmount = transferAction.getCount(); if (isCursor(transferAction.getDestination())) { - int sourceSlot = bedrockSlotToJava(transferAction.getSource()); GeyserItemStack sourceItem = inventory.getItem(sourceSlot); if (playerInv.getCursor().isEmpty()) { playerInv.setCursor(sourceItem.copy(0), session); @@ -294,7 +307,6 @@ public class PlayerInventoryTranslator extends InventoryTranslator { affectedSlots.add(sourceSlot); } else if (isCursor(transferAction.getSource())) { - int destSlot = bedrockSlotToJava(transferAction.getDestination()); GeyserItemStack sourceItem = playerInv.getCursor(); if (inventory.getItem(destSlot).isEmpty()) { inventory.setItem(destSlot, sourceItem.copy(0), session); @@ -307,8 +319,6 @@ public class PlayerInventoryTranslator extends InventoryTranslator { affectedSlots.add(destSlot); } else { - int sourceSlot = bedrockSlotToJava(transferAction.getSource()); - int destSlot = bedrockSlotToJava(transferAction.getDestination()); GeyserItemStack sourceItem = inventory.getItem(sourceSlot); if (inventory.getItem(destSlot).isEmpty()) { inventory.setItem(destSlot, sourceItem.copy(0), session); From 07be40256369e8a1cfb3dc464af065391c326d19 Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Sat, 22 Feb 2025 12:31:37 +0100 Subject: [PATCH 551/897] Add run tasks and remove useless variables (#5362) * Add run tasks and remove useless variables The benefit of run tasks is that proxies like velocity can be prototyped on without using standalone or a GUI. Thus simplifying the prototyping/fixing process. * Drop runwaterfall --- bootstrap/spigot/build.gradle.kts | 7 +++++++ bootstrap/standalone/build.gradle.kts | 3 --- bootstrap/velocity/build.gradle.kts | 7 +++++++ gradle/libs.versions.toml | 5 +++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index feabfdd7a..3a6c6b976 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("geyser.platform-conventions") id("geyser.modrinth-uploading-conventions") + alias(libs.plugins.runpaper) } dependencies { @@ -90,3 +91,9 @@ modrinth { "1.19.1", "1.19.2", "1.19.3", "1.19.4", "1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4", "1.20.5", "1.20.6") loaders.addAll("spigot", "paper") } + +tasks { + runServer { + minecraftVersion(libs.versions.runpaperversion.get()) + } +} diff --git a/bootstrap/standalone/build.gradle.kts b/bootstrap/standalone/build.gradle.kts index b210693c1..e794c266c 100644 --- a/bootstrap/standalone/build.gradle.kts +++ b/bootstrap/standalone/build.gradle.kts @@ -5,9 +5,6 @@ plugins { id("geyser.platform-conventions") } -val terminalConsoleVersion = "1.2.0" -val jlineVersion = "3.21.0" - dependencies { api(projects.core) diff --git a/bootstrap/velocity/build.gradle.kts b/bootstrap/velocity/build.gradle.kts index 05035e271..eec6c23d6 100644 --- a/bootstrap/velocity/build.gradle.kts +++ b/bootstrap/velocity/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("geyser.platform-conventions") id("geyser.modrinth-uploading-conventions") + alias(libs.plugins.runvelocity) } dependencies { @@ -83,3 +84,9 @@ modrinth { uploadFile.set(tasks.getByPath("shadowJar")) loaders.addAll("velocity") } + +tasks { + runVelocity { + version(libs.versions.runvelocityversion.get()) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ab475829..15691e2d9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,6 +41,9 @@ mixin = "0.8.5" mixinextras = "0.3.5" minecraft = "1.21.4" mockito = "5.+" +runtask = "2.3.1" +runpaperversion = "1.21.4" +runvelocityversion = "3.4.0-SNAPSHOT" # plugin versions indra = "3.1.3" @@ -150,6 +153,8 @@ minotaur = { group = "com.modrinth.minotaur", name = "Minotaur", version.ref = " [plugins] indra = { id = "net.kyori.indra", version.ref = "indra" } blossom = { id = "net.kyori.blossom", version.ref = "blossom" } +runvelocity = { id = "xyz.jpenilla.run-velocity", version.ref = "runtask" } +runpaper = { id = "xyz.jpenilla.run-paper", version.ref = "runtask" } [bundles] jackson = [ "jackson-annotations", "jackson-databind", "jackson-dataformat-yaml" ] From 87d9907413e30c96d588d2c7257e0f590cd169c4 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 23 Feb 2025 18:37:01 +0100 Subject: [PATCH 552/897] Increase packet limits for multiple connected clients playing from one IP address (#5351) * Fix https://github.com/GeyserMC/Geyser/issues/4926 * Extend the RakServerRateLimiter, now that it is possible * Update core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java * cast to int --- .../geyser/network/netty/GeyserServer.java | 4 ++ .../netty/handler/RakGeyserRateLimiter.java | 50 +++++++++++++++++++ .../geyser/session/SessionManager.java | 35 ++++++++++++- gradle/libs.versions.toml | 2 +- 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index efbd8bdff..fec254996 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -59,6 +59,7 @@ import org.geysermc.geyser.network.CIDRMatcher; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.GeyserServerInitializer; import org.geysermc.geyser.network.netty.handler.RakConnectionRequestHandler; +import org.geysermc.geyser.network.netty.handler.RakGeyserRateLimiter; import org.geysermc.geyser.network.netty.handler.RakPingHandler; import org.geysermc.geyser.network.netty.proxy.ProxyServerHandler; import org.geysermc.geyser.ping.GeyserPingInfo; @@ -175,6 +176,9 @@ public final class GeyserServer { if (Boolean.parseBoolean(System.getProperty("Geyser.RakRateLimitingDisabled", "false")) || isWhitelistedProxyProtocol) { // We would already block any non-whitelisted IP addresses in onConnectionRequest so we can remove the rate limiter channel.pipeline().remove(RakServerRateLimiter.NAME); + } else { + // Use our own rate limiter to allow multiple players from the same IP + channel.pipeline().replace(RakServerRateLimiter.NAME, RakGeyserRateLimiter.NAME, new RakGeyserRateLimiter(channel)); } } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java new file mode 100644 index 000000000..65e66eb33 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019-2025 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.network.netty.handler; + +import io.netty.channel.Channel; +import org.cloudburstmc.netty.channel.raknet.RakServerChannel; +import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerRateLimiter; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.session.SessionManager; + +import java.net.InetAddress; + +public class RakGeyserRateLimiter extends RakServerRateLimiter { + public static final String NAME = "rak-geyser-rate-limiter"; + private final SessionManager sessionManager; + + public RakGeyserRateLimiter(Channel channel) { + super((RakServerChannel) channel); + this.sessionManager = GeyserImpl.getInstance().getSessionManager(); + } + + @Override + protected int getAddressMaxPacketCount(InetAddress address) { + // Using a factor of 0.8 for now, as the default packet count is already padded for multiple + return (int) (super.getAddressMaxPacketCount(address) * sessionManager.getAddressMultiplier(address) * 0.8); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java index 14881d059..2175e3aaa 100644 --- a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java @@ -32,8 +32,15 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.text.GeyserLocale; -import java.util.*; +import java.net.InetAddress; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; public final class SessionManager { /** @@ -47,6 +54,13 @@ public final class SessionManager { @Getter private final Map sessions = new ConcurrentHashMap<>(); + /** + * Stores the number of connected sessions per address they're connected from. + * Used to raise per-IP connection limits. + */ + @Getter(AccessLevel.PACKAGE) + private final Map connectedClients = new ConcurrentHashMap<>(); + /** * Called once the player has successfully authenticated to the Geyser server. */ @@ -60,6 +74,14 @@ public final class SessionManager { public void addSession(UUID uuid, GeyserSession session) { pendingSessions.remove(session); sessions.put(uuid, session); + connectedClients.compute(session.getSocketAddress().getAddress(), (key, count) -> { + if (count == null) { + return new AtomicInteger(0); + } + + count.getAndIncrement(); + return count; + }); } public void removeSession(GeyserSession session) { @@ -68,6 +90,17 @@ public final class SessionManager { // Connection was likely pending pendingSessions.remove(session); } + connectedClients.computeIfPresent(session.getSocketAddress().getAddress(), (key, count) -> { + if (count.decrementAndGet() <= 0) { + return null; + } + return count; + }); + } + + public int getAddressMultiplier(InetAddress ip) { + AtomicInteger atomicInteger = connectedClients.get(ip); + return atomicInteger == null ? 1 : atomicInteger.get(); } public @Nullable GeyserSession sessionByXuid(@NonNull String xuid) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 15691e2d9..ae35c6e34 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ websocket = "1.5.1" protocol-connection = "3.0.0.Beta6-20250212.131009-3" protocol-common = "3.0.0.Beta6-20250212.131009-3" protocol-codec = "3.0.0.Beta6-20250212.131009-3" -raknet = "1.0.0.CR3-20250128.101054-17" +raknet = "1.0.0.CR3-20250218.160705-18" minecraftauth = "4.1.1" mcprotocollib = "1.21.4-20250218.175633-22" adventure = "4.14.0" From f0657c0d86eb7ff392016674f96703809f08caa4 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 23 Feb 2025 20:25:44 +0100 Subject: [PATCH 553/897] Don't restrict the default packet limit --- .../geyser/network/netty/handler/RakGeyserRateLimiter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java index 65e66eb33..2e6f9be79 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java @@ -44,7 +44,6 @@ public class RakGeyserRateLimiter extends RakServerRateLimiter { @Override protected int getAddressMaxPacketCount(InetAddress address) { - // Using a factor of 0.8 for now, as the default packet count is already padded for multiple - return (int) (super.getAddressMaxPacketCount(address) * sessionManager.getAddressMultiplier(address) * 0.8); + return super.getAddressMaxPacketCount(address) * sessionManager.getAddressMultiplier(address); } } From 9733311508a249e32a915e67e6569d177abcd59f Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 23 Feb 2025 21:10:05 +0100 Subject: [PATCH 554/897] Revert latest Geyser changes --- .../org/geysermc/geyser/network/netty/GeyserServer.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index fec254996..fd26b63e1 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -59,7 +59,6 @@ import org.geysermc.geyser.network.CIDRMatcher; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.GeyserServerInitializer; import org.geysermc.geyser.network.netty.handler.RakConnectionRequestHandler; -import org.geysermc.geyser.network.netty.handler.RakGeyserRateLimiter; import org.geysermc.geyser.network.netty.handler.RakPingHandler; import org.geysermc.geyser.network.netty.proxy.ProxyServerHandler; import org.geysermc.geyser.ping.GeyserPingInfo; @@ -176,10 +175,11 @@ public final class GeyserServer { if (Boolean.parseBoolean(System.getProperty("Geyser.RakRateLimitingDisabled", "false")) || isWhitelistedProxyProtocol) { // We would already block any non-whitelisted IP addresses in onConnectionRequest so we can remove the rate limiter channel.pipeline().remove(RakServerRateLimiter.NAME); - } else { - // Use our own rate limiter to allow multiple players from the same IP - channel.pipeline().replace(RakServerRateLimiter.NAME, RakGeyserRateLimiter.NAME, new RakGeyserRateLimiter(channel)); } +// else { +// // Use our own rate limiter to allow multiple players from the same IP +// channel.pipeline().replace(RakServerRateLimiter.NAME, RakGeyserRateLimiter.NAME, new RakGeyserRateLimiter(channel)); +// } } public void shutdown() { From 2b17a03bdf93aff7d7963e3fe7541708e927ddad Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 25 Feb 2025 21:38:29 +0100 Subject: [PATCH 555/897] Fix: Horses not taking fall damage when they should fixes https://github.com/GeyserMC/Geyser/issues/5269 --- .../geyser/entity/type/LivingEntity.java | 4 ---- .../geyser/network/netty/GeyserServer.java | 8 ++++---- .../netty/handler/RakGeyserRateLimiter.java | 3 ++- .../geysermc/geyser/session/SessionManager.java | 16 ++++++++-------- .../entity/player/input/BedrockMovePlayer.java | 2 +- .../input/BedrockPlayerAuthInputTranslator.java | 2 ++ 6 files changed, 17 insertions(+), 18 deletions(-) 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 ca9dca6e0..8c1ab80f0 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 @@ -160,10 +160,6 @@ public class LivingEntity extends Entity { updateNametag(team, team == null || team.isVisibleFor(session.getPlayerEntity().getUsername())); } - public void hideNametag() { - setNametag("", false); - } - public void setLivingEntityFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index fd26b63e1..fec254996 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -59,6 +59,7 @@ import org.geysermc.geyser.network.CIDRMatcher; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.GeyserServerInitializer; import org.geysermc.geyser.network.netty.handler.RakConnectionRequestHandler; +import org.geysermc.geyser.network.netty.handler.RakGeyserRateLimiter; import org.geysermc.geyser.network.netty.handler.RakPingHandler; import org.geysermc.geyser.network.netty.proxy.ProxyServerHandler; import org.geysermc.geyser.ping.GeyserPingInfo; @@ -175,11 +176,10 @@ public final class GeyserServer { if (Boolean.parseBoolean(System.getProperty("Geyser.RakRateLimitingDisabled", "false")) || isWhitelistedProxyProtocol) { // We would already block any non-whitelisted IP addresses in onConnectionRequest so we can remove the rate limiter channel.pipeline().remove(RakServerRateLimiter.NAME); + } else { + // Use our own rate limiter to allow multiple players from the same IP + channel.pipeline().replace(RakServerRateLimiter.NAME, RakGeyserRateLimiter.NAME, new RakGeyserRateLimiter(channel)); } -// else { -// // Use our own rate limiter to allow multiple players from the same IP -// channel.pipeline().replace(RakServerRateLimiter.NAME, RakGeyserRateLimiter.NAME, new RakGeyserRateLimiter(channel)); -// } } public void shutdown() { diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java index 2e6f9be79..7ccf8fdfb 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java @@ -44,6 +44,7 @@ public class RakGeyserRateLimiter extends RakServerRateLimiter { @Override protected int getAddressMaxPacketCount(InetAddress address) { - return super.getAddressMaxPacketCount(address) * sessionManager.getAddressMultiplier(address); + // The default packet limit is already padded, so we reduce it by 20% + return (int) (super.getAddressMaxPacketCount(address) * sessionManager.getAddressMultiplier(address) * 0.8); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java index 2175e3aaa..14d2a2eff 100644 --- a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java @@ -66,6 +66,14 @@ public final class SessionManager { */ public void addPendingSession(GeyserSession session) { pendingSessions.add(session); + connectedClients.compute(session.getSocketAddress().getAddress(), (key, count) -> { + if (count == null) { + return new AtomicInteger(1); + } + + count.incrementAndGet(); + return count; + }); } /** @@ -74,14 +82,6 @@ public final class SessionManager { public void addSession(UUID uuid, GeyserSession session) { pendingSessions.remove(session); sessions.put(uuid, session); - connectedClients.compute(session.getSocketAddress().getAddress(), (key, count) -> { - if (count == null) { - return new AtomicInteger(0); - } - - count.getAndIncrement(); - return count; - }); } public void removeSession(GeyserSession session) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java index ce8afa269..ac5a62802 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java @@ -76,7 +76,7 @@ final class BedrockMovePlayer { boolean hasVehicle = entity.getVehicle() != null; // shouldSendPositionReminder also increments a tick counter, so make sure it's always called unless the player is on a vehicle. - boolean positionChanged = !hasVehicle && session.getInputCache().shouldSendPositionReminder() || actualPositionChanged; + boolean positionChanged = !hasVehicle && (session.getInputCache().shouldSendPositionReminder() || actualPositionChanged); boolean rotationChanged = hasVehicle || (entity.getYaw() != yaw || entity.getPitch() != pitch || entity.getHeadYaw() != headYaw); if (session.getLookBackScheduledFuture() != null) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java index b57187018..ee5a0dadb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java @@ -285,6 +285,8 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator Date: Tue, 25 Feb 2025 22:07:47 +0100 Subject: [PATCH 556/897] Properly translate infinite effects, ensure specific hud elements are hidden when logging in with spectator mode --- .../geyser/impl/camera/GeyserCameraData.java | 14 ++++++++------ .../protocol/java/JavaLoginTranslator.java | 2 +- .../java/entity/JavaUpdateMobEffectTranslator.java | 8 +------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java index 7582502b3..beb10db86 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java @@ -66,12 +66,14 @@ public class GeyserCameraData implements CameraData { * Helps with tidying up the GUI; Java-style. */ private static final GuiElement[] SPECTATOR_HIDDEN_ELEMENTS = { - GuiElement.AIR_BUBBLES_BAR, - GuiElement.ARMOR, - GuiElement.HEALTH, - GuiElement.FOOD_BAR, - GuiElement.PROGRESS_BAR, - GuiElement.TOOL_TIPS + GuiElement.AIR_BUBBLES_BAR, + GuiElement.ARMOR, + GuiElement.HEALTH, + GuiElement.FOOD_BAR, + GuiElement.PROGRESS_BAR, + GuiElement.TOOL_TIPS, + GuiElement.PAPER_DOLL, + GuiElement.VEHICLE_HEALTH }; private final GeyserSession session; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 7a33c53d6..5bb839a43 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -82,7 +82,6 @@ public class JavaLoginTranslator extends PacketTranslator Date: Tue, 25 Feb 2025 22:33:10 +0100 Subject: [PATCH 557/897] Switch all ping passthroughs to json to avoid parsing warning (#5363) --- .../platform/bungeecord/GeyserBungeePingPassthrough.java | 4 +++- .../geysermc/geyser/platform/mod/ModPingPassthrough.java | 5 +---- .../platform/spigot/GeyserPaperPingPassthrough.java | 7 ++++++- .../platform/spigot/GeyserSpigotPingPassthrough.java | 8 +++++++- .../platform/velocity/GeyserVelocityPingPassthrough.java | 4 ++-- .../platform/velocity/command/VelocityCommandSource.java | 2 +- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java index 472c5f10a..e1f22c838 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.platform.bungeecord; import lombok.AllArgsConstructor; +import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ServerPing; import net.md_5.bungee.api.chat.BaseComponent; @@ -74,7 +76,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List ServerPing response = event.getResponse(); return new GeyserPingInfo( - response.getDescriptionComponent().toLegacyText(), + GsonComponentSerializer.gson().serialize(BungeeComponentSerializer.get().deserialize(new BaseComponent[]{ response.getDescriptionComponent() })), response.getPlayers().getMax(), response.getPlayers().getOnline() ); diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java index a2bbfa379..e1f9c01e2 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java @@ -80,11 +80,8 @@ public class ModPingPassthrough implements IGeyserPingPassthrough { } } - String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description(), RegistryAccess.EMPTY); - String legacyDescription = LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(jsonDescription, Component.empty())); - return new GeyserPingInfo( - legacyDescription, + net.minecraft.network.chat.Component.Serializer.toJson(status.description(), RegistryAccess.EMPTY), status.players().map(ServerStatus.Players::max).orElse(1), status.players().map(ServerStatus.Players::online).orElse(0) ); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java index 6a962f450..60d5dee55 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java @@ -27,6 +27,8 @@ package org.geysermc.geyser.platform.spigot; import com.destroystokyo.paper.event.server.PaperServerListPingEvent; import com.destroystokyo.paper.network.StatusClient; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -81,7 +83,10 @@ public final class GeyserPaperPingPassthrough implements IGeyserPingPassthrough players = new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()); } - return new GeyserPingInfo(event.getMotd(), players); + return new GeyserPingInfo( + GsonComponentSerializer.gson().serialize(LegacyComponentSerializer.legacySection().deserialize(event.getMotd())), + players + ); } catch (Exception | LinkageError e) { // LinkageError in the event that method/constructor signatures change logger.debug("Error while getting Paper ping passthrough: " + e); return null; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java index 4b1e42871..acd19ae18 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java @@ -26,6 +26,8 @@ package org.geysermc.geyser.platform.spigot; import lombok.AllArgsConstructor; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.server.ServerListPingEvent; @@ -52,7 +54,11 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough { try { ServerListPingEvent event = new GeyserPingEvent(inetSocketAddress.getAddress(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers()); Bukkit.getPluginManager().callEvent(event); - return new GeyserPingInfo(event.getMotd(), event.getMaxPlayers(), event.getNumPlayers()); + return new GeyserPingInfo( + GsonComponentSerializer.gson().serialize(LegacyComponentSerializer.legacySection().deserialize(event.getMotd())), + event.getMaxPlayers(), + event.getNumPlayers() + ); } catch (Exception | LinkageError e) { // LinkageError in the event that method/constructor signatures change logger.debug("Error while getting Bukkit ping passthrough: " + e); return null; diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java index f20076597..0db3c662a 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java @@ -33,7 +33,7 @@ import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.api.proxy.server.ServerPing.Version; import lombok.AllArgsConstructor; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; @@ -60,7 +60,7 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough { throw new RuntimeException(e); } return new GeyserPingInfo( - LegacyComponentSerializer.legacy('§').serialize(event.getPing().getDescriptionComponent()), + GsonComponentSerializer.gson().serialize(event.getPing().getDescriptionComponent()), event.getPing().getPlayers().map(ServerPing.Players::getMax).orElse(1), event.getPing().getPlayers().map(ServerPing.Players::getOnline).orElse(0) ); diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java index 2240f9988..f55f145ed 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSource.java @@ -60,7 +60,7 @@ public class VelocityCommandSource implements GeyserCommandSource { @Override public void sendMessage(@NonNull String message) { - handle.sendMessage(LegacyComponentSerializer.legacy('§').deserialize(message)); + handle.sendMessage(LegacyComponentSerializer.legacySection().deserialize(message)); } @Override From 97cc87631157b133b29cdf9912e487170b44ac3e Mon Sep 17 00:00:00 2001 From: Alex <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Wed, 26 Feb 2025 09:52:02 +0100 Subject: [PATCH 558/897] Fix missing console logs with Geyser-Standalone gui present (#5376) * Fix missing console logs with gui present * Properly redirect stdout & stderr & also redirect JUL --- bootstrap/standalone/build.gradle.kts | 2 + .../standalone/GeyserStandaloneBootstrap.java | 30 +++----- .../standalone/GeyserStandaloneLogger.java | 12 +++ .../standalone/gui/GeyserStandaloneGUI.java | 77 ++++++++++++------- .../standalone/src/main/resources/log4j2.xml | 4 - gradle/libs.versions.toml | 4 +- 6 files changed, 76 insertions(+), 53 deletions(-) diff --git a/bootstrap/standalone/build.gradle.kts b/bootstrap/standalone/build.gradle.kts index e794c266c..5a13056eb 100644 --- a/bootstrap/standalone/build.gradle.kts +++ b/bootstrap/standalone/build.gradle.kts @@ -40,4 +40,6 @@ tasks.named("run") { dir.mkdirs() jvmArgs("-Dio.netty.leakDetection.level=PARANOID") workingDir = dir + + standardInput = System.`in` } diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 87fbbf0aa..5bdb206db 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -32,12 +32,9 @@ import com.fasterxml.jackson.databind.introspect.AnnotatedField; import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; import io.netty.util.ResourceLeakDetector; import lombok.Getter; -import net.minecrell.terminalconsole.TerminalConsoleAppender; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; @@ -92,6 +89,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); // Can eat performance } + System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager"); + GeyserStandaloneLogger.setupStreams(); + GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap(); // Set defaults boolean useGuiOpts = bootstrap.useGui; @@ -175,17 +175,10 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { @Override public void onGeyserInitialize() { log4jLogger = (Logger) LogManager.getRootLogger(); - for (Appender appender : log4jLogger.getAppenders().values()) { - // Remove the appender that is not in use - // Prevents multiple appenders/double logging and removes harmless errors - if ((useGui && appender instanceof TerminalConsoleAppender) || (!useGui && appender instanceof ConsoleAppender)) { - log4jLogger.removeAppender(appender); - } - } if (useGui && gui == null) { gui = new GeyserStandaloneGUI(geyserLogger); - gui.redirectSystemStreams(); + gui.addGuiAppender(); gui.startUpdateThread(); } @@ -198,7 +191,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { public void onGeyserEnable() { try { File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", - (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); + (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class); handleArgsConfigOptions(); @@ -246,9 +239,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); - if (!useGui) { - geyserLogger.start(); // Throws an error otherwise - } + geyserLogger.start(); } /** @@ -261,7 +252,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { Class graphicsEnv = Class.forName("java.awt.GraphicsEnvironment"); Method isHeadless = graphicsEnv.getDeclaredMethod("isHeadless"); return (boolean) isHeadless.invoke(null); - } catch (Exception ignore) { } + } catch (Exception ignore) { + } return true; } @@ -347,12 +339,12 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { // Get the ignored properties Set ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector() - .findPropertyIgnoralByName(OBJECT_MAPPER.getSerializationConfig() ,beanDescription.getClassInfo()).getIgnored(); + .findPropertyIgnoralByName(OBJECT_MAPPER.getSerializationConfig(), beanDescription.getClassInfo()).getIgnored(); // Filter properties removing the ignored ones return properties.stream() - .filter(property -> !ignoredProperties.contains(property.getName())) - .collect(Collectors.toList()); + .filter(property -> !ignoredProperties.contains(property.getName())) + .collect(Collectors.toList()); } /** 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 b614a7b23..9c744f015 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 @@ -28,7 +28,10 @@ package org.geysermc.geyser.platform.standalone; import lombok.extern.slf4j.Slf4j; import net.minecrell.terminalconsole.SimpleTerminalConsole; import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.io.IoBuilder; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.command.GeyserCommandSource; @@ -39,6 +42,15 @@ import org.jline.reader.LineReaderBuilder; @Slf4j public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, GeyserCommandSource { + private static final Logger logger = LogManager.getLogger("GeyserConsole"); + + /** + * Sets up {@code System.out} and {@code System.err} to redirect to log4j. + */ + public static void setupStreams() { + System.setOut(IoBuilder.forLogger(logger).setLevel(Level.INFO).buildPrintStream()); + System.setErr(IoBuilder.forLogger(logger).setLevel(Level.ERROR).buildPrintStream()); + } @Override protected LineReader buildReader(LineReaderBuilder builder) { diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java index 4cbd178af..b1acb585b 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java @@ -25,7 +25,14 @@ package org.geysermc.geyser.platform.standalone.gui; -import org.checkerframework.checker.nullness.qual.NonNull; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.NullConfiguration; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.core.pattern.PatternFormatter; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.command.CommandRegistry; @@ -36,11 +43,16 @@ import javax.swing.*; import javax.swing.table.DefaultTableModel; import javax.swing.text.Document; import java.awt.*; -import java.awt.event.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -83,7 +95,8 @@ public class GeyserStandaloneGUI { // Remove Java UI look try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception ignored) { } + } catch (Exception ignored) { + } // Show a confirm dialog on close frame.addWindowListener(new WindowAdapter() { @@ -181,7 +194,8 @@ public class GeyserStandaloneGUI { openButton.addActionListener(e -> { try { Desktop.getDesktop().open(new File("./")); - } catch (IOException ignored) { } + } catch (IOException ignored) { + } }); fileMenu.add(openButton); @@ -245,29 +259,8 @@ public class GeyserStandaloneGUI { /** * Redirect the default io streams to the text pane */ - public void redirectSystemStreams() { - // Setup a new output stream to forward it to the text pane - OutputStream out = new OutputStream() { - @Override - public void write(final int b) { - appendConsole(String.valueOf((char) b)); - } - - @Override - public void write(byte @NonNull [] b, int off, int len) { - appendConsole(new String(b, off, len)); - } - - @Override - public void write(byte @NonNull[] b) { - write(b, 0, b.length); - } - }; - - // Override the system output streams - System.setOut(new PrintStream(out, true)); - System.setErr(new PrintStream(out, true)); - + public void addGuiAppender() { + new GUIAppender().start(); } /** @@ -354,4 +347,30 @@ public class GeyserStandaloneGUI { commandInput.setText(""); // clear the input } } + + private class GUIAppender extends AbstractAppender { + private static final List FORMATTERS = PatternLayout.createPatternParser(new NullConfiguration()) + .parse( + "[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n", + true, + false, + false + ); + + protected GUIAppender() { + super("GUIAppender", null, null, false, Property.EMPTY_ARRAY); + + ((Logger) LogManager.getRootLogger()).addAppender(this); + } + + @Override + public void append(LogEvent event) { + StringBuilder formatted = new StringBuilder(); + for (PatternFormatter formatter : FORMATTERS) { + formatter.format(event, formatted); + } + + appendConsole(formatted.toString()); + } + } } diff --git a/bootstrap/standalone/src/main/resources/log4j2.xml b/bootstrap/standalone/src/main/resources/log4j2.xml index bf361a851..0304e1924 100644 --- a/bootstrap/standalone/src/main/resources/log4j2.xml +++ b/bootstrap/standalone/src/main/resources/log4j2.xml @@ -4,9 +4,6 @@ - - - @@ -18,7 +15,6 @@ - diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ae35c6e34..f7a8d2824 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -91,6 +91,8 @@ netty-transport-native-io_uring = { group = "io.netty.incubator", name = "netty- log4j-api = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" } log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4j" } log4j-slf4j2-impl = { group = "org.apache.logging.log4j", name = "log4j-slf4j2-impl", version.ref = "log4j" } +log4j-iostreams = { group = "org.apache.logging.log4j", name = "log4j-iostreams", version.ref = "log4j" } +log4j-jul = { group = "org.apache.logging.log4j", name = "log4j-jul", version.ref = "log4j" } jline-terminal = { group = "org.jline", name = "jline-terminal", version.ref = "jline" } jline-terminal-jna = { group = "org.jline", name = "jline-terminal-jna", version.ref = "jline" } @@ -160,6 +162,6 @@ runpaper = { id = "xyz.jpenilla.run-paper", version.ref = "runtask" } 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" ] +log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl", "log4j-iostreams", "log4j-jul" ] jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ] protocol = [ "protocol-common", "protocol-codec", "protocol-connection" ] From 52bcdf0d2f1b868a7e209a4f331e347635f6d225 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 27 Feb 2025 15:29:58 +0100 Subject: [PATCH 559/897] Fix: Allow players to hit air (#5369) This also implements blocking block breaking & attacking entities while steering boats to match the Java clients behavior. Further, it now also updates the shifting state before sending inputs to the Java client, also matching behavior there. --- README.md | 2 +- .../org/geysermc/geyser/dump/DumpInfo.java | 3 +- .../geyser/session/GeyserSession.java | 22 +++++------ .../geyser/session/cache/InputCache.java | 20 +++++++++- .../BrushableBlockEntityTranslator.java | 2 +- .../bedrock/BedrockAnimateTranslator.java | 22 ++++++++--- ...BedrockInventoryTransactionTranslator.java | 5 +++ .../player/input/BedrockBlockActions.java | 27 ++++++++++++- .../BedrockPlayerAuthInputTranslator.java | 39 ++++++++++++------- .../BedrockLevelSoundEventTranslator.java | 19 --------- .../java/entity/JavaAnimateTranslator.java | 8 ++-- 11 files changed, 109 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 57aaaf6fe..c6962f65e 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.21.40 - 1.21.60 and Minecraft Java 1.21.4. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.21.40 - 1.21.61 and Minecraft Java 1.21.4. 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/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 515e1a629..847eda133 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -178,9 +178,8 @@ public class DumpInfo { NetworkInfo() { if (AsteriskSerializer.showSensitive) { - try { + try (Socket socket = new Socket()) { // This is the most reliable for getting the main local IP - Socket socket = new Socket(); socket.connect(new InetSocketAddress("geysermc.org", 80)); this.internalIP = socket.getLocalAddress().getHostAddress(); } catch (IOException e1) { 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 261e57aed..96f553e20 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -536,10 +536,17 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * 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. + * -1 means there is no active arm swing */ private int armAnimationTicks = -1; + /** + * The tick in which the player last hit air. + * Used to ensure we dont send two sing packets for one hit. + */ + @Setter + private int lastAirHitTick; + /** * Controls whether the daylight cycle gamerule has been sent to the client, so the sun/moon remain motionless. */ @@ -1113,13 +1120,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public void updateTickingState(float tickRate, boolean frozen) { tickThread.cancel(false); - this.tickingFrozen = frozen; tickRate = MathUtils.clamp(tickRate, 1.0f, 10000.0f); - millisecondsPerTick = 1000.0f / tickRate; - nanosecondsPerTick = MathUtils.ceil(1000000000.0f / tickRate); tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS); } @@ -1132,7 +1136,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } catch (Throwable e) { geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); } - } /** @@ -1365,13 +1368,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } /** - * For issue 2113 and combating arm ticking activating being delayed in - * BedrockAnimateTranslator. + * You can't break blocks, attack entities, or use items while driving in a boat */ - public void armSwingPending() { - if (armAnimationTicks == -1) { - armAnimationTicks = -2; - } + public boolean isHandsBusy() { + return steeringRight || steeringLeft; } /** 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 index f12c4d3c8..b6b0703d1 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java @@ -32,8 +32,11 @@ 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.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPlayerInputPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; import java.util.Set; @@ -53,7 +56,7 @@ public final class InputCache { this.session = session; } - public void processInputs(PlayerAuthInputPacket packet) { + public void processInputs(PlayerEntity entity, PlayerAuthInputPacket packet) { // Input is sent to the server before packet positions, as of 1.21.2 Set bedrockInput = packet.getInputData(); var oldInputPacket = this.inputPacket; @@ -74,6 +77,8 @@ public final class InputCache { right = analogMovement.getX() < 0; } + boolean sneaking = bedrockInput.contains(PlayerAuthInputData.SNEAKING); + // TODO when is UP_LEFT, etc. used? this.inputPacket = this.inputPacket .withForward(up) @@ -81,9 +86,20 @@ public final class InputCache { .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)) + .withShift(sneaking) .withSprint(bedrockInput.contains(PlayerAuthInputData.SPRINTING)); // SPRINTING will trigger even if the player isn't moving + // Send sneaking state before inputs, matches Java client + if (oldInputPacket.isShift() != sneaking) { + if (sneaking) { + session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(entity.javaId(), PlayerState.START_SNEAKING)); + session.startSneaking(); + } else { + session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(entity.javaId(), PlayerState.STOP_SNEAKING)); + session.stopSneaking(); + } + } + if (oldInputPacket != this.inputPacket) { // Simple equality check is fine since we're checking for an instance change. session.sendDownstreamGamePacket(this.inputPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java index de0ce62b3..cc6d08647 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BrushableBlockEntityTranslator.java @@ -64,7 +64,7 @@ public class BrushableBlockEntityTranslator extends BlockEntityTranslator implem } NbtMapBuilder itemBuilder = NbtMap.builder() .putString("Name", mapping.getBedrockIdentifier()) - .putByte("Count", (byte) itemTag.getByte("Count")); + .putByte("Count", itemTag.getByte("Count")); bedrockNbt.putCompound("item", itemBuilder.build()); // controls which side the item protrudes from 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 5f3b9662f..04a641313 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 @@ -45,10 +45,22 @@ public class BedrockAnimateTranslator extends PacketTranslator { } if (packet.getAction() == AnimatePacket.Action.SWING_ARM) { - session.armSwingPending(); - // Delay so entity damage can be processed first + + // If this is the case, we just hit the air. Poor air. + // Touch devices send PlayerAuthInputPackets with MISSED_SWING, and then the animate packet. + // This tends to happen 1-2 ticks after the auth input packet. + if (session.getTicks() - session.getLastAirHitTick() < 3) { + return; + } + + // Windows unfortunately sends the animate packet first, then the auth input packet with the MISSED_SWING. + // Often, these are sent in the same tick. In that case, the wait here ensures the auth input packet is processed first. + // Other times, there is a 1-tick-delay, which would result in the swing packet sent here. The BedrockAuthInputTranslator's + // MISSED_SWING case also accounts for that by checking if a swing was sent a tick ago here. + + // Also, delay the swing so entity damage can be processed first session.scheduleInEventLoop(() -> { - if (session.getArmAnimationTicks() != 0) { + if (session.getArmAnimationTicks() != 0 && (session.getTicks() - session.getLastAirHitTick() > 2)) { // 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. @@ -61,12 +73,12 @@ public class BedrockAnimateTranslator extends PacketTranslator { // 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. + // all actions on our end, and send swings where needed. Can be done once we replicate Block and Item interactions fully. session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); session.activateArmAnimationTicking(); } }, - 25, + (long) (session.getMillisecondsPerTick() * 0.5), TimeUnit.MILLISECONDS ); } 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 2a3d1eb57..f48b8b1c8 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 @@ -454,6 +454,11 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator processEntityInteraction(session, packet, entity); // Interact case 1 -> { // Attack + if (session.isHandsBusy()) { + // See Minecraft#startAttack and LocalPlayer#isHandsBusy + return; + } + int entityId; if (entity.getDefinition() == EntityDefinitions.ENDER_DRAGON) { // Redirects the attack to its body entity, this only happens when 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 index c604f5be1..4473a1d60 100644 --- 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 @@ -32,7 +32,6 @@ 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.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; @@ -84,6 +83,10 @@ final class BedrockBlockActions { break; } + if (!canMine(session, vector)) { + return; + } + // Start the block breaking animation int blockState = session.getGeyser().getWorldManager().getBlockAt(session, vector); LevelEventPacket startBreak = new LevelEventPacket(); @@ -126,6 +129,11 @@ final class BedrockBlockActions { if (session.getGameMode() == GameMode.CREATIVE) { break; } + + if (!canMine(session, vector)) { + return; + } + int breakingBlock = session.getBreakingBlock(); if (breakingBlock == -1) { breakingBlock = Block.JAVA_AIR_ID; @@ -187,6 +195,7 @@ final class BedrockBlockActions { stopBreak.setPosition(vector.toFloat()); stopBreak.setData(0); session.setBreakingBlock(-1); + session.setBlockBreakStartTime(0); session.sendUpstreamPacket(stopBreak); } // Handled in BedrockInventoryTransactionTranslator @@ -195,6 +204,22 @@ final class BedrockBlockActions { } } + private static boolean canMine(GeyserSession session, Vector3i vector) { + if (session.isHandsBusy()) { + session.setBreakingBlock(-1); + session.setBlockBreakStartTime(0); + + LevelEventPacket stopBreak = new LevelEventPacket(); + stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK); + stopBreak.setPosition(vector.toFloat()); + stopBreak.setData(0); + session.setBreakingBlock(-1); + session.sendUpstreamPacket(stopBreak); + return false; + } + return true; + } + private static void spawnBlockBreakParticles(GeyserSession session, Direction direction, Vector3i position, BlockState blockState) { LevelEventPacket levelEventPacket = new LevelEventPacket(); switch (direction) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java index ee5a0dadb..62e574a3a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java @@ -29,14 +29,17 @@ import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.InputMode; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.PlayerActionType; import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.ItemUseTransaction; +import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.BoatEntity; import org.geysermc.geyser.entity.type.Entity; @@ -53,6 +56,7 @@ import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransacti 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; @@ -61,6 +65,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.Serv 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 java.util.Set; @@ -72,7 +77,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator 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); @@ -154,7 +147,25 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator sendPlayerGlideToggle(session, entity); - case MISSED_SWING -> CooldownUtils.sendCooldown(session); // Java edition sends a cooldown when hitting air. + case MISSED_SWING -> { + session.setLastAirHitTick(session.getTicks()); + + if (session.getArmAnimationTicks() != 0 && session.getArmAnimationTicks() != 1) { + session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); + session.activateArmAnimationTicking(); + } + + // Touch devices expect an animation packet sent back to them + if (packet.getInputMode().equals(InputMode.TOUCH)) { + AnimatePacket animatePacket = new AnimatePacket(); + animatePacket.setAction(AnimatePacket.Action.SWING_ARM); + animatePacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); + session.sendUpstreamPacket(animatePacket); + } + + // Java edition sends a cooldown when hitting air. + CooldownUtils.sendCooldown(session); + } } } if (entity.getVehicle() instanceof BoatEntity) { 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 62b1b8b14..e99a31363 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 @@ -28,7 +28,6 @@ package org.geysermc.geyser.translator.protocol.bedrock.world; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; -import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; @@ -38,7 +37,6 @@ import org.geysermc.geyser.translator.protocol.Translator; 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.Hand; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; @Translator(packet = LevelSoundEventPacket.class) @@ -56,23 +54,6 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator Date: Thu, 27 Feb 2025 17:00:03 +0100 Subject: [PATCH 560/897] Fix https://github.com/GeyserMC/Geyser/issues/5377 --- .../cache/registry/JavaRegistries.java | 2 + .../inventory/LoomInventoryTranslator.java | 57 +++++-------------- 2 files changed, 15 insertions(+), 44 deletions(-) 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 index 646b647d0..2792589c7 100644 --- 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.session.cache.registry; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.type.Block; @@ -48,6 +49,7 @@ public class JavaRegistries { 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); + public static final JavaRegistryKey BANNER_PATTERNS = create("banner_pattern", RegistryCache::bannerPatterns); private static JavaRegistryKey create(String key, JavaRegistryKey.NetworkSerializer networkSerializer, JavaRegistryKey.NetworkDeserializer networkDeserializer) { JavaRegistryKey registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index d75228f9b..cf507b793 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -25,8 +25,7 @@ package org.geysermc.geyser.translator.inventory; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; @@ -39,15 +38,19 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestActionType; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.SlotType; +import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.item.type.BannerItem; import org.geysermc.geyser.item.type.DyeItem; import org.geysermc.geyser.level.block.Blocks; 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.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; @@ -56,47 +59,8 @@ import java.util.ArrayList; import java.util.List; public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { - /** - * A map of Bedrock patterns to Java index. Used to request for a specific banner pattern. - */ - private static final Object2IntMap PATTERN_TO_INDEX = new Object2IntOpenHashMap<>(); - static { - // Added from left-to-right then up-to-down in the order Java presents it - int index = 0; - PATTERN_TO_INDEX.put("bl", index++); - PATTERN_TO_INDEX.put("br", index++); - PATTERN_TO_INDEX.put("tl", index++); - PATTERN_TO_INDEX.put("tr", index++); - PATTERN_TO_INDEX.put("bs", index++); - PATTERN_TO_INDEX.put("ts", index++); - PATTERN_TO_INDEX.put("ls", index++); - PATTERN_TO_INDEX.put("rs", index++); - PATTERN_TO_INDEX.put("cs", index++); - PATTERN_TO_INDEX.put("ms", index++); - PATTERN_TO_INDEX.put("drs", index++); - PATTERN_TO_INDEX.put("dls", index++); - PATTERN_TO_INDEX.put("ss", index++); - PATTERN_TO_INDEX.put("cr", index++); - PATTERN_TO_INDEX.put("sc", index++); - PATTERN_TO_INDEX.put("bt", index++); - PATTERN_TO_INDEX.put("tt", index++); - PATTERN_TO_INDEX.put("bts", index++); - PATTERN_TO_INDEX.put("tts", index++); - PATTERN_TO_INDEX.put("ld", index++); - PATTERN_TO_INDEX.put("rd", index++); - PATTERN_TO_INDEX.put("lud", index++); - PATTERN_TO_INDEX.put("rud", index++); - PATTERN_TO_INDEX.put("mc", index++); - PATTERN_TO_INDEX.put("mr", index++); - PATTERN_TO_INDEX.put("vh", index++); - PATTERN_TO_INDEX.put("hh", index++); - PATTERN_TO_INDEX.put("vhr", index++); - PATTERN_TO_INDEX.put("hhb", index++); - PATTERN_TO_INDEX.put("bo", index++); - PATTERN_TO_INDEX.put("gra", index++); - PATTERN_TO_INDEX.put("gru", index); - } + private static final Tag NO_ITEMS_REQUIRED = new Tag<>(JavaRegistries.BANNER_PATTERNS, Key.key("no_item_required")); public LoomInventoryTranslator() { super(4, Blocks.LOOM, ContainerType.LOOM, UIInventoryUpdater.INSTANCE); @@ -136,8 +100,13 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { String bedrockPattern = ((CraftLoomAction) headerData).getPatternId(); - // Get the Java index of this pattern - int index = PATTERN_TO_INDEX.getOrDefault(bedrockPattern, -1); + BannerPattern requestedPattern = BannerPattern.getByBedrockIdentifier(bedrockPattern); + if (requestedPattern == null) { + GeyserImpl.getInstance().getLogger().warning("Unknown Bedrock pattern id: " + bedrockPattern); + return rejectRequest(request); + } + + int index = session.getTagCache().get(NO_ITEMS_REQUIRED).indexOf(requestedPattern); if (index == -1) { return rejectRequest(request); } From dd7a0d31616d852a976b4caa46b209824cad149e Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 27 Feb 2025 17:37:37 +0100 Subject: [PATCH 561/897] Fix https://github.com/GeyserMC/Geyser/issues/5347 --- .../entity/JavaUpdateMobEffectTranslator.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java index 0d4819f14..8ff5d6d29 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java @@ -25,14 +25,19 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundUpdateMobEffectPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEffectPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; +import org.geysermc.geyser.entity.attribute.GeyserAttributeType; 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.geyser.util.EntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundUpdateMobEffectPacket; + +import java.util.Collections; @Translator(packet = ClientboundUpdateMobEffectPacket.class) public class JavaUpdateMobEffectTranslator extends PacketTranslator { @@ -58,5 +63,20 @@ public class JavaUpdateMobEffectTranslator extends PacketTranslator Date: Thu, 27 Feb 2025 20:58:08 +0200 Subject: [PATCH 562/897] Indicate 1.21.62 support (#5378) Co-authored-by: chris --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c6962f65e..dcd9b8530 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.21.40 - 1.21.61 and Minecraft Java 1.21.4. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.21.40 - 1.21.62 and Minecraft Java 1.21.4. 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. From 758700cb2271ed54a3890bcdaac9c3c3db04f7a9 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 27 Feb 2025 20:11:16 +0100 Subject: [PATCH 563/897] Fix render distance issues (#5381) * Potentially fix render distance issues * AGGRESSIVE fix render distance issues --------- Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../geyser/session/GeyserSession.java | 21 ++++++++++++++++++- .../org/geysermc/geyser/util/ChunkUtils.java | 9 +++++++- 2 files changed, 28 insertions(+), 2 deletions(-) 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 96f553e20..f303ae3ce 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -341,7 +341,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private Vector2i lastChunkPosition = null; - @Setter private int clientRenderDistance = -1; private int serverRenderDistance = -1; @@ -1453,11 +1452,31 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { sendDownstreamGamePacket(new ServerboundChatCommandSignedPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet())); } + public void setClientRenderDistance(int clientRenderDistance) { + boolean oldSquareToCircle = this.clientRenderDistance < this.serverRenderDistance; + this.clientRenderDistance = clientRenderDistance; + boolean newSquareToCircle = this.clientRenderDistance < this.serverRenderDistance; + + if (this.serverRenderDistance != -1 && oldSquareToCircle != newSquareToCircle) { + recalculateBedrockRenderDistance(); + } + } + public void setServerRenderDistance(int renderDistance) { // Ensure render distance is not above 96 as sending a larger value at any point crashes mobile clients and 96 is the max of any bedrock platform renderDistance = Math.min(renderDistance, 96); this.serverRenderDistance = renderDistance; + recalculateBedrockRenderDistance(); + } + + /** + * Ensures that the ChunkRadiusUpdatedPacket uses the correct render distance for whatever the client distance is set as. + * If the server render distance is larger than the client's, then account for this and add some extra padding. + * We don't want to apply this for every render distance, if at all possible, because + */ + private void recalculateBedrockRenderDistance() { + int renderDistance = ChunkUtils.squareToCircle(this.serverRenderDistance); ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); chunkRadiusUpdatedPacket.setRadius(renderDistance); upstream.sendPacket(chunkRadiusUpdatedPacket); diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index 96471a2ce..cb149426d 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -99,13 +99,20 @@ public class ChunkUtils { chunkPublisherUpdatePacket.setPosition(position); // Mitigates chunks not loading on 1.17.1 Paper and 1.19.3 Fabric. As of Bedrock 1.19.60. // https://github.com/GeyserMC/Geyser/issues/3490 - chunkPublisherUpdatePacket.setRadius(GenericMath.ceil((session.getServerRenderDistance() + 1) * MathUtils.SQRT_OF_TWO) << 4); + chunkPublisherUpdatePacket.setRadius(squareToCircle(session.getServerRenderDistance()) << 4); session.sendUpstreamPacket(chunkPublisherUpdatePacket); session.setLastChunkPosition(newChunkPos); } } + /** + * Converts a Java render distance number to the equivalent in Bedrock. + */ + public static int squareToCircle(int renderDistance) { + return GenericMath.ceil((renderDistance + 1) * MathUtils.SQRT_OF_TWO); + } + /** * Sends a block update to the Bedrock client. If the platform is not Spigot, this also * adds that block to the cache. From ce1535991c94e1d39804e55cf9c7c6bad5a7158d Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Sun, 2 Mar 2025 18:53:33 +0100 Subject: [PATCH 564/897] fix https://github.com/GeyserMC/Geyser/issues/5387 --- .../main/java/org/geysermc/geyser/session/GeyserSession.java | 3 ++- .../bedrock/entity/player/BedrockInteractTranslator.java | 4 ++++ .../player/input/BedrockPlayerAuthInputTranslator.java | 5 +++-- .../protocol/java/entity/JavaSetPassengersTranslator.java | 4 ++++ 4 files changed, 13 insertions(+), 3 deletions(-) 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 f303ae3ce..005e72097 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -126,6 +126,7 @@ import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.GeyserEntityData; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; +import org.geysermc.geyser.entity.type.BoatEntity; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.entity.type.Tickable; @@ -1370,7 +1371,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * You can't break blocks, attack entities, or use items while driving in a boat */ public boolean isHandsBusy() { - return steeringRight || steeringLeft; + return playerEntity.getVehicle() instanceof BoatEntity && (steeringRight || steeringLeft); } /** 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 62487b20d..794375fde 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 @@ -78,6 +78,10 @@ public class BedrockInteractTranslator extends PacketTranslator ServerboundPlayerCommandPacket sneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); session.sendDownstreamGamePacket(sneakPacket); + // Reset steering to avoid these accidentally triggering session#isHandsBusy + session.setSteeringLeft(false); + session.setSteeringRight(false); + Entity currentVehicle = session.getPlayerEntity().getVehicle(); if (currentVehicle != null) { session.setMountVehicleScheduledFuture(session.scheduleInEventLoop(() -> { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java index 62e574a3a..8e09c6c98 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java @@ -39,7 +39,6 @@ import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.BoatEntity; import org.geysermc.geyser.entity.type.Entity; @@ -168,7 +167,9 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator Date: Mon, 3 Mar 2025 20:56:02 +0800 Subject: [PATCH 565/897] Fix button sounds (#5367) * fix buttons * delete unused mapper * remove ignore arm swing * Update mappings --- .../geysermc/geyser/level/block/Blocks.java | 28 +++++----- .../geyser/level/block/type/ButtonBlock.java | 32 +++++++++++ .../registry/loader/SoundRegistryLoader.java | 7 +-- .../geyser/registry/type/SoundMapping.java | 16 ++---- ...BedrockInventoryTransactionTranslator.java | 10 +++- .../player/input/BedrockBlockActions.java | 1 - .../java/level/JavaLevelEventTranslator.java | 2 +- .../ButtonSoundInteractionTranslator.java | 53 +++++++++++++++++++ .../org/geysermc/geyser/util/SoundUtils.java | 28 +++++----- core/src/main/resources/mappings | 2 +- 10 files changed, 131 insertions(+), 48 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/ButtonBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/sound/block/ButtonSoundInteractionTranslator.java 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 7dc526ee3..527e49b14 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 @@ -630,7 +630,7 @@ public final class Blocks { 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))); - public static final Block STONE_BUTTON = register(new Block("stone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block STONE_BUTTON = register(new ButtonBlock("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))); @@ -997,43 +997,43 @@ public final class Blocks { .intState(AGE_7))); public static final Block POTATOES = register(new Block("potatoes", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7))); - public static final Block OAK_BUTTON = register(new Block("oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block OAK_BUTTON = register(new ButtonBlock("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 SPRUCE_BUTTON = register(new Block("spruce_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block SPRUCE_BUTTON = register(new ButtonBlock("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))); - public static final Block BIRCH_BUTTON = register(new Block("birch_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block BIRCH_BUTTON = register(new ButtonBlock("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))); - public static final Block JUNGLE_BUTTON = register(new Block("jungle_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block JUNGLE_BUTTON = register(new ButtonBlock("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))); - public static final Block ACACIA_BUTTON = register(new Block("acacia_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block ACACIA_BUTTON = register(new ButtonBlock("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))); - public static final Block CHERRY_BUTTON = register(new Block("cherry_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block CHERRY_BUTTON = register(new ButtonBlock("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))); - public static final Block DARK_OAK_BUTTON = register(new Block("dark_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block DARK_OAK_BUTTON = register(new ButtonBlock("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))); - public static final Block PALE_OAK_BUTTON = register(new Block("pale_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block PALE_OAK_BUTTON = register(new ButtonBlock("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) + public static final Block MANGROVE_BUTTON = register(new ButtonBlock("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))); - public static final Block BAMBOO_BUTTON = register(new Block("bamboo_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block BAMBOO_BUTTON = register(new ButtonBlock("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))); @@ -2232,11 +2232,11 @@ public final class Blocks { .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) + public static final Block CRIMSON_BUTTON = register(new ButtonBlock("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))); - public static final Block WARPED_BUTTON = register(new Block("warped_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block WARPED_BUTTON = register(new ButtonBlock("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))); @@ -2336,7 +2336,7 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + public static final Block POLISHED_BLACKSTONE_BUTTON = register(new ButtonBlock("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))); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/ButtonBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/ButtonBlock.java new file mode 100644 index 000000000..2a2ae4702 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/ButtonBlock.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 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.level.block.type; + +public class ButtonBlock extends Block { + public ButtonBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundRegistryLoader.java index 318cc08d7..7033740c1 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundRegistryLoader.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.registry.loader; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.type.SoundMapping; @@ -39,7 +40,6 @@ import java.util.Map; * Loads sounds from the given input. */ public class SoundRegistryLoader implements RegistryLoader> { - @Override public Map load(String input) { JsonNode soundsTree; @@ -51,7 +51,7 @@ public class SoundRegistryLoader implements RegistryLoader soundMappings = new HashMap<>(); Iterator> soundsIterator = soundsTree.fields(); - while(soundsIterator.hasNext()) { + while (soundsIterator.hasNext()) { Map.Entry next = soundsIterator.next(); JsonNode brMap = next.getValue(); String javaSound = next.getKey(); @@ -61,7 +61,8 @@ public class SoundRegistryLoader implements RegistryLoader { ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index 5b4ff1de7..f2daf92bd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -90,7 +90,7 @@ public class JavaLevelEventTranslator extends PacketTranslator Date: Mon, 3 Mar 2025 20:17:14 +0100 Subject: [PATCH 566/897] Fix: beacon speed effect causing visual glitches looking like a heartbeat almost looks like the player is alive, lol fixes https://github.com/GeyserMC/Geyser/issues/5388 --- .../entity/attribute/GeyserAttributeType.java | 4 +-- .../entity/JavaUpdateMobEffectTranslator.java | 33 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index 10e93810e..80db3354e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -25,10 +25,10 @@ package org.geysermc.geyser.entity.attribute; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.protocol.bedrock.data.AttributeData; import lombok.AllArgsConstructor; import lombok.Getter; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.protocol.bedrock.data.AttributeData; @Getter @AllArgsConstructor diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java index 8ff5d6d29..5554251a0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java @@ -25,16 +25,17 @@ package org.geysermc.geyser.translator.protocol.java.entity; +import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.packet.MobEffectPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.EntityEffectCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.EntityUtils; -import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundUpdateMobEffectPacket; import java.util.Collections; @@ -49,8 +50,15 @@ public class JavaUpdateMobEffectTranslator extends PacketTranslator session.getPlayerEntity().getAttributes().get(GeyserAttributeType.ABSORPTION); + // Fixes https://github.com/GeyserMC/Geyser/issues/5388 + case SPEED -> session.getPlayerEntity().getAttributes().get(GeyserAttributeType.MOVEMENT_SPEED); + default -> null; + }; + + if (attribute == null) { return; } UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); attributesPacket.setRuntimeEntityId(entity.getGeyserId()); - // Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit - attributesPacket.setAttributes(Collections.singletonList( - GeyserAttributeType.ABSORPTION.getAttribute(absorptionAttribute.getValue()))); + attributesPacket.setAttributes(Collections.singletonList(attribute)); session.sendUpstreamPacket(attributesPacket); } } From 679bc4147e6a9e7315787a840198fc68f03b6d04 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 4 Mar 2025 16:40:14 +0000 Subject: [PATCH 567/897] Change advancement form mechanics to match Java behaviour, fix NPE (#5396) * Change advancement form mechanics to match Java behaviour, fix NPE * Remove unused import * Remove debug statement whoops * Fix another NPE * Close the form first when reopening it --- .../command/defaults/AdvancementsCommand.java | 2 +- .../session/cache/AdvancementsCache.java | 40 +++++++++++++++++-- .../JavaSelectAdvancementsTabTranslator.java | 5 +-- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java index 0cba28f33..e82c0b66b 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java @@ -42,6 +42,6 @@ public class AdvancementsCommand extends GeyserCommand { @Override public void execute(CommandContext context) { GeyserSession session = Objects.requireNonNull(context.sender().connection()); - session.getAdvancementsCache().buildAndShowMenuForm(); + session.getAdvancementsCache().buildAndShowForm(); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java index ac04bdf04..68b83225e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java @@ -28,7 +28,6 @@ package org.geysermc.geyser.session.cache; import org.geysermc.mcprotocollib.protocol.data.game.advancement.Advancement; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSeenAdvancementsPacket; import lombok.Getter; -import lombok.Setter; import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.geyser.level.GeyserAdvancement; import org.geysermc.geyser.session.GeyserSession; @@ -41,6 +40,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; public class AdvancementsCache { /** @@ -58,15 +58,39 @@ public class AdvancementsCache { /** * Stores player's chosen advancement's ID and title for use in form creators. */ - @Setter private String currentAdvancementCategoryId = null; + /** + * Stores if the player is currently viewing advancements. + */ + private boolean formOpen = false; + private final GeyserSession session; public AdvancementsCache(GeyserSession session) { this.session = session; } + public void setCurrentAdvancementCategoryId(String categoryId) { + if (!Objects.equals(currentAdvancementCategoryId, categoryId)) { + // Only open and show list form if we're going to a different category + currentAdvancementCategoryId = categoryId; + if (formOpen) { + session.closeForm(); + buildAndShowForm(); + formOpen = true; + } + } + } + + public void buildAndShowForm() { + if (currentAdvancementCategoryId == null) { + buildAndShowMenuForm(); + } else { + buildAndShowListForm(); + } + } + /** * Build and send a form with all advancement categories */ @@ -88,9 +112,11 @@ public class AdvancementsCache { builder.content("advancements.empty"); } - builder.validResultHandler((response) -> { + builder.closedResultHandler(() -> { + formOpen = false; + }).validResultHandler((response) -> { String id = rootAdvancementIds.get(response.clickedButtonId()); - if (!id.equals("")) { + if (!id.isEmpty()) { // Send a packet indicating that we are opening this particular advancement window ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id); session.sendDownstreamGamePacket(packet); @@ -99,6 +125,7 @@ public class AdvancementsCache { } }); + formOpen = true; session.sendForm(builder); } @@ -133,6 +160,9 @@ public class AdvancementsCache { builder.closedResultHandler(() -> { // Indicate that we have closed the current advancement tab + // Don't set currentAdvancementCategoryId to null here, so that when the advancements form is shown again (buildAndShowForm), + // the tab that was last open is opened again, which matches Java behaviour + formOpen = false; session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket()); }).validResultHandler((response) -> { @@ -142,6 +172,7 @@ public class AdvancementsCache { } else { buildAndShowMenuForm(); // Indicate that we have closed the current advancement tab + currentAdvancementCategoryId = null; session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket()); } }); @@ -206,6 +237,7 @@ public class AdvancementsCache { .validResultHandler((response) -> buildAndShowListForm()) .closedResultHandler(() -> { // Indicate that we have closed the current advancement tab + formOpen = false; session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket()); }) ); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectAdvancementsTabTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectAdvancementsTabTranslator.java index 04c018472..9da4dec62 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectAdvancementsTabTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSelectAdvancementsTabTranslator.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.protocol.java; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundSelectAdvancementsTabPacket; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.AdvancementsCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -39,8 +38,6 @@ public class JavaSelectAdvancementsTabTranslator extends PacketTranslator Date: Wed, 5 Mar 2025 22:02:09 +0100 Subject: [PATCH 568/897] Fix https://github.com/GeyserMC/Geyser/issues/5395, fix https://github.com/GeyserMC/Geyser/issues/5398 --- .../org/geysermc/geyser/impl/camera/GeyserCameraData.java | 7 ++++++- .../geyser/network/netty/handler/RakGeyserRateLimiter.java | 3 +-- .../translator/protocol/java/JavaLoginTranslator.java | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java index beb10db86..759828744 100644 --- a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java +++ b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java @@ -272,7 +272,12 @@ public class GeyserCameraData implements CameraData { elementSet.add(HUD_ELEMENT_VALUES[element.id()]); } - session.sendUpstreamPacket(packet); + if (session.isSentSpawnPacket()) { + session.sendUpstreamPacket(packet); + } else { + // Ensures hidden GUI elements properly hide when we spawn in the spectator gamemode + session.getUpstream().queuePostStartGamePacket(packet); + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java index 7ccf8fdfb..2e6f9be79 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java @@ -44,7 +44,6 @@ public class RakGeyserRateLimiter extends RakServerRateLimiter { @Override protected int getAddressMaxPacketCount(InetAddress address) { - // The default packet limit is already padded, so we reduce it by 20% - return (int) (super.getAddressMaxPacketCount(address) * sessionManager.getAddressMultiplier(address) * 0.8); + return super.getAddressMaxPacketCount(address) * sessionManager.getAddressMultiplier(address); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 5bb839a43..7a33c53d6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -82,6 +82,7 @@ public class JavaLoginTranslator extends PacketTranslator Date: Wed, 12 Mar 2025 00:58:31 +0100 Subject: [PATCH 569/897] Fix https://github.com/GeyserMC/Geyser/issues/5405 --- .../org/geysermc/geyser/translator/item/ItemTranslator.java | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 f2213bd07..0c8c63f00 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 @@ -174,7 +174,7 @@ public final class ItemTranslator { // Translate item-specific components javaItem.translateComponentsToBedrock(session, components, nbtBuilder); - Rarity rarity = Rarity.fromId(components.get(DataComponentTypes.RARITY)); + Rarity rarity = Rarity.fromId(components.getOrDefault(DataComponentTypes.RARITY, 0)); String customName = getCustomName(session, customComponents, bedrockItem, rarity.getColor(), false, false); if (customName != null) { PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f7a8d2824..a91ba0fbd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta6-20250212.131009-3" protocol-codec = "3.0.0.Beta6-20250212.131009-3" raknet = "1.0.0.CR3-20250218.160705-18" minecraftauth = "4.1.1" -mcprotocollib = "1.21.4-20250218.175633-22" +mcprotocollib = "1.21.4-20250311.232133-24" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 32160c5c6426a07ffc7f0b9e80a76631e8b3a8ff Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 16 Mar 2025 01:28:46 +0100 Subject: [PATCH 570/897] Fix chunks not loading when riding a vehicle, fix world border corrections not applying (#5410) --- .../player/input/BedrockMovePlayer.java | 130 ++++++++++-------- 1 file changed, 73 insertions(+), 57 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java index ac5a62802..23132a28b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java @@ -76,7 +76,7 @@ final class BedrockMovePlayer { boolean hasVehicle = entity.getVehicle() != null; // shouldSendPositionReminder also increments a tick counter, so make sure it's always called unless the player is on a vehicle. - boolean positionChanged = !hasVehicle && (session.getInputCache().shouldSendPositionReminder() || actualPositionChanged); + boolean positionChangedAndShouldUpdate = !hasVehicle && (session.getInputCache().shouldSendPositionReminder() || actualPositionChanged); boolean rotationChanged = hasVehicle || (entity.getYaw() != yaw || entity.getPitch() != pitch || entity.getHeadYaw() != headYaw); if (session.getLookBackScheduledFuture() != null) { @@ -87,15 +87,23 @@ final class BedrockMovePlayer { } // Client is telling us it wants to move down, but something is blocking it from doing so. - boolean isOnGround = packet.getInputData().contains(PlayerAuthInputData.VERTICAL_COLLISION) && packet.getDelta().getY() < 0; + boolean isOnGround; + if (hasVehicle) { + // VERTICAL_COLLISION is not accurate while in a vehicle (as of 1.21.62) + isOnGround = Math.abs(packet.getDelta().getY()) < 0.1; + } else { + isOnGround = packet.getInputData().contains(PlayerAuthInputData.VERTICAL_COLLISION) && packet.getDelta().getY() < 0; + } + // This takes into account no movement sent from the client, but the player is trying to move anyway. // (Press into a wall in a corner - you're trying to move but nothing actually happens) + // This isn't sent when a player is riding a vehicle (as of 1.21.62) boolean horizontalCollision = packet.getInputData().contains(PlayerAuthInputData.HORIZONTAL_COLLISION); // If only the pitch and yaw changed // This isn't needed, but it makes the packets closer to vanilla // It also means you can't "lag back" while only looking, in theory - if (!positionChanged && rotationChanged) { + if (!positionChangedAndShouldUpdate && rotationChanged) { ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(isOnGround, horizontalCollision, yaw, pitch); entity.setYaw(yaw); @@ -103,71 +111,79 @@ final class BedrockMovePlayer { entity.setHeadYaw(headYaw); session.sendDownstreamGamePacket(playerRotationPacket); - } else if (positionChanged) { + + // Player position MUST be updated on our end, otherwise e.g. chunk loading breaks + if (hasVehicle) { + entity.setPositionManual(packet.getPosition()); + session.getSkullCache().updateVisibleSkulls(); + } + } else if (positionChangedAndShouldUpdate) { if (isValidMove(session, entity.getPosition(), packet.getPosition())) { - CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), isOnGround, packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT)); - if (result != null) { // A null return value cancels the packet - Vector3d position = result.correctedMovement(); - boolean isBelowVoid = entity.isVoidPositionDesynched(); + if (!session.getWorldBorder().isPassingIntoBorderBoundaries(entity.getPosition(), true)) { + CollisionResult result = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), isOnGround, packet.getInputData().contains(PlayerAuthInputData.HANDLE_TELEPORT)); + if (result != null) { // A null return value cancels the packet + Vector3d position = result.correctedMovement(); + boolean isBelowVoid = entity.isVoidPositionDesynched(); - boolean teleportThroughVoidFloor, mustResyncPosition; - // Compare positions here for void floor fix below before the player's position variable is set to the packet position - if (entity.getPosition().getY() >= packet.getPosition().getY() && !isBelowVoid) { - int floorY = position.getFloorY(); - int voidFloorLocation = entity.voidFloorPosition(); - teleportThroughVoidFloor = floorY <= (voidFloorLocation + 1) && floorY >= voidFloorLocation; - } else { - teleportThroughVoidFloor = false; - } + boolean teleportThroughVoidFloor, mustResyncPosition; + // Compare positions here for void floor fix below before the player's position variable is set to the packet position + if (entity.getPosition().getY() >= packet.getPosition().getY() && !isBelowVoid) { + int floorY = position.getFloorY(); + int voidFloorLocation = entity.voidFloorPosition(); + teleportThroughVoidFloor = floorY <= (voidFloorLocation + 1) && floorY >= voidFloorLocation; + } else { + teleportThroughVoidFloor = false; + } - if (teleportThroughVoidFloor || isBelowVoid) { - // https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground. - isOnGround = false; - } + if (teleportThroughVoidFloor || isBelowVoid) { + // https://github.com/GeyserMC/Geyser/issues/3521 - no void floor in Java so we cannot be on the ground. + isOnGround = false; + } - if (isBelowVoid) { - int floorY = position.getFloorY(); - int voidFloorLocation = entity.voidFloorPosition(); - mustResyncPosition = floorY < voidFloorLocation && floorY >= voidFloorLocation - 1; - } else { - mustResyncPosition = false; - } + if (isBelowVoid) { + int floorY = position.getFloorY(); + int voidFloorLocation = entity.voidFloorPosition(); + mustResyncPosition = floorY < voidFloorLocation && floorY >= voidFloorLocation - 1; + } else { + mustResyncPosition = false; + } - double yPosition = position.getY(); - if (entity.isVoidPositionDesynched()) { // not using the cached variable on purpose - yPosition += 4; // We are de-synched since we had to teleport below the void floor. - } + double yPosition = position.getY(); + if (entity.isVoidPositionDesynched()) { // not using the cached variable on purpose + yPosition += 4; // We are de-synched since we had to teleport below the void floor. + } - Packet movePacket; - if (rotationChanged) { - // Send rotation updates as well - movePacket = new ServerboundMovePlayerPosRotPacket( + Packet movePacket; + if (rotationChanged) { + // Send rotation updates as well + movePacket = new ServerboundMovePlayerPosRotPacket( isOnGround, horizontalCollision, position.getX(), yPosition, position.getZ(), yaw, pitch - ); - entity.setYaw(yaw); - entity.setPitch(pitch); - entity.setHeadYaw(headYaw); - } else { - // Rotation did not change; don't send an update with rotation - movePacket = new ServerboundMovePlayerPosPacket(isOnGround, horizontalCollision, position.getX(), yPosition, position.getZ()); + ); + entity.setYaw(yaw); + entity.setPitch(pitch); + entity.setHeadYaw(headYaw); + } else { + // Rotation did not change; don't send an update with rotation + movePacket = new ServerboundMovePlayerPosPacket(isOnGround, horizontalCollision, position.getX(), yPosition, position.getZ()); + } + + entity.setPositionManual(packet.getPosition()); + + // Send final movement changes + session.sendDownstreamGamePacket(movePacket); + + if (teleportThroughVoidFloor) { + entity.teleportVoidFloorFix(false); + } else if (mustResyncPosition) { + entity.teleportVoidFloorFix(true); + } + + session.getInputCache().markPositionPacketSent(); + session.getSkullCache().updateVisibleSkulls(); } - - entity.setPositionManual(packet.getPosition()); - - // Send final movement changes - session.sendDownstreamGamePacket(movePacket); - - if (teleportThroughVoidFloor) { - entity.teleportVoidFloorFix(false); - } else if (mustResyncPosition) { - entity.teleportVoidFloorFix(true); - } - - session.getInputCache().markPositionPacketSent(); - session.getSkullCache().updateVisibleSkulls(); } } else { // Not a valid move From 512c68a88392e8f2354d790a1d30f6b00f4f5d34 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 18 Mar 2025 22:02:29 +0100 Subject: [PATCH 571/897] The team should still be used when there is a score display name (#5415) --- .../display/score/SidebarDisplayScore.java | 8 +- .../network/ScoreboardIssueTests.java | 113 ++++++++++++++++-- 2 files changed, 105 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/SidebarDisplayScore.java b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/SidebarDisplayScore.java index 42c0dbbf7..c6f4e9f43 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/SidebarDisplayScore.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/display/score/SidebarDisplayScore.java @@ -61,13 +61,15 @@ public final class SidebarDisplayScore extends DisplayScore { markUpdated(); String finalName = reference.name(); - String displayName = reference.displayName(); + String displayName = reference.displayName(); if (displayName != null) { finalName = displayName; - } else if (team != null) { + } + + if (team != null) { this.lastTeamUpdate = team.lastUpdate(); - finalName = team.displayName(reference.name()); + finalName = team.displayName(finalName); } NumberFormat numberFormat = reference.numberFormat(); 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 2239c9819..086d972dc 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,29 @@ 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 java.util.EnumSet; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import net.kyori.adventure.text.Component; +import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; import org.geysermc.geyser.entity.type.living.monster.EnderDragonPartEntity; import org.geysermc.geyser.session.cache.EntityCache; import org.geysermc.geyser.translator.protocol.java.entity.JavaRemoveEntitiesTranslator; @@ -40,7 +55,10 @@ import org.geysermc.geyser.translator.protocol.java.entity.JavaSetEntityDataTran import org.geysermc.geyser.translator.protocol.java.entity.player.JavaPlayerInfoUpdateTranslator; import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddEntityTranslator; import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddExperienceOrbTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetPlayerTeamTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetScoreTranslator; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntryAction; @@ -53,6 +71,9 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.CollisionRule; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ObjectiveAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; @@ -60,18 +81,12 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.Clie import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityDataPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetObjectivePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetScorePacket; import org.junit.jupiter.api.Test; -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. */ @@ -95,7 +110,7 @@ public class ScoreboardIssueTests { String displayName = context.mockOrSpy(EntityCache.class).getEntityByJavaId(2).getDisplayName(); assertEquals("entity.minecraft.experience_orb", displayName); - context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[] { 2 })); + context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[]{2})); }); // we know that spawning and removing the entity should be fine @@ -153,7 +168,7 @@ public class ScoreboardIssueTests { playerInfoUpdateTranslator, new ClientboundPlayerInfoUpdatePacket( EnumSet.of(PlayerListEntryAction.ADD_PLAYER, PlayerListEntryAction.UPDATE_LISTED), - new PlayerListEntry[] { + new PlayerListEntry[]{ new PlayerListEntry(npcUuid, new GameProfile(npcUuid, "1297"), false, 0, GameMode.SURVIVAL, null, false, 0, null, 0, null, null) })); @@ -183,7 +198,7 @@ public class ScoreboardIssueTests { ); context.translate( setPlayerTeamTranslator, - new ClientboundSetPlayerTeamPacket("npc_team_1297", TeamAction.ADD_PLAYER, new String[]{ "1297" })); + new ClientboundSetPlayerTeamPacket("npc_team_1297", TeamAction.ADD_PLAYER, new String[]{"1297"})); context.translate(addEntityTranslator, new ClientboundAddEntityPacket(1297, npcUuid, EntityType.PLAYER, 1, 2, 3, 4, 5, 6)); // then it updates the displayed skin parts, which isn't relevant for us @@ -245,7 +260,7 @@ public class ScoreboardIssueTests { ); context.translate( setPlayerTeamTranslator, - new ClientboundSetPlayerTeamPacket("npc_team_1298", TeamAction.ADD_PLAYER, new String[]{ hologramUuid.toString() })); + new ClientboundSetPlayerTeamPacket("npc_team_1298", TeamAction.ADD_PLAYER, new String[]{hologramUuid.toString()})); assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); @@ -255,4 +270,76 @@ public class ScoreboardIssueTests { }); }); } + + /** + * Test for #5353. + * It follows a code snippet provided in the PR description. + */ + @Test + void prefixNotShowing() { + mockContextScoreboard(context -> { + var setObjectiveTranslator = new JavaSetObjectiveTranslator(); + var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); + var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); + var setScoreTranslator = new JavaSetScoreTranslator(); + + context.translate( + setObjectiveTranslator, + new ClientboundSetObjectivePacket( + "sb-0", + ObjectiveAction.ADD, + Component.text("Test Scoreboard"), + ScoreType.INTEGER, + null + ) + ); + assertNoNextPacket(context); + + context.translate( + setDisplayObjectiveTranslator, + new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "sb-0") + ); + assertNextPacket(context, () -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("Test Scoreboard"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "sbt-1", + Component.text("displaynametest"), + Component.text("§aScore: 10"), + Component.empty(), + false, + false, + NameTagVisibility.NEVER, + CollisionRule.NEVER, + TeamColor.DARK_GREEN, + new String[]{"§0"}) + ); + assertNoNextPacket(context); + + context.translate( + setScoreTranslator, + new ClientboundSetScorePacket( + "§0", + "sb-0", + 10 + ).withDisplay(Component.empty()) + ); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 10, "§2§aScore: 10§r§2§r§2"))); + return packet; + }); + assertNoNextPacket(context); + }); + } } From 69329f2cad5002906f5ccda41b730e9c031836e7 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 25 Mar 2025 15:49:18 +0100 Subject: [PATCH 572/897] Feature: Resource Pack API additions - ResourcePackOptions and a GeyserDefineResourcePacksEvent (#4978) --- .../api/event/bedrock/SessionJoinEvent.java | 1 + .../SessionLoadResourcePacksEvent.java | 73 ++++- .../GeyserDefineResourcePacksEvent.java | 104 +++++++ .../GeyserLoadResourcePacksEvent.java | 5 +- .../event/lifecycle/GeyserPreReloadEvent.java | 2 +- .../geysermc/geyser/api/pack/PackCodec.java | 42 ++- .../geyser/api/pack/PathPackCodec.java | 4 +- .../geyser/api/pack/ResourcePack.java | 72 +++++ .../geyser/api/pack/ResourcePackManifest.java | 162 +++++++++- .../geyser/api/pack/UrlPackCodec.java | 51 ++++ .../pack/exception/ResourcePackException.java | 97 ++++++ .../api/pack/option/PriorityOption.java | 59 ++++ .../api/pack/option/ResourcePackOption.java | 76 +++++ .../geyser/api/pack/option/SubpackOption.java | 71 +++++ .../api/pack/option/UrlFallbackOption.java | 56 ++++ .../bungeecord/GeyserBungeeLogger.java | 7 + .../geyser/platform/mod/GeyserModLogger.java | 7 + .../platform/spigot/GeyserSpigotLogger.java | 7 + .../standalone/GeyserStandaloneLogger.java | 5 + .../velocity/GeyserVelocityLogger.java | 9 +- .../viaproxy/GeyserViaProxyLogger.java | 7 + .../java/org/geysermc/geyser/GeyserImpl.java | 5 +- .../org/geysermc/geyser/GeyserLogger.java | 9 + .../GeyserDefineResourcePacksEventImpl.java | 123 ++++++++ .../SessionLoadResourcePacksEventImpl.java | 177 ++++++++++- .../geyser/network/UpstreamPacketHandler.java | 94 ++++-- .../geyser/pack/GeyserResourcePack.java | 52 +++- .../pack/GeyserResourcePackManifest.java | 32 +- .../geyser/pack/ResourcePackHolder.java | 45 +++ .../pack/option/GeyserPriorityOption.java | 55 ++++ .../pack/option/GeyserSubpackOption.java | 66 ++++ .../pack/option/GeyserUrlFallbackOption.java | 53 ++++ .../geyser/pack/option/OptionHolder.java | 135 +++++++++ .../geyser/pack/path/GeyserPathPackCodec.java | 9 +- .../geyser/pack/url/GeyserUrlPackCodec.java | 96 ++++++ .../geysermc/geyser/registry/Registries.java | 6 +- .../loader/ProviderRegistryLoader.java | 22 +- .../registry/loader/ResourcePackLoader.java | 285 ++++++++++++++++-- .../geyser/scoreboard/Scoreboard.java | 34 +-- .../geyser/session/GeyserSessionAdapter.java | 4 +- .../geysermc/geyser/skin/SkinProvider.java | 2 +- .../org/geysermc/geyser/util/WebUtils.java | 119 +++++++- .../loader/ResourcePackLoaderTest.java | 4 +- .../network/util/EmptyGeyserLogger.java | 5 + gradle.properties | 2 +- 45 files changed, 2213 insertions(+), 138 deletions(-) create mode 100644 api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineResourcePacksEvent.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/pack/UrlPackCodec.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/pack/exception/ResourcePackException.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/pack/option/PriorityOption.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/pack/option/ResourcePackOption.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/pack/option/SubpackOption.java create mode 100644 api/src/main/java/org/geysermc/geyser/api/pack/option/UrlFallbackOption.java create mode 100644 core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineResourcePacksEventImpl.java create mode 100644 core/src/main/java/org/geysermc/geyser/pack/ResourcePackHolder.java create mode 100644 core/src/main/java/org/geysermc/geyser/pack/option/GeyserPriorityOption.java create mode 100644 core/src/main/java/org/geysermc/geyser/pack/option/GeyserSubpackOption.java create mode 100644 core/src/main/java/org/geysermc/geyser/pack/option/GeyserUrlFallbackOption.java create mode 100644 core/src/main/java/org/geysermc/geyser/pack/option/OptionHolder.java create mode 100644 core/src/main/java/org/geysermc/geyser/pack/url/GeyserUrlPackCodec.java diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionJoinEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionJoinEvent.java index ab2088c00..0228214a7 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionJoinEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionJoinEvent.java @@ -31,6 +31,7 @@ import org.geysermc.geyser.api.event.connection.ConnectionEvent; /** * Called when Geyser session connected to a Java remote server and is in a play-ready state. + * @since 2.1.1 */ public final class SessionJoinEvent extends ConnectionEvent { public SessionJoinEvent(@NonNull GeyserConnection connection) { diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoadResourcePacksEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoadResourcePacksEvent.java index c2f1cd427..edce76f6a 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoadResourcePacksEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoadResourcePacksEvent.java @@ -26,15 +26,20 @@ package org.geysermc.geyser.api.event.bedrock; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.connection.ConnectionEvent; import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.exception.ResourcePackException; +import org.geysermc.geyser.api.pack.option.ResourcePackOption; +import java.util.Collection; import java.util.List; import java.util.UUID; /** - * Called when Geyser initializes a session for a new Bedrock client and is in the process of sending resource packs. + * Called when Geyser initializes a session for a new Bedrock client and is in the process of sending {@link ResourcePack}'s. + * @since 2.1.1 */ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent { public SessionLoadResourcePacksEvent(@NonNull GeyserConnection connection) { @@ -42,26 +47,70 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent { } /** - * Gets an unmodifiable list of {@link ResourcePack}s that will be sent to the client. + * Gets the {@link ResourcePack}'s that will be sent to this {@link GeyserConnection}. + * To remove packs, use {@link #unregister(UUID)}, as the list returned + * by this method is unmodifiable. * - * @return an unmodifiable list of resource packs that will be sent to the client. + * @return an unmodifiable list of {@link ResourcePack}'s + * @since 2.1.1 */ public abstract @NonNull List resourcePacks(); /** - * Registers a {@link ResourcePack} to be sent to the client. - * - * @param resourcePack a resource pack that will be sent to the client. - * @return true if the resource pack was added successfully, - * or false if already present + * @deprecated Use {{@link #register(ResourcePack, ResourcePackOption[])}} instead */ - public abstract boolean register(@NonNull ResourcePack resourcePack); + @Deprecated + public abstract boolean register(@NonNull ResourcePack pack); /** - * Unregisters a resource pack from being sent to the client. + * Registers a {@link ResourcePack} to be sent to the client, optionally alongside + * specific {@link ResourcePackOption}'s specifying how it will be applied by the client. * - * @param uuid the UUID of the resource pack - * @return true whether the resource pack was removed from the list of resource packs. + * @param pack the {@link ResourcePack} that will be sent to the client + * @param options {@link ResourcePackOption}'s that specify how the client loads the pack + * @throws ResourcePackException if an issue occurred during pack registration + * @since 2.6.2 + */ + public abstract void register(@NonNull ResourcePack pack, @Nullable ResourcePackOption... options); + + /** + * Sets {@link ResourcePackOption}'s for a {@link ResourcePack}. + * This method can also be used to override options for resource packs already registered in the + * {@link org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent}. + * + * @param uuid the uuid of the resource pack to register the options for + * @param options the {@link ResourcePackOption}'s to register for the resource pack + * @throws ResourcePackException if an issue occurred during {@link ResourcePackOption} registration + * @since 2.6.2 + */ + public abstract void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption... options); + + /** + * Returns a collection of {@link ResourcePackOption}'s for a registered {@link ResourcePack}. + * The collection returned here is not modifiable. + * + * @param uuid the {@link ResourcePack} for which the options are set + * @return a collection of {@link ResourcePackOption}'s + * @throws ResourcePackException if the pack was not registered + * @since 2.6.2 + */ + public abstract Collection> options(@NonNull UUID uuid); + + /** + * Returns the current {@link ResourcePackOption}, or null, for a given {@link ResourcePackOption.Type}. + * + * @param uuid the {@link ResourcePack} for which to query this option type + * @param type the {@link ResourcePackOption.Type} of the option to query + * @throws ResourcePackException if the queried option is invalid or not present on the resource pack + * @since 2.6.2 + */ + public abstract @Nullable ResourcePackOption option(@NonNull UUID uuid, ResourcePackOption.@NonNull Type type); + + /** + * Unregisters a {@link ResourcePack} from the list of packs sent to this {@link GeyserConnection}. + * + * @param uuid the UUID of the {@link ResourcePack} to be removed + * @since 2.1.1 */ public abstract boolean unregister(@NonNull UUID uuid); } diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineResourcePacksEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineResourcePacksEvent.java new file mode 100644 index 000000000..4128f1c47 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineResourcePacksEvent.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2019-2025 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.api.event.lifecycle; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.event.Event; +import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.exception.ResourcePackException; +import org.geysermc.geyser.api.pack.option.ResourcePackOption; + +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +/** + * Called when {@link ResourcePack}'s are loaded within Geyser. + * @since 2.6.2 + */ +public abstract class GeyserDefineResourcePacksEvent implements Event { + + /** + * Gets the {@link ResourcePack}'s that will be sent to connecting Bedrock clients. + * To remove packs, use {@link #unregister(UUID)}, as the list returned + * by this method is unmodifiable. + * + * @return an unmodifiable list of {@link ResourcePack}'s + * @since 2.6.2 + */ + public abstract @NonNull List resourcePacks(); + + /** + * Registers a {@link ResourcePack} to be sent to the client, optionally alongside + * {@link ResourcePackOption}'s specifying how it will be applied on clients. + * + * @param pack a resource pack that will be sent to the client + * @param options {@link ResourcePackOption}'s that specify how clients load the pack + * @throws ResourcePackException if an issue occurred during pack registration + * @since 2.6.2 + */ + public abstract void register(@NonNull ResourcePack pack, @Nullable ResourcePackOption... options); + + /** + * Sets {@link ResourcePackOption}'s for a {@link ResourcePack}. + * + * @param uuid the uuid of the resource pack to register the options for + * @param options the {@link ResourcePackOption}'s to register for the resource pack + * @throws ResourcePackException if an issue occurred during {@link ResourcePackOption} registration + * @since 2.6.2 + */ + public abstract void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption... options); + + /** + * Returns a collection of {@link ResourcePackOption}'s for a registered {@link ResourcePack}. + * The collection returned here is not modifiable. + * + * @param uuid the uuid of the {@link ResourcePack} for which the options are set + * @return a collection of {@link ResourcePackOption}'s + * @throws ResourcePackException if the pack was not registered + * @since 2.6.2 + */ + public abstract Collection> options(@NonNull UUID uuid); + + /** + * Returns the current option, or null, for a given {@link ResourcePackOption.Type}. + * + * @param uuid the {@link ResourcePack} for which to query this option type + * @param type the {@link ResourcePackOption.Type} of the option to query + * @throws ResourcePackException if the queried option is invalid or not present on the resource pack + * @since 2.6.2 + */ + public abstract @Nullable ResourcePackOption option(@NonNull UUID uuid, ResourcePackOption.@NonNull Type type); + + /** + * Unregisters a {@link ResourcePack} from the list of packs sent to connecting Bedrock clients. + * + * @param uuid the UUID of the {@link ResourcePack} to be removed + * @since 2.6.2 + */ + public abstract void unregister(@NonNull UUID uuid); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java index e9b283ecb..047f9df57 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java @@ -32,9 +32,8 @@ import java.nio.file.Path; import java.util.List; /** - * Called when resource packs are loaded within Geyser. - * - * @param resourcePacks a mutable list of the currently listed resource packs + * @deprecated Use the {@link GeyserDefineResourcePacksEvent} instead. */ +@Deprecated public record GeyserLoadResourcePacksEvent(@NonNull List resourcePacks) implements Event { } diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreReloadEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreReloadEvent.java index 16d5058da..9147ad4b8 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreReloadEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreReloadEvent.java @@ -33,7 +33,7 @@ import org.geysermc.geyser.api.extension.ExtensionManager; /** * Called when Geyser is about to reload. Primarily aimed at extensions, so they can decide on their own what to reload. - * After this event is fired, some lifecycle events can be fired again - such as the {@link GeyserLoadResourcePacksEvent}. + * After this event is fired, some lifecycle events can be fired again - such as the {@link GeyserDefineResourcePacksEvent}. * * @param extensionManager the extension manager * @param eventBus the event bus diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java b/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java index 884129fa3..c83fce4c4 100644 --- a/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java +++ b/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java @@ -35,6 +35,7 @@ import java.nio.file.Path; /** * Represents a pack codec that can be used * to provide resource packs to clients. + * @since 2.1.1 */ public abstract class PackCodec { @@ -42,6 +43,7 @@ public abstract class PackCodec { * Gets the sha256 hash of the resource pack. * * @return the hash of the resource pack + * @since 2.1.1 */ public abstract byte @NonNull [] sha256(); @@ -49,34 +51,66 @@ public abstract class PackCodec { * Gets the resource pack size. * * @return the resource pack file size + * @since 2.1.1 */ public abstract long size(); /** - * Serializes the given resource pack into a byte buffer. + * @deprecated use {@link #serialize()} instead. + */ + @Deprecated + @NonNull + public SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException { + return serialize(); + }; + + /** + * Serializes the given codec into a byte buffer. * - * @param resourcePack the resource pack to serialize * @return the serialized resource pack + * @since 2.6.2 */ @NonNull - public abstract SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException; + public abstract SeekableByteChannel serialize() throws IOException; /** * Creates a new resource pack from this codec. * * @return the new resource pack + * @since 2.1.1 */ @NonNull protected abstract ResourcePack create(); + /** + * Creates a new resource pack builder from this codec. + * + * @return the new resource pack builder + * @since 2.6.2 + */ + protected abstract ResourcePack.@NonNull Builder createBuilder(); + /** * Creates a new pack provider from the given path. * * @param path the path to create the pack provider from * @return the new pack provider + * @since 2.1.1 */ @NonNull - public static PackCodec path(@NonNull Path path) { + public static PathPackCodec path(@NonNull Path path) { return GeyserApi.api().provider(PathPackCodec.class, path); } + + /** + * Creates a new pack provider from the given url. + * + * @param url the url to create the pack provider from + * @return the new pack provider + * @since 2.6.2 + */ + @NonNull + public static UrlPackCodec url(@NonNull String url) { + return GeyserApi.api().provider(UrlPackCodec.class, url); + } } diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java b/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java index a3770451a..d6d668fb2 100644 --- a/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java +++ b/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java @@ -32,6 +32,7 @@ import java.nio.file.Path; /** * Represents a pack codec that creates a resource * pack from a path on the filesystem. + * @since 2.1.1 */ public abstract class PathPackCodec extends PackCodec { @@ -39,7 +40,8 @@ public abstract class PathPackCodec extends PackCodec { * Gets the path of the resource pack. * * @return the path of the resource pack + * @since 2.1.1 */ @NonNull public abstract Path path(); -} \ No newline at end of file +} diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePack.java b/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePack.java index de1beaf65..19b579f26 100644 --- a/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePack.java +++ b/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePack.java @@ -26,12 +26,17 @@ package org.geysermc.geyser.api.pack; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.common.returnsreceiver.qual.This; +import org.geysermc.geyser.api.GeyserApi; + +import java.util.UUID; /** * Represents a resource pack sent to Bedrock clients *

    * This representation of a resource pack only contains what * Geyser requires to send it to the client. + * @since 2.1.1 */ public interface ResourcePack { @@ -39,6 +44,7 @@ public interface ResourcePack { * The {@link PackCodec codec} for this pack. * * @return the codec for this pack + * @since 2.1.1 */ @NonNull PackCodec codec(); @@ -47,6 +53,7 @@ public interface ResourcePack { * Gets the resource pack manifest. * * @return the resource pack manifest + * @since 2.1.1 */ @NonNull ResourcePackManifest manifest(); @@ -55,18 +62,83 @@ public interface ResourcePack { * Gets the content key of the resource pack. Lack of a content key is represented by an empty String. * * @return the content key of the resource pack + * @since 2.1.1 */ @NonNull String contentKey(); + /** + * Shortcut for getting the UUID from the {@link ResourcePackManifest}. + * + * @return the resource pack uuid + * @since 2.6.2 + */ + @NonNull + default UUID uuid() { + return manifest().header().uuid(); + } + /** * Creates a resource pack with the given {@link PackCodec}. * * @param codec the pack codec * @return the resource pack + * @since 2.1.1 */ @NonNull static ResourcePack create(@NonNull PackCodec codec) { return codec.create(); } + + /** + * Returns a {@link Builder} for a resource pack. + * It can be used to set a content key. + * + * @param codec the {@link PackCodec} to base the builder on + * @return a {@link Builder} to build a resource pack + * @since 2.6.2 + */ + static Builder builder(@NonNull PackCodec codec) { + return GeyserApi.api().provider(Builder.class, codec); + } + + /** + * A builder for a resource pack. It allows providing a content key manually. + * @since 2.6.2 + */ + interface Builder { + + /** + * @return the {@link ResourcePackManifest} of this resource pack + * @since 2.6.2 + */ + ResourcePackManifest manifest(); + + /** + * @return the {@link PackCodec} of this resource pack + * @since 2.6.2 + */ + PackCodec codec(); + + /** + * @return the current content key, or an empty string if not set + * @since 2.6.2 + */ + String contentKey(); + + /** + * Sets a content key for this resource pack. + * + * @param contentKey the content key + * @return this builder + * @since 2.6.2 + */ + @This Builder contentKey(@NonNull String contentKey); + + /** + * @return the resource pack + * @since 2.6.2 + */ + ResourcePack build(); + } } diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePackManifest.java b/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePackManifest.java index c9ccdd6c5..737682e22 100644 --- a/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePackManifest.java +++ b/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePackManifest.java @@ -26,55 +26,99 @@ package org.geysermc.geyser.api.pack; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent; +import org.geysermc.geyser.api.pack.option.SubpackOption; import java.util.Collection; import java.util.UUID; /** - * Represents a resource pack manifest. + * Represents a Bedrock edition resource pack manifest (manifest.json). + * All resource packs are required to have such a file as it identifies the resource pack. + * See + * Microsoft's docs for more info. + * @since 2.1.1 */ public interface ResourcePackManifest { /** * Gets the format version of the resource pack. + *

    + * "1" is used for skin packs, + * "2" is used for resource and behavior packs, and world templates. * * @return the format version + * @since 2.1.1 */ int formatVersion(); /** - * Gets the header of the resource pack. + * Gets the {@link Header} of the resource pack. * - * @return the header + * @return the {@link Header} + * @since 2.1.1 */ @NonNull Header header(); /** - * Gets the modules of the resource pack. + * Gets the {@link Module}'s of the resource pack. * - * @return the modules + * @return a collection of modules + * @since 2.1.1 */ @NonNull Collection modules(); /** - * Gets the dependencies of the resource pack. + * Gets the {@link Dependency}'s of the resource pack. * - * @return the dependencies + * @return a collection of dependencies + * @since 2.6.2 */ @NonNull Collection dependencies(); + /** + * Gets the {@link Subpack}'s of the resource pack. + * See Microsoft's docs on subpacks + * for more information. + * + * @return a collection of subpacks + * @since 2.6.2 + */ + @NonNull + Collection subpacks(); + + /** + * Gets the {@link Setting}'s of the resource pack. + * These are shown to Bedrock client's in the resource pack settings menu (see here) + * to inform users about what the resource pack and sub-packs include. + * + * @return a collection of settings + * @since 2.6.2 + */ + @NonNull + Collection settings(); + /** * Represents the header of a resource pack. + * It contains the main information about the resource pack, such as + * the name, description, or uuid. + * See + * Microsoft's docs for further details on headers. + * @since 2.1.1 */ interface Header { /** - * Gets the UUID of the resource pack. + * Gets the UUID of the resource pack. It is a unique identifier that differentiates this resource pack from any other resource pack. + * Bedrock clients will cache resource packs, and download resource packs when the uuid is new (or the version changes). * * @return the UUID + * @since 2.1.1 */ @NonNull UUID uuid(); @@ -83,6 +127,7 @@ public interface ResourcePackManifest { * Gets the version of the resource pack. * * @return the version + * @since 2.1.1 */ @NonNull Version version(); @@ -91,6 +136,7 @@ public interface ResourcePackManifest { * Gets the name of the resource pack. * * @return the name + * @since 2.1.1 */ @NonNull String name(); @@ -99,6 +145,7 @@ public interface ResourcePackManifest { * Gets the description of the resource pack. * * @return the description + * @since 2.1.1 */ @NonNull String description(); @@ -107,6 +154,7 @@ public interface ResourcePackManifest { * Gets the minimum supported Minecraft version of the resource pack. * * @return the minimum supported Minecraft version + * @since 2.1.1 */ @NonNull Version minimumSupportedMinecraftVersion(); @@ -114,21 +162,29 @@ public interface ResourcePackManifest { /** * Represents a module of a resource pack. + * It contains information about the content type that is + * offered by this resource pack. + * See + * Microsoft's docs for further details on modules. + * @since 2.1.1 */ interface Module { /** * Gets the UUID of the module. + * This should usually be different from the UUID in the {@link Header}. * * @return the UUID + * @since 2.1.1 */ @NonNull UUID uuid(); /** - * Gets the version of the module. + * Gets the {@link Version} of the module. * - * @return the version + * @return the {@link Version} + * @since 2.1.1 */ @NonNull Version version(); @@ -137,6 +193,7 @@ public interface ResourcePackManifest { * Gets the type of the module. * * @return the type + * @since 2.1.1 */ @NonNull String type(); @@ -145,6 +202,7 @@ public interface ResourcePackManifest { * Gets the description of the module. * * @return the description + * @since 2.1.1 */ @NonNull String description(); @@ -152,28 +210,102 @@ public interface ResourcePackManifest { /** * Represents a dependency of a resource pack. + * These are references to other resource packs that must be + * present in order for this resource pack to apply. + * See + * Microsoft's docs for further details on dependencies. + * @since 2.1.1 */ interface Dependency { /** - * Gets the UUID of the dependency. + * Gets the UUID of the resource pack dependency. * * @return the uuid + * @since 2.1.1 */ @NonNull UUID uuid(); /** - * Gets the version of the dependency. + * Gets the {@link Version} of the dependency. * - * @return the version + * @return the {@link Version} + * @since 2.1.1 */ @NonNull Version version(); } + /** + * Represents a subpack of a resource pack. These are often used for "variants" of the resource pack, + * such as lesser details, or additional features either to be determined by player's taste or adapted to the player device's performance. + * See Micoroft's docs for more information. + */ + interface Subpack { + + /** + * Gets the folder name where this sub-pack is placed in. + * + * @return the folder name + * @since 2.6.2 + */ + @NonNull + String folderName(); + + /** + * Gets the name of this subpack. Required for each subpack to be valid. + * To make a Bedrock client load any subpack, register the resource pack + * in the {@link SessionLoadResourcePacksEvent} or {@link GeyserDefineResourcePacksEvent} and specify a + * {@link SubpackOption} with the name of the subpack to load. + * + * @return the subpack name + * @since 2.6.2 + */ + @NonNull + String name(); + + /** + * Gets the memory tier of this Subpack, representing how much RAM a device must have to run it. + * Each memory tier requires 0.25 GB of RAM. For example, a memory tier of 0 is no requirement, + * and a memory tier of 4 requires 1GB of RAM. + * + * @return the memory tier + * @since 2.6.2 + */ + @Nullable + Float memoryTier(); + } + + /** + * Represents a setting that is shown client-side that describe what a pack does. + * Multiple setting entries are shown in separate paragraphs. + * @since 2.6.2 + */ + interface Setting { + + /** + * The type of the setting. Usually just "label". + * + * @return the type + * @since 2.6.2 + */ + @NonNull + String type(); + + /** + * The text shown for the setting. + * + * @return the text content + * @since 2.6.2 + */ + @NonNull + String text(); + } + /** * Represents a version of a resource pack. + * @since 2.1.1 */ interface Version { @@ -181,6 +313,7 @@ public interface ResourcePackManifest { * Gets the major version. * * @return the major version + * @since 2.1.1 */ int major(); @@ -188,6 +321,7 @@ public interface ResourcePackManifest { * Gets the minor version. * * @return the minor version + * @since 2.1.1 */ int minor(); @@ -195,6 +329,7 @@ public interface ResourcePackManifest { * Gets the patch version. * * @return the patch version + * @since 2.1.1 */ int patch(); @@ -202,6 +337,7 @@ public interface ResourcePackManifest { * Gets the version formatted as a String. * * @return the version string + * @since 2.1.1 */ @NonNull String toString(); } diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/UrlPackCodec.java b/api/src/main/java/org/geysermc/geyser/api/pack/UrlPackCodec.java new file mode 100644 index 000000000..e729e3fbb --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/pack/UrlPackCodec.java @@ -0,0 +1,51 @@ +/* + * 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.api.pack; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * Represents a pack codec that creates a resource + * pack from a URL. + *

    + * Due to Bedrock limitations, the URL must: + *

      + *
    • be a direct download link to a .zip or .mcpack resource pack
    • + *
    • use the application type `application/zip` and set a correct content length
    • + *
    + * @since 2.6.2 + */ +public abstract class UrlPackCodec extends PackCodec { + + /** + * Gets the URL to the resource pack location. + * + * @return the URL of the resource pack + * @since 2.6.2 + */ + @NonNull + public abstract String url(); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/exception/ResourcePackException.java b/api/src/main/java/org/geysermc/geyser/api/pack/exception/ResourcePackException.java new file mode 100644 index 000000000..66b3924d5 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/pack/exception/ResourcePackException.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025 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.api.pack.exception; + +import java.io.Serial; + +/** + * Used to indicate an exception that occurred while handling resource pack registration, + * or during resource pack option validation. + * @since 2.6.2 + */ +public class ResourcePackException extends IllegalArgumentException { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * The {@link Cause} of this exception. + */ + private final Cause cause; + + /** + * @param cause the cause of this exception + * @since 2.6.2 + */ + public ResourcePackException(Cause cause) { + super(cause.message()); + this.cause = cause; + } + + /** + * @param cause the cause of this exception + * @param message an additional, more in-depth message about the issue. + * @since 2.6.2 + */ + public ResourcePackException(Cause cause, String message) { + super(message); + this.cause = cause; + } + + /** + * @return the cause of this exception + * @since 2.6.2 + */ + public Cause cause() { + return cause; + } + + /** + * Represents different causes with explanatory messages stating which issue occurred. + * @since 2.6.2 + */ + public enum Cause { + DUPLICATE("A resource pack with this UUID was already registered!"), + INVALID_PACK("This resource pack is not a valid Bedrock edition resource pack!"), + INVALID_PACK_OPTION("Attempted to register an invalid resource pack option!"), + PACK_NOT_FOUND("No resource pack was found!"), + UNKNOWN_IMPLEMENTATION("Use the resource pack codecs to create resource packs."); + + private final String message; + + /** + * @return the message of this cause + * @since 2.6.2 + */ + public String message() { + return message; + } + + Cause(String message) { + this.message = message; + } + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/option/PriorityOption.java b/api/src/main/java/org/geysermc/geyser/api/pack/option/PriorityOption.java new file mode 100644 index 000000000..f1f91e9a9 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/pack/option/PriorityOption.java @@ -0,0 +1,59 @@ +/* + * 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.api.pack.option; + +import org.geysermc.geyser.api.GeyserApi; + +/** + * Allows specifying a pack priority that decides the order on how packs are sent to the client. + * If two resource packs modify the same texture - for example if one removes the pumpkin overlay and + * the other is just making it translucent, one of the packs will override the other. + * Specifically, the pack with the higher priority will override the pack changes of the lower priority. + * @since 2.6.2 + */ +public interface PriorityOption extends ResourcePackOption { + + PriorityOption HIGHEST = PriorityOption.priority(100); + PriorityOption HIGH = PriorityOption.priority(50); + PriorityOption NORMAL = PriorityOption.priority(0); + PriorityOption LOW = PriorityOption.priority(-50); + PriorityOption LOWEST = PriorityOption.priority(-100); + + /** + * Constructs a priority option based on a value between 0 and 10. + * The higher the number, the higher will this pack appear in the resource pack stack. + * + * @param priority an integer that is above 0, but smaller than 10 + * @return the priority option + * @since 2.6.2 + */ + static PriorityOption priority(int priority) { + if (priority < -100 || priority > 100) { + throw new IllegalArgumentException("Priority must be between 0 and 10 inclusive!"); + } + return GeyserApi.api().provider(PriorityOption.class, priority); + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/option/ResourcePackOption.java b/api/src/main/java/org/geysermc/geyser/api/pack/option/ResourcePackOption.java new file mode 100644 index 000000000..a86ad88db --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/pack/option/ResourcePackOption.java @@ -0,0 +1,76 @@ +/* + * 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.api.pack.option; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.exception.ResourcePackException; + +/** + * Represents a resource pack option that can be used to specify how a resource + * pack is sent to Bedrock clients. + *

    + * Not all options can be applied to all resource packs. For example, you cannot specify + * a specific subpack to be loaded on resource packs that do not have subpacks. + * To see which limitations apply to specific resource pack options, check the javadocs + * or see the {@link #validate(ResourcePack)} method. + * @since 2.6.2 + */ +public interface ResourcePackOption { + + /** + * @return the option type + * @since 2.6.2 + */ + @NonNull Type type(); + + /** + * @return the value of the option + * @since 2.6.2 + */ + @NonNull T value(); + + /** + * Used to validate a specific options for a pack. + * Some options are not applicable to some packs. + * + * @param pack the resource pack to validate the option for + * @throws ResourcePackException with the {@link ResourcePackException.Cause#INVALID_PACK_OPTION} cause + * @since 2.6.2 + */ + void validate(@NonNull ResourcePack pack); + + /** + * Represents the different types of resource pack options. + * @since 2.6.2 + */ + enum Type { + SUBPACK, + PRIORITY, + FALLBACK + } + +} diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/option/SubpackOption.java b/api/src/main/java/org/geysermc/geyser/api/pack/option/SubpackOption.java new file mode 100644 index 000000000..a0462afa7 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/pack/option/SubpackOption.java @@ -0,0 +1,71 @@ +/* + * 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.api.pack.option; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.GeyserApi; +import org.geysermc.geyser.api.pack.ResourcePackManifest; + +/** + * Can be used to specify which subpack from a resource pack a player should load. + * Available subpacks can be seen in a resource pack manifest {@link ResourcePackManifest#subpacks()}. + * @since 2.6.2 + */ +public interface SubpackOption extends ResourcePackOption { + + /** + * Creates a subpack option based on a {@link ResourcePackManifest.Subpack}. + * + * @param subpack the chosen subpack + * @return a subpack option specifying that subpack + * @since 2.6.2 + */ + static SubpackOption subpack(ResourcePackManifest.@NonNull Subpack subpack) { + return named(subpack.name()); + } + + /** + * Creates a subpack option based on a subpack name. + * + * @param subpackName the name of the subpack + * @return a subpack option specifying a subpack with that name + * @since 2.6.2 + */ + static SubpackOption named(@NonNull String subpackName) { + return GeyserApi.api().provider(SubpackOption.class, subpackName); + } + + /** + * Creates a subpack option with no subpack specified. + * + * @return a subpack option specifying no subpack + * @since 2.6.2 + */ + static SubpackOption empty() { + return GeyserApi.api().provider(SubpackOption.class, ""); + } + +} diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/option/UrlFallbackOption.java b/api/src/main/java/org/geysermc/geyser/api/pack/option/UrlFallbackOption.java new file mode 100644 index 000000000..9431c8cdd --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/pack/option/UrlFallbackOption.java @@ -0,0 +1,56 @@ +/* + * 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.api.pack.option; + +import org.geysermc.geyser.api.GeyserApi; +import org.geysermc.geyser.api.pack.PathPackCodec; +import org.geysermc.geyser.api.pack.UrlPackCodec; + +/** + * Can be used for resource packs created with the {@link UrlPackCodec}. + * When a Bedrock client is unable to download a resource pack from a URL, Geyser will, by default, + * serve the resource pack over raknet (as packs are served with the {@link PathPackCodec}). + * This option can be used to disable that behavior, and disconnect the player instead. + * By default, the {@link UrlFallbackOption#TRUE} option is set. + * @since 2.6.2 + */ +public interface UrlFallbackOption extends ResourcePackOption { + + UrlFallbackOption TRUE = fallback(true); + UrlFallbackOption FALSE = fallback(false); + + /** + * Whether to fall back to serving packs over the raknet connection + * + * @param fallback whether to fall back + * @return a UrlFallbackOption with the specified behavior + * @since 2.6.2 + */ + static UrlFallbackOption fallback(boolean fallback) { + return GeyserApi.api().provider(UrlFallbackOption.class, fallback); + } + +} diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java index e8cf7ee39..e9b18acca 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java @@ -75,4 +75,11 @@ public class GeyserBungeeLogger implements GeyserLogger { info(message); } } + + @Override + public void debug(String message, Object... arguments) { + if (debug) { + info(String.format(message, arguments)); + } + } } diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java index 9260288d7..9903d0d2e 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java @@ -84,6 +84,13 @@ public class GeyserModLogger implements GeyserLogger { } } + @Override + public void debug(String message, Object... arguments) { + if (debug) { + logger.info(message, arguments); + } + } + @Override public void setDebug(boolean debug) { this.debug = debug; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java index 5c6101eae..231255fec 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java @@ -75,4 +75,11 @@ public class GeyserSpigotLogger implements GeyserLogger { info(message); } } + + @Override + public void debug(String message, Object... arguments) { + if (debug) { + info(String.format(message, arguments)); + } + } } 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 9c744f015..510ac0e79 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 @@ -115,6 +115,11 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey log.debug(ChatColor.GRAY + message); } + @Override + public void debug(String message, Object... arguments) { + log.debug(ChatColor.GRAY + message, arguments); + } + @Override public void setDebug(boolean debug) { Configurator.setLevel(log.getName(), debug ? Level.DEBUG : Level.INFO); diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java index 4d10e4daf..5155d8958 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java @@ -73,4 +73,11 @@ public class GeyserVelocityLogger implements GeyserLogger { info(message); } } -} \ No newline at end of file + + @Override + public void debug(String message, Object... arguments) { + if (debug) { + logger.info(message, arguments); + } + } +} diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java index 10f414b51..fdcfe2279 100644 --- a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java +++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java @@ -75,6 +75,13 @@ public class GeyserViaProxyLogger implements GeyserLogger, GeyserCommandSource { } } + @Override + public void debug(String message, Object... arguments) { + if (this.debug) { + this.debug(String.format(message, arguments)); + } + } + @Override public void setDebug(boolean debug) { this.debug = debug; diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index e81d528aa..c7b8ff031 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -80,6 +80,7 @@ import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.GeyserServer; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.loader.ResourcePackLoader; import org.geysermc.geyser.registry.provider.ProviderSupplier; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; import org.geysermc.geyser.session.GeyserSession; @@ -677,9 +678,7 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { runIfNonNull(newsHandler, NewsHandler::shutdown); runIfNonNull(erosionUnixListener, UnixSocketClientListener::close); - if (Registries.RESOURCE_PACKS.loaded()) { - Registries.RESOURCE_PACKS.get().clear(); - } + ResourcePackLoader.clear(); this.setEnabled(false); } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java index f408de29c..92b50751a 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java @@ -103,6 +103,15 @@ public interface GeyserLogger extends GeyserCommandSource { debug(String.valueOf(object)); } + /** + * Logs and formats a message to console if debug mode is enabled, + * with the provided arguments. + * + * @param message the message to log + * @param arguments the arguments to replace in the message + */ + void debug(String message, Object... arguments); + /** * Sets if the logger should print debug messages * diff --git a/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineResourcePacksEventImpl.java b/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineResourcePacksEventImpl.java new file mode 100644 index 000000000..2e62a4482 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineResourcePacksEventImpl.java @@ -0,0 +1,123 @@ +/* + * 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.event.type; + +import lombok.Getter; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent; +import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.exception.ResourcePackException; +import org.geysermc.geyser.api.pack.option.ResourcePackOption; +import org.geysermc.geyser.pack.GeyserResourcePack; +import org.geysermc.geyser.pack.ResourcePackHolder; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +@Getter +public class GeyserDefineResourcePacksEventImpl extends GeyserDefineResourcePacksEvent { + private final Map packs; + + public GeyserDefineResourcePacksEventImpl(Map packMap) { + this.packs = packMap; + } + + @Override + public @NonNull List resourcePacks() { + return packs.values().stream().map(ResourcePackHolder::resourcePack).toList(); + } + + @Override + public void register(@NonNull ResourcePack resourcePack, @Nullable ResourcePackOption... options) { + Objects.requireNonNull(resourcePack, "resource pack must not be null!"); + if (!(resourcePack instanceof GeyserResourcePack pack)) { + throw new ResourcePackException(ResourcePackException.Cause.UNKNOWN_IMPLEMENTATION); + } + + UUID uuid = resourcePack.uuid(); + if (packs.containsKey(uuid)) { + throw new ResourcePackException(ResourcePackException.Cause.DUPLICATE); + } + + ResourcePackHolder holder = ResourcePackHolder.of(pack); + attemptRegisterOptions(holder, options); + packs.put(uuid, holder); + } + + @Override + public void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption... options) { + Objects.requireNonNull(uuid); + Objects.requireNonNull(options); + + ResourcePackHolder holder = packs.get(uuid); + if (holder == null) { + throw new ResourcePackException(ResourcePackException.Cause.PACK_NOT_FOUND); + } + + attemptRegisterOptions(holder, options); + } + + @Override + public Collection> options(@NonNull UUID uuid) { + Objects.requireNonNull(uuid); + ResourcePackHolder packHolder = packs.get(uuid); + if (packHolder == null) { + throw new ResourcePackException(ResourcePackException.Cause.PACK_NOT_FOUND); + } + + return packHolder.optionHolder().immutableValues(); + } + + @Override + public @Nullable ResourcePackOption option(@NonNull UUID uuid, ResourcePackOption.@NonNull Type type) { + Objects.requireNonNull(uuid); + Objects.requireNonNull(type); + + ResourcePackHolder packHolder = packs.get(uuid); + if (packHolder == null) { + throw new ResourcePackException(ResourcePackException.Cause.PACK_NOT_FOUND); + } + + return packHolder.optionHolder().get(type); + } + + @Override + public void unregister(@NonNull UUID uuid) { + packs.remove(uuid); + } + + private void attemptRegisterOptions(@NonNull ResourcePackHolder holder, @Nullable ResourcePackOption... options) { + if (options == null) { + return; + } + + holder.optionHolder().validateAndAdd(holder.pack(), options); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/event/type/SessionLoadResourcePacksEventImpl.java b/core/src/main/java/org/geysermc/geyser/event/type/SessionLoadResourcePacksEventImpl.java index 5bc0dd0bd..a926e5400 100644 --- a/core/src/main/java/org/geysermc/geyser/event/type/SessionLoadResourcePacksEventImpl.java +++ b/core/src/main/java/org/geysermc/geyser/event/type/SessionLoadResourcePacksEventImpl.java @@ -25,45 +25,200 @@ package org.geysermc.geyser.event.type; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.protocol.bedrock.packet.ResourcePackStackPacket; +import org.cloudburstmc.protocol.bedrock.packet.ResourcePacksInfoPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent; import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.ResourcePackManifest; +import org.geysermc.geyser.api.pack.exception.ResourcePackException; +import org.geysermc.geyser.api.pack.option.PriorityOption; +import org.geysermc.geyser.api.pack.option.ResourcePackOption; +import org.geysermc.geyser.pack.GeyserResourcePack; +import org.geysermc.geyser.pack.ResourcePackHolder; +import org.geysermc.geyser.pack.option.OptionHolder; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent { - private final Map packs; + /** + * The packs for this Session. A {@link ResourcePackHolder} may contain resource pack options registered + * during the {@link org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent}. + */ + @Getter + private final Map packs; - public SessionLoadResourcePacksEventImpl(GeyserSession session, Map packMap) { + /** + * The additional, per-session options for the resource packs of this session. + * These options are prioritized over the "default" options registered + * in the {@link org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent} + */ + private final Map sessionPackOptionOverrides; + + public SessionLoadResourcePacksEventImpl(GeyserSession session) { super(session); - this.packs = packMap; - } - - public @NonNull Map getPacks() { - return packs; + this.packs = new Object2ObjectLinkedOpenHashMap<>(Registries.RESOURCE_PACKS.get()); + this.sessionPackOptionOverrides = new Object2ObjectOpenHashMap<>(); } @Override public @NonNull List resourcePacks() { - return List.copyOf(packs.values()); + return packs.values().stream().map(ResourcePackHolder::resourcePack).toList(); } @Override public boolean register(@NonNull ResourcePack resourcePack) { - UUID packID = resourcePack.manifest().header().uuid(); - if (packs.containsValue(resourcePack) || packs.containsKey(packID)) { + try { + register(resourcePack, PriorityOption.NORMAL); + } catch (ResourcePackException e) { + GeyserImpl.getInstance().getLogger().error("An exception occurred while registering resource pack: " + e.getMessage(), e); return false; } - packs.put(resourcePack.manifest().header().uuid(), resourcePack); return true; } + @Override + public void register(@NonNull ResourcePack resourcePack, @Nullable ResourcePackOption... options) { + Objects.requireNonNull(resourcePack); + if (!(resourcePack instanceof GeyserResourcePack pack)) { + throw new ResourcePackException(ResourcePackException.Cause.UNKNOWN_IMPLEMENTATION); + } + + UUID uuid = resourcePack.uuid(); + if (packs.containsKey(uuid)) { + throw new ResourcePackException(ResourcePackException.Cause.DUPLICATE); + } + + attemptRegisterOptions(pack, options); + packs.put(uuid, ResourcePackHolder.of(pack)); + } + + @Override + public void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption... options) { + Objects.requireNonNull(uuid, "uuid cannot be null"); + Objects.requireNonNull(options, "options cannot be null"); + ResourcePackHolder holder = packs.get(uuid); + if (holder == null) { + throw new ResourcePackException(ResourcePackException.Cause.PACK_NOT_FOUND); + } + + attemptRegisterOptions(holder.pack(), options); + } + + @Override + public Collection> options(@NonNull UUID uuid) { + Objects.requireNonNull(uuid); + ResourcePackHolder packHolder = packs.get(uuid); + if (packHolder == null) { + throw new ResourcePackException(ResourcePackException.Cause.PACK_NOT_FOUND); + } + + OptionHolder optionHolder = sessionPackOptionOverrides.get(uuid); + if (optionHolder == null) { + // No need to create a new session option holder + return packHolder.optionHolder().immutableValues(); + } + + return optionHolder.immutableValues(packHolder.optionHolder()); + } + + @Override + public @Nullable ResourcePackOption option(@NonNull UUID uuid, ResourcePackOption.@NonNull Type type) { + Objects.requireNonNull(uuid); + Objects.requireNonNull(type); + + ResourcePackHolder packHolder = packs.get(uuid); + if (packHolder == null) { + throw new ResourcePackException(ResourcePackException.Cause.PACK_NOT_FOUND); + } + + @Nullable OptionHolder additionalOptions = sessionPackOptionOverrides.get(uuid); + OptionHolder defaultHolder = packHolder.optionHolder(); + Objects.requireNonNull(defaultHolder); // should never be null + + return OptionHolder.optionByType(type, additionalOptions, defaultHolder); + } + @Override public boolean unregister(@NonNull UUID uuid) { + sessionPackOptionOverrides.remove(uuid); return packs.remove(uuid) != null; } + + private void attemptRegisterOptions(@NonNull GeyserResourcePack pack, @Nullable ResourcePackOption... options) { + if (options == null) { + return; + } + + OptionHolder holder = this.sessionPackOptionOverrides.computeIfAbsent(pack.uuid(), $ -> new OptionHolder()); + holder.validateAndAdd(pack, options); + } + + // Methods used internally for e.g. ordered packs, or resource pack entries + + public List orderedPacks() { + return packs.values().stream() + // Map each ResourcePack to a pair of (GeyserResourcePack, Priority) + .map(holder -> new AbstractMap.SimpleEntry<>(holder.pack(), priority(holder.pack()))) + // Sort by priority in descending order + .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) + // Map the sorted entries to ResourcePackStackPacket.Entry + .map(entry -> { + ResourcePackManifest.Header header = entry.getKey().manifest().header(); + return new ResourcePackStackPacket.Entry( + header.uuid().toString(), + header.version().toString(), + subpackName(entry.getKey()) + ); + }) + .toList(); + } + + public List infoPacketEntries() { + List entries = new ArrayList<>(); + + for (ResourcePackHolder holder : packs.values()) { + GeyserResourcePack pack = holder.pack(); + ResourcePackManifest.Header header = pack.manifest().header(); + entries.add(new ResourcePacksInfoPacket.Entry( + header.uuid(), header.version().toString(), pack.codec().size(), pack.contentKey(), + subpackName(pack), header.uuid().toString(), false, false, false, subpackName(pack)) + ); + } + + return entries; + } + + // Helper methods to get the options for a ResourcePack + + public T value(UUID uuid, ResourcePackOption.Type type, T defaultValue) { + OptionHolder holder = sessionPackOptionOverrides.get(uuid); + OptionHolder defaultHolder = packs.get(uuid).optionHolder(); + Objects.requireNonNull(defaultHolder); // should never be null + + return OptionHolder.valueOrFallback(type, holder, defaultHolder, defaultValue); + } + + private double priority(GeyserResourcePack pack) { + return value(pack.uuid(), ResourcePackOption.Type.PRIORITY, PriorityOption.NORMAL.value()); + } + + private String subpackName(GeyserResourcePack pack) { + return value(pack.uuid(), ResourcePackOption.Type.SUBPACK, ""); + } } 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 c67ea6545..f2bd7a5c5 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -58,10 +58,14 @@ import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.pack.PackCodec; import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.api.pack.ResourcePackManifest; +import org.geysermc.geyser.api.pack.UrlPackCodec; +import org.geysermc.geyser.api.pack.option.ResourcePackOption; import org.geysermc.geyser.event.type.SessionLoadResourcePacksEventImpl; import org.geysermc.geyser.pack.GeyserResourcePack; +import org.geysermc.geyser.pack.ResourcePackHolder; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.loader.ResourcePackLoader; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.PendingMicrosoftAuthentication; import org.geysermc.geyser.text.GeyserLocale; @@ -74,7 +78,6 @@ import java.nio.ByteBuffer; import java.nio.channels.SeekableByteChannel; import java.util.ArrayDeque; import java.util.Deque; -import java.util.HashMap; import java.util.OptionalInt; import java.util.UUID; @@ -199,17 +202,12 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { geyser.getSessionManager().addPendingSession(session); - this.resourcePackLoadEvent = new SessionLoadResourcePacksEventImpl(session, new HashMap<>(Registries.RESOURCE_PACKS.get())); + this.resourcePackLoadEvent = new SessionLoadResourcePacksEventImpl(session); this.geyser.eventBus().fire(this.resourcePackLoadEvent); ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket(); - for (ResourcePack pack : this.resourcePackLoadEvent.resourcePacks()) { - PackCodec codec = pack.codec(); - ResourcePackManifest.Header header = pack.manifest().header(); - resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry( - header.uuid(), header.version().toString(), codec.size(), pack.contentKey(), - "", header.uuid().toString(), false, false, false, "")); - } + resourcePacksInfo.getResourcePackInfos().addAll(this.resourcePackLoadEvent.infoPacketEntries()); + resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks()); resourcePacksInfo.setWorldTemplateId(UUID.randomUUID()); resourcePacksInfo.setWorldTemplateVersion("*"); @@ -222,7 +220,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public PacketSignal handle(ResourcePackClientResponsePacket packet) { switch (packet.getStatus()) { - case COMPLETED: + case COMPLETED -> { if (geyser.getConfig().getRemote().authType() != AuthType.ONLINE) { session.authenticate(session.getAuthData().name()); } else if (!couldLoginUserByName(session.getAuthData().name())) { @@ -230,30 +228,21 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { session.connect(); } geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.connect", session.getAuthData().name())); - break; - - case SEND_PACKS: + } + case SEND_PACKS -> { packsToSend.addAll(packet.getPackIds()); sendPackDataInfo(packsToSend.pop()); - break; - - case HAVE_ALL_PACKS: + } + case HAVE_ALL_PACKS -> { ResourcePackStackPacket stackPacket = new ResourcePackStackPacket(); stackPacket.setExperimentsPreviouslyToggled(false); stackPacket.setForcedToAccept(false); // Leaving this as false allows the player to choose to download or not stackPacket.setGameVersion(session.getClientData().getGameVersion()); - - for (ResourcePack pack : this.resourcePackLoadEvent.resourcePacks()) { - ResourcePackManifest.Header header = pack.manifest().header(); - stackPacket.getResourcePacks().add(new ResourcePackStackPacket.Entry(header.uuid().toString(), header.version().toString(), "")); - } + stackPacket.getResourcePacks().addAll(this.resourcePackLoadEvent.orderedPacks()); session.sendUpstreamPacket(stackPacket); - break; - - default: - session.disconnect("disconnectionScreen.resourcePack"); - break; + } + default -> session.disconnect("disconnectionScreen.resourcePack"); } return PacketSignal.HANDLED; @@ -302,10 +291,29 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public PacketSignal handle(ResourcePackChunkRequestPacket packet) { + ResourcePackHolder holder = this.resourcePackLoadEvent.getPacks().get(packet.getPackId()); + + if (holder == null) { + GeyserImpl.getInstance().getLogger().debug("Client {0} tried to request pack id {1} not sent to it!", + session.bedrockUsername(), packet.getPackId()); + session.disconnect("disconnectionScreen.resourcePack"); + return PacketSignal.HANDLED; + } + + ResourcePack pack = holder.pack(); ResourcePackChunkDataPacket data = new ResourcePackChunkDataPacket(); - ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packet.getPackId()); PackCodec codec = pack.codec(); + // If a remote pack ends up here, that usually implies that a client was not able to download the pack + if (codec instanceof UrlPackCodec urlPackCodec) { + ResourcePackLoader.testRemotePack(session, urlPackCodec, packet.getPackId(), packet.getPackVersion()); + + if (!resourcePackLoadEvent.value(pack.uuid(), ResourcePackOption.Type.FALLBACK, true)) { + session.disconnect("Unable to provide downloaded resource pack. Contact an administrator!"); + return PacketSignal.HANDLED; + } + } + data.setChunkIndex(packet.getChunkIndex()); data.setProgress((long) packet.getChunkIndex() * GeyserResourcePack.CHUNK_SIZE); data.setPackVersion(packet.getPackVersion()); @@ -315,10 +323,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { long remainingSize = codec.size() - offset; byte[] packData = new byte[(int) MathUtils.constrain(remainingSize, 0, GeyserResourcePack.CHUNK_SIZE)]; - try (SeekableByteChannel channel = codec.serialize(pack)) { + try (SeekableByteChannel channel = codec.serialize()) { channel.position(offset); channel.read(ByteBuffer.wrap(packData, 0, packData.length)); } catch (IOException e) { + session.disconnect("disconnectionScreen.resourcePack"); e.printStackTrace(); } @@ -337,8 +346,33 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { private void sendPackDataInfo(String id) { ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket(); String[] packID = id.split("_"); - UUID uuid = UUID.fromString(packID[0]); - ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(uuid); + + if (packID.length < 2) { + GeyserImpl.getInstance().getLogger().debug("Client {0} tried to request invalid pack id {1}!", + session.bedrockUsername(), packID); + session.disconnect("disconnectionScreen.resourcePack"); + return; + } + + UUID packId; + try { + packId = UUID.fromString(packID[0]); + } catch (IllegalArgumentException e) { + GeyserImpl.getInstance().getLogger().debug("Client {0} tried to request pack with an invalid id {1})", + session.bedrockUsername(), id); + session.disconnect("disconnectionScreen.resourcePack"); + return; + } + + ResourcePackHolder holder = this.resourcePackLoadEvent.getPacks().get(packId); + if (holder == null) { + GeyserImpl.getInstance().getLogger().debug("Client {0} tried to request pack id {1} not sent to it!", + session.bedrockUsername(), id); + session.disconnect("disconnectionScreen.resourcePack"); + return; + } + + ResourcePack pack = holder.pack(); PackCodec codec = pack.codec(); ResourcePackManifest.Header header = pack.manifest().header(); diff --git a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePack.java b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePack.java index 82408b6e7..306bb9aa8 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePack.java +++ b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePack.java @@ -25,14 +25,64 @@ package org.geysermc.geyser.pack; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.pack.PackCodec; import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.api.pack.ResourcePackManifest; -public record GeyserResourcePack(PackCodec codec, ResourcePackManifest manifest, String contentKey) implements ResourcePack { +import java.util.Objects; + +public record GeyserResourcePack( + @NonNull PackCodec codec, + @NonNull ResourcePackManifest manifest, + @NonNull String contentKey +) implements ResourcePack { /** * The size of each chunk to use when sending the resource packs to clients in bytes */ public static final int CHUNK_SIZE = 102400; + + public static class Builder implements ResourcePack.Builder { + + public Builder(PackCodec codec, ResourcePackManifest manifest) { + this.codec = codec; + this.manifest = manifest; + } + + public Builder(PackCodec codec, ResourcePackManifest manifest, String contentKey) { + this.codec = codec; + this.manifest = manifest; + this.contentKey = contentKey; + } + + private final PackCodec codec; + private final ResourcePackManifest manifest; + private String contentKey = ""; + + @Override + public ResourcePackManifest manifest() { + return manifest; + } + + @Override + public PackCodec codec() { + return codec; + } + + @Override + public String contentKey() { + return contentKey; + } + + public Builder contentKey(@NonNull String contentKey) { + Objects.requireNonNull(contentKey); + this.contentKey = contentKey; + return this; + } + + public GeyserResourcePack build() { + return new GeyserResourcePack(codec, manifest, contentKey); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java index 25a0f0ee0..6b309e910 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java +++ b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java @@ -35,9 +35,30 @@ import org.geysermc.geyser.api.pack.ResourcePackManifest; import java.io.IOException; import java.util.Collection; +import java.util.Collections; import java.util.UUID; -public record GeyserResourcePackManifest(@JsonProperty("format_version") int formatVersion, Header header, Collection modules, Collection dependencies) implements ResourcePackManifest { +public record GeyserResourcePackManifest( + @JsonProperty("format_version") int formatVersion, + Header header, + Collection modules, + Collection dependencies, + Collection subpacks, + Collection settings +) implements ResourcePackManifest { + public GeyserResourcePackManifest(int formatVersion, + Header header, + Collection modules, + Collection dependencies, + Collection subpacks, + Collection settings) { + this.formatVersion = formatVersion; + this.header = header; + this.modules = ensureNonNull(modules); + this.dependencies = ensureNonNull(dependencies); + this.subpacks = ensureNonNull(subpacks); + this.settings = ensureNonNull(settings); + } public record Header(UUID uuid, Version version, String name, String description, @JsonProperty("min_engine_version") Version minimumSupportedMinecraftVersion) implements ResourcePackManifest.Header { } @@ -45,6 +66,15 @@ public record GeyserResourcePackManifest(@JsonProperty("format_version") int for public record Dependency(UUID uuid, Version version) implements ResourcePackManifest.Dependency { } + public record Subpack(@JsonProperty("folder_name") String folderName, String name, @JsonProperty("memory_tier") Float memoryTier) implements ResourcePackManifest.Subpack { } + + public record Setting(String type, String text) implements ResourcePackManifest.Setting { } + + static Collection ensureNonNull(Collection collection) { + if (collection == null) return Collections.emptyList(); + return Collections.unmodifiableCollection(collection); + } + @JsonDeserialize(using = Version.VersionDeserializer.class) public record Version(int major, int minor, int patch) implements ResourcePackManifest.Version { diff --git a/core/src/main/java/org/geysermc/geyser/pack/ResourcePackHolder.java b/core/src/main/java/org/geysermc/geyser/pack/ResourcePackHolder.java new file mode 100644 index 000000000..f475127e7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/pack/ResourcePackHolder.java @@ -0,0 +1,45 @@ +/* + * 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.pack; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.option.PriorityOption; +import org.geysermc.geyser.pack.option.OptionHolder; + +public record ResourcePackHolder( + @NonNull GeyserResourcePack pack, + @NonNull OptionHolder optionHolder +) { + + public static ResourcePackHolder of(GeyserResourcePack pack) { + return new ResourcePackHolder(pack, new OptionHolder(PriorityOption.NORMAL)); + } + + public ResourcePack resourcePack() { + return this.pack; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/pack/option/GeyserPriorityOption.java b/core/src/main/java/org/geysermc/geyser/pack/option/GeyserPriorityOption.java new file mode 100644 index 000000000..a62386b24 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/pack/option/GeyserPriorityOption.java @@ -0,0 +1,55 @@ +/* + * 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.pack.option; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.exception.ResourcePackException; +import org.geysermc.geyser.api.pack.option.PriorityOption; + +import java.util.Objects; + +public record GeyserPriorityOption(int priority) implements PriorityOption { + + @Override + public @NonNull Type type() { + return Type.PRIORITY; + } + + @Override + public @NonNull Integer value() { + return priority; + } + + @Override + public void validate(@NonNull ResourcePack pack) { + Objects.requireNonNull(pack); + if (priority < -100 || priority > 100) { + throw new ResourcePackException(ResourcePackException.Cause.INVALID_PACK_OPTION, + "Priority must be between -100 and 100 inclusive!"); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/pack/option/GeyserSubpackOption.java b/core/src/main/java/org/geysermc/geyser/pack/option/GeyserSubpackOption.java new file mode 100644 index 000000000..9f26820dd --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/pack/option/GeyserSubpackOption.java @@ -0,0 +1,66 @@ +/* + * 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.pack.option; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.ResourcePackManifest; +import org.geysermc.geyser.api.pack.exception.ResourcePackException; +import org.geysermc.geyser.api.pack.option.SubpackOption; + +import java.util.Objects; + +/** + * Can be used to specify which subpack from a resource pack a player should load. + * Available subpacks can be seen in a resource pack manifest {@link ResourcePackManifest#subpacks()} + */ +public record GeyserSubpackOption(String subpackName) implements SubpackOption { + + @Override + public @NonNull Type type() { + return Type.SUBPACK; + } + + @Override + public @NonNull String value() { + return subpackName; + } + + @Override + public void validate(@NonNull ResourcePack pack) { + Objects.requireNonNull(pack); + + // Allow empty subpack names - they're the same as "none" + if (subpackName.isEmpty()) { + return; + } + + if (pack.manifest().subpacks().stream().noneMatch(subpack -> subpack.name().equals(subpackName))) { + throw new ResourcePackException(ResourcePackException.Cause.INVALID_PACK_OPTION, + "No subpack with the name %s found!".formatted(subpackName)); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/pack/option/GeyserUrlFallbackOption.java b/core/src/main/java/org/geysermc/geyser/pack/option/GeyserUrlFallbackOption.java new file mode 100644 index 000000000..7a3d3d3da --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/pack/option/GeyserUrlFallbackOption.java @@ -0,0 +1,53 @@ +/* + * 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.pack.option; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.UrlPackCodec; +import org.geysermc.geyser.api.pack.exception.ResourcePackException; +import org.geysermc.geyser.api.pack.option.UrlFallbackOption; + +public record GeyserUrlFallbackOption(Boolean enabled) implements UrlFallbackOption { + + @Override + public @NonNull Type type() { + return Type.FALLBACK; + } + + @Override + public @NonNull Boolean value() { + return enabled; + } + + @Override + public void validate(@NonNull ResourcePack pack) { + if (!(pack.codec() instanceof UrlPackCodec)) { + throw new ResourcePackException(ResourcePackException.Cause.INVALID_PACK_OPTION, + "The UrlFallbackOption cannot be set on resource packs not created using the url pack codec!"); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/pack/option/OptionHolder.java b/core/src/main/java/org/geysermc/geyser/pack/option/OptionHolder.java new file mode 100644 index 000000000..f6ec741df --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/pack/option/OptionHolder.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.pack.option; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.option.PriorityOption; +import org.geysermc.geyser.api.pack.option.ResourcePackOption; +import org.geysermc.geyser.pack.GeyserResourcePack; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class OptionHolder extends HashMap> { + + public OptionHolder() { + super(); + } + + // Used when adding resource packs initially to ensure that a priority option is always set + // It is however NOT used for session-options, as then the "normal" prio might override + // the resource pack option + public OptionHolder(PriorityOption option) { + super(); + put(option.type(), option); + } + + public void validateAndAdd(ResourcePack pack, ResourcePackOption... options) { + for (ResourcePackOption option : options) { + // Validate before adding + option.validate(pack); + + // Ensure that we do not have duplicate types. + if (super.containsKey(option.type())) { + super.replace(option.type(), option); + } else { + super.put(option.type(), option); + } + } + } + + @SuppressWarnings("unchecked") + public static T valueOrFallback(ResourcePackOption.@NonNull Type type, + @Nullable OptionHolder sessionPackOptions, + @NonNull OptionHolder resourcePackOptions, + @NonNull T defaultValue) { + ResourcePackOption option; + + // First: the session's options, if they exist + if (sessionPackOptions != null) { + option = sessionPackOptions.get(type); + if (option != null) { + return (T) option.value(); + } + } + + // Second: check the resource pack options + option = resourcePackOptions.get(type); + if (option != null) { + return (T) option.value(); + } + + // Finally: return default + return defaultValue; + } + + public static @Nullable ResourcePackOption optionByType(ResourcePackOption.@NonNull Type type, + @Nullable OptionHolder sessionPackOptions, + @NonNull OptionHolder resourcePackOptions) { + + // First: the session-specific options, if these exist + if (sessionPackOptions != null) { + ResourcePackOption option = sessionPackOptions.get(type); + if (option != null) { + return option; + } + } + + // Second: check the default holder for the option, if it exists; + // Or return null if the option isn't set. + return resourcePackOptions.get(type); + } + + public void remove(ResourcePackOption option) { + super.remove(option.type()); + } + + /** + * @return the options of this holder in an immutable collection + */ + public Collection> immutableValues() { + return Collections.unmodifiableCollection(values()); + } + + /** + * @return the options of this option holder, with fallbacks to options of a {@link GeyserResourcePack} + * if they're not already overridden here + */ + public Collection> immutableValues(OptionHolder defaultValues) { + // Create a map to hold the combined values + Map> combinedOptions = new HashMap<>(this); + + // Add options from the pack if not already overridden by this OptionHolder + defaultValues.forEach(combinedOptions::putIfAbsent); + + // Return an immutable collection of the combined options + return Collections.unmodifiableCollection(combinedOptions.values()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/pack/path/GeyserPathPackCodec.java b/core/src/main/java/org/geysermc/geyser/pack/path/GeyserPathPackCodec.java index 84067600f..ea6f319f9 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/path/GeyserPathPackCodec.java +++ b/core/src/main/java/org/geysermc/geyser/pack/path/GeyserPathPackCodec.java @@ -79,15 +79,20 @@ public class GeyserPathPackCodec extends PathPackCodec { } @Override - public @NonNull SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException { + public @NonNull SeekableByteChannel serialize() throws IOException { return FileChannel.open(this.path); } @Override - protected @NonNull ResourcePack create() { + protected ResourcePack.@NonNull Builder createBuilder() { return ResourcePackLoader.readPack(this.path); } + @Override + protected @NonNull ResourcePack create() { + return createBuilder().build(); + } + private void checkLastModified() { try { FileTime lastModified = Files.getLastModifiedTime(this.path); diff --git a/core/src/main/java/org/geysermc/geyser/pack/url/GeyserUrlPackCodec.java b/core/src/main/java/org/geysermc/geyser/pack/url/GeyserUrlPackCodec.java new file mode 100644 index 000000000..ee7f48c90 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/pack/url/GeyserUrlPackCodec.java @@ -0,0 +1,96 @@ +/* + * 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.pack.url; + +import lombok.Getter; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.pack.PathPackCodec; +import org.geysermc.geyser.api.pack.UrlPackCodec; +import org.geysermc.geyser.pack.GeyserResourcePack; +import org.geysermc.geyser.registry.loader.ResourcePackLoader; + +import java.io.IOException; +import java.nio.channels.SeekableByteChannel; +import java.util.Objects; + +public class GeyserUrlPackCodec extends UrlPackCodec { + private final @NonNull String url; + @Getter + private PathPackCodec fallback; + + public GeyserUrlPackCodec(@NonNull String url) throws IllegalArgumentException { + Objects.requireNonNull(url); + this.url = url; + } + + @Override + public byte @NonNull [] sha256() { + Objects.requireNonNull(fallback, "must call #create() before attempting to get the sha256!"); + return fallback.sha256(); + } + + @Override + public long size() { + Objects.requireNonNull(fallback, "must call #create() before attempting to get the size!"); + return fallback.size(); + } + + @Override + public @NonNull SeekableByteChannel serialize() throws IOException { + Objects.requireNonNull(fallback, "must call #create() before attempting to serialize!!"); + return fallback.serialize(); + } + + @Override + @NonNull + public GeyserResourcePack create() { + return createBuilder().build(); + } + + @Override + protected GeyserResourcePack.@NonNull Builder createBuilder() { + if (this.fallback == null) { + try { + ResourcePackLoader.downloadPack(url, false).whenComplete((pack, throwable) -> { + if (throwable != null) { + throw new IllegalArgumentException(throwable); + } else if (pack != null) { + this.fallback = pack; + } + }).join(); // Needed to ensure that we don't attempt to read a pack before downloading/checking it + } catch (Exception e) { + throw new IllegalArgumentException("Failed to download pack from the url %s (%s)!".formatted(url, e.getMessage())); + } + } + + return ResourcePackLoader.readPack(this); + } + + @Override + public @NonNull String url() { + return this.url; + } +} 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 fc41275ae..af0c9dbc0 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -34,10 +34,10 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.pack.ResourcePackHolder; import org.geysermc.geyser.registry.loader.BiomeIdentifierRegistryLoader; import org.geysermc.geyser.registry.loader.BlockEntityRegistryLoader; import org.geysermc.geyser.registry.loader.ParticleTypesRegistryLoader; @@ -166,9 +166,9 @@ public final class Registries { //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. + * A mapped registry holding {@link ResourcePackHolder}'s with the pack uuid as keys. */ - public static final SimpleMappedDeferredRegistry RESOURCE_PACKS = SimpleMappedDeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), RegistryLoaders.RESOURCE_PACKS); + 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. diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java index 94de0c298..b1f62ca99 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java @@ -40,10 +40,14 @@ import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; import org.geysermc.geyser.api.pack.PathPackCodec; -import org.geysermc.geyser.impl.camera.GeyserCameraFade; -import org.geysermc.geyser.impl.camera.GeyserCameraPosition; +import org.geysermc.geyser.api.pack.UrlPackCodec; +import org.geysermc.geyser.api.pack.option.PriorityOption; +import org.geysermc.geyser.api.pack.option.SubpackOption; +import org.geysermc.geyser.api.pack.option.UrlFallbackOption; import org.geysermc.geyser.event.GeyserEventRegistrar; import org.geysermc.geyser.extension.command.GeyserExtensionCommand; +import org.geysermc.geyser.impl.camera.GeyserCameraFade; +import org.geysermc.geyser.impl.camera.GeyserCameraPosition; import org.geysermc.geyser.item.GeyserCustomItemData; import org.geysermc.geyser.item.GeyserCustomItemOptions; import org.geysermc.geyser.item.GeyserNonVanillaCustomItemData; @@ -53,7 +57,11 @@ import org.geysermc.geyser.level.block.GeyserGeometryComponent; import org.geysermc.geyser.level.block.GeyserJavaBlockState; import org.geysermc.geyser.level.block.GeyserMaterialInstance; import org.geysermc.geyser.level.block.GeyserNonVanillaCustomBlockData; +import org.geysermc.geyser.pack.option.GeyserPriorityOption; +import org.geysermc.geyser.pack.option.GeyserSubpackOption; +import org.geysermc.geyser.pack.option.GeyserUrlFallbackOption; import org.geysermc.geyser.pack.path.GeyserPathPackCodec; +import org.geysermc.geyser.pack.url.GeyserUrlPackCodec; import org.geysermc.geyser.registry.provider.ProviderSupplier; import java.nio.file.Path; @@ -66,9 +74,10 @@ public class ProviderRegistryLoader implements RegistryLoader, Prov @Override public Map, ProviderSupplier> load(Map, ProviderSupplier> providers) { - // misc + // commands providers.put(Command.Builder.class, args -> new GeyserExtensionCommand.Builder<>((Extension) args[0])); + // custom blocks providers.put(CustomBlockComponents.Builder.class, args -> new GeyserCustomBlockComponents.Builder()); providers.put(CustomBlockData.Builder.class, args -> new GeyserCustomBlockData.Builder()); providers.put(JavaBlockState.Builder.class, args -> new GeyserJavaBlockState.Builder()); @@ -76,8 +85,15 @@ public class ProviderRegistryLoader implements RegistryLoader, Prov providers.put(MaterialInstance.Builder.class, args -> new GeyserMaterialInstance.Builder()); providers.put(GeometryComponent.Builder.class, args -> new GeyserGeometryComponent.Builder()); + // misc providers.put(EventRegistrar.class, args -> new GeyserEventRegistrar(args[0])); + + // packs providers.put(PathPackCodec.class, args -> new GeyserPathPackCodec((Path) args[0])); + providers.put(UrlPackCodec.class, args -> new GeyserUrlPackCodec((String) args[0])); + providers.put(PriorityOption.class, args -> new GeyserPriorityOption((int) args[0])); + providers.put(SubpackOption.class, args -> new GeyserSubpackOption((String) args[0])); + providers.put(UrlFallbackOption.class, args -> new GeyserUrlFallbackOption((Boolean) args[0])); // items providers.put(CustomItemData.Builder.class, args -> new GeyserCustomItemData.Builder()); diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java index adb64b8af..e53903154 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java @@ -25,16 +25,30 @@ package org.geysermc.geyser.registry.loader; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.lifecycle.GeyserLoadResourcePacksEvent; +import org.geysermc.geyser.api.pack.PathPackCodec; import org.geysermc.geyser.api.pack.ResourcePack; +import org.geysermc.geyser.api.pack.ResourcePackManifest; +import org.geysermc.geyser.api.pack.UrlPackCodec; +import org.geysermc.geyser.event.type.GeyserDefineResourcePacksEventImpl; import org.geysermc.geyser.pack.GeyserResourcePack; import org.geysermc.geyser.pack.GeyserResourcePackManifest; +import org.geysermc.geyser.pack.ResourcePackHolder; import org.geysermc.geyser.pack.SkullResourcePackManager; import org.geysermc.geyser.pack.path.GeyserPathPackCodec; +import org.geysermc.geyser.pack.url.GeyserUrlPackCodec; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.geysermc.geyser.util.WebUtils; +import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; @@ -42,10 +56,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -53,9 +70,17 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** - * Loads {@link ResourcePack}s within a {@link Path} directory, firing the {@link GeyserLoadResourcePacksEvent}. + * Loads {@link ResourcePack}s within a {@link Path} directory, firing the {@link GeyserDefineResourcePacksEventImpl}. */ -public class ResourcePackLoader implements RegistryLoader> { +public class ResourcePackLoader implements RegistryLoader> { + + /** + * Used to keep track of remote resource packs that the client rejected. + * If a client rejects such a pack, it falls back to the old method, and Geyser serves a cached variant. + */ + private static final Cache CACHED_FAILED_PACKS = CacheBuilder.newBuilder() + .expireAfterWrite(1, TimeUnit.HOURS) + .build(); static final PathMatcher PACK_MATCHER = FileSystems.getDefault().getPathMatcher("glob:**.{zip,mcpack}"); @@ -65,8 +90,8 @@ public class ResourcePackLoader implements RegistryLoader load(Path directory) { - Map packMap = new HashMap<>(); + public Map load(Path directory) { + Map packMap = new Object2ObjectOpenHashMap<>(); if (!Files.exists(directory)) { try { @@ -77,7 +102,7 @@ public class ResourcePackLoader implements RegistryLoader resourcePacks; - try (Stream stream = Files.walk(directory)) { + try (Stream stream = Files.list(directory)) { resourcePacks = stream.filter(PACK_MATCHER::matches) .collect(Collectors.toCollection(ArrayList::new)); // toList() does not guarantee mutability } catch (Exception e) { @@ -95,33 +120,76 @@ public class ResourcePackLoader implements RegistryLoader manifestReference = new AtomicReference<>(); try (ZipFile zip = new ZipFile(path.toFile()); @@ -129,7 +197,7 @@ public class ResourcePackLoader implements RegistryLoader { String name = x.getName(); if (SHOW_RESOURCE_PACK_LENGTH_WARNING && name.length() >= 80) { - GeyserImpl.getInstance().getLogger().warning("The resource pack " + path.getFileName() + GeyserImpl.getInstance().getLogger().warning("The resource pack " + packLocation + " has a file in it that meets or exceeds 80 characters in its path (" + name + ", " + name.length() + " characters long). This will cause problems on some Bedrock platforms." + " Please rename it to be shorter, or reduce the amount of folders needed to get to the file."); @@ -148,17 +216,190 @@ public class ResourcePackLoader implements RegistryLoader loadRemotePacks() { + GeyserImpl instance = GeyserImpl.getInstance(); + // Unable to make this a static variable, as the test would fail + final Path cachedDirectory = instance.getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs"); + + if (!Files.exists(cachedDirectory)) { + try { + Files.createDirectories(cachedDirectory); + } catch (IOException e) { + instance.getLogger().error("Could not create remote pack cache directory", e); + return new Object2ObjectOpenHashMap<>(); + } + } + + //List remotePackUrls = instance.getConfig().getResourcePackUrls(); + List remotePackUrls = List.of(); + Map packMap = new Object2ObjectOpenHashMap<>(); + + for (String url : remotePackUrls) { + try { + GeyserUrlPackCodec codec = new GeyserUrlPackCodec(url); + GeyserResourcePack pack = codec.create(); + packMap.put(pack.uuid(), ResourcePackHolder.of(pack)); + } catch (Throwable e) { + instance.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.resource_pack.broken", url)); + instance.getLogger().error(e.getMessage()); + if (instance.getLogger().isDebug()) { + e.printStackTrace(); + } + } + } + + return packMap; + } + + /** + * Used when a Bedrock client requests a Bedrock resource pack from the server when it should be downloading it + * from a remote provider. Since this would be called each time a Bedrock client requests a piece of the Bedrock pack, + * this uses a cache to ensure we aren't re-checking a dozen times. + * + * @param codec the codec of the resource pack that wasn't successfully downloaded by a Bedrock client. + */ + public static void testRemotePack(GeyserSession session, UrlPackCodec codec, UUID packId, String packVersion) { + if (CACHED_FAILED_PACKS.getIfPresent(codec.url()) == null) { + String url = codec.url(); + CACHED_FAILED_PACKS.put(url, codec); + GeyserImpl.getInstance().getLogger().warning( + "Bedrock client (%s, playing on %s) was not able to download the resource pack at %s. Checking for changes now:" + .formatted(session.bedrockUsername(), session.getClientData().getDeviceOs().name(), codec.url()) + ); + + downloadPack(codec.url(), true).whenComplete((pathPackCodec, e) -> { + if (e != null) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.resource_pack.broken", url), e); + if (GeyserImpl.getInstance().getLogger().isDebug()) { + e.printStackTrace(); + if (pathPackCodec != null) { + deleteFile(pathPackCodec.path()); + } + return; + } + } + + if (pathPackCodec == null) { + return; // Already warned about + } + + GeyserResourcePack newPack = readPack(pathPackCodec.path()).build(); + if (newPack.uuid().equals(packId)) { + if (packVersion.equals(newPack.manifest().header().version().toString())) { + GeyserImpl.getInstance().getLogger().info("No version or pack change detected: Was the resource pack server down?"); + } else { + GeyserImpl.getInstance().getLogger().info("Detected a new resource pack version (%s, old version %s) for pack at %s!" + .formatted(packVersion, newPack.manifest().header().version().toString(), url)); + } + } else { + GeyserImpl.getInstance().getLogger().info("Detected a new resource pack at the url %s!".formatted(url)); + } + + // This should be safe to do as we're not directly using registries to read packs. + // Instead, they're cached per-session in the SessionLoadResourcePacks event + Registries.RESOURCE_PACKS.get().remove(packId); + Registries.RESOURCE_PACKS.get().put(newPack.uuid(), ResourcePackHolder.of(newPack)); + + if (codec instanceof GeyserUrlPackCodec geyserUrlPackCodec + && geyserUrlPackCodec.getFallback() != null) { + Path path = geyserUrlPackCodec.getFallback().path(); + try { + GeyserImpl.getInstance().getScheduledThread().schedule(() -> { + CACHED_FAILED_PACKS.invalidate(codec.url()); + deleteFile(path); + }, 5, TimeUnit.MINUTES); + } catch (RejectedExecutionException exception) { + // No scheduling here, probably because we're shutting down? + deleteFile(path); + } + } + }); + } + } + + private static void deleteFile(Path path) { + if (path.toFile().exists()) { + try { + Files.delete(path); + } catch (IOException e) { + GeyserImpl.getInstance().getLogger().error("Unable to delete old pack! " + e.getMessage()); + e.printStackTrace(); + } + } + } + + public static CompletableFuture<@Nullable PathPackCodec> downloadPack(String url, boolean testing) throws IllegalArgumentException { + return CompletableFuture.supplyAsync(() -> { + Path path = WebUtils.downloadRemotePack(url, testing); + + // Already warned about these above + if (path == null) { + return null; + } + + // Check if the pack is a .zip or .mcpack file + if (!PACK_MATCHER.matches(path)) { + throw new IllegalArgumentException("Invalid pack format from url %s! Not a .zip or .mcpack file.".formatted(url)); + } + + try { + try (ZipFile zip = new ZipFile(path.toFile())) { + if (zip.stream().noneMatch(x -> x.getName().contains("manifest.json"))) { + throw new IllegalArgumentException("The pack at the url " + url + " does not contain a manifest file!"); + } + + // Check if a "manifest.json" or "pack_manifest.json" file is located directly in the zip... does not work otherwise. + // (something like MyZip.zip/manifest.json) will not, but will if it's a subfolder (MyPack.zip/MyPack/manifest.json) + if (zip.getEntry("manifest.json") != null || zip.getEntry("pack_manifest.json") != null) { + if (GeyserImpl.getInstance().getLogger().isDebug()) { + GeyserImpl.getInstance().getLogger().info("The remote resource pack from " + url + " contains a manifest.json file at the root of the zip file. " + + "This may not work for remote packs, and could cause Bedrock clients to fall back to request the pack from the server. " + + "Please put the pack file in a subfolder, and provide that zip in the URL."); + } + } + } + } catch (IOException e) { + throw new IllegalArgumentException(GeyserLocale.getLocaleStringLog("geyser.resource_pack.broken", url), e); + } + + return new GeyserPathPackCodec(path); + }); + } + + public static void clear() { + if (Registries.RESOURCE_PACKS.loaded()) { + Registries.RESOURCE_PACKS.get().clear(); + } + CACHED_FAILED_PACKS.invalidateAll(); + } + + public static void cleanupRemotePacks() { + File cacheFolder = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs").toFile(); + if (!cacheFolder.exists()) { + return; + } + + int count = 0; + final long expireTime = (((long) 1000 * 60 * 60)); // one hour + for (File cachedPack : Objects.requireNonNull(cacheFolder.listFiles())) { + if (cachedPack.lastModified() < System.currentTimeMillis() - expireTime) { + //noinspection ResultOfMethodCallIgnored + cachedPack.delete(); + count++; + } + } + + if (count > 0) { + GeyserImpl.getInstance().getLogger().debug(String.format("Removed %d cached resource pack files as they are no longer in use!", count)); } } } diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java index 3d3bfb48d..10d8aa525 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java @@ -25,23 +25,7 @@ package org.geysermc.geyser.scoreboard; -import static org.geysermc.geyser.scoreboard.UpdateType.REMOVE; - import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumMap; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Function; -import java.util.stream.Collectors; import lombok.Getter; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; @@ -57,12 +41,28 @@ import org.geysermc.geyser.scoreboard.display.slot.DisplaySlot; import org.geysermc.geyser.scoreboard.display.slot.PlayerlistDisplaySlot; import org.geysermc.geyser.scoreboard.display.slot.SidebarDisplaySlot; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import org.jetbrains.annotations.Contract; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.geysermc.geyser.scoreboard.UpdateType.REMOVE; + /** * Here follows some information about how scoreboards work in Java Edition, that is related to the workings of this * class: diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java index 812456644..363635ba6 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSessionAdapter.java @@ -68,7 +68,7 @@ public class GeyserSessionAdapter extends SessionAdapter { @Override public void packetSending(PacketSendingEvent event) { - if (event.getPacket() instanceof ClientIntentionPacket) { + if (event.getPacket() instanceof ClientIntentionPacket intentionPacket) { BedrockClientData clientData = geyserSession.getClientData(); String addressSuffix; @@ -109,8 +109,6 @@ public class GeyserSessionAdapter extends SessionAdapter { addressSuffix = ""; } - ClientIntentionPacket intentionPacket = event.getPacket(); - String address; if (geyser.getConfig().getRemote().isForwardHost()) { address = clientData.getServerAddress().split(":")[0]; diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index aec1fa4de..f3ad0be2f 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java @@ -167,7 +167,7 @@ public class SkinProvider { if (count > 0) { GeyserImpl.getInstance().getLogger().debug(String.format("Removed %d cached image files as they have expired", count)); } - }, 10, 1440, TimeUnit.MINUTES); + }, 10, 1, TimeUnit.DAYS); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index 1b7f2d9d9..4a228d2cb 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -28,22 +28,26 @@ package org.geysermc.geyser.util; import com.fasterxml.jackson.databind.JsonNode; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; import javax.naming.directory.Attribute; import javax.naming.directory.InitialDirContext; import java.io.*; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; +import java.net.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.stream.Stream; public class WebUtils { + private static final Path REMOTE_PACK_CACHE = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs"); + /** * Makes a web request to the given URL and returns the body as a string * @@ -96,6 +100,115 @@ public class WebUtils { } } + /** + * Checks a remote pack URL to see if it is valid + * If it is, it will download the pack file and return a path to it + * + * @param url The URL to check + * @param force If true, the pack will be downloaded even if it is cached to a separate location. + * @return Path to the downloaded pack file, or null if it was unable to be loaded + */ + @SuppressWarnings("ResultOfMethodCallIgnored") + public static @Nullable Path downloadRemotePack(String url, boolean force) { + GeyserLogger logger = GeyserImpl.getInstance().getLogger(); + try { + HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(); + + con.setConnectTimeout(10000); + con.setReadTimeout(10000); + con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().platformName() + "/" + GeyserImpl.VERSION); + con.setInstanceFollowRedirects(true); + + int responseCode = con.getResponseCode(); + if (responseCode >= 400) { + throw new IllegalStateException(String.format("Invalid response code from remote pack at URL: %s (code: %d)", url, responseCode)); + } + + int size = con.getContentLength(); + String type = con.getContentType(); + + if (size <= 0) { + throw new IllegalArgumentException(String.format("Invalid content length received from remote pack at URL: %s (size: %d)", url, size)); + } + + if (type == null || !type.equals("application/zip")) { + throw new IllegalArgumentException(String.format("Url %s tries to provide a resource pack using the %s content type, which is not supported by Bedrock edition! " + + "Bedrock Edition only supports the application/zip content type.", url, type)); + } + + Path packMetadata = REMOTE_PACK_CACHE.resolve(url.hashCode() + ".metadata"); + Path downloadLocation; + + // If we downloaded this pack before, reuse it if the ETag matches. + if (Files.exists(packMetadata) && !force) { + try { + List metadata = Files.readAllLines(packMetadata, StandardCharsets.UTF_8); + int cachedSize = Integer.parseInt(metadata.get(0)); + String cachedEtag = metadata.get(1); + long cachedLastModified = Long.parseLong(metadata.get(2)); + downloadLocation = REMOTE_PACK_CACHE.resolve(metadata.get(3)); + + if (cachedSize == size && + cachedEtag.equals(con.getHeaderField("ETag")) && + cachedLastModified == con.getLastModified() && + downloadLocation.toFile().exists()) { + logger.debug("Using cached pack (%s) for %s.".formatted(downloadLocation.getFileName(), url)); + downloadLocation.toFile().setLastModified(System.currentTimeMillis()); + packMetadata.toFile().setLastModified(System.currentTimeMillis()); + return downloadLocation; + } else { + logger.debug("Deleting cached pack/metadata (%s) as it appears to have changed!".formatted(url)); + Files.deleteIfExists(packMetadata); + Files.deleteIfExists(downloadLocation); + } + } catch (IOException e) { + GeyserImpl.getInstance().getLogger().error("Failed to read cached pack metadata! " + e); + packMetadata.toFile().deleteOnExit(); + } + } + + downloadLocation = REMOTE_PACK_CACHE.resolve(url.hashCode() + "_" + System.currentTimeMillis() + ".zip"); + Files.copy(con.getInputStream(), downloadLocation, StandardCopyOption.REPLACE_EXISTING); + + // This needs to match as the client fails to download the pack otherwise + long downloadSize = Files.size(downloadLocation); + if (downloadSize != size) { + Files.delete(downloadLocation); + throw new IllegalStateException("Size mismatch with resource pack at url: %s. Downloaded pack has %s bytes, expected %s bytes!" + .formatted(url, downloadSize, size)); + } + + try { + Files.write( + packMetadata, + Arrays.asList( + String.valueOf(size), + con.getHeaderField("ETag"), + String.valueOf(con.getLastModified()), + downloadLocation.getFileName().toString() + )); + packMetadata.toFile().setLastModified(System.currentTimeMillis()); + } catch (IOException e) { + GeyserImpl.getInstance().getLogger().error("Failed to write cached pack metadata: " + e.getMessage()); + Files.delete(packMetadata); + Files.delete(downloadLocation); + return null; + } + + downloadLocation.toFile().setLastModified(System.currentTimeMillis()); + return downloadLocation; + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Unable to download resource pack from malformed URL %s! ".formatted(url)); + } catch (SocketTimeoutException | ConnectException e) { + logger.error("Unable to download pack from url %s due to network error! ( %s )".formatted(url, e.getMessage())); + logger.debug(e); + } catch (IOException e) { + throw new IllegalStateException("Unable to download and save remote resource pack from: %s ( %s )!".formatted(url, e.getMessage())); + } + return null; + } + + /** * Post a string to the given URL * diff --git a/core/src/test/java/org/geysermc/geyser/registry/loader/ResourcePackLoaderTest.java b/core/src/test/java/org/geysermc/geyser/registry/loader/ResourcePackLoaderTest.java index ce2fd2a6f..510680848 100644 --- a/core/src/test/java/org/geysermc/geyser/registry/loader/ResourcePackLoaderTest.java +++ b/core/src/test/java/org/geysermc/geyser/registry/loader/ResourcePackLoaderTest.java @@ -62,7 +62,7 @@ public class ResourcePackLoaderTest { public void testPack() throws Exception { // this mcpack only contains a folder, which the manifest is in Path path = getResource("empty_pack.mcpack"); - ResourcePack pack = ResourcePackLoader.readPack(path); + ResourcePack pack = ResourcePackLoader.readPack(path).build(); assertEquals("", pack.contentKey()); // should probably add some more tests here related to the manifest } @@ -71,7 +71,7 @@ public class ResourcePackLoaderTest { public void testEncryptedPack() throws Exception { // this zip only contains a contents.json and manifest.json at the root Path path = getResource("encrypted_pack.zip"); - ResourcePack pack = ResourcePackLoader.readPack(path); + ResourcePack pack = ResourcePackLoader.readPack(path).build(); assertEquals("JAGcSXcXwcODc1YS70GzeWAUKEO172UA", pack.contentKey()); } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/EmptyGeyserLogger.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/EmptyGeyserLogger.java index f147e766d..e033b7288 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/EmptyGeyserLogger.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/EmptyGeyserLogger.java @@ -63,6 +63,11 @@ public class EmptyGeyserLogger implements GeyserLogger { } + @Override + public void debug(String message, Object... arguments) { + + } + @Override public void setDebug(boolean debug) { diff --git a/gradle.properties b/gradle.properties index 5557e53ca..343f7a51e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,5 +8,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.6.1-SNAPSHOT +version=2.6.2-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From 24f774e76751e538e69e08aa57c2d1a82528a7a8 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 25 Mar 2025 16:34:00 +0100 Subject: [PATCH 573/897] 1.21.70 support (#5414) * Initial work on 1.21.70 * Update mappings, fixup jitpack * Use LevelSoundEventPacket instead of LevelSoundEvent2Packet, ensure only temperate cow/pig/chicken/thrown egg entities spawn, update item components * Update cloudburst/protocol dependency, target master mappings branch --- README.md | 2 +- .../kotlin/geyser.base-conventions.gradle.kts | 5 +- .../geyser/entity/EntityDefinitions.java | 31 +- .../properties/GeyserEntityProperties.java | 2 +- .../properties/VanillaEntityProperties.java | 74 + .../geyser/entity/type/BoatEntity.java | 10 +- .../geysermc/geyser/entity/type/Entity.java | 5 + .../entity/type/ThrowableItemEntity.java | 11 + .../type/living/animal/ChickenEntity.java | 8 + .../entity/type/living/animal/CowEntity.java | 8 + .../type/living/animal/MooshroomEntity.java | 6 + .../entity/type/living/animal/PigEntity.java | 8 + .../living/animal/tameable/WolfEntity.java | 7 + .../type/living/monster/EndermanEntity.java | 4 +- .../geysermc/geyser/network/GameProtocol.java | 8 +- .../geyser/network/InvalidPacketHandler.java | 2 +- .../geyser/network/LoggingPacketHandler.java | 10 + .../populator/BlockRegistryPopulator.java | 40 +- .../registry/populator/Conversion766_748.java | 4 + .../registry/populator/Conversion776_766.java | 61 + .../populator/ItemRegistryPopulator.java | 2 + .../geyser/session/GeyserSession.java | 4 +- .../entity/JavaEntityEventTranslator.java | 6 +- .../resources/bedrock/biome_definitions.dat | Bin 39004 -> 41609 bytes .../bedrock/block_palette.1_21_70.nbt | Bin 0 -> 193872 bytes .../bedrock/creative_items.1_21_70.json | 8960 +++++++++++++ .../resources/bedrock/item_components.nbt | Bin 14202 -> 14228 bytes .../resources/bedrock/item_tags.1_21_60.json | 1651 ++- .../resources/bedrock/item_tags.1_21_70.json | 829 ++ .../bedrock/runtime_item_states.1_21_70.json | 10784 ++++++++++++++++ core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 23 +- 32 files changed, 21655 insertions(+), 912 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/properties/VanillaEntityProperties.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java create mode 100644 core/src/main/resources/bedrock/block_palette.1_21_70.nbt create mode 100644 core/src/main/resources/bedrock/creative_items.1_21_70.json create mode 100644 core/src/main/resources/bedrock/item_tags.1_21_70.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_21_70.json diff --git a/README.md b/README.md index dcd9b8530..db462db26 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.21.40 - 1.21.62 and Minecraft Java 1.21.4. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.21.40 - 1.21.70 and Minecraft Java 1.21.4. 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/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 093f0a8c0..09440ac6a 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -62,11 +62,12 @@ repositories { name = "viaversion" } + // For Adventure snapshots + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") + // Jitpack for e.g. MCPL maven("https://jitpack.io") { content { includeGroupByRegex("com\\.github\\..*") } } - // For Adventure snapshots - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") } 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 c8488238d..757c126b9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.entity; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.factory.EntityFactory; -import org.geysermc.geyser.entity.properties.GeyserEntityProperties; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.AbstractArrowEntity; import org.geysermc.geyser.entity.type.AbstractWindChargeEntity; import org.geysermc.geyser.entity.type.AreaEffectCloudEntity; @@ -462,6 +462,7 @@ public final class EntityDefinitions { EGG = EntityDefinition.inherited(ThrowableItemEntity::new, throwableItemBase) .type(EntityType.EGG) .heightAndWidth(0.25f) + .properties(VanillaEntityProperties.CLIMATE_VARIANT) .build(); ENDER_PEARL = EntityDefinition.inherited(ThrowableItemEntity::new, throwableItemBase) .type(EntityType.ENDER_PEARL) @@ -685,15 +686,7 @@ public final class EntityDefinitions { .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setActive) .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setIsTearingDown) .addTranslator(MetadataTypes.OPTIONAL_POSITION, CreakingEntity::setHomePos) - .properties(new GeyserEntityProperties.Builder() - .addEnum(CreakingEntity.CREAKING_STATE, - "neutral", - "hostile_observed", - "hostile_unobserved", - "twitching", - "crumbling") - .addInt(CreakingEntity.CREAKING_SWAYING_TICKS, 0, 6) - .build()) + .properties(VanillaEntityProperties.CREAKING) .build(); CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase) .type(EntityType.CREEPER) @@ -946,15 +939,7 @@ public final class EntityDefinitions { ARMADILLO = EntityDefinition.inherited(ArmadilloEntity::new, ageableEntityBase) .type(EntityType.ARMADILLO) .height(0.65f).width(0.7f) - .properties(new GeyserEntityProperties.Builder() - .addEnum( - "minecraft:armadillo_state", - "unrolled", - "rolled_up", - "rolled_up_peeking", - "rolled_up_relaxing", - "rolled_up_unrolling") - .build()) + .properties(VanillaEntityProperties.ARMADILLO) .addTranslator(MetadataTypes.ARMADILLO_STATE, ArmadilloEntity::setArmadilloState) .build(); AXOLOTL = EntityDefinition.inherited(AxolotlEntity::new, ageableEntityBase) @@ -967,19 +952,19 @@ public final class EntityDefinitions { BEE = EntityDefinition.inherited(BeeEntity::new, ageableEntityBase) .type(EntityType.BEE) .heightAndWidth(0.6f) - .properties(new GeyserEntityProperties.Builder() - .addBoolean("minecraft:has_nectar") - .build()) + .properties(VanillaEntityProperties.BEE) .addTranslator(MetadataTypes.BYTE, BeeEntity::setBeeFlags) .addTranslator(MetadataTypes.INT, BeeEntity::setAngerTime) .build(); CHICKEN = EntityDefinition.inherited(ChickenEntity::new, ageableEntityBase) .type(EntityType.CHICKEN) .height(0.7f).width(0.4f) + .properties(VanillaEntityProperties.CLIMATE_VARIANT) .build(); COW = EntityDefinition.inherited(CowEntity::new, ageableEntityBase) .type(EntityType.COW) .height(1.4f).width(0.9f) + .properties(VanillaEntityProperties.CLIMATE_VARIANT) .build(); FOX = EntityDefinition.inherited(FoxEntity::new, ageableEntityBase) .type(EntityType.FOX) @@ -1030,6 +1015,7 @@ public final class EntityDefinitions { PIG = EntityDefinition.inherited(PigEntity::new, ageableEntityBase) .type(EntityType.PIG) .heightAndWidth(0.9f) + .properties(VanillaEntityProperties.CLIMATE_VARIANT) .addTranslator(MetadataTypes.BOOLEAN, (pigEntity, entityMetadata) -> pigEntity.setFlag(EntityFlag.SADDLED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataTypes.INT, PigEntity::setBoost) .build(); @@ -1176,6 +1162,7 @@ public final class EntityDefinitions { WOLF = EntityDefinition.inherited(WolfEntity::new, tameableEntityBase) .type(EntityType.WOLF) .height(0.85f).width(0.6f) + .properties(VanillaEntityProperties.WOLF_SOUND_VARIANT) // "Begging" on wiki.vg, "Interested" in Nukkit - the tilt of the head .addTranslator(MetadataTypes.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataTypes.INT, WolfEntity::setCollarColor) diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java index 1729b0583..eaa7b7448 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java @@ -162,4 +162,4 @@ public class GeyserEntityProperties { return new GeyserEntityProperties(properties, propertyIndices); } } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/VanillaEntityProperties.java b/core/src/main/java/org/geysermc/geyser/entity/properties/VanillaEntityProperties.java new file mode 100644 index 000000000..305dbf22e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/VanillaEntityProperties.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025 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.properties; + +import org.geysermc.geyser.entity.type.living.monster.CreakingEntity; + +public class VanillaEntityProperties { + + public static final String CLIMATE_VARIANT_ID = "minecraft:climate_variant"; + + public static final GeyserEntityProperties ARMADILLO = new GeyserEntityProperties.Builder() + .addEnum("minecraft:armadillo_state", + "unrolled", + "rolled_up", + "rolled_up_peeking", + "rolled_up_relaxing", + "rolled_up_unrolling") + .build(); + + public static final GeyserEntityProperties BEE = new GeyserEntityProperties.Builder() + .addBoolean("minecraft:has_nectar") + .build(); + + public static final GeyserEntityProperties CLIMATE_VARIANT = new GeyserEntityProperties.Builder() + .addEnum(CLIMATE_VARIANT_ID, + "temperate", + "warm", + "cold") + .build(); + + public static final GeyserEntityProperties CREAKING = new GeyserEntityProperties.Builder() + .addEnum(CreakingEntity.CREAKING_STATE, + "neutral", + "hostile_observed", + "hostile_unobserved", + "twitching", + "crumbling") + .addInt(CreakingEntity.CREAKING_SWAYING_TICKS, 0, 6) + .build(); + + public static final GeyserEntityProperties WOLF_SOUND_VARIANT = new GeyserEntityProperties.Builder() + .addEnum("minecraft:sound_variant", + "default", + "big", + "cute", + "grumpy", + "mad", + "puglin", + "sad") + .build(); +} 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 7d789fb2a..f93845d9a 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 @@ -28,6 +28,7 @@ package org.geysermc.geyser.entity.type; import lombok.Getter; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.geysermc.geyser.entity.EntityDefinition; @@ -85,7 +86,14 @@ public class BoatEntity extends Entity implements Leashable, Tickable { // 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); - dirtyMetadata.put(EntityDataTypes.BUOYANCY_DATA, BUOYANCY_DATA); + dirtyMetadata.put(EntityDataTypes.BUOYANCY_DATA, BUOYANCY_DATA);; + } + + @Override + protected void initializeMetadata() { + super.initializeMetadata(); + // Without this flag you cant stand on boats + setFlag(EntityFlag.COLLIDABLE, true); } @Override 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 c986a8067..eac070327 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 @@ -200,6 +200,7 @@ public class Entity implements GeyserEntity { addAdditionalSpawnData(addEntityPacket); valid = true; + session.sendUpstreamPacket(addEntityPacket); flagsDirty = false; @@ -372,6 +373,10 @@ public class Entity implements GeyserEntity { flagsDirty = false; } dirtyMetadata.apply(entityDataPacket.getMetadata()); + if (propertyManager != null && propertyManager.hasProperties()) { + propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties()); + propertyManager.applyFloatProperties(entityDataPacket.getProperties().getFloatProperties()); + } session.sendUpstreamPacket(entityDataPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java index fbbe2de50..e49ce864a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java @@ -28,10 +28,13 @@ package org.geysermc.geyser.entity.type; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.UUID; @@ -53,6 +56,14 @@ public class ThrowableItemEntity extends ThrowableEntity { age = 0; } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + if (definition.entityType() == EntityType.EGG) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + } + @Override protected void initializeMetadata() { super.initializeMetadata(); 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 0c8e437c8..231c408d6 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 @@ -27,7 +27,9 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; @@ -41,6 +43,12 @@ public class ChickenEntity extends AnimalEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + @Override @Nullable protected Tag getFoodTag() { 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 66210068b..6c83b9dd1 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 @@ -30,7 +30,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; @@ -48,6 +50,12 @@ public class CowEntity extends AnimalEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + @NonNull @Override protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 2c9040b53..dce1adf79 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; @@ -52,6 +53,11 @@ public class MooshroomEntity extends CowEntity { dirtyMetadata.put(EntityDataTypes.VARIANT, isBrown ? 1 : 0); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + // There are no variants for mooshroom cows, so far + } + @NonNull @Override protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { 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 b8ba2c94f..d4227cfd9 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 @@ -31,7 +31,9 @@ import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent; @@ -58,6 +60,12 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + @Override @Nullable protected Tag getFoodTag() { 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 c8b6a6f58..0fb742f71 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 @@ -30,6 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -67,6 +68,12 @@ public class WolfEntity extends TameableEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add("minecraft:sound_variant", "default"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + @Override public void setTameableFlags(ByteEntityMetadata entityMetadata) { super.setTameableFlags(entityMetadata); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java index 586ba5cd9..94ff657d2 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java @@ -30,7 +30,7 @@ import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -57,7 +57,7 @@ public class EndermanEntity extends MonsterEntity { //TODO see if Bedrock controls this differently // Java Edition this controls which ambient sound is used if (entityMetadata.getPrimitiveValue()) { - LevelSoundEvent2Packet packet = new LevelSoundEvent2Packet(); + LevelSoundEventPacket packet = new LevelSoundEventPacket(); packet.setSound(SoundEvent.STARE); packet.setPosition(this.position); packet.setExtraData(-1); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 8625dfac5..a9c86ba07 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -30,6 +30,7 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776; +import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; @@ -48,8 +49,8 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v776.CODEC.toBuilder() - .minecraftVersion("1.21.60") + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v786.CODEC.toBuilder() + .minecraftVersion("1.21.70") .build()); /** @@ -70,6 +71,9 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v766.CODEC.toBuilder() .minecraftVersion("1.21.50 - 1.21.51") .build())); + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v776.CODEC.toBuilder() + .minecraftVersion("1.21.60 - 1.21.62") + .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } diff --git a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java index 974d6fdce..34b97f36f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java @@ -51,7 +51,7 @@ public class InvalidPacketHandler extends ChannelInboundHandlerAdapter { if (!(rootCause instanceof IllegalArgumentException)) { // Kick users that cause exceptions - logger.warning("Exception caught in session of" + session.bedrockUsername() + ": " + rootCause.getMessage()); + logger.warning("Exception caught in session of " + session.bedrockUsername() + ": " + rootCause.getMessage()); session.disconnect("An internal error occurred!"); return; } diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index 2d8db9517..39c3f5aa9 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -906,4 +906,14 @@ public class LoggingPacketHandler implements BedrockPacketHandler { public PacketSignal handle(ServerboundDiagnosticsPacket packet) { return defaultHandler(packet); } + + @Override + public PacketSignal handle(UpdateClientOptionsPacket packet) { + return defaultHandler(packet); + } + + @Override + public PacketSignal handle(PlayerUpdateEntityOverridesPacket packet) { + return defaultHandler(packet); + } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 59cdd52c4..81f1fec46 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -45,6 +45,7 @@ import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776; +import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786; import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -117,41 +118,10 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { var blockMappers = ImmutableMap., Remapper>builder() .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), Conversion766_748::remapBlock) - .put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), tag -> tag) // TODO: Finish me - .put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), tag -> { - final String name = tag.getString("name"); - if (name.equals("minecraft:creaking_heart") && tag.getCompound("states").containsKey("active")) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("active"); - builder.putString("creaking_heart_state", "awake"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - if ((name.endsWith("_door") || name.endsWith("fence_gate")) && tag.getCompound("states").containsKey("direction")) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - Integer directionCardinality = (Integer) builder.remove("direction"); - switch (directionCardinality) { - case 0: - builder.putString("minecraft:cardinal_direction", "south"); - break; - case 1: - builder.putString("minecraft:cardinal_direction", "west"); - break; - case 2: - builder.putString( "minecraft:cardinal_direction" , "north"); - break; - case 3: - builder.putString("minecraft:cardinal_direction", "east"); - break; - default: - throw new AssertionError("Invalid direction: " + directionCardinality); - } - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - return tag; - }) - .build(); + .put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), Conversion776_766::remapBlock) + .put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_21_70", Bedrock_v786.CODEC.getProtocolVersion()), tag -> tag) + .build(); // We can keep this strong as nothing should be garbage collected // Safe to intern since Cloudburst NBT is immutable diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java index 4568d0154..6f2bc61e2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java @@ -85,6 +85,10 @@ public class Conversion766_748 { } static NbtMap remapBlock(NbtMap tag) { + + // First: Downgrade from 1.21.60 -> 1.21.50 + tag = Conversion776_766.remapBlock(tag); + String name = tag.getString("name").replace("minecraft:", ""); if (PALE_WOODEN_BLOCKS.contains(name)) { return withName(tag, name.replace("pale_oak", "birch")); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java new file mode 100644 index 000000000..edc2543ae --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 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 org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; + +public class Conversion776_766 { + + public static NbtMap remapBlock(NbtMap tag) { + final String name = tag.getString("name"); + + if (name.equals("minecraft:creaking_heart")) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + String value = (String) builder.remove("creaking_heart_state"); + builder.putBoolean("active", value.equals("awake")); + + return tag.toBuilder().putCompound("states", builder.build()).build(); + } + + if (name.endsWith("_door") || name.endsWith("fence_gate")) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + String cardinalDirection = (String) builder.remove("minecraft:cardinal_direction"); + switch (cardinalDirection) { + case "south" -> builder.putInt("direction", 0); + case "west" -> builder.putInt("direction", 1); + case "east" -> builder.putInt("direction", 3); + case "north" -> builder.putInt("direction", 2); + default -> throw new AssertionError("Invalid direction: " + cardinalDirection); + } + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + + return tag; + } + +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index c0c006549..0b8d7f982 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -48,6 +48,7 @@ import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776; +import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; @@ -151,6 +152,7 @@ public class ItemRegistryPopulator { paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping)); paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v766.CODEC.getProtocolVersion())); paletteVersions.add(new PaletteVersion("1_21_60", Bedrock_v776.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_70", Bedrock_v786.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); 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 005e72097..c1ca49af4 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -91,7 +91,7 @@ import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket; import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; import org.cloudburstmc.protocol.bedrock.packet.SetCommandsEnabledPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket; @@ -1933,7 +1933,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } public void playSoundEvent(SoundEvent sound, Vector3f position) { - LevelSoundEvent2Packet packet = new LevelSoundEvent2Packet(); + LevelSoundEventPacket packet = new LevelSoundEventPacket(); packet.setPosition(position); packet.setSound(sound); packet.setIdentifier(":"); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index 2e2734410..9599be3fc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -33,7 +33,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; @@ -143,7 +143,7 @@ public class JavaEntityEventTranslator extends PacketTranslatoru+c(WTDGz( zCai9L#AF}-<1jG;r}#kP1M&DuWDg_w72TqV4;r%vqlwdH4`#`H&~tBZDOqTRw|nmS zo&W#*KYqXe`DwZ6t?Nb0stJyjvoLL{ue2*kloAzgWI~J!m>ZMA3f!7)h3P&YxosLZ z!8|I1Sn0k3z<#i^ql^V!WkdAn6CgQku&tud)WdY;6U1Z9gnq&19+a zpCYCTKHmLo#%hgbbt@atToZu$u#E)wtTRl-JC0|xixSB(LsxLe=`+l((kOnZb<&kL zW3gDX2v^G7Fg?*lxVjF8vBDMC-W)=Y#Bba?DG5mCXwb64Ng{^?70V)`p@an~GOCbk zt|i7?Q5?lM36}=E@OEh{nfH9bz+InPThPdSu%HIXA71kY@Wy2qz3oAmRXyOE3zDgZ z&Z5!^a}+CB25)s`Ri)uQPSc!C8a<(ffW&GO4FQ-l9<3~3@n59@f8zJ#JET_+?)yKY zu=&R3!Z3?JNCNwx-o@DAbkO79UKZfSq;Ka<0M}eG=sC=SCA31_t%m||bJ8eM)ApN* z+zT}`HCA&>mZq>+CY{1^N|J?WiOkba@Pc8oW3x$pPiMw9JCUVLry=D3|2p0xuf$>jH1b8g10yJKXR= zixJX}oYMfvp~t`1y4`ZD{()}aK^92=F-9{oc)U4h#Gxg3E1D`aaXQoB&*RtiD(@{H zLGid2A4a3O&e=i5;a(_CPCWUI2_C6t!QB}uAY?wcZ3>c~JChlCZ11gdSUlqbl)Lr;~$cc)nxzz;*aXt7xh3-mb34w;PBkm!Ow zjD{so0TeCFr?GUAp5TDkkO#RScEKTDX6~R(=S6gp>ZF~4v|P6*Lr{fF@oGYvP`MR{8k;hXPDChQQgrIb9HR1|fwZZfWo=H)i0hTJ z#d?)KpJkyZU0$o8Q%Dq1cAyx`Y`t3H?#!BAE8(@;LRfNZ_9eyuYKEN~W8?vg0eCO{ zwNA|CRwv9zEDWdFLf~E690u3fj5;)A=16d}SpUysqC(rBi9upMrLSbt8Ig2(MHnm_Gk~5%!|O7?>U5P?n4^N N>fB)?luqWM{{Zdj%On5* delta 1227 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�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%0D5tAIn&rSNrX^Z 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 Date: Thu, 20 Mar 2025 16:26:10 +0100 Subject: [PATCH 574/897] Initial 1.21.5 changes --- .../kotlin/geyser.base-conventions.gradle.kts | 1 + .../geyser/entity/EntityDefinitions.java | 9 +- .../entity/type/AreaEffectCloudEntity.java | 4 +- .../geyser/entity/type/LivingEntity.java | 30 +- .../geyser/entity/type/ThrowableEntity.java | 4 +- .../entity/type/living/animal/PigEntity.java | 8 + .../type/living/animal/StriderEntity.java | 4 - .../animal/horse/AbstractHorseEntity.java | 12 +- .../geyser/inventory/MerchantContainer.java | 10 +- .../inventory/item/GeyserInstrument.java | 24 +- .../java/org/geysermc/geyser/item/Items.java | 15 +- .../geysermc/geyser/item/type/BannerItem.java | 3 +- .../geyser/item/type/GoatHornItem.java | 18 +- .../org/geysermc/geyser/item/type/Item.java | 24 +- .../geysermc/geyser/level/block/Blocks.java | 44 +- .../level/block/property/Properties.java | 5 +- .../geyser/network/netty/LocalSession.java | 3 +- .../populator/BlockRegistryPopulator.java | 5 +- .../DataComponentRegistryPopulator.java | 2 + .../{ => conversion}/Conversion766_748.java | 23 +- .../{ => conversion}/Conversion776_766.java | 6 +- .../conversion/Conversion786_776.java | 60 + .../conversion/ConversionHelper.java | 47 + .../geyser/session/cache/tags/BlockTag.java | 7 +- .../geyser/session/cache/tags/ItemTag.java | 3 + .../translator/item/ItemTranslator.java | 14 +- ...BedrockInventoryTransactionTranslator.java | 53 +- .../{spawn => }/JavaAddEntityTranslator.java | 6 +- .../spawn/JavaAddExperienceOrbTranslator.java | 49 - .../JavaMerchantOffersTranslator.java | 35 +- .../java/level/JavaGameEventTranslator.java | 24 +- .../geyser/util/StructureBlockUtils.java | 3 +- .../resources/java/item_data_components.json | 14620 ++++++++++------ .../network/ScoreboardIssueTests.java | 174 +- gradle/libs.versions.toml | 2 +- 35 files changed, 9197 insertions(+), 6154 deletions(-) rename core/src/main/java/org/geysermc/geyser/registry/populator/{ => conversion}/Conversion766_748.java (87%) rename core/src/main/java/org/geysermc/geyser/registry/populator/{ => conversion}/Conversion776_766.java (94%) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion786_776.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/conversion/ConversionHelper.java rename core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/{spawn => }/JavaAddEntityTranslator.java (97%) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 09440ac6a..93b4d8c13 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -70,4 +70,5 @@ repositories { content { includeGroupByRegex("com\\.github\\..*") } } + mavenLocal() } 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 757c126b9..baf6a9990 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -473,8 +473,9 @@ public final class EntityDefinitions { .heightAndWidth(0.25f) .identifier("minecraft:xp_bottle") .build(); + // TODO 1.21.5 lingering potion POTION = EntityDefinition.inherited(ThrownPotionEntity::new, throwableItemBase) - .type(EntityType.POTION) + .type(EntityType.SPLASH_POTION) .heightAndWidth(0.25f) .identifier("minecraft:splash_potion") .build(); @@ -960,6 +961,7 @@ public final class EntityDefinitions { .type(EntityType.CHICKEN) .height(0.7f).width(0.4f) .properties(VanillaEntityProperties.CLIMATE_VARIANT) + .addTranslator(MetadataTypes.CHICKEN_VARIANT, ChickenEntity::setVariant) .build(); COW = EntityDefinition.inherited(CowEntity::new, ageableEntityBase) .type(EntityType.COW) @@ -1016,8 +1018,8 @@ public final class EntityDefinitions { .type(EntityType.PIG) .heightAndWidth(0.9f) .properties(VanillaEntityProperties.CLIMATE_VARIANT) - .addTranslator(MetadataTypes.BOOLEAN, (pigEntity, entityMetadata) -> pigEntity.setFlag(EntityFlag.SADDLED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataTypes.INT, PigEntity::setBoost) + .addTranslator(MetadataTypes.PIG_VARIANT, PigEntity::setVariant) .build(); POLAR_BEAR = EntityDefinition.inherited(PolarBearEntity::new, ageableEntityBase) .type(EntityType.POLAR_BEAR) @@ -1045,7 +1047,6 @@ public final class EntityDefinitions { .height(1.7f).width(0.9f) .addTranslator(MetadataTypes.INT, StriderEntity::setBoost) .addTranslator(MetadataTypes.BOOLEAN, StriderEntity::setCold) - .addTranslator(MetadataTypes.BOOLEAN, StriderEntity::setSaddled) .build(); TURTLE = EntityDefinition.inherited(TurtleEntity::new, ageableEntityBase) .type(EntityType.TURTLE) @@ -1144,7 +1145,7 @@ public final class EntityDefinitions { EntityDefinition tameableEntityBase = EntityDefinition.inherited(null, ageableEntityBase) // No factory, is abstract .addTranslator(MetadataTypes.BYTE, TameableEntity::setTameableFlags) - .addTranslator(MetadataTypes.OPTIONAL_UUID, TameableEntity::setOwner) + .addTranslator(MetadataTypes.OPTIONAL_LIVING_ENTITY_REFERENCE, TameableEntity::setOwner) .build(); CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase) .type(EntityType.CAT) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java index 165495506..546f66700 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java @@ -35,7 +35,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.MathUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ColorParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; import java.util.UUID; @@ -72,7 +72,7 @@ public class AreaEffectCloudEntity extends Entity { Registries.PARTICLES.map(particle.getType(), p -> p.levelEventType() instanceof ParticleType particleType ? particleType : null).ifPresent(type -> dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_PARTICLE, type)); - if (particle.getData() instanceof EntityEffectParticleData effectParticleData) { + if (particle.getData() instanceof ColorParticleData effectParticleData) { dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, effectParticleData.getColor()); } } 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 8c1ab80f0..70ef2300e 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 @@ -62,7 +62,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Object import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ColorParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; @@ -80,6 +80,7 @@ public class LivingEntity extends Entity { protected ItemData leggings = ItemData.AIR; protected ItemData boots = ItemData.AIR; protected ItemData body = ItemData.AIR; + protected ItemData saddle = ItemData.AIR; protected ItemData hand = ItemData.AIR; protected ItemData offhand = ItemData.AIR; @@ -118,10 +119,6 @@ public class LivingEntity extends Entity { this.chestplate = ItemTranslator.translateToBedrock(session, stack); } - public void setBody(ItemStack stack) { - this.body = ItemTranslator.translateToBedrock(session, stack); - } - public void setLeggings(ItemStack stack) { this.leggings = ItemTranslator.translateToBedrock(session, stack); } @@ -130,6 +127,15 @@ public class LivingEntity extends Entity { this.boots = ItemTranslator.translateToBedrock(session, stack); } + public void setBody(ItemStack stack) { + this.body = ItemTranslator.translateToBedrock(session, stack); + } + + public void setSaddle(ItemStack stack) { + this.saddle = ItemTranslator.translateToBedrock(session, stack); + updateSaddled(stack.getId() == Items.SADDLE.javaId()); + } + public void setHand(ItemStack stack) { this.hand = ItemTranslator.translateToBedrock(session, stack); } @@ -138,6 +144,18 @@ public class LivingEntity extends Entity { this.offhand = ItemTranslator.translateToBedrock(session, stack); } + protected void updateSaddled(boolean saddled) { + setFlag(EntityFlag.SADDLED, saddled); + updateBedrockMetadata(); + + // Update the interactive tag, if necessary + // TODO 1.21.5 retest + Entity mouseoverEntity = session.getMouseoverEntity(); + if (mouseoverEntity != null && mouseoverEntity.getEntityId() == entityId) { + mouseoverEntity.updateInteractiveTag(); + } + } + public void switchHands() { ItemData offhand = this.offhand; this.offhand = this.hand; @@ -202,7 +220,7 @@ public class LivingEntity extends Entity { continue; } - int color = ((EntityEffectParticleData) particle.getData()).getColor(); + int color = ((ColorParticleData) particle.getData()).getColor(); r += ((color >> 16) & 0xFF) / 255f; g += ((color >> 8) & 0xFF) / 255f; b += ((color) & 0xFF) / 255f; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java index 25bbdbd3c..85abc1c40 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java @@ -120,7 +120,7 @@ public class ThrowableEntity extends Entity implements Tickable { protected float getGravity() { if (getFlag(EntityFlag.HAS_GRAVITY)) { switch (definition.entityType()) { - case POTION: + case LINGERING_POTION, SPLASH_POTION: return 0.05f; case EXPERIENCE_BOTTLE: return 0.07f; @@ -146,7 +146,7 @@ public class ThrowableEntity extends Entity implements Tickable { return 0.8f; } else { switch (definition.entityType()) { - case POTION: + case LINGERING_POTION, SPLASH_POTION: case EXPERIENCE_BOTTLE: case SNOWBALL: case EGG: 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 d4227cfd9..fb7ef3357 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 @@ -48,6 +48,10 @@ 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; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PigVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -155,4 +159,8 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle { public boolean isClientControlled() { return getPlayerPassenger() == session.getPlayerEntity() && session.getPlayerInventory().isHolding(Items.CARROT_ON_A_STICK); } + + public void setVariant(EntityMetadata,? extends MetadataType>> holderEntityMetadata) { + // TODO + } } 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 62318e255..236b22c51 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 @@ -69,10 +69,6 @@ public class StriderEntity extends AnimalEntity implements Tickable, ClientVehic isCold = entityMetadata.getPrimitiveValue(); } - public void setSaddled(BooleanEntityMetadata entityMetadata) { - setFlag(EntityFlag.SADDLED, entityMetadata.getPrimitiveValue()); - } - @Override public void updateBedrockMetadata() { // Make sure they are not shaking when riding another entity 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 100a29299..80995be1c 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 @@ -79,12 +79,19 @@ public class AbstractHorseEntity extends AnimalEntity { session.sendUpstreamPacket(attributesPacket); } + @Override + public void updateSaddled(boolean saddled) { + // Shows the jump meter + setFlag(EntityFlag.CAN_POWER_JUMP, saddled); + super.updateSaddled(saddled); + } + + // TODO 1.21.5 saddled flag doesnt exist anymore public void setHorseFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); boolean tamed = (xd & 0x02) == 0x02; boolean saddled = (xd & 0x04) == 0x04; setFlag(EntityFlag.TAMED, tamed); - setFlag(EntityFlag.SADDLED, saddled); setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10); setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20); @@ -114,9 +121,6 @@ public class AbstractHorseEntity extends AnimalEntity { // Set container type if tamed dirtyMetadata.put(EntityDataTypes.CONTAINER_TYPE, tamed ? (byte) ContainerType.HORSE.getId() : (byte) 0); - - // Shows the jump meter - setFlag(EntityFlag.CAN_POWER_JUMP, saddled); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java index 0bfa6d1a7..631b73936 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java @@ -34,11 +34,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket; +import java.util.List; + public class MerchantContainer extends Container { @Getter @Setter private Entity villager; @Setter - private VillagerTrade[] villagerTrades; + private List villagerTrades; @Getter @Setter private ClientboundMerchantOffersPacket pendingOffersPacket; @Getter @Setter @@ -49,9 +51,9 @@ public class MerchantContainer extends Container { } public void onTradeSelected(GeyserSession session, int slot) { - if (villagerTrades != null && slot >= 0 && slot < villagerTrades.length) { - VillagerTrade trade = villagerTrades[slot]; - setItem(2, GeyserItemStack.from(trade.getOutput()), session); + if (villagerTrades != null && slot >= 0 && slot < villagerTrades.size()) { + VillagerTrade trade = villagerTrades.get(slot); + setItem(2, GeyserItemStack.from(trade.getResult()), session); tradeExperience += trade.getXp(); villager.getDirtyMetadata().put(EntityDataTypes.TRADE_EXPERIENCE, tradeExperience); 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 index 9983a8e90..38d4f2cd5 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/GeyserInstrument.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/GeyserInstrument.java @@ -34,8 +34,7 @@ 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.item.component.InstrumentComponent; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; import java.util.Locale; @@ -90,34 +89,35 @@ public interface GeyserInstrument { return -1; } - static GeyserInstrument fromHolder(GeyserSession session, Holder holder) { - if (holder.isId()) { - return session.getRegistryCache().instruments().byId(holder.id()); + // TODO 1.21.5 + static GeyserInstrument fromComponent(GeyserSession session, InstrumentComponent component) { + if (component.instrumentHolder().isId()) { + return session.getRegistryCache().instruments().byId(component.instrumentHolder().id()); } - Instrument custom = holder.custom(); + InstrumentComponent.Instrument custom = component.instrumentHolder().custom(); return new Wrapper(custom, session.locale()); } - record Wrapper(Instrument instrument, String locale) implements GeyserInstrument { + record Wrapper(InstrumentComponent.Instrument instrument, String locale) implements GeyserInstrument { @Override public String soundEvent() { - return instrument.getSoundEvent().getName(); + return instrument.soundEvent().getName(); } @Override public float range() { - return instrument.getRange(); + return instrument.range(); } @Override public String description() { - return MessageTranslator.convertMessageForTooltip(instrument.getDescription(), locale); + return MessageTranslator.convertMessageForTooltip(instrument.description(), locale); } @Override public BedrockInstrument bedrockInstrument() { - if (instrument.getSoundEvent() instanceof BuiltinSound) { - return BedrockInstrument.getByJavaIdentifier(MinecraftKey.key(instrument.getSoundEvent().getName())); + if (instrument.soundEvent() instanceof BuiltinSound) { + return BedrockInstrument.getByJavaIdentifier(MinecraftKey.key(instrument.soundEvent().getName())); } // Probably custom return null; 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 664c956c3..5fd64c4d4 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -270,9 +270,13 @@ public final class Items { public static final Item COBWEB = register(new BlockItem(builder(), Blocks.COBWEB)); public static final Item SHORT_GRASS = register(new BlockItem(builder(), Blocks.SHORT_GRASS)); public static final Item FERN = register(new BlockItem(builder(), Blocks.FERN)); + public static final Item BUSH = register(new BlockItem(builder(), Blocks.BUSH)); public static final Item AZALEA = register(new BlockItem(builder(), Blocks.AZALEA)); public static final Item FLOWERING_AZALEA = register(new BlockItem(builder(), Blocks.FLOWERING_AZALEA)); public static final Item DEAD_BUSH = register(new BlockItem(builder(), Blocks.DEAD_BUSH)); + public static final Item FIREFLY_BUSH = register(new BlockItem(builder(), Blocks.FIREFLY_BUSH)); + public static final Item SHORT_DRY_GRASS = register(new BlockItem(builder(), Blocks.SHORT_DRY_GRASS)); + public static final Item TALL_DRY_GRASS = register(new BlockItem(builder(), Blocks.TALL_DRY_GRASS)); public static final Item SEAGRASS = register(new BlockItem(builder(), Blocks.SEAGRASS)); public static final Item SEA_PICKLE = register(new BlockItem(builder(), Blocks.SEA_PICKLE)); public static final Item WHITE_WOOL = register(new BlockItem(builder(), Blocks.WHITE_WOOL)); @@ -321,6 +325,8 @@ public final class Items { 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 PINK_PETALS = register(new BlockItem(builder(), Blocks.PINK_PETALS)); + public static final Item WILDFLOWERS = register(new BlockItem(builder(), Blocks.WILDFLOWERS)); + public static final Item LEAF_LITTER = register(new BlockItem(builder(), Blocks.LEAF_LITTER)); 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)); @@ -389,6 +395,7 @@ public final class Items { public static final Item ICE = register(new BlockItem(builder(), Blocks.ICE)); public static final Item SNOW_BLOCK = register(new BlockItem(builder(), Blocks.SNOW_BLOCK)); public static final Item CACTUS = register(new BlockItem(builder(), Blocks.CACTUS)); + public static final Item CACTUS_FLOWER = register(new BlockItem(builder(), Blocks.CACTUS_FLOWER)); public static final Item CLAY = register(new BlockItem(builder(), Blocks.CLAY)); public static final Item JUKEBOX = register(new BlockItem(builder(), Blocks.JUKEBOX)); public static final Item OAK_FENCE = register(new BlockItem(builder(), Blocks.OAK_FENCE)); @@ -891,6 +898,8 @@ public final class Items { public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder())); 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 TEST_BLOCK = register(new BlockItem(builder(), Blocks.TEST_BLOCK)); + public static final Item TEST_INSTANCE_BLOCK = register(new BlockItem(builder(), Blocks.TEST_INSTANCE_BLOCK)); public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", builder())); public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder())); public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder())); @@ -1027,6 +1036,8 @@ public final class Items { public static final Item BOOK = register(new Item("book", builder())); public static final Item SLIME_BALL = register(new Item("slime_ball", builder())); public static final Item EGG = register(new Item("egg", builder())); + public static final Item BLUE_EGG = register(new Item("blue_egg", builder())); + public static final Item BROWN_EGG = register(new Item("brown_egg", builder())); 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())); @@ -1120,7 +1131,7 @@ public final class Items { 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.POWDER_SNOW_CAULDRON, Blocks.LAVA_CAULDRON, Blocks.WATER_CAULDRON)); + public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.WATER_CAULDRON, Blocks.LAVA_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())); @@ -1210,7 +1221,7 @@ public final class Items { public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder())); public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder())); public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder())); - public static final Item MACE = register(new Item("mace", builder())); + public static final Item MACE = register(new Item("mace", builder().attackDamage(6.0))); 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)); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index 2a5f76c33..f7229e202 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -46,7 +46,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; import java.util.ArrayList; import java.util.List; @@ -226,7 +225,7 @@ public class BannerItem extends BlockItem { } components.put(DataComponentTypes.BANNER_PATTERNS, patternLayers); - components.put(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE); + // TODO 1.21.5 hide components??? components.put(DataComponentTypes.ITEM_NAME, Component .translatable("block.minecraft.ominous_banner") .style(Style.style(TextColor.color(16755200))) 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 bd1ac0724..e4173d2bb 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 @@ -36,7 +36,7 @@ import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.InstrumentComponent; public class GoatHornItem extends Item { public GoatHornItem(String javaIdentifier, Builder builder) { @@ -50,9 +50,9 @@ public class GoatHornItem extends Item { return builder; } - Holder holder = components.get(DataComponentTypes.INSTRUMENT); - if (holder != null) { - GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder); + InstrumentComponent instrumentComponent = components.get(DataComponentTypes.INSTRUMENT); + if (instrumentComponent != null) { + GeyserInstrument instrument = GeyserInstrument.fromComponent(session, instrumentComponent); int bedrockId = instrument.bedrockId(); if (bedrockId >= 0) { builder.damage(bedrockId); @@ -66,10 +66,10 @@ public class GoatHornItem extends Item { public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { super.translateComponentsToBedrock(session, components, builder); - Holder holder = components.get(DataComponentTypes.INSTRUMENT); - if (holder != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null - && components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) { - GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder); + InstrumentComponent component = components.get(DataComponentTypes.INSTRUMENT); + // TODO 1.21.5 hiding???? + if (component != null) { + GeyserInstrument instrument = GeyserInstrument.fromComponent(session, component); if (instrument.bedrockInstrument() == null) { builder.getOrCreateLore().add(instrument.description()); } @@ -82,7 +82,7 @@ public class GoatHornItem extends Item { int damage = itemData.getDamage(); // This could cause an issue since -1 is returned for non-vanilla goat horns - itemStack.getOrCreateComponents().put(DataComponentTypes.INSTRUMENT, Holder.ofId(GeyserInstrument.bedrockIdToJava(session, damage))); + itemStack.getOrCreateComponents().put(DataComponentTypes.INSTRUMENT, new InstrumentComponent(Holder.ofId(GeyserInstrument.bedrockIdToJava(session, damage)), null)); 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 f0ae57018..2c3303689 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 @@ -46,12 +46,10 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; -import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DyedItemColor; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; import org.jetbrains.annotations.UnmodifiableView; @@ -159,12 +157,13 @@ public class Item { */ public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { List loreComponents = components.get(DataComponentTypes.LORE); - if (loreComponents != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null) { - List lore = builder.getOrCreateLore(); - for (Component loreComponent : loreComponents) { - lore.add(MessageTranslator.convertMessage(loreComponent, session.locale())); - } - } + // TODO 1.21.5 +// if (loreComponents != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null) { +// List lore = builder.getOrCreateLore(); +// for (Component loreComponent : loreComponents) { +// lore.add(MessageTranslator.convertMessage(loreComponent, session.locale())); +// } +// } Integer damage = components.get(DataComponentTypes.DAMAGE); if (damage != null) { @@ -266,10 +265,11 @@ public class Item { } protected final void translateDyedColor(DataComponents components, BedrockItemBuilder builder) { - DyedItemColor dyedItemColor = components.get(DataComponentTypes.DYED_COLOR); - if (dyedItemColor != null) { - builder.putInt("customColor", dyedItemColor.getRgb()); - } + // TODO 1.21.5 +// DyedItemColor dyedItemColor = components.get(DataComponentTypes.DYED_COLOR); +// if (dyedItemColor != null) { +// builder.putInt("customColor", dyedItemColor.getRgb()); +// } } /** 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 527e49b14..b90bacdd1 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 @@ -325,6 +325,9 @@ public final class Blocks { 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 BUSH = register(new Block("bush", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block SHORT_DRY_GRASS = register(new Block("short_dry_grass", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block TALL_DRY_GRASS = register(new Block("tall_dry_grass", 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))); @@ -399,8 +402,8 @@ public final class Blocks { 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(10.0f) - .booleanState(ACTIVE) .enumState(AXIS, Axis.VALUES) + .enumState(CREAKING_HEART_STATE) .booleanState(NATURAL))); 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) @@ -630,7 +633,7 @@ public final class Blocks { 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))); - public static final Block STONE_BUTTON = register(new ButtonBlock("stone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); @@ -640,6 +643,7 @@ public final class Blocks { 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))); + public static final Block CACTUS_FLOWER = register(new Block("cactus_flower", builder().pushReaction(PistonBehavior.DESTROY))); 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))); @@ -997,43 +1001,43 @@ public final class Blocks { .intState(AGE_7))); public static final Block POTATOES = register(new Block("potatoes", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7))); - public static final Block OAK_BUTTON = register(new ButtonBlock("oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block SPRUCE_BUTTON = register(new ButtonBlock("spruce_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BIRCH_BUTTON = register(new ButtonBlock("birch_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block JUNGLE_BUTTON = register(new ButtonBlock("jungle_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block ACACIA_BUTTON = register(new ButtonBlock("acacia_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block CHERRY_BUTTON = register(new ButtonBlock("cherry_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block DARK_OAK_BUTTON = register(new ButtonBlock("dark_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block PALE_OAK_BUTTON = register(new ButtonBlock("pale_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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 ButtonBlock("mangrove_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block BAMBOO_BUTTON = register(new ButtonBlock("bamboo_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); @@ -2232,11 +2236,11 @@ public final class Blocks { .enumState(HALF) .enumState(STAIRS_SHAPE) .booleanState(WATERLOGGED))); - public static final Block CRIMSON_BUTTON = register(new ButtonBlock("crimson_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); - public static final Block WARPED_BUTTON = register(new ButtonBlock("warped_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); @@ -2268,6 +2272,9 @@ public final class Blocks { .enumState(STRUCTUREBLOCK_MODE))); public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity(BlockEntityType.JIGSAW).requiresCorrectToolForDrops().destroyTime(-1.0f) .enumState(ORIENTATION, FrontAndTop.VALUES))); + public static final Block TEST_BLOCK = register(new Block("test_block", builder().setBlockEntity(BlockEntityType.TEST_BLOCK).destroyTime(-1.0f) + .enumState(TEST_BLOCK_MODE))); + public static final Block TEST_INSTANCE_BLOCK = register(new Block("test_instance_block", builder().setBlockEntity(BlockEntityType.TEST_INSTANCE_BLOCK).destroyTime(-1.0f))); public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f) .intState(LEVEL_COMPOSTER))); public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f) @@ -2336,7 +2343,7 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block POLISHED_BLACKSTONE_BUTTON = register(new ButtonBlock("polished_blackstone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + 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))); @@ -2790,6 +2797,12 @@ public final class Blocks { 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))); + public static final Block WILDFLOWERS = register(new Block("wildflowers", builder().pushReaction(PistonBehavior.DESTROY) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(FLOWER_AMOUNT))); + public static final Block LEAF_LITTER = register(new Block("leaf_litter", builder().pushReaction(PistonBehavior.DESTROY) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(SEGMENT_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) @@ -2921,6 +2934,7 @@ public final class Blocks { public static final Block CLOSED_EYEBLOSSOM = register(new Block("closed_eyeblossom", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_OPEN_EYEBLOSSOM = register(new FlowerPotBlock("potted_open_eyeblossom", OPEN_EYEBLOSSOM, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_CLOSED_EYEBLOSSOM = register(new FlowerPotBlock("potted_closed_eyeblossom", CLOSED_EYEBLOSSOM, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block FIREFLY_BUSH = register(new Block("firefly_bush", builder().pushReaction(PistonBehavior.DESTROY))); 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 f295c4f51..a837bd532 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 @@ -29,7 +29,6 @@ import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Direction; public final class Properties { - public static final BooleanProperty ACTIVE = BooleanProperty.create("active"); public static final BooleanProperty ATTACHED = BooleanProperty.create("attached"); public static final BooleanProperty BERRIES = BooleanProperty.create("berries"); public static final BooleanProperty BLOOM = BooleanProperty.create("bloom"); @@ -77,6 +76,7 @@ public final class Properties { public static final EnumProperty FACING_HOPPER = EnumProperty.create("facing", Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST); public static final EnumProperty HORIZONTAL_FACING = EnumProperty.create("facing", Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST); public static final IntegerProperty FLOWER_AMOUNT = IntegerProperty.create("flower_amount", 1, 4); + public static final IntegerProperty SEGMENT_AMOUNT = IntegerProperty.create("segment_amount", 1, 4); public static final EnumProperty ORIENTATION = EnumProperty.create("orientation", FrontAndTop.VALUES); public static final BasicEnumProperty ATTACH_FACE = BasicEnumProperty.create("face", "floor", "wall", "ceiling"); public static final BasicEnumProperty BELL_ATTACHMENT = BasicEnumProperty.create("attachment", "floor", "ceiling", "single_wall", "double_wall"); @@ -145,5 +145,8 @@ 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_HEART_STATE = BasicEnumProperty.create("creaking_heart_state", "uprooted", "dormant", "awake"); public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous"); + public static final BasicEnumProperty TEST_BLOCK_MODE = BasicEnumProperty.create("mode", "start", "log", "fail", "accept"); + public static final BooleanProperty MAP = BooleanProperty.create("map"); } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 0f6e6b5bc..620a693a2 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -41,6 +41,7 @@ import org.geysermc.mcprotocollib.network.helper.NettyHelper; import org.geysermc.mcprotocollib.network.netty.MinecraftChannelInitializer; import org.geysermc.mcprotocollib.network.packet.PacketProtocol; import org.geysermc.mcprotocollib.network.session.ClientNetworkSession; +import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -56,7 +57,7 @@ public final class LocalSession extends ClientNetworkSession { private final SocketAddress spoofedRemoteAddress; - public LocalSession(SocketAddress targetAddress, String clientIp, PacketProtocol protocol, Executor packetHandlerExecutor) { + public LocalSession(SocketAddress targetAddress, String clientIp, MinecraftProtocol protocol, Executor packetHandlerExecutor) { super(targetAddress, protocol, packetHandlerExecutor, null, null); this.spoofedRemoteAddress = new InetSocketAddress(clientIp, 0); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 81f1fec46..d8e8a68ce 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -58,6 +58,9 @@ import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.FlowerPotBlock; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.populator.conversion.Conversion766_748; +import org.geysermc.geyser.registry.populator.conversion.Conversion776_766; +import org.geysermc.geyser.registry.populator.conversion.Conversion786_776; import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.GeyserBedrockBlock; @@ -119,7 +122,7 @@ public final class BlockRegistryPopulator { var blockMappers = ImmutableMap., Remapper>builder() .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), Conversion766_748::remapBlock) .put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), Conversion776_766::remapBlock) - .put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), Conversion786_776::remapBlock) .put(ObjectIntPair.of("1_21_70", Bedrock_v786.CODEC.getProtocolVersion()), tag -> tag) .build(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java index ef3168f41..29d85cdd2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java @@ -75,6 +75,7 @@ public final class DataComponentRegistryPopulator { byte[] bytes = Base64.getDecoder().decode(encodedValue); ByteBuf buf = Unpooled.wrappedBuffer(bytes); int varInt = MinecraftTypes.readVarInt(buf); + System.out.println("int: " + varInt + " " + componentEntry.getKey()); DataComponentType dataComponentType = DataComponentTypes.from(varInt); DataComponent dataComponent = dataComponentType.readDataComponent(buf); @@ -84,6 +85,7 @@ public final class DataComponentRegistryPopulator { defaultComponents.add(new DataComponents(ImmutableMap.copyOf(map))); } } catch (Exception e) { + // TODO 1.21.5 enchantment reading is broken throw new AssertionError("Unable to load or parse components", e); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java b/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion766_748.java similarity index 87% rename from core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java rename to core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion766_748.java index 6f2bc61e2..b63797d74 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion766_748.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 GeyserMC. http://geysermc.org + * Copyright (c) 2024-2025 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,16 +23,18 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.registry.populator; +package org.geysermc.geyser.registry.populator.conversion; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.geyser.level.block.Blocks; import java.util.ArrayList; import java.util.List; import java.util.Set; +import static org.geysermc.geyser.registry.populator.conversion.ConversionHelper.withName; +import static org.geysermc.geyser.registry.populator.conversion.ConversionHelper.withoutStates; + public class Conversion766_748 { static List PALE_WOODEN_BLOCKS = new ArrayList<>(); static List OTHER_NEW_BLOCKS = new ArrayList<>(); @@ -84,7 +86,7 @@ public class Conversion766_748 { OTHER_NEW_BLOCKS.add("resin_brick_double_slab"); } - static NbtMap remapBlock(NbtMap tag) { + public static NbtMap remapBlock(NbtMap tag) { // First: Downgrade from 1.21.60 -> 1.21.50 tag = Conversion776_766.remapBlock(tag); @@ -116,17 +118,4 @@ public class Conversion766_748 { return tag; } - - static NbtMap withName(NbtMap tag, String name) { - NbtMapBuilder builder = tag.toBuilder(); - builder.replace("name", "minecraft:" + name); - return builder.build(); - } - - static NbtMap withoutStates(String name) { - NbtMapBuilder tagBuilder = NbtMap.builder(); - tagBuilder.putString("name", "minecraft:" + name); - tagBuilder.putCompound("states", NbtMap.builder().build()); - return tagBuilder.build(); - } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java b/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion776_766.java similarity index 94% rename from core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java rename to core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion776_766.java index edc2543ae..325ad5ca9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion776_766.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.registry.populator; +package org.geysermc.geyser.registry.populator.conversion; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -31,6 +31,10 @@ import org.cloudburstmc.nbt.NbtMapBuilder; public class Conversion776_766 { public static NbtMap remapBlock(NbtMap tag) { + + // First: Downgrade from 1.21.70 + tag = Conversion786_776.remapBlock(tag); + final String name = tag.getString("name"); if (name.equals("minecraft:creaking_heart")) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion786_776.java b/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion786_776.java new file mode 100644 index 000000000..ee4518a95 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/Conversion786_776.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 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.conversion; + +import org.cloudburstmc.nbt.NbtMap; + +import static org.geysermc.geyser.registry.populator.conversion.ConversionHelper.withName; +import static org.geysermc.geyser.registry.populator.conversion.ConversionHelper.withoutStates; + +public class Conversion786_776 { + + public static NbtMap remapBlock(NbtMap nbtMap) { + + final String name = nbtMap.getString("name"); + if (name.equals("minecraft:bush")) { + return withName(nbtMap, "fern"); + } + + if (name.equals("minecraft:firefly_bush")) { + return withName(nbtMap, "deadbush"); + } + + if (name.equals("minecraft:tall_dry_grass") || name.equals("minecraft:short_dry_grass")) { + return withName(nbtMap, "short_grass"); + } + + if (name.equals("minecraft:cactus_flower")) { + return withName(nbtMap, "unknown"); + } + + if (name.equals("minecraft:leaf_litter") || name.equals("minecraft:wildflowers")) { + return withoutStates("unknown"); + } + + return nbtMap; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/ConversionHelper.java b/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/ConversionHelper.java new file mode 100644 index 000000000..0bc9708ac --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/conversion/ConversionHelper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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.conversion; + +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; + +// A variety of methods to help with re-mapping blocks and items to older versions. +public class ConversionHelper { + + static NbtMap withName(NbtMap tag, String name) { + NbtMapBuilder builder = tag.toBuilder(); + builder.replace("name", "minecraft:" + name); + return builder.build(); + } + + static NbtMap withoutStates(String name) { + NbtMapBuilder tagBuilder = NbtMap.builder(); + tagBuilder.putString("name", "minecraft:" + name); + tagBuilder.putCompound("states", NbtMap.EMPTY); + return tagBuilder.build(); + } + +} 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 59d301a89..924b168a4 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 @@ -141,6 +141,7 @@ public final class BlockTag { 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 EDIBLE_FOR_SHEEP = create("edible_for_sheep"); 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"); @@ -171,6 +172,7 @@ public final class BlockTag { 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 SWORD_INSTANTLY_MINES = create("sword_instantly_mines"); 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"); @@ -200,13 +202,15 @@ public final class BlockTag { 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 BATS_SPAWNABLE_ON = create("bats_spawnable_on"); + public static final Tag CAMELS_SPAWNABLE_ON = create("camels_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 DRY_VEGETATION_MAY_PLACE_ON = create("dry_vegetation_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 REPLACEABLE_BY_MUSHROOMS = create("replaceable_by_mushrooms"); 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"); @@ -219,6 +223,7 @@ public final class BlockTag { 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 PLAYS_AMBIENT_DESERT_BLOCK_SOUNDS = create("plays_ambient_desert_block_sounds"); public static final Tag AIR = create("air"); private BlockTag() {} 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 e2f4f2db3..50398a765 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 @@ -76,6 +76,7 @@ public final class ItemTag { 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 FLOWERS = create("flowers"); public static final Tag BEDS = create("beds"); public static final Tag FENCES = create("fences"); public static final Tag PIGLIN_REPELLENTS = create("piglin_repellents"); @@ -85,6 +86,7 @@ public final class ItemTag { public static final Tag DUPLICATES_ALLAYS = create("duplicates_allays"); public static final Tag BREWING_FUEL = create("brewing_fuel"); public static final Tag SHULKER_BOXES = create("shulker_boxes"); + public static final Tag EGGS = create("eggs"); 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"); @@ -181,6 +183,7 @@ public final class ItemTag { public static final Tag DYEABLE = create("dyeable"); public static final Tag FURNACE_MINECART_FUEL = create("furnace_minecart_fuel"); public static final Tag BUNDLES = create("bundles"); + public static final Tag BOOK_CLONING_TARGET = create("book_cloning_target"); public static final Tag SKELETON_PREFERRED_WEAPONS = create("skeleton_preferred_weapons"); public static final Tag DROWNED_PREFERRED_WEAPONS = create("drowned_preferred_weapons"); public static final Tag PIGLIN_PREFERRED_WEAPONS = create("piglin_preferred_weapons"); 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 0c8c63f00..9d01f0d8c 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 @@ -168,6 +168,9 @@ public final class ItemTranslator { public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents customComponents) { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); + // TODO 1.21.5: + // - Hiding components + // Populates default components that aren't sent over the network DataComponents components = javaItem.gatherComponents(customComponents); @@ -180,22 +183,22 @@ public final class ItemTranslator { PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); // Make custom effect information visible // Ignore when item have "hide_additional_tooltip" component - if (potionContents != null && components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) { + if (potionContents != null) { // && components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) { customName += getPotionEffectInfo(potionContents, session.locale()); } nbtBuilder.setCustomName(customName); } - boolean hideTooltips = components.get(DataComponentTypes.HIDE_TOOLTIP) != null; + //boolean hideTooltips = components.get(DataComponentTypes.HIDE_TOOLTIP) != null; ItemAttributeModifiers attributeModifiers = components.get(DataComponentTypes.ATTRIBUTE_MODIFIERS); - if (attributeModifiers != null && attributeModifiers.isShowInTooltip() && !hideTooltips) { + if (attributeModifiers != null) { //&& attributeModifiers.isShowInTooltip() && !hideTooltips) { // only add if attribute modifiers do not indicate to hide them addAttributeLore(session, attributeModifiers, nbtBuilder, session.locale()); } - if (session.isAdvancedTooltips() && !hideTooltips) { + if (session.isAdvancedTooltips()) { //&& !hideTooltips) { addAdvancedTooltips(components, nbtBuilder, javaItem, session.locale()); } @@ -545,7 +548,8 @@ public final class ItemTranslator { if (!customNameOnly) { PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); if (potionContents != null) { - String potionName = getPotionName(potionContents, mapping, components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) != null, session.locale()); + // TODO 1.21.5 + String potionName = getPotionName(potionContents, mapping, false /*components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) != null */, session.locale()); if (potionName != null) { return ChatColor.RESET + ChatColor.ESCAPE + translationColor + potionName; } 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 bfc71089a..c44f21213 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.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; @@ -41,8 +40,6 @@ 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.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; @@ -52,7 +49,6 @@ 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; @@ -78,16 +74,12 @@ 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; 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.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; @@ -388,29 +380,30 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator holder = session.getPlayerInventory() - .getItemInHand() - .getComponent(DataComponentTypes.INSTRUMENT); - 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); - } - } +// Holder holder = session.getPlayerInventory() +// .getItemInHand() +// .getComponent(DataComponentTypes.INSTRUMENT); +// if (holder != null) { +// GeyserInstrument instrument = GeyserInstrument.fromComponent(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); +// } +// } } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAddEntityTranslator.java similarity index 97% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAddEntityTranslator.java index ed1951243..738d3c07e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaAddEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2025 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,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.protocol.java.entity.spawn; +package org.geysermc.geyser.translator.protocol.java.entity; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.GeyserImpl; @@ -47,7 +47,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.object.FallingBlockD import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ProjectileData; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.WardenData; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundAddEntityPacket; @Translator(packet = ClientboundAddEntityPacket.class) public class JavaAddEntityTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java deleted file mode 100644 index 8f37eb4d4..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java +++ /dev/null @@ -1,49 +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.java.entity.spawn; - -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; -import org.cloudburstmc.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.ExpOrbEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; - -@Translator(packet = ClientboundAddExperienceOrbPacket.class) -public class JavaAddExperienceOrbTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, ClientboundAddExperienceOrbPacket packet) { - Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); - - Entity entity = new ExpOrbEntity( - session, packet.getExp(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), position - ); - - session.getEntityCache().spawnEntity(entity); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java index e4ff0539f..8a06698c0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java @@ -73,11 +73,11 @@ public class JavaMerchantOffersTranslator extends PacketTranslator tags = new ArrayList<>(addExtraTrade ? packet.getTrades().length + 1 : packet.getTrades().length); - for (int i = 0; i < packet.getTrades().length; i++) { - VillagerTrade trade = packet.getTrades()[i]; + boolean addExtraTrade = packet.isShowProgress() && packet.getVillagerLevel() < 5; + List tags = new ArrayList<>(addExtraTrade ? packet.getOffers().size() + 1 : packet.getOffers().size()); + for (int i = 0; i < packet.getOffers().size(); i++) { + VillagerTrade trade = packet.getOffers().get(i); NbtMapBuilder recipe = NbtMap.builder(); recipe.putInt("netId", i + 1); - recipe.putInt("maxUses", trade.isTradeDisabled() ? 0 : trade.getMaxUses()); + recipe.putInt("maxUses", trade.isOutOfStock() ? 0 : trade.getMaxUses()); recipe.putInt("traderExp", trade.getXp()); recipe.putFloat("priceMultiplierA", trade.getPriceMultiplier()); recipe.putFloat("priceMultiplierB", 0.0f); - recipe.put("sell", getItemTag(session, trade.getOutput())); + recipe.put("sell", getItemTag(session, trade.getResult())); // The buy count before demand and special price adjustments // The first input CAN be null as of Java 1.19.0/Bedrock 1.19.10 // Replicable item: https://gist.github.com/Camotoy/3f3f23d1f80981d1b4472bdb23bba698 from https://github.com/GeyserMC/Geyser/issues/3171 - recipe.putInt("buyCountA", trade.getFirstInput() != null ? Math.max(trade.getFirstInput().getAmount(), 0) : 0); - recipe.putInt("buyCountB", trade.getSecondInput() != null ? Math.max(trade.getSecondInput().getAmount(), 0) : 0); + recipe.putInt("buyCountA", trade.getItemCostA() != null ? Math.max(trade.getItemCostA().count(), 0) : 0); + recipe.putInt("buyCountB", trade.getItemCostB() != null ? Math.max(trade.getItemCostB().count(), 0) : 0); recipe.putInt("demand", trade.getDemand()); // Seems to have no effect recipe.putInt("tier", packet.getVillagerLevel() > 0 ? packet.getVillagerLevel() - 1 : 0); // -1 crashes client - recipe.put("buyA", getItemTag(session, trade.getFirstInput(), trade.getSpecialPrice(), trade.getDemand(), trade.getPriceMultiplier())); - recipe.put("buyB", getItemTag(session, trade.getSecondInput())); - recipe.putInt("uses", trade.getNumUses()); + recipe.put("buyA", getItemTag(session, toItemStack(trade.getItemCostA()), trade.getSpecialPriceDiff(), trade.getDemand(), trade.getPriceMultiplier())); + recipe.put("buyB", getItemTag(session, toItemStack(trade.getItemCostB()))); + recipe.putInt("uses", trade.getUses()); recipe.putByte("rewardExp", (byte) 1); tags.add(recipe.build()); } @@ -158,6 +158,11 @@ public class JavaMerchantOffersTranslator extends PacketTranslator { ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN); @@ -114,7 +114,7 @@ public class JavaGameEventTranslator extends PacketTranslator("doimmediaterespawn", packet.getValue() == RespawnScreenValue.IMMEDIATE_RESPAWN)); session.sendUpstreamPacket(gamerulePacket); break; - case INVALID_BED: + case NO_RESPAWN_BLOCK_AVAILABLE: // Not sent as a proper message? Odd. session.sendMessage(MinecraftLocale.getLocaleString("block.minecraft.spawn.not_valid", session.locale())); break; - case ARROW_HIT_PLAYER: + case PLAY_ARROW_HIT_SOUND: PlaySoundPacket arrowSoundPacket = new PlaySoundPacket(); arrowSoundPacket.setSound("random.orb"); arrowSoundPacket.setPitch(0.5f); @@ -143,9 +143,9 @@ public class JavaGameEventTranslator extends PacketTranslator#5075 - */ - @Test - void entityWithoutUuid() { - // experience orbs are the only known entities without an uuid, see Entity#teamIdentifier for more info - mockContextScoreboard(context -> { - var addExperienceOrbTranslator = new JavaAddExperienceOrbTranslator(); - var removeEntitiesTranslator = new JavaRemoveEntitiesTranslator(); - - // Entity#teamIdentifier used to throw because it returned uuid.toString where uuid could be null. - // this would result in both EntityCache#spawnEntity and EntityCache#removeEntity throwing an exception, - // because the entity would be registered and deregistered to the scoreboard. - assertDoesNotThrow(() -> { - context.translate(addExperienceOrbTranslator, new ClientboundAddExperienceOrbPacket(2, 0, 0, 0, 1)); - - String displayName = context.mockOrSpy(EntityCache.class).getEntityByJavaId(2).getDisplayName(); - assertEquals("entity.minecraft.experience_orb", displayName); - - context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[]{2})); - }); - - // we know that spawning and removing the entity should be fine - assertNextPacketType(context, AddEntityPacket.class); - assertNextPacketType(context, RemoveEntityPacket.class); - }); - } + // TODO 1.21.5 +// /** +// * Test for #5075 +// */ +// @Test +// void entityWithoutUuid() { +// // experience orbs are the only known entities without an uuid, see Entity#teamIdentifier for more info +// mockContextScoreboard(context -> { +// var addExperienceOrbTranslator = new JavaAddExperienceOrbTranslator(); +// var removeEntitiesTranslator = new JavaRemoveEntitiesTranslator(); +// +// // Entity#teamIdentifier used to throw because it returned uuid.toString where uuid could be null. +// // this would result in both EntityCache#spawnEntity and EntityCache#removeEntity throwing an exception, +// // because the entity would be registered and deregistered to the scoreboard. +// assertDoesNotThrow(() -> { +// context.translate(addExperienceOrbTranslator, new ClientboundAddExperienceOrbPacket(2, 0, 0, 0, 1)); +// +// String displayName = context.mockOrSpy(EntityCache.class).getEntityByJavaId(2).getDisplayName(); +// assertEquals("entity.minecraft.experience_orb", displayName); +// +// context.translate(removeEntitiesTranslator, new ClientboundRemoveEntitiesPacket(new int[] { 2 })); +// }); +// +// // we know that spawning and removing the entity should be fine +// assertNextPacketType(context, AddEntityPacket.class); +// assertNextPacketType(context, RemoveEntityPacket.class); +// }); +// } /** * Test for #5078 @@ -168,7 +148,7 @@ public class ScoreboardIssueTests { playerInfoUpdateTranslator, new ClientboundPlayerInfoUpdatePacket( EnumSet.of(PlayerListEntryAction.ADD_PLAYER, PlayerListEntryAction.UPDATE_LISTED), - new PlayerListEntry[]{ + new PlayerListEntry[] { new PlayerListEntry(npcUuid, new GameProfile(npcUuid, "1297"), false, 0, GameMode.SURVIVAL, null, false, 0, null, 0, null, null) })); @@ -198,7 +178,7 @@ public class ScoreboardIssueTests { ); context.translate( setPlayerTeamTranslator, - new ClientboundSetPlayerTeamPacket("npc_team_1297", TeamAction.ADD_PLAYER, new String[]{"1297"})); + new ClientboundSetPlayerTeamPacket("npc_team_1297", TeamAction.ADD_PLAYER, new String[]{ "1297" })); context.translate(addEntityTranslator, new ClientboundAddEntityPacket(1297, npcUuid, EntityType.PLAYER, 1, 2, 3, 4, 5, 6)); // then it updates the displayed skin parts, which isn't relevant for us @@ -260,7 +240,7 @@ public class ScoreboardIssueTests { ); context.translate( setPlayerTeamTranslator, - new ClientboundSetPlayerTeamPacket("npc_team_1298", TeamAction.ADD_PLAYER, new String[]{hologramUuid.toString()})); + new ClientboundSetPlayerTeamPacket("npc_team_1298", TeamAction.ADD_PLAYER, new String[]{ hologramUuid.toString() })); assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); @@ -270,76 +250,4 @@ public class ScoreboardIssueTests { }); }); } - - /** - * Test for #5353. - * It follows a code snippet provided in the PR description. - */ - @Test - void prefixNotShowing() { - mockContextScoreboard(context -> { - var setObjectiveTranslator = new JavaSetObjectiveTranslator(); - var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); - var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - var setScoreTranslator = new JavaSetScoreTranslator(); - - context.translate( - setObjectiveTranslator, - new ClientboundSetObjectivePacket( - "sb-0", - ObjectiveAction.ADD, - Component.text("Test Scoreboard"), - ScoreType.INTEGER, - null - ) - ); - assertNoNextPacket(context); - - context.translate( - setDisplayObjectiveTranslator, - new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "sb-0") - ); - assertNextPacket(context, () -> { - var packet = new SetDisplayObjectivePacket(); - packet.setObjectiveId("0"); - packet.setDisplayName("Test Scoreboard"); - packet.setCriteria("dummy"); - packet.setDisplaySlot("sidebar"); - packet.setSortOrder(1); - return packet; - }); - - context.translate( - setPlayerTeamTranslator, - new ClientboundSetPlayerTeamPacket( - "sbt-1", - Component.text("displaynametest"), - Component.text("§aScore: 10"), - Component.empty(), - false, - false, - NameTagVisibility.NEVER, - CollisionRule.NEVER, - TeamColor.DARK_GREEN, - new String[]{"§0"}) - ); - assertNoNextPacket(context); - - context.translate( - setScoreTranslator, - new ClientboundSetScorePacket( - "§0", - "sb-0", - 10 - ).withDisplay(Component.empty()) - ); - assertNextPacket(context, () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(1, "0", 10, "§2§aScore: 10§r§2§r§2"))); - return packet; - }); - assertNoNextPacket(context); - }); - } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f19ed7678..0f6d1faf5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta6-20250324.162731-5" protocol-codec = "3.0.0.Beta6-20250324.162731-5" raknet = "1.0.0.CR3-20250218.160705-18" minecraftauth = "4.1.1" -mcprotocollib = "1.21.4-20250311.232133-24" +mcprotocollib = "1.21.5-SNAPSHOT" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 8035a26198ec09efbd54416a74c646b0d7ce56bb Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 22 Mar 2025 08:02:46 +0000 Subject: [PATCH 575/897] Support new tooltip display component and other 1.21.5 things (#5417) * Work on supporting new tooltip display component * Fix some stuff and allow any item to function as saddle with the right components * Some fixes and TODOs * Re-implement tropical fish variant tooltip * Fix hiding advanced tooltips * Fix ominous banner tooltip, custom name and some TODOs * Implement RegistryEntryData to allow getting an object from registry cache by its key * Fix goat horns (I think) * We prefer checkers for the nullable/nonnull annotations * Remove unused NotNull import Co-authored-by: chris --------- Co-authored-by: chris --- .../kotlin/geyser.base-conventions.gradle.kts | 4 +- .../geyser/entity/type/FireworkEntity.java | 4 +- .../geyser/entity/type/LivingEntity.java | 16 ++++- .../living/animal/TropicalFishEntity.java | 4 ++ .../inventory/item/GeyserInstrument.java | 15 +++-- .../geysermc/geyser/item/TooltipOptions.java | 59 +++++++++++++++++ .../geysermc/geyser/item/type/ArmorItem.java | 6 +- .../geyser/item/type/AxolotlBucketItem.java | 5 +- .../geysermc/geyser/item/type/BannerItem.java | 9 ++- .../geyser/item/type/CompassItem.java | 5 +- .../geyser/item/type/CrossbowItem.java | 5 +- .../geyser/item/type/DecoratedPotItem.java | 5 +- .../geyser/item/type/DyeableArmorItem.java | 5 +- .../geyser/item/type/EnchantedBookItem.java | 5 +- .../geyser/item/type/FireworkRocketItem.java | 5 +- .../geyser/item/type/FireworkStarItem.java | 5 +- .../geyser/item/type/FishingRodItem.java | 5 +- .../geyser/item/type/GoatHornItem.java | 8 +-- .../org/geysermc/geyser/item/type/Item.java | 17 ++--- .../geysermc/geyser/item/type/MapItem.java | 5 +- .../geyser/item/type/PlayerHeadItem.java | 5 +- .../geysermc/geyser/item/type/ShieldItem.java | 5 +- .../geyser/item/type/ShulkerBoxItem.java | 5 +- .../item/type/TropicalFishBucketItem.java | 55 ++++++++++------ .../geyser/item/type/WolfArmorItem.java | 5 +- .../geyser/item/type/WritableBookItem.java | 5 +- .../geyser/item/type/WrittenBookItem.java | 5 +- .../geyser/session/cache/RegistryCache.java | 5 +- .../session/cache/registry/JavaRegistry.java | 18 ++++- .../cache/registry/JavaRegistryKey.java | 3 +- .../cache/registry/RegistryEntryData.java | 31 +++++++++ .../cache/registry/SimpleJavaRegistry.java | 42 ++++++++++-- .../translator/item/ItemTranslator.java | 65 +++++++++---------- ...BedrockInventoryTransactionTranslator.java | 52 ++++++++------- 34 files changed, 348 insertions(+), 145 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/TooltipOptions.java create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/registry/RegistryEntryData.java diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 93b4d8c13..3f7b48a2f 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -26,7 +26,7 @@ dependencies { } repositories { - // mavenLocal() + mavenLocal() mavenCentral() @@ -69,6 +69,4 @@ repositories { maven("https://jitpack.io") { content { includeGroupByRegex("com\\.github\\..*") } } - - mavenLocal() } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java index ebe35320e..d7a9990fe 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java @@ -31,6 +31,7 @@ import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; @@ -59,7 +60,8 @@ public class FireworkEntity extends Entity { // TODO this looked the same, so I'm going to assume it is and (keep below comment if true) // Translate using item methods to get firework NBT for Bedrock BedrockItemBuilder builder = new BedrockItemBuilder(); - Items.FIREWORK_ROCKET.translateComponentsToBedrock(session, components, builder); + TooltipOptions tooltip = TooltipOptions.fromComponents(components); + Items.FIREWORK_ROCKET.translateComponentsToBedrock(session, components, tooltip, builder); dirtyMetadata.put(EntityDataTypes.DISPLAY_FIREWORK, builder.build()); } 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 70ef2300e..6ef6ba0c9 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 @@ -44,6 +44,8 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; @@ -51,6 +53,7 @@ import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; 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.EntityMetadata; @@ -62,6 +65,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Object import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Equippable; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ColorParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; @@ -133,7 +138,16 @@ public class LivingEntity extends Entity { public void setSaddle(ItemStack stack) { this.saddle = ItemTranslator.translateToBedrock(session, stack); - updateSaddled(stack.getId() == Items.SADDLE.javaId()); + + boolean saddled = false; + Item item = Registries.JAVA_ITEMS.get(stack.getId()); + if (item != null) { + DataComponents components = item.gatherComponents(stack.getDataComponentsPatch()); + Equippable equippable = components.get(DataComponentTypes.EQUIPPABLE); + saddled = equippable != null && equippable.slot() == EquipmentSlot.SADDLE; + } + + updateSaddled(saddled); } public void setHand(ItemStack stack) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java index b6751bc3f..182bb176f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java @@ -61,6 +61,10 @@ public class TropicalFishEntity extends AbstractFishEntity { dirtyMetadata.put(EntityDataTypes.COLOR_2, getPatternColor(varNumber)); // Pattern color 0-15 } + public static int getPackedVariant(int pattern, int baseColor, int patternColor) { + return pattern & 65535 | (baseColor & 0xFF) << 16 | (patternColor & 0xFF) << 24; + } + public static int getShape(int variant) { return Math.min(variant & 0xFF, 1); } 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 index 38d4f2cd5..71f43a23e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/GeyserInstrument.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/GeyserInstrument.java @@ -89,13 +89,18 @@ public interface GeyserInstrument { return -1; } - // TODO 1.21.5 + // TODO test in 1.21.5 static GeyserInstrument fromComponent(GeyserSession session, InstrumentComponent component) { - if (component.instrumentHolder().isId()) { - return session.getRegistryCache().instruments().byId(component.instrumentHolder().id()); + if (component.instrumentLocation() != null) { + return session.getRegistryCache().instruments().byKey(component.instrumentLocation()); + } else if (component.instrumentHolder() != null) { + if (component.instrumentHolder().isId()) { + return session.getRegistryCache().instruments().byId(component.instrumentHolder().id()); + } + InstrumentComponent.Instrument custom = component.instrumentHolder().custom(); + return new Wrapper(custom, session.locale()); } - InstrumentComponent.Instrument custom = component.instrumentHolder().custom(); - return new Wrapper(custom, session.locale()); + throw new IllegalStateException("InstrumentComponent must have either a location or a holder"); } record Wrapper(InstrumentComponent.Instrument instrument, String locale) implements GeyserInstrument { diff --git a/core/src/main/java/org/geysermc/geyser/item/TooltipOptions.java b/core/src/main/java/org/geysermc/geyser/item/TooltipOptions.java new file mode 100644 index 000000000..2fa9af789 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/TooltipOptions.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 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.item; + +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.TooltipDisplay; + +@FunctionalInterface +public interface TooltipOptions { + + TooltipOptions ALL_SHOWN = component -> true; + + TooltipOptions ALL_HIDDEN = component -> false; + + boolean showInTooltip(DataComponentType component); + + static TooltipOptions fromComponents(DataComponents components) { + TooltipDisplay display = components.get(DataComponentTypes.TOOLTIP_DISPLAY); + if (display == null) { + return ALL_SHOWN; + } else if (display.hideTooltip()) { + return ALL_HIDDEN; + } else if (display.hiddenComponents().isEmpty()) { + return ALL_SHOWN; + } + + return component -> !display.hiddenComponents().contains(component); + } + + static boolean hideTooltip(DataComponents components) { + TooltipDisplay display = components.get(DataComponentTypes.TOOLTIP_DISPLAY); + return display != null && display.hideTooltip(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java index c20cc490e..5eca97f87 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java @@ -30,6 +30,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ArmorTrim; @@ -43,8 +44,8 @@ public class ArmorItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); ArmorTrim trim = components.get(DataComponentTypes.TRIM); if (trim != null) { @@ -54,6 +55,7 @@ public class ArmorItem extends Item { // discard custom trim patterns/materials to prevent visual glitches on bedrock if (!getNamespace(material.getMaterialId()).equals("minecraft") || !getNamespace(pattern.getPatternId()).equals("minecraft")) { + // TODO - how is this shown in tooltip? should we add a custom trim tooltip to the lore here return; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java index 8895d45a8..3d3214697 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -37,8 +38,8 @@ public class AxolotlBucketItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); // Bedrock Edition displays the properties of the axolotl. Java does not. // To work around this, set the custom name to the Axolotl translation and it's displayed correctly diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java index f7229e202..2f3f64b75 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java @@ -36,6 +36,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.item.DyeColor; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -46,6 +47,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.TooltipDisplay; import java.util.ArrayList; import java.util.List; @@ -202,8 +204,8 @@ public class BannerItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); List patterns = components.get(DataComponentTypes.BANNER_PATTERNS); if (patterns != null) { @@ -225,7 +227,8 @@ public class BannerItem extends BlockItem { } components.put(DataComponentTypes.BANNER_PATTERNS, patternLayers); - // TODO 1.21.5 hide components??? + // The ominous banner item in the Java creative menu just has banner patterns hidden as of 1.21.5 + components.put(DataComponentTypes.TOOLTIP_DISPLAY, new TooltipDisplay(false, List.of(DataComponentTypes.BANNER_PATTERNS))); components.put(DataComponentTypes.ITEM_NAME, Component .translatable("block.minecraft.ominous_banner") .style(Style.style(TextColor.color(16755200))) 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 d6403a8c3..ef1ca52c5 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 @@ -29,6 +29,7 @@ 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.inventory.GeyserItemStack; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; @@ -59,8 +60,8 @@ public class CompassItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); LodestoneTracker tracker = components.get(DataComponentTypes.LODESTONE_TRACKER); if (tracker != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java index 13e79958e..9eb95e4fb 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/CrossbowItem.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -44,8 +45,8 @@ public class CrossbowItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); List chargedProjectiles = components.get(DataComponentTypes.CHARGED_PROJECTILES); if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java index fa08bd7ec..a81a8cb52 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DecoratedPotItem.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -44,8 +45,8 @@ public class DecoratedPotItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); List decorations = components.get(DataComponentTypes.POT_DECORATIONS); // TODO maybe unbox in MCProtocolLib if (decorations != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java index 480385d07..b85a41782 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/DyeableArmorItem.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -36,8 +37,8 @@ public class DyeableArmorItem extends ArmorItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); // Note that this is handled as of 1.20.5 in the ItemColors class. // But horse leather armor and body leather armor are now both armor items. So it works! diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index f5ddb698b..bc6dcde67 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.BedrockEnchantment; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -50,8 +51,8 @@ public class EnchantedBookItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); List bedrockEnchants = new ArrayList<>(); ItemEnchantments enchantments = components.get(DataComponentTypes.STORED_ENCHANTMENTS); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java index 265d3aad7..a0060044f 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkRocketItem.java @@ -31,6 +31,7 @@ import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.level.FireworkColor; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -48,8 +49,8 @@ public class FireworkRocketItem extends Item implements BedrockRequiresTagItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); Fireworks fireworks = components.get(DataComponentTypes.FIREWORKS); if (fireworks == null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java index 170d386fd..ff6a19e61 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FireworkStarItem.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -40,8 +41,8 @@ public class FireworkStarItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); Fireworks.FireworkExplosion explosion = components.get(DataComponentTypes.FIREWORK_EXPLOSION); if (explosion != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java index 32b1d5df5..a066fdbab 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FishingRodItem.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -36,8 +37,8 @@ public class FishingRodItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); // Fix damage inconsistency builder.getDamage().ifPresent(damage -> builder.setDamage(getBedrockDamage(damage))); 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 e4173d2bb..7d0cfa796 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 @@ -29,6 +29,7 @@ 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.item.TooltipOptions; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; @@ -63,12 +64,11 @@ public class GoatHornItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); InstrumentComponent component = components.get(DataComponentTypes.INSTRUMENT); - // TODO 1.21.5 hiding???? - if (component != null) { + if (component != null && tooltip.showInTooltip(DataComponentTypes.INSTRUMENT)) { GeyserInstrument instrument = GeyserInstrument.fromComponent(session, component); if (instrument.bedrockInstrument() == null) { builder.getOrCreateLore().add(instrument.description()); 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 2c3303689..9919aa308 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 @@ -37,6 +37,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.Registries; @@ -46,6 +47,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; +import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; @@ -155,15 +157,14 @@ public class Item { /** * Takes components from Java Edition and map them into Bedrock. */ - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { List loreComponents = components.get(DataComponentTypes.LORE); - // TODO 1.21.5 -// if (loreComponents != null && components.get(DataComponentTypes.HIDE_TOOLTIP) == null) { -// List lore = builder.getOrCreateLore(); -// for (Component loreComponent : loreComponents) { -// lore.add(MessageTranslator.convertMessage(loreComponent, session.locale())); -// } -// } + if (loreComponents != null && tooltip.showInTooltip(DataComponentTypes.LORE)) { + List lore = builder.getOrCreateLore(); + for (Component loreComponent : loreComponents) { + lore.add(MessageTranslator.convertMessage(loreComponent, session.locale())); + } + } Integer damage = components.get(DataComponentTypes.DAMAGE); if (damage != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java index f19da5968..332c5210c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/MapItem.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; @@ -37,8 +38,8 @@ public class MapItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); Integer mapValue = components.get(DataComponentTypes.MAP_ID); if (mapValue == null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java index 502d9be0d..7f29751a4 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PlayerHeadItem.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; @@ -42,8 +43,8 @@ public class PlayerHeadItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); // Use the correct color, determined by the rarity of the item char rarity = Rarity.fromId(components.get(DataComponentTypes.RARITY)).getColor(); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java index 01cea9c17..9d44920f0 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShieldItem.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer; @@ -40,8 +41,8 @@ public class ShieldItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); List patterns = components.get(DataComponentTypes.BANNER_PATTERNS); if (patterns != null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java index a53a9b7bc..e2e910b17 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ShulkerBoxItem.java @@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -53,8 +54,8 @@ public class ShulkerBoxItem extends BlockItem { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); List contents = components.get(DataComponentTypes.CONTAINER); if (contents == null || contents.isEmpty()) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java index a93cc5934..011d5bb22 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TropicalFishBucketItem.java @@ -30,8 +30,8 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.checkerframework.checker.nullness.qual.NonNull; -import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.entity.type.living.animal.TropicalFishEntity; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.item.BedrockItemBuilder; @@ -49,37 +49,54 @@ public class TropicalFishBucketItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); // Prevent name from appearing as "Bucket of" builder.putByte("AppendCustomName", (byte) 1); builder.putString("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.tropical_fish", session.locale())); + // Add Java's client side lore tag - // Do you know how frequently Java NBT used to be before 1.20.5? It was a lot. And now it's just this lowly check. - NbtMap entityTag = components.get(DataComponentTypes.BUCKET_ENTITY_DATA); - if (entityTag != null && !entityTag.isEmpty()) { - //TODO test - int bucketVariant = entityTag.getInt("BucketVariantTag"); + Integer pattern = components.get(DataComponentTypes.TROPICAL_FISH_PATTERN); + Integer baseColor = components.get(DataComponentTypes.TROPICAL_FISH_BASE_COLOR); + Integer patternColor = components.get(DataComponentTypes.TROPICAL_FISH_PATTERN_COLOR); + + // The pattern component decides whether to show the tooltip of all 3 components, as of Java 1.21.5 + if ((pattern != null || (baseColor != null && patternColor != null)) && tooltip.showInTooltip(DataComponentTypes.TROPICAL_FISH_PATTERN)) { + //TODO test this for 1.21.5 + int packedVariant = getPackedVariant(pattern, baseColor, patternColor); List lore = builder.getOrCreateLore(); - int predefinedVariantId = TropicalFishEntity.getPredefinedId(bucketVariant); + int predefinedVariantId = TropicalFishEntity.getPredefinedId(packedVariant); if (predefinedVariantId != -1) { - Component tooltip = Component.translatable("entity.minecraft.tropical_fish.predefined." + predefinedVariantId, LORE_STYLE); - lore.add(0, MessageTranslator.convertMessage(tooltip, session.locale())); + Component line = Component.translatable("entity.minecraft.tropical_fish.predefined." + predefinedVariantId, LORE_STYLE); + lore.add(0, MessageTranslator.convertMessage(line, session.locale())); } else { - Component typeTooltip = Component.translatable("entity.minecraft.tropical_fish.type." + TropicalFishEntity.getVariantName(bucketVariant), LORE_STYLE); + Component typeTooltip = Component.translatable("entity.minecraft.tropical_fish.type." + TropicalFishEntity.getVariantName(packedVariant), LORE_STYLE); lore.add(0, MessageTranslator.convertMessage(typeTooltip, session.locale())); - byte baseColor = TropicalFishEntity.getBaseColor(bucketVariant); - byte patternColor = TropicalFishEntity.getPatternColor(bucketVariant); - Component colorTooltip = Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(baseColor), LORE_STYLE); - if (baseColor != patternColor) { - colorTooltip = colorTooltip.append(Component.text(", ", LORE_STYLE)) - .append(Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(patternColor), LORE_STYLE)); + if (baseColor != null && patternColor != null) { + Component colorTooltip = Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(baseColor.byteValue()), LORE_STYLE); + if (!baseColor.equals(patternColor)) { + colorTooltip = colorTooltip.append(Component.text(", ", LORE_STYLE)) + .append(Component.translatable("color.minecraft." + TropicalFishEntity.getColorName(patternColor.byteValue()), LORE_STYLE)); + } + lore.add(1, MessageTranslator.convertMessage(colorTooltip, session.locale())); } - lore.add(1, MessageTranslator.convertMessage(colorTooltip, session.locale())); } } } + + private static int getPackedVariant(Integer pattern, Integer baseColor, Integer patternColor) { + if (pattern == null) { + pattern = 0; + } + if (baseColor == null) { + baseColor = 0; + } + if (patternColor == null) { + patternColor = 0; + } + return TropicalFishEntity.getPackedVariant(pattern, baseColor, patternColor); + } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java index 41c72f532..086bf3a9c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WolfArmorItem.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -36,8 +37,8 @@ public class WolfArmorItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); // Note that this is handled as of 1.21 in the ItemColors class. translateDyedColor(components, builder); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java index 177ca0b2a..78a744a87 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WritableBookItem.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -46,8 +47,8 @@ public class WritableBookItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); WritableBookContent bookContent = components.get(DataComponentTypes.WRITABLE_BOOK_CONTENT); if (bookContent == null) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java index 9cb661e70..22064e44c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/WrittenBookItem.java @@ -30,6 +30,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -51,8 +52,8 @@ public class WrittenBookItem extends Item { } @Override - public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { - super.translateComponentsToBedrock(session, components, builder); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull TooltipOptions tooltip, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, tooltip, builder); WrittenBookContent bookContent = components.get(DataComponentTypes.WRITTEN_BOOK_CONTENT); if (bookContent == null) { 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 ecd293bff..1f0de4444 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 @@ -51,6 +51,7 @@ 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.RegistryEntryData; import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; import org.geysermc.geyser.text.ChatDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; @@ -189,7 +190,7 @@ public final class RegistryCache { entryIdMap.put(entries.get(i).getId(), i); } - List builder = new ArrayList<>(entries.size()); + List> builder = new ArrayList<>(entries.size()); for (int i = 0; i < entries.size(); i++) { RegistryEntry entry = entries.get(i); // If the data is null, that's the server telling us we need to use our default values. @@ -203,7 +204,7 @@ public final class RegistryCache { RegistryEntryContext context = new RegistryEntryContext(entry, entryIdMap, registryCache.session); // This is what Geyser wants to keep as a value for this registry. T cacheEntry = reader.apply(context); - builder.add(i, cacheEntry); + builder.add(i, new RegistryEntryData<>(entry.getId(), cacheEntry)); } localCache.reset(builder); }); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java index d7c7782ea..e51dbf043 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.session.cache.registry; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.index.qual.NonNegative; import java.util.List; @@ -39,15 +40,30 @@ public interface JavaRegistry { */ T byId(@NonNegative int id); + /** + * Looks up a registry entry by its key. The object can be null, or not present. + */ + T byKey(Key key); + + /** + * Looks up a registry entry by its ID, and returns it wrapped in {@link RegistryEntryData} so that its registered key is also known. The object can be null, or not present. + */ + RegistryEntryData entryById(@NonNegative int id); + /** * Reverse looks-up an object to return its network ID, or -1. */ int byValue(T value); + /** + * Reverse looks-up an object to return it wrapped in {@link RegistryEntryData}, or null. + */ + RegistryEntryData entryByValue(T value); + /** * Resets the objects by these IDs. */ - void reset(List values); + void reset(List> values); /** * All values of this registry, as a list. 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 index 369bea7a4..364d998ee 100644 --- 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 @@ -26,10 +26,9 @@ package org.geysermc.geyser.session.cache.registry; import net.kyori.adventure.key.Key; +import org.checkerframework.checker.nullness.qual.Nullable; 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. diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/RegistryEntryData.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/RegistryEntryData.java new file mode 100644 index 000000000..ed0b2fdec --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/RegistryEntryData.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 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; + +public record RegistryEntryData(Key key, T data) { +} diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java index 7b79a40be..3e3d8ba6c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java @@ -26,15 +26,34 @@ package org.geysermc.geyser.session.cache.registry; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.index.qual.NonNegative; import java.util.List; public class SimpleJavaRegistry implements JavaRegistry { - protected final ObjectArrayList values = new ObjectArrayList<>(); + protected final ObjectArrayList> values = new ObjectArrayList<>(); @Override public T byId(@NonNegative int id) { + if (id < 0 || id >= this.values.size()) { + return null; + } + return this.values.get(id).data(); + } + + @Override + public T byKey(Key key) { + for (RegistryEntryData entry : values) { + if (entry.key().equals(key)) { + return entry.data(); + } + } + return null; + } + + @Override + public RegistryEntryData entryById(@NonNegative int id) { if (id < 0 || id >= this.values.size()) { return null; } @@ -43,11 +62,26 @@ public class SimpleJavaRegistry implements JavaRegistry { @Override public int byValue(T value) { - return this.values.indexOf(value); + for (int i = 0; i < this.values.size(); i++) { + if (values.get(i).data().equals(value)) { + return i; + } + } + return -1; } @Override - public void reset(List values) { + public RegistryEntryData entryByValue(T value) { + for (RegistryEntryData entry : this.values) { + if (entry.data().equals(value)) { + return entry; + } + } + return null; + } + + @Override + public void reset(List> values) { this.values.clear(); this.values.addAll(values); this.values.trim(); @@ -55,7 +89,7 @@ public class SimpleJavaRegistry implements JavaRegistry { @Override public List values() { - return this.values; + return this.values.stream().map(RegistryEntryData::data).toList(); } @Override 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 9d01f0d8c..04f5f5bb3 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 @@ -43,8 +43,10 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.TooltipOptions; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.item.type.PotionItem; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; @@ -168,37 +170,32 @@ public final class ItemTranslator { public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents customComponents) { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); - // TODO 1.21.5: - // - Hiding components - // Populates default components that aren't sent over the network DataComponents components = javaItem.gatherComponents(customComponents); + TooltipOptions tooltip = TooltipOptions.fromComponents(components); // Translate item-specific components - javaItem.translateComponentsToBedrock(session, components, nbtBuilder); + javaItem.translateComponentsToBedrock(session, components, tooltip, nbtBuilder); Rarity rarity = Rarity.fromId(components.getOrDefault(DataComponentTypes.RARITY, 0)); String customName = getCustomName(session, customComponents, bedrockItem, rarity.getColor(), false, false); if (customName != null) { PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); - // Make custom effect information visible - // Ignore when item have "hide_additional_tooltip" component - if (potionContents != null) { // && components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) == null) { - customName += getPotionEffectInfo(potionContents, session.locale()); + // Make custom effect information visible when shown in tooltip + if (potionContents != null && tooltip.showInTooltip(DataComponentTypes.POTION_CONTENTS)) { + customName += getPotionEffectInfo(potionContents, session.locale()); // TODO should this be done with lore instead? } nbtBuilder.setCustomName(customName); } - //boolean hideTooltips = components.get(DataComponentTypes.HIDE_TOOLTIP) != null; - ItemAttributeModifiers attributeModifiers = components.get(DataComponentTypes.ATTRIBUTE_MODIFIERS); - if (attributeModifiers != null) { //&& attributeModifiers.isShowInTooltip() && !hideTooltips) { + if (attributeModifiers != null && tooltip.showInTooltip(DataComponentTypes.ATTRIBUTE_MODIFIERS )) { // only add if attribute modifiers do not indicate to hide them addAttributeLore(session, attributeModifiers, nbtBuilder, session.locale()); } - if (session.isAdvancedTooltips()) { //&& !hideTooltips) { + if (session.isAdvancedTooltips() && !TooltipOptions.hideTooltip(components)) { addAdvancedTooltips(components, nbtBuilder, javaItem, session.locale()); } @@ -391,7 +388,7 @@ public final class ItemTranslator { return finalText.toString(); } - public static String getPotionName(PotionContents contents, ItemMapping mapping, boolean hideAdditionalTooltip, String language) { + public static String getPotionName(PotionContents contents, ItemMapping mapping, String language) { String customPotionName = contents.getCustomName(); Potion potion = Potion.getByJavaId(contents.getPotionId()); @@ -401,22 +398,10 @@ public final class ItemTranslator { Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + customPotionName), language); } - if (!hideAdditionalTooltip && !contents.getCustomEffects().isEmpty()) { + if (!contents.getCustomEffects().isEmpty()) { // Make a name when has custom effects - String potionName; - if (potion != null) { - potionName = potion.toString().toLowerCase(Locale.ROOT); - if (potionName.startsWith("strong_")) { - potionName = potionName.substring(6); - } else if (potionName.startsWith("long_")) { - potionName = potionName.substring(4); - } - } else { - potionName = "empty"; - } - return MessageTranslator.convertMessage( - Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + potionName), - language); + String potionName = potion == null ? "empty" : potion.toString().toLowerCase(Locale.ROOT); + return MessageTranslator.convertMessage(Component.translatable(mapping.getJavaItem().translationKey() + ".effect." + potionName), language); } return null; } @@ -538,22 +523,31 @@ public final class ItemTranslator { * @param translationColor if this item is not available on Java, the color that the new name should be. * Normally, this should just be white, but for shulker boxes this should be gray. */ - public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, char translationColor, boolean customNameOnly, boolean includeAll) { + public static String getCustomName(GeyserSession session, DataComponents components, ItemMapping mapping, + char translationColor, boolean customNameOnly, boolean includeAll) { if (components != null) { + // If the tooltip is hidden entirely, return an empty custom name + if (TooltipOptions.hideTooltip(components)) { + return ""; // TODO test this + } + // ItemStack#getHoverName as of 1.20.5 Component customName = components.get(DataComponentTypes.CUSTOM_NAME); if (customName != null) { return MessageTranslator.convertMessage(customName, session.locale()); } + if (!customNameOnly) { - PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); - if (potionContents != null) { - // TODO 1.21.5 - String potionName = getPotionName(potionContents, mapping, false /*components.get(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) != null */, session.locale()); - if (potionName != null) { - return ChatColor.RESET + ChatColor.ESCAPE + translationColor + potionName; + if (mapping.getJavaItem() instanceof PotionItem) { + PotionContents potionContents = components.get(DataComponentTypes.POTION_CONTENTS); + if (potionContents != null) { + String potionName = getPotionName(potionContents, mapping, session.locale()); // TODO also test this + if (potionName != null) { + return ChatColor.RESET + ChatColor.ESCAPE + translationColor + potionName; + } } } + if (includeAll) { // Fix book title display in tooltips of shulker box WrittenBookContent bookContent = components.get(DataComponentTypes.WRITTEN_BOOK_CONTENT); @@ -561,6 +555,7 @@ public final class ItemTranslator { return ChatColor.RESET + ChatColor.ESCAPE + translationColor + bookContent.getTitle().getRaw(); } } + customName = components.get(DataComponentTypes.ITEM_NAME); if (customName != null) { // Get the translated name and prefix it with a reset char to prevent italics - matches Java Edition 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 c44f21213..d3e2ba5df 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,6 +30,7 @@ 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.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; @@ -40,6 +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.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; @@ -49,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; @@ -74,12 +78,15 @@ 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.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.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.InstrumentComponent; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; @@ -380,30 +387,29 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator holder = session.getPlayerInventory() -// .getItemInHand() -// .getComponent(DataComponentTypes.INSTRUMENT); -// if (holder != null) { -// GeyserInstrument instrument = GeyserInstrument.fromComponent(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); -// } -// } + InstrumentComponent component = session.getPlayerInventory() + .getItemInHand() + .getComponent(DataComponentTypes.INSTRUMENT); + if (component != null) { + GeyserInstrument instrument = GeyserInstrument.fromComponent(session, component); + 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); + } + } } } } From c398d5c62ce25c73afba93db9c1dfc38b3c09e9a Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 22 Mar 2025 08:39:44 +0000 Subject: [PATCH 576/897] Work on farmland variants, not sure if this will work --- .../geyser/entity/EntityDefinitions.java | 6 +- .../type/living/animal/MooshroomEntity.java | 1 + .../animal/{ => farm}/ChickenEntity.java | 14 ++- .../living/animal/{ => farm}/CowEntity.java | 15 +++- .../living/animal/{ => farm}/PigEntity.java | 14 +-- .../animal/farm/TemperatureVariantAnimal.java | 90 +++++++++++++++++++ .../geyser/session/cache/RegistryCache.java | 9 ++ .../cache/registry/JavaRegistries.java | 6 +- .../inventory/LoomInventoryTranslator.java | 2 +- 9 files changed, 141 insertions(+), 16 deletions(-) rename core/src/main/java/org/geysermc/geyser/entity/type/living/animal/{ => farm}/ChickenEntity.java (81%) rename core/src/main/java/org/geysermc/geyser/entity/type/living/animal/{ => farm}/CowEntity.java (87%) rename core/src/main/java/org/geysermc/geyser/entity/type/living/animal/{ => farm}/PigEntity.java (92%) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java 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 baf6a9990..05024f274 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -80,8 +80,8 @@ import org.geysermc.geyser.entity.type.living.TadpoleEntity; import org.geysermc.geyser.entity.type.living.animal.ArmadilloEntity; import org.geysermc.geyser.entity.type.living.animal.AxolotlEntity; import org.geysermc.geyser.entity.type.living.animal.BeeEntity; -import org.geysermc.geyser.entity.type.living.animal.ChickenEntity; -import org.geysermc.geyser.entity.type.living.animal.CowEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.ChickenEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.CowEntity; import org.geysermc.geyser.entity.type.living.animal.FoxEntity; import org.geysermc.geyser.entity.type.living.animal.FrogEntity; import org.geysermc.geyser.entity.type.living.animal.GoatEntity; @@ -89,7 +89,7 @@ import org.geysermc.geyser.entity.type.living.animal.HoglinEntity; import org.geysermc.geyser.entity.type.living.animal.MooshroomEntity; import org.geysermc.geyser.entity.type.living.animal.OcelotEntity; import org.geysermc.geyser.entity.type.living.animal.PandaEntity; -import org.geysermc.geyser.entity.type.living.animal.PigEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.PigEntity; import org.geysermc.geyser.entity.type.living.animal.PolarBearEntity; import org.geysermc.geyser.entity.type.living.animal.PufferFishEntity; import org.geysermc.geyser.entity.type.living.animal.RabbitEntity; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index dce1adf79..622c599e7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -30,6 +30,7 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.type.living.animal.farm.CowEntity; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; 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/farm/ChickenEntity.java similarity index 81% rename from core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java rename to core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java index 231c408d6..afd8a6ce6 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/farm/ChickenEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2025 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,21 +23,24 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.entity.type.living.animal; +package org.geysermc.geyser.entity.type.living.animal.farm; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.properties.VanillaEntityProperties; +import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.Tag; import java.util.UUID; -public class ChickenEntity extends AnimalEntity { +public class ChickenEntity extends TemperatureVariantAnimal { public ChickenEntity(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); @@ -54,4 +57,9 @@ public class ChickenEntity extends AnimalEntity { protected Tag getFoodTag() { return ItemTag.CHICKEN_FOOD; } + + @Override + protected JavaRegistryKey variantRegistry() { + return JavaRegistries.CHICKEN_VARIANT; + } } 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/farm/CowEntity.java similarity index 87% rename from core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java rename to core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java index 6c83b9dd1..8f7740f90 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/farm/CowEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2025 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,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.entity.type.living.animal; +package org.geysermc.geyser.entity.type.living.animal.farm; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -33,10 +33,13 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.properties.VanillaEntityProperties; +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.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; @@ -45,7 +48,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class CowEntity extends AnimalEntity { +public class CowEntity extends TemperatureVariantAnimal { + public CowEntity(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); } @@ -82,4 +86,9 @@ public class CowEntity extends AnimalEntity { protected Tag getFoodTag() { return ItemTag.COW_FOOD; } + + @Override + protected JavaRegistryKey variantRegistry() { + return JavaRegistries.COW_VARIANT; + } } 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/farm/PigEntity.java similarity index 92% rename from core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java rename to core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java index fb7ef3357..4508a0158 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/farm/PigEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2025 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,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.entity.type.living.animal; +package org.geysermc.geyser.entity.type.living.animal.farm; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.Tickable; +import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent; import org.geysermc.geyser.entity.vehicle.ClientVehicle; @@ -43,6 +44,8 @@ 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.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.EntityUtils; @@ -57,7 +60,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle { +public class PigEntity extends TemperatureVariantAnimal implements Tickable, ClientVehicle { private final BoostableVehicleComponent vehicleComponent = new BoostableVehicleComponent<>(this, 1.0f); public PigEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -160,7 +163,8 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle { return getPlayerPassenger() == session.getPlayerEntity() && session.getPlayerInventory().isHolding(Items.CARROT_ON_A_STICK); } - public void setVariant(EntityMetadata,? extends MetadataType>> holderEntityMetadata) { - // TODO + @Override + protected JavaRegistryKey variantRegistry() { + return JavaRegistries.PIG_VARIANT; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java new file mode 100644 index 000000000..7b675ef98 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 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.animal.farm; + +import net.kyori.adventure.key.Key; +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.entity.type.living.animal.AnimalEntity; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.util.MinecraftKey; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; + +import java.util.Locale; +import java.util.UUID; +import java.util.function.Function; + +public abstract class TemperatureVariantAnimal extends AnimalEntity { + + public TemperatureVariantAnimal(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); + } + + protected abstract JavaRegistryKey variantRegistry(); + + public void setVariant(EntityMetadata, ? extends MetadataType>> variant) { + BuiltInVariant animalVariant; + if (variant.getValue().isId()) { + animalVariant = variantRegistry().fromNetworkId(session, variant.getValue().id()); + if (animalVariant == null) { + animalVariant = BuiltInVariant.TEMPERATE; + } + } else { + animalVariant = BuiltInVariant.TEMPERATE; + } + dirtyMetadata.put(EntityDataTypes.VARIANT, animalVariant.ordinal()); + } + + public enum BuiltInVariant { + COLD, + TEMPERATE, + WARM; + + public static final Function READER = context -> getByJavaIdentifier(context.id()); + + private final Key javaIdentifier; + + BuiltInVariant() { + javaIdentifier = MinecraftKey.key(name().toLowerCase(Locale.ROOT)); + } + + public static @Nullable BuiltInVariant getByJavaIdentifier(Key identifier) { + for (BuiltInVariant variant : values()) { + if (variant.javaIdentifier.equals(identifier)) { + return variant; + } + } + return null; + } + } +} 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 1f0de4444..979da99fb 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 @@ -38,6 +38,7 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.item.GeyserInstrument; @@ -94,6 +95,10 @@ public final class RegistryCache { register("banner_pattern", cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); register("wolf_variant", cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); + register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, TemperatureVariantAnimal.BuiltInVariant.READER); + register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, TemperatureVariantAnimal.BuiltInVariant.READER); + register(JavaRegistries.CHICKEN_VARIANT, cache -> cache.chickenVariants, TemperatureVariantAnimal.BuiltInVariant.READER); + // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); Map> defaults = new HashMap<>(); @@ -134,6 +139,10 @@ public final class RegistryCache { private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); private final JavaRegistry instruments = new SimpleJavaRegistry<>(); + private final JavaRegistry pigVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry cowVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry chickenVariants = new SimpleJavaRegistry<>(); + public RegistryCache(GeyserSession session) { this.session = session; } 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 index 2792589c7..224c60348 100644 --- 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.session.cache.registry; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.item.type.Item; @@ -49,7 +50,10 @@ public class JavaRegistries { 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); - public static final JavaRegistryKey BANNER_PATTERNS = create("banner_pattern", RegistryCache::bannerPatterns); + public static final JavaRegistryKey BANNER_PATTERN = create("banner_pattern", RegistryCache::bannerPatterns); + public static final JavaRegistryKey PIG_VARIANT = create("pig_variant", RegistryCache::pigVariants); + public static final JavaRegistryKey COW_VARIANT = create("cow_variant", RegistryCache::cowVariants); + public static final JavaRegistryKey CHICKEN_VARIANT = create("chicken_variant", RegistryCache::chickenVariants); private static JavaRegistryKey create(String key, JavaRegistryKey.NetworkSerializer networkSerializer, JavaRegistryKey.NetworkDeserializer networkDeserializer) { JavaRegistryKey registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index cf507b793..8ab21e8c4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -60,7 +60,7 @@ import java.util.List; public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { - private static final Tag NO_ITEMS_REQUIRED = new Tag<>(JavaRegistries.BANNER_PATTERNS, Key.key("no_item_required")); + private static final Tag NO_ITEMS_REQUIRED = new Tag<>(JavaRegistries.BANNER_PATTERN, Key.key("no_item_required")); public LoomInventoryTranslator() { super(4, Blocks.LOOM, ContainerType.LOOM, UIInventoryUpdater.INSTANCE); From d19fa2aa956f67a0998caebadb6e295394b5353a Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 22 Mar 2025 09:35:59 +0000 Subject: [PATCH 577/897] Implement data driven cats --- .../geyser/entity/EntityDefinitions.java | 1 + .../animal/farm/TemperatureVariantAnimal.java | 3 + .../living/animal/tameable/CatEntity.java | 56 ++++++++++++++++--- .../geyser/session/cache/RegistryCache.java | 7 ++- .../cache/registry/JavaRegistries.java | 2 + 5 files changed, 60 insertions(+), 9 deletions(-) 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 05024f274..af3aecd18 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -967,6 +967,7 @@ public final class EntityDefinitions { .type(EntityType.COW) .height(1.4f).width(0.9f) .properties(VanillaEntityProperties.CLIMATE_VARIANT) + .addTranslator(MetadataTypes.COW_VARIANT, CowEntity::setVariant) .build(); FOX = EntityDefinition.inherited(FoxEntity::new, ageableEntityBase) .type(EntityType.FOX) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java index 7b675ef98..e6dc63e72 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java @@ -62,9 +62,12 @@ public abstract class TemperatureVariantAnimal extends AnimalEntity { } else { animalVariant = BuiltInVariant.TEMPERATE; } + // TODO does this work? dirtyMetadata.put(EntityDataTypes.VARIANT, animalVariant.ordinal()); } + // Ordered by bedrock id + // TODO: are these ordered correctly? Does the order differ for mobs? public enum BuiltInVariant { COLD, TEMPERATE, 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 fb53c18ed..b5f7ffb19 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; +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.Vector3f; @@ -34,16 +35,21 @@ 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.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; 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.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import java.util.Locale; import java.util.UUID; +import java.util.function.Function; public class CatEntity extends TameableEntity { @@ -81,17 +87,17 @@ public class CatEntity extends TameableEntity { updateCollarColor(); } + // TODO this is a holder when MCPL updates + // TODO also checks if this works public void setCatVariant(IntEntityMetadata entityMetadata) { // Different colors in Java and Bedrock for some reason int metadataValue = entityMetadata.getPrimitiveValue(); - int variantColor = switch (metadataValue) { - case 0 -> 8; - case 8 -> 0; - case 9 -> 10; - case 10 -> 9; - default -> metadataValue; - }; - dirtyMetadata.put(EntityDataTypes.VARIANT, variantColor); + + BuiltInVariant variant = JavaRegistries.CAT_VARIANT.fromNetworkId(session, metadataValue); + if (variant == null) { + variant = BuiltInVariant.BLACK; // Default variant on Java + } + dirtyMetadata.put(EntityDataTypes.VARIANT, variant.ordinal()); } public void setResting(BooleanEntityMetadata entityMetadata) { @@ -138,4 +144,38 @@ public class CatEntity extends TameableEntity { return !canEat(itemInHand) || health >= maxHealth && tamed ? InteractionResult.PASS : InteractionResult.SUCCESS; } } + + // Ordered by bedrock id + // TODO: are these ordered correctly? + // TODO lessen code duplication with other variant mobs + public enum BuiltInVariant { + WHITE, + BLACK, + RED, + SIAMESE, + BRITISH_SHORTHAIR, + CALICO, + PERSIAN, + RAGDOLL, + TABBY, + ALL_BLACK, + JELLIE; + + public static final Function READER = context -> getByJavaIdentifier(context.id()); + + private final Key javaIdentifier; + + BuiltInVariant() { + javaIdentifier = MinecraftKey.key(name().toLowerCase(Locale.ROOT)); + } + + public static @Nullable BuiltInVariant getByJavaIdentifier(Key identifier) { + for (BuiltInVariant variant : values()) { + if (variant.javaIdentifier.equals(identifier)) { + return variant; + } + } + return null; + } + } } 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 979da99fb..49e0d5566 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 @@ -39,6 +39,7 @@ import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; +import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.inventory.item.GeyserInstrument; @@ -95,6 +96,8 @@ public final class RegistryCache { register("banner_pattern", cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); register("wolf_variant", cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); + register(JavaRegistries.CAT_VARIANT, cache -> cache.catVariants, CatEntity.BuiltInVariant.READER); + register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, TemperatureVariantAnimal.BuiltInVariant.READER); register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, TemperatureVariantAnimal.BuiltInVariant.READER); register(JavaRegistries.CHICKEN_VARIANT, cache -> cache.chickenVariants, TemperatureVariantAnimal.BuiltInVariant.READER); @@ -136,9 +139,11 @@ public final class RegistryCache { private final JavaRegistry trimPatterns = new SimpleJavaRegistry<>(); private final JavaRegistry bannerPatterns = new SimpleJavaRegistry<>(); - private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); private final JavaRegistry instruments = new SimpleJavaRegistry<>(); + private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry catVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry pigVariants = new SimpleJavaRegistry<>(); private final JavaRegistry cowVariants = new SimpleJavaRegistry<>(); private final JavaRegistry chickenVariants = new SimpleJavaRegistry<>(); 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 index 224c60348..fd195b38a 100644 --- 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 @@ -28,6 +28,7 @@ package org.geysermc.geyser.session.cache.registry; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; +import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.item.type.Item; @@ -51,6 +52,7 @@ public class JavaRegistries { public static final JavaRegistryKey ITEM = create("item", Registries.JAVA_ITEMS, Item::javaId); public static final JavaRegistryKey ENCHANTMENT = create("enchantment", RegistryCache::enchantments); public static final JavaRegistryKey BANNER_PATTERN = create("banner_pattern", RegistryCache::bannerPatterns); + public static final JavaRegistryKey CAT_VARIANT = create("cat_variant", RegistryCache::catVariants); public static final JavaRegistryKey PIG_VARIANT = create("pig_variant", RegistryCache::pigVariants); public static final JavaRegistryKey COW_VARIANT = create("cow_variant", RegistryCache::cowVariants); public static final JavaRegistryKey CHICKEN_VARIANT = create("chicken_variant", RegistryCache::chickenVariants); From 4ebd048411a7b5ca42da3c163838a0359e7c2446 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 22 Mar 2025 09:44:18 +0000 Subject: [PATCH 578/897] Implement data driven frogs, some refactoring with wolf variants --- .../entity/type/living/animal/FrogEntity.java | 45 ++++++++++++++++--- .../living/animal/tameable/WolfEntity.java | 26 ++++++----- .../geyser/session/cache/RegistryCache.java | 7 ++- .../cache/registry/JavaRegistries.java | 6 +++ 4 files changed, 66 insertions(+), 18 deletions(-) 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 a0b909b75..0826b532d 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -33,14 +34,19 @@ 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.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.Tag; +import org.geysermc.geyser.util.MinecraftKey; 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; +import java.util.Locale; import java.util.OptionalInt; import java.util.UUID; +import java.util.function.Function; public class FrogEntity extends AnimalEntity { public FrogEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -56,13 +62,15 @@ public class FrogEntity extends AnimalEntity { super.setPose(pose); } + // TODO this is a holder when MCPL updates + // TODO also check if this works public void setFrogVariant(IntEntityMetadata entityMetadata) { - int variant = entityMetadata.getPrimitiveValue(); - dirtyMetadata.put(EntityDataTypes.VARIANT, switch (variant) { - case 1 -> 2; // White - case 2 -> 1; // Green - default -> variant; - }); + BuiltInVariant variant = JavaRegistries.FROG_VARIANT.fromNetworkId(session, entityMetadata.getPrimitiveValue()); + if (variant == null) { + variant = BuiltInVariant.TEMPERATE; + } + + dirtyMetadata.put(EntityDataTypes.VARIANT, variant.ordinal()); } public void setTongueTarget(ObjectEntityMetadata entityMetadata) { @@ -82,4 +90,29 @@ public class FrogEntity extends AnimalEntity { protected Tag getFoodTag() { return ItemTag.FROG_FOOD; } + + // Ordered by bedrock id + // TODO: are these ordered correctly? + public enum BuiltInVariant { + TEMPERATE, + COLD, + WARM; + + public static final Function READER = context -> getByJavaIdentifier(context.id()); + + private final Key javaIdentifier; + + BuiltInVariant() { + javaIdentifier = MinecraftKey.key(name().toLowerCase(Locale.ROOT)); + } + + public static @Nullable BuiltInVariant getByJavaIdentifier(Key identifier) { + for (BuiltInVariant variant : values()) { + if (variant.javaIdentifier.equals(identifier)) { + return variant; + } + } + 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 0fb742f71..2e142b72e 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; +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.Vector3f; @@ -39,11 +40,14 @@ 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.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; 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; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -58,6 +62,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.Collections; import java.util.Locale; import java.util.UUID; +import java.util.function.Function; public class WolfEntity extends TameableEntity { private byte collarColor = 14; // Red - default @@ -116,10 +121,11 @@ public class WolfEntity extends TameableEntity { // 1.20.5+ public void setWolfVariant(ObjectEntityMetadata> entityMetadata) { + // TODO set to pale if custom holder? entityMetadata.getValue().ifId(id -> { - BuiltInWolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(id); + BuiltInVariant wolfVariant = JavaRegistries.WOLF_VARIANT.fromNetworkId(session, id); if (wolfVariant == null) { - wolfVariant = BuiltInWolfVariant.PALE; + wolfVariant = BuiltInVariant.PALE; } dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal()); }); @@ -195,7 +201,7 @@ public class WolfEntity extends TameableEntity { } // Ordered by bedrock id - public enum BuiltInWolfVariant { + public enum BuiltInVariant { PALE, ASHEN, BLACK, @@ -206,17 +212,17 @@ public class WolfEntity extends TameableEntity { STRIPED, WOODS; - private static final BuiltInWolfVariant[] VALUES = values(); + public static final Function READER = context -> getByJavaIdentifier(context.id()); - private final String javaIdentifier; + private final Key javaIdentifier; - BuiltInWolfVariant() { - this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT); + BuiltInVariant() { + this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ROOT)); } - public static @Nullable BuiltInWolfVariant getByJavaIdentifier(String javaIdentifier) { - for (BuiltInWolfVariant wolfVariant : VALUES) { - if (wolfVariant.javaIdentifier.equals(javaIdentifier)) { + public static @Nullable BuiltInVariant getByJavaIdentifier(Key identifier) { + for (BuiltInVariant wolfVariant : values()) { + if (wolfVariant.javaIdentifier.equals(identifier)) { return wolfVariant; } } 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 49e0d5566..4fbcbf08d 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 @@ -38,6 +38,7 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.entity.type.living.animal.FrogEntity; import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; @@ -94,9 +95,10 @@ public final class RegistryCache { register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register("banner_pattern", cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); - register("wolf_variant", cache -> cache.wolfVariants, context -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(context.id().asString())); register(JavaRegistries.CAT_VARIANT, cache -> cache.catVariants, CatEntity.BuiltInVariant.READER); + register(JavaRegistries.FROG_VARIANT, cache -> cache.frogVariants, FrogEntity.BuiltInVariant.READER); + register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, WolfEntity.BuiltInVariant.READER); register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, TemperatureVariantAnimal.BuiltInVariant.READER); register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, TemperatureVariantAnimal.BuiltInVariant.READER); @@ -141,8 +143,9 @@ public final class RegistryCache { private final JavaRegistry bannerPatterns = new SimpleJavaRegistry<>(); private final JavaRegistry instruments = new SimpleJavaRegistry<>(); - private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); private final JavaRegistry catVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry frogVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); private final JavaRegistry pigVariants = new SimpleJavaRegistry<>(); private final JavaRegistry cowVariants = new SimpleJavaRegistry<>(); 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 index fd195b38a..732a2cc4a 100644 --- 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 @@ -27,8 +27,10 @@ package org.geysermc.geyser.session.cache.registry; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.entity.type.living.animal.FrogEntity; import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; +import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.item.type.Item; @@ -52,7 +54,11 @@ public class JavaRegistries { public static final JavaRegistryKey ITEM = create("item", Registries.JAVA_ITEMS, Item::javaId); public static final JavaRegistryKey ENCHANTMENT = create("enchantment", RegistryCache::enchantments); public static final JavaRegistryKey BANNER_PATTERN = create("banner_pattern", RegistryCache::bannerPatterns); + public static final JavaRegistryKey CAT_VARIANT = create("cat_variant", RegistryCache::catVariants); + public static final JavaRegistryKey FROG_VARIANT = create("frog_variant", RegistryCache::frogVariants); + public static final JavaRegistryKey WOLF_VARIANT = create("wolf_variant", RegistryCache::wolfVariants); + public static final JavaRegistryKey PIG_VARIANT = create("pig_variant", RegistryCache::pigVariants); public static final JavaRegistryKey COW_VARIANT = create("cow_variant", RegistryCache::cowVariants); public static final JavaRegistryKey CHICKEN_VARIANT = create("chicken_variant", RegistryCache::chickenVariants); From c8c09c9b7dc9b8db484efbf70e72ee7b3083fd8e Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 22 Mar 2025 10:46:14 +0000 Subject: [PATCH 579/897] Work on abstracting entity variants to reduce code duplication --- .../entity/type/living/animal/FrogEntity.java | 51 +++---- .../type/living/animal/VariantHolder.java | 126 ++++++++++++++++++ .../animal/farm/TemperatureVariantAnimal.java | 5 +- .../living/animal/tameable/CatEntity.java | 54 +++----- .../living/animal/tameable/WolfEntity.java | 55 +++----- .../geyser/session/cache/RegistryCache.java | 7 +- 6 files changed, 186 insertions(+), 112 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java 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 0826b532d..d770770f9 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal; -import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -35,20 +34,17 @@ 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.registry.JavaRegistries; -import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.Tag; -import org.geysermc.geyser.util.MinecraftKey; 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; -import java.util.Locale; import java.util.OptionalInt; import java.util.UUID; -import java.util.function.Function; -public class FrogEntity extends AnimalEntity { +// TODO this is implementing VariantHolder until MCPL updates +public class FrogEntity extends AnimalEntity implements VariantHolder { public FrogEntity(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); } @@ -62,15 +58,19 @@ public class FrogEntity extends AnimalEntity { super.setPose(pose); } - // TODO this is a holder when MCPL updates - // TODO also check if this works - public void setFrogVariant(IntEntityMetadata entityMetadata) { - BuiltInVariant variant = JavaRegistries.FROG_VARIANT.fromNetworkId(session, entityMetadata.getPrimitiveValue()); - if (variant == null) { - variant = BuiltInVariant.TEMPERATE; - } + @Override + public JavaRegistryKey variantRegistry() { + return JavaRegistries.FROG_VARIANT; + } - dirtyMetadata.put(EntityDataTypes.VARIANT, variant.ordinal()); + @Override + public void setBedrockVariant(int bedrockId) { + dirtyMetadata.put(EntityDataTypes.VARIANT, bedrockId); + } + + @Override + public BuiltIn defaultVariant() { + return BuiltInVariant.TEMPERATE; } public void setTongueTarget(ObjectEntityMetadata entityMetadata) { @@ -93,26 +93,9 @@ public class FrogEntity extends AnimalEntity { // Ordered by bedrock id // TODO: are these ordered correctly? - public enum BuiltInVariant { + public enum BuiltInVariant implements BuiltIn { TEMPERATE, COLD, - WARM; - - public static final Function READER = context -> getByJavaIdentifier(context.id()); - - private final Key javaIdentifier; - - BuiltInVariant() { - javaIdentifier = MinecraftKey.key(name().toLowerCase(Locale.ROOT)); - } - - public static @Nullable BuiltInVariant getByJavaIdentifier(Key identifier) { - for (BuiltInVariant variant : values()) { - if (variant.javaIdentifier.equals(identifier)) { - return variant; - } - } - return null; - } + WARM } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java new file mode 100644 index 000000000..f337810fc --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2025 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.animal; + +import net.kyori.adventure.key.Key; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.util.MinecraftKey; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; + +import java.util.Locale; +import java.util.function.Function; + +/** + * Utility interface to help set up data-driven entity variants for mobs. + * + *

    This interface is designed for mobs that have their variant wrapped in a {@link Holder}. Implementations usually have to + * implement {@link VariantHolder#variantRegistry()}, {@link VariantHolder#setBedrockVariant(int)}, and {@link VariantHolder#defaultVariant()}, and should also + * have an enum with built-in variants on bedrock (implementing {@link BuiltIn}).

    + * + * @param the MCPL variant class that a {@link Holder} wraps. + */ +public interface VariantHolder { + + default void setVariant(EntityMetadata, ? extends MetadataType>> variant) { + setVariant(variant.getValue()); + } + + /** + * Sets the variant of the entity. Defaults to {@link VariantHolder#defaultVariant()} for custom holders and non-vanilla IDs. + */ + default void setVariant(Holder variant) { + BuiltIn builtInVariant; + if (variant.isId()) { + builtInVariant = variantRegistry().fromNetworkId(getSession(), variant.id()); + if (builtInVariant == null) { + builtInVariant = defaultVariant(); + } + } else { + builtInVariant = defaultVariant(); + } + setBedrockVariant(builtInVariant.ordinal()); + } + + GeyserSession getSession(); + + /** + * The registry in {@link org.geysermc.geyser.session.cache.registry.JavaRegistries} for this mob's variants. The registry can utilise the {@link VariantHolder#reader(Class)} method + * to create a reader to be used in {@link org.geysermc.geyser.session.cache.RegistryCache}. + */ + JavaRegistryKey> variantRegistry(); + + /** + * Should set the variant on bedrock's metadata (or however the variant is set for the mob). The bedrock ID has already been checked and is always valid. + */ + void setBedrockVariant(int bedrockId); + + /** + * Should return the default variant, that is to be used when this mob's variant is a custom or non-vanilla one. + */ + BuiltIn defaultVariant(); + + /** + * Creates a registry reader for this mob's variants. + * + *

    This reader simply matches the identifiers of registry entries with built-in variants. If no built-in variant matches, null is returned.

    + */ + static >> Function reader(Class clazz) { + BuiltInVariant[] variants = clazz.getEnumConstants(); + if (variants == null) { + throw new IllegalArgumentException("Class is not an enum"); + } + return context -> { + for (BuiltInVariant variant : variants) { + if (((BuiltIn) variant).javaIdentifier().equals(context.id())) { + return variant; + } + } + return null; + }; + } + + /** + * Should be implemented on an enum within the entity class. The enum lists vanilla variants that can appear on bedrock, in the order of their bedrock network ID. + * + *

    The enum constants should be named the same as their Java identifiers.

    + * + * @param the same as the parent entity class. Used for type checking. + */ + interface BuiltIn { + + String name(); + + int ordinal(); + + default Key javaIdentifier() { + return MinecraftKey.key(name().toLowerCase(Locale.ROOT)); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java index e6dc63e72..a347ea1ac 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java @@ -31,6 +31,7 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; +import org.geysermc.geyser.entity.type.living.animal.VariantHolder; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; @@ -43,7 +44,7 @@ import java.util.Locale; import java.util.UUID; import java.util.function.Function; -public abstract class TemperatureVariantAnimal extends AnimalEntity { +public abstract class TemperatureVariantAnimal extends AnimalEntity implements VariantHolder { public TemperatureVariantAnimal(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -68,7 +69,7 @@ public abstract class TemperatureVariantAnimal extends AnimalEntity { // Ordered by bedrock id // TODO: are these ordered correctly? Does the order differ for mobs? - public enum BuiltInVariant { + public enum BuiltInVariant implements BuiltIn { COLD, TEMPERATE, WARM; 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 b5f7ffb19..2582a2eb8 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 @@ -25,33 +25,31 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; -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.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.entity.type.living.animal.VariantHolder; 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.registry.JavaRegistries; -import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; 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.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import java.util.Locale; import java.util.UUID; -import java.util.function.Function; -public class CatEntity extends TameableEntity { +// TODO this is implementing VariantHolder until MCPL updates +public class CatEntity extends TameableEntity implements VariantHolder { private byte collarColor = 14; // Red - default @@ -87,17 +85,19 @@ public class CatEntity extends TameableEntity { updateCollarColor(); } - // TODO this is a holder when MCPL updates - // TODO also checks if this works - public void setCatVariant(IntEntityMetadata entityMetadata) { - // Different colors in Java and Bedrock for some reason - int metadataValue = entityMetadata.getPrimitiveValue(); + @Override + public JavaRegistryKey variantRegistry() { + return JavaRegistries.CAT_VARIANT; + } - BuiltInVariant variant = JavaRegistries.CAT_VARIANT.fromNetworkId(session, metadataValue); - if (variant == null) { - variant = BuiltInVariant.BLACK; // Default variant on Java - } - dirtyMetadata.put(EntityDataTypes.VARIANT, variant.ordinal()); + @Override + public void setBedrockVariant(int bedrockId) { + dirtyMetadata.put(EntityDataTypes.VARIANT, bedrockId); + } + + @Override + public BuiltIn defaultVariant() { + return BuiltInVariant.BLACK; // Default variant on Java } public void setResting(BooleanEntityMetadata entityMetadata) { @@ -147,8 +147,7 @@ public class CatEntity extends TameableEntity { // Ordered by bedrock id // TODO: are these ordered correctly? - // TODO lessen code duplication with other variant mobs - public enum BuiltInVariant { + public enum BuiltInVariant implements BuiltIn { WHITE, BLACK, RED, @@ -159,23 +158,6 @@ public class CatEntity extends TameableEntity { RAGDOLL, TABBY, ALL_BLACK, - JELLIE; - - public static final Function READER = context -> getByJavaIdentifier(context.id()); - - private final Key javaIdentifier; - - BuiltInVariant() { - javaIdentifier = MinecraftKey.key(name().toLowerCase(Locale.ROOT)); - } - - public static @Nullable BuiltInVariant getByJavaIdentifier(Key identifier) { - for (BuiltInVariant variant : values()) { - if (variant.javaIdentifier.equals(identifier)) { - return variant; - } - } - return null; - } + JELLIE } } 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 2e142b72e..a5a514a0c 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; -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.Vector3f; @@ -34,6 +33,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.type.living.animal.VariantHolder; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.enchantment.EnchantmentComponent; @@ -41,18 +41,15 @@ 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.registry.JavaRegistries; -import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; 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; -import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; 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.item.ItemStack; @@ -60,11 +57,9 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.Collections; -import java.util.Locale; import java.util.UUID; -import java.util.function.Function; -public class WolfEntity extends TameableEntity { +public class WolfEntity extends TameableEntity implements VariantHolder { private byte collarColor = 14; // Red - default private HolderSet repairableItems = null; private boolean isCurseOfBinding = false; @@ -119,16 +114,19 @@ public class WolfEntity extends TameableEntity { dirtyMetadata.put(EntityDataTypes.COLOR, time != 0 ? (byte) 0 : collarColor); } - // 1.20.5+ - public void setWolfVariant(ObjectEntityMetadata> entityMetadata) { - // TODO set to pale if custom holder? - entityMetadata.getValue().ifId(id -> { - BuiltInVariant wolfVariant = JavaRegistries.WOLF_VARIANT.fromNetworkId(session, id); - if (wolfVariant == null) { - wolfVariant = BuiltInVariant.PALE; - } - dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal()); - }); + @Override + public JavaRegistryKey variantRegistry() { + return JavaRegistries.WOLF_VARIANT; + } + + @Override + public void setBedrockVariant(int bedrockId) { + dirtyMetadata.put(EntityDataTypes.VARIANT, bedrockId); + } + + @Override + public BuiltIn defaultVariant() { + return BuiltInVariant.PALE; } @Override @@ -201,7 +199,7 @@ public class WolfEntity extends TameableEntity { } // Ordered by bedrock id - public enum BuiltInVariant { + public enum BuiltInVariant implements BuiltIn { PALE, ASHEN, BLACK, @@ -210,23 +208,6 @@ public class WolfEntity extends TameableEntity { SNOWY, SPOTTED, STRIPED, - WOODS; - - public static final Function READER = context -> getByJavaIdentifier(context.id()); - - private final Key javaIdentifier; - - BuiltInVariant() { - this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ROOT)); - } - - public static @Nullable BuiltInVariant getByJavaIdentifier(Key identifier) { - for (BuiltInVariant wolfVariant : values()) { - if (wolfVariant.javaIdentifier.equals(identifier)) { - return wolfVariant; - } - } - return null; - } + WOODS } } 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 4fbcbf08d..6ce65c9f3 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 @@ -39,6 +39,7 @@ import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.living.animal.FrogEntity; +import org.geysermc.geyser.entity.type.living.animal.VariantHolder; import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; @@ -96,9 +97,9 @@ public final class RegistryCache { register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register("banner_pattern", cache -> cache.bannerPatterns, context -> BannerPattern.getByJavaIdentifier(context.id())); - register(JavaRegistries.CAT_VARIANT, cache -> cache.catVariants, CatEntity.BuiltInVariant.READER); - register(JavaRegistries.FROG_VARIANT, cache -> cache.frogVariants, FrogEntity.BuiltInVariant.READER); - register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, WolfEntity.BuiltInVariant.READER); + register(JavaRegistries.CAT_VARIANT, cache -> cache.catVariants, VariantHolder.reader(CatEntity.BuiltInVariant.class)); + register(JavaRegistries.FROG_VARIANT, cache -> cache.frogVariants, VariantHolder.reader(FrogEntity.BuiltInVariant.class)); + register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, VariantHolder.reader(WolfEntity.BuiltInVariant.class)); register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, TemperatureVariantAnimal.BuiltInVariant.READER); register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, TemperatureVariantAnimal.BuiltInVariant.READER); From 4c2ac05a53ca74f0c06f546276d97a8c640ebf42 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 22 Mar 2025 11:13:54 +0000 Subject: [PATCH 580/897] Implement VariantHolder for farm animals, still have to figure out how to do this efficiently --- .../geyser/entity/EntityDefinitions.java | 6 +-- .../type/living/animal/MooshroomEntity.java | 1 + .../living/animal/farm/ChickenEntity.java | 3 +- .../type/living/animal/farm/CowEntity.java | 3 +- .../type/living/animal/farm/PigEntity.java | 6 +-- .../animal/farm/TemperatureVariantAnimal.java | 51 ++++--------------- .../geyser/session/cache/RegistryCache.java | 6 +-- 7 files changed, 20 insertions(+), 56 deletions(-) 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 af3aecd18..f725a0a78 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -980,7 +980,7 @@ public final class EntityDefinitions { FROG = EntityDefinition.inherited(FrogEntity::new, ageableEntityBase) .type(EntityType.FROG) .heightAndWidth(0.5f) - .addTranslator(MetadataTypes.FROG_VARIANT, FrogEntity::setFrogVariant) + .addTranslator(MetadataTypes.FROG_VARIANT, FrogEntity::setVariant) .addTranslator(MetadataTypes.OPTIONAL_VARINT, FrogEntity::setTongueTarget) .build(); HOGLIN = EntityDefinition.inherited(HoglinEntity::new, ageableEntityBase) @@ -1151,7 +1151,7 @@ public final class EntityDefinitions { CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase) .type(EntityType.CAT) .height(0.35f).width(0.3f) - .addTranslator(MetadataTypes.CAT_VARIANT, CatEntity::setCatVariant) + .addTranslator(MetadataTypes.CAT_VARIANT, CatEntity::setVariant) .addTranslator(MetadataTypes.BOOLEAN, CatEntity::setResting) .addTranslator(null) // "resting state one" //TODO .addTranslator(MetadataTypes.INT, CatEntity::setCollarColor) @@ -1169,7 +1169,7 @@ public final class EntityDefinitions { .addTranslator(MetadataTypes.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataTypes.INT, WolfEntity::setCollarColor) .addTranslator(MetadataTypes.INT, WolfEntity::setWolfAngerTime) - .addTranslator(MetadataTypes.WOLF_VARIANT, WolfEntity::setWolfVariant) + .addTranslator(MetadataTypes.WOLF_VARIANT, WolfEntity::setVariant) .build(); // As of 1.18 these don't track entity data at all diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 622c599e7..24386d4f6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -49,6 +49,7 @@ public class MooshroomEntity extends CowEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + // TODO fix this with super public void setVariant(ObjectEntityMetadata entityMetadata) { isBrown = entityMetadata.getValue().equals("brown"); dirtyMetadata.put(EntityDataTypes.VARIANT, isBrown ? 1 : 0); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java index afd8a6ce6..da0c2c0fb 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java @@ -30,7 +30,6 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.properties.VanillaEntityProperties; -import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.registry.JavaRegistries; @@ -59,7 +58,7 @@ public class ChickenEntity extends TemperatureVariantAnimal { } @Override - protected JavaRegistryKey variantRegistry() { + public JavaRegistryKey variantRegistry() { return JavaRegistries.CHICKEN_VARIANT; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java index 8f7740f90..8ed9172ed 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java @@ -33,7 +33,6 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.properties.VanillaEntityProperties; -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; @@ -88,7 +87,7 @@ public class CowEntity extends TemperatureVariantAnimal { } @Override - protected JavaRegistryKey variantRegistry() { + public JavaRegistryKey variantRegistry() { return JavaRegistries.COW_VARIANT; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java index 4508a0158..c9dda65a9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java @@ -35,7 +35,6 @@ import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.Tickable; -import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent; import org.geysermc.geyser.entity.vehicle.ClientVehicle; @@ -51,9 +50,6 @@ 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; -import org.geysermc.mcprotocollib.protocol.data.game.Holder; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PigVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -164,7 +160,7 @@ public class PigEntity extends TemperatureVariantAnimal implements T } @Override - protected JavaRegistryKey variantRegistry() { + public JavaRegistryKey variantRegistry() { return JavaRegistries.PIG_VARIANT; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java index a347ea1ac..0f806e0ba 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java @@ -25,25 +25,16 @@ package org.geysermc.geyser.entity.type.living.animal.farm; -import net.kyori.adventure.key.Key; -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.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.entity.type.living.animal.VariantHolder; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; -import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; -import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.Holder; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; -import java.util.Locale; import java.util.UUID; -import java.util.function.Function; +// TODO figure out how to do the generics here public abstract class TemperatureVariantAnimal extends AnimalEntity implements VariantHolder { public TemperatureVariantAnimal(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, @@ -51,20 +42,15 @@ public abstract class TemperatureVariantAnimal extends AnimalEntity imp super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - protected abstract JavaRegistryKey variantRegistry(); - - public void setVariant(EntityMetadata, ? extends MetadataType>> variant) { - BuiltInVariant animalVariant; - if (variant.getValue().isId()) { - animalVariant = variantRegistry().fromNetworkId(session, variant.getValue().id()); - if (animalVariant == null) { - animalVariant = BuiltInVariant.TEMPERATE; - } - } else { - animalVariant = BuiltInVariant.TEMPERATE; - } + @Override + public void setBedrockVariant(int bedrockId) { // TODO does this work? - dirtyMetadata.put(EntityDataTypes.VARIANT, animalVariant.ordinal()); + dirtyMetadata.put(EntityDataTypes.VARIANT, bedrockId); + } + + @Override + public BuiltIn defaultVariant() { + return BuiltInVariant.TEMPERATE; } // Ordered by bedrock id @@ -72,23 +58,6 @@ public abstract class TemperatureVariantAnimal extends AnimalEntity imp public enum BuiltInVariant implements BuiltIn { COLD, TEMPERATE, - WARM; - - public static final Function READER = context -> getByJavaIdentifier(context.id()); - - private final Key javaIdentifier; - - BuiltInVariant() { - javaIdentifier = MinecraftKey.key(name().toLowerCase(Locale.ROOT)); - } - - public static @Nullable BuiltInVariant getByJavaIdentifier(Key identifier) { - for (BuiltInVariant variant : values()) { - if (variant.javaIdentifier.equals(identifier)) { - return variant; - } - } - return null; - } + WARM } } 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 6ce65c9f3..dfbfb071c 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 @@ -101,9 +101,9 @@ public final class RegistryCache { register(JavaRegistries.FROG_VARIANT, cache -> cache.frogVariants, VariantHolder.reader(FrogEntity.BuiltInVariant.class)); register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, VariantHolder.reader(WolfEntity.BuiltInVariant.class)); - register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, TemperatureVariantAnimal.BuiltInVariant.READER); - register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, TemperatureVariantAnimal.BuiltInVariant.READER); - register(JavaRegistries.CHICKEN_VARIANT, cache -> cache.chickenVariants, TemperatureVariantAnimal.BuiltInVariant.READER); + register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, VariantHolder.reader(TemperatureVariantAnimal.BuiltInVariant.class)); + register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, VariantHolder.reader(TemperatureVariantAnimal.BuiltInVariant.class)); + register(JavaRegistries.CHICKEN_VARIANT, cache -> cache.chickenVariants, VariantHolder.reader(TemperatureVariantAnimal.BuiltInVariant.class)); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); From 20863336857001145c29d00b2634381194a0ba60 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 22 Mar 2025 12:28:09 +0000 Subject: [PATCH 581/897] Use entity properties for farm animal variants --- .../entity/type/living/animal/FrogEntity.java | 4 +- .../type/living/animal/VariantHolder.java | 21 ++++---- .../type/living/animal/VariantIntHolder.java | 54 +++++++++++++++++++ .../living/animal/farm/ChickenEntity.java | 8 --- .../type/living/animal/farm/CowEntity.java | 8 --- .../type/living/animal/farm/PigEntity.java | 8 --- .../animal/farm/TemperatureVariantAnimal.java | 24 +++++---- .../living/animal/tameable/CatEntity.java | 6 +-- .../living/animal/tameable/WolfEntity.java | 6 +-- 9 files changed, 87 insertions(+), 52 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantIntHolder.java 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 d770770f9..ef126e8d9 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 @@ -44,7 +44,7 @@ import java.util.OptionalInt; import java.util.UUID; // TODO this is implementing VariantHolder until MCPL updates -public class FrogEntity extends AnimalEntity implements VariantHolder { +public class FrogEntity extends AnimalEntity implements VariantIntHolder { public FrogEntity(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); } @@ -64,7 +64,7 @@ public class FrogEntity extends AnimalEntity implements VariantHolder { } @Override - public void setBedrockVariant(int bedrockId) { + public void setBedrockVariantId(int bedrockId) { dirtyMetadata.put(EntityDataTypes.VARIANT, bedrockId); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java index f337810fc..5f8da630f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java @@ -41,12 +41,13 @@ import java.util.function.Function; * Utility interface to help set up data-driven entity variants for mobs. * *

    This interface is designed for mobs that have their variant wrapped in a {@link Holder}. Implementations usually have to - * implement {@link VariantHolder#variantRegistry()}, {@link VariantHolder#setBedrockVariant(int)}, and {@link VariantHolder#defaultVariant()}, and should also + * implement {@link VariantHolder#variantRegistry()}, {@link VariantHolder#setBedrockVariant(BuiltIn)}, and {@link VariantHolder#defaultVariant()}, and should also * have an enum with built-in variants on bedrock (implementing {@link BuiltIn}).

    * * @param the MCPL variant class that a {@link Holder} wraps. + * @param the enum of Bedrock variants. */ -public interface VariantHolder { +public interface VariantHolder> { default void setVariant(EntityMetadata, ? extends MetadataType>> variant) { setVariant(variant.getValue()); @@ -56,7 +57,7 @@ public interface VariantHolder { * Sets the variant of the entity. Defaults to {@link VariantHolder#defaultVariant()} for custom holders and non-vanilla IDs. */ default void setVariant(Holder variant) { - BuiltIn builtInVariant; + BedrockVariant builtInVariant; if (variant.isId()) { builtInVariant = variantRegistry().fromNetworkId(getSession(), variant.id()); if (builtInVariant == null) { @@ -65,7 +66,7 @@ public interface VariantHolder { } else { builtInVariant = defaultVariant(); } - setBedrockVariant(builtInVariant.ordinal()); + setBedrockVariant(builtInVariant); } GeyserSession getSession(); @@ -74,17 +75,17 @@ public interface VariantHolder { * The registry in {@link org.geysermc.geyser.session.cache.registry.JavaRegistries} for this mob's variants. The registry can utilise the {@link VariantHolder#reader(Class)} method * to create a reader to be used in {@link org.geysermc.geyser.session.cache.RegistryCache}. */ - JavaRegistryKey> variantRegistry(); + JavaRegistryKey variantRegistry(); /** - * Should set the variant on bedrock's metadata (or however the variant is set for the mob). The bedrock ID has already been checked and is always valid. + * Should set the variant for bedrock. */ - void setBedrockVariant(int bedrockId); + void setBedrockVariant(BedrockVariant bedrockVariant); /** * Should return the default variant, that is to be used when this mob's variant is a custom or non-vanilla one. */ - BuiltIn defaultVariant(); + BedrockVariant defaultVariant(); /** * Creates a registry reader for this mob's variants. @@ -107,7 +108,7 @@ public interface VariantHolder { } /** - * Should be implemented on an enum within the entity class. The enum lists vanilla variants that can appear on bedrock, in the order of their bedrock network ID. + * Should be implemented on an enum within the entity class. The enum lists vanilla variants that can appear on bedrock. * *

    The enum constants should be named the same as their Java identifiers.

    * @@ -117,8 +118,6 @@ public interface VariantHolder { String name(); - int ordinal(); - default Key javaIdentifier() { return MinecraftKey.key(name().toLowerCase(Locale.ROOT)); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantIntHolder.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantIntHolder.java new file mode 100644 index 000000000..c2d7bae48 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantIntHolder.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 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.animal; + +/** + * Extension to {@link VariantHolder} to make it easier to implement on mobs that use bedrock's metadata system to set their variants, which are quite common. + * + * @see VariantHolder + */ +public interface VariantIntHolder extends VariantHolder> { + + @Override + default void setBedrockVariant(BuiltIn variant) { + setBedrockVariantId(variant.ordinal()); + } + + /** + * Should set the variant on bedrock's metadata. The bedrock ID has already been checked and is always valid. + */ + void setBedrockVariantId(int bedrockId); + + /** + * The enum constants should be ordered in the order of their bedrock network ID. + * + * @see org.geysermc.geyser.entity.type.living.animal.VariantHolder.BuiltIn + */ + interface BuiltIn extends VariantHolder.BuiltIn { + + int ordinal(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java index da0c2c0fb..d9d26769a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java @@ -27,9 +27,7 @@ package org.geysermc.geyser.entity.type.living.animal.farm; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.registry.JavaRegistries; @@ -45,12 +43,6 @@ public class ChickenEntity extends TemperatureVariantAnimal { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - @Override - public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { - propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); - propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); - } - @Override @Nullable protected Tag getFoodTag() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java index 8ed9172ed..cecf9b017 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java @@ -30,9 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; @@ -53,12 +51,6 @@ public class CowEntity extends TemperatureVariantAnimal { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - @Override - public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { - propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); - propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); - } - @NonNull @Override protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java index c9dda65a9..97ef136f4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java @@ -31,9 +31,7 @@ import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent; @@ -63,12 +61,6 @@ public class PigEntity extends TemperatureVariantAnimal implements T super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - @Override - public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { - propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); - propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); - } - @Override @Nullable protected Tag getFoodTag() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java index 0f806e0ba..f9954a10f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java @@ -26,16 +26,18 @@ package org.geysermc.geyser.entity.type.living.animal.farm; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.entity.type.living.animal.VariantHolder; import org.geysermc.geyser.session.GeyserSession; +import java.util.Locale; import java.util.UUID; // TODO figure out how to do the generics here -public abstract class TemperatureVariantAnimal extends AnimalEntity implements VariantHolder { +public abstract class TemperatureVariantAnimal extends AnimalEntity implements VariantHolder { public TemperatureVariantAnimal(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -43,19 +45,23 @@ public abstract class TemperatureVariantAnimal extends AnimalEntity imp } @Override - public void setBedrockVariant(int bedrockId) { - // TODO does this work? - dirtyMetadata.put(EntityDataTypes.VARIANT, bedrockId); + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); } @Override - public BuiltIn defaultVariant() { + public void setBedrockVariant(BuiltInVariant variant) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, variant.name().toLowerCase(Locale.ROOT)); + updateBedrockEntityProperties(); + } + + @Override + public BuiltInVariant defaultVariant() { return BuiltInVariant.TEMPERATE; } - // Ordered by bedrock id - // TODO: are these ordered correctly? Does the order differ for mobs? - public enum BuiltInVariant implements BuiltIn { + public enum BuiltInVariant implements BuiltIn { COLD, TEMPERATE, WARM 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 2582a2eb8..b7637214d 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 @@ -31,7 +31,7 @@ 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.entity.type.living.animal.VariantHolder; +import org.geysermc.geyser.entity.type.living.animal.VariantIntHolder; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; @@ -49,7 +49,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; // TODO this is implementing VariantHolder until MCPL updates -public class CatEntity extends TameableEntity implements VariantHolder { +public class CatEntity extends TameableEntity implements VariantIntHolder { private byte collarColor = 14; // Red - default @@ -91,7 +91,7 @@ public class CatEntity extends TameableEntity implements VariantHolder { } @Override - public void setBedrockVariant(int bedrockId) { + public void setBedrockVariantId(int bedrockId) { dirtyMetadata.put(EntityDataTypes.VARIANT, bedrockId); } 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 a5a514a0c..a41e46793 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 @@ -33,7 +33,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.entity.type.living.animal.VariantHolder; +import org.geysermc.geyser.entity.type.living.animal.VariantIntHolder; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.enchantment.EnchantmentComponent; @@ -59,7 +59,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.Collections; import java.util.UUID; -public class WolfEntity extends TameableEntity implements VariantHolder { +public class WolfEntity extends TameableEntity implements VariantIntHolder { private byte collarColor = 14; // Red - default private HolderSet repairableItems = null; private boolean isCurseOfBinding = false; @@ -120,7 +120,7 @@ public class WolfEntity extends TameableEntity implements VariantHolder Date: Sat, 22 Mar 2025 12:50:20 +0000 Subject: [PATCH 582/897] "Fix" farm animal variants --- .../type/living/animal/MooshroomEntity.java | 1 - .../type/living/animal/farm/ChickenEntity.java | 13 ++++++++++++- .../type/living/animal/farm/CowEntity.java | 13 ++++++++++++- .../type/living/animal/farm/PigEntity.java | 13 ++++++++++++- .../animal/farm/TemperatureVariantAnimal.java | 16 +++------------- .../geyser/session/cache/RegistryCache.java | 16 +++++++++------- .../session/cache/registry/JavaRegistries.java | 10 ++++++---- 7 files changed, 54 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 24386d4f6..622c599e7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -49,7 +49,6 @@ public class MooshroomEntity extends CowEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - // TODO fix this with super public void setVariant(ObjectEntityMetadata entityMetadata) { isBrown = entityMetadata.getValue().equals("brown"); dirtyMetadata.put(EntityDataTypes.VARIANT, isBrown ? 1 : 0); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java index d9d26769a..e5638dc17 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java @@ -37,7 +37,7 @@ import org.geysermc.geyser.session.cache.tags.Tag; import java.util.UUID; -public class ChickenEntity extends TemperatureVariantAnimal { +public class ChickenEntity extends TemperatureVariantAnimal { public ChickenEntity(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); @@ -53,4 +53,15 @@ public class ChickenEntity extends TemperatureVariantAnimal { public JavaRegistryKey variantRegistry() { return JavaRegistries.CHICKEN_VARIANT; } + + @Override + public BuiltInVariant defaultVariant() { + return BuiltInVariant.TEMPERATE; + } + + public enum BuiltInVariant implements BuiltIn { + COLD, + TEMPERATE, + WARM + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java index cecf9b017..442fb27aa 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java @@ -45,7 +45,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class CowEntity extends TemperatureVariantAnimal { +public class CowEntity extends TemperatureVariantAnimal { public CowEntity(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); @@ -82,4 +82,15 @@ public class CowEntity extends TemperatureVariantAnimal { public JavaRegistryKey variantRegistry() { return JavaRegistries.COW_VARIANT; } + + @Override + public BuiltInVariant defaultVariant() { + return BuiltInVariant.TEMPERATE; + } + + public enum BuiltInVariant implements BuiltIn { + COLD, + TEMPERATE, + WARM + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java index 97ef136f4..bf0416842 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java @@ -54,7 +54,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class PigEntity extends TemperatureVariantAnimal implements Tickable, ClientVehicle { +public class PigEntity extends TemperatureVariantAnimal implements Tickable, ClientVehicle { private final BoostableVehicleComponent vehicleComponent = new BoostableVehicleComponent<>(this, 1.0f); public PigEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -155,4 +155,15 @@ public class PigEntity extends TemperatureVariantAnimal implements T public JavaRegistryKey variantRegistry() { return JavaRegistries.PIG_VARIANT; } + + @Override + public BuiltInVariant defaultVariant() { + return BuiltInVariant.TEMPERATE; + } + + public enum BuiltInVariant implements BuiltIn { + COLD, + TEMPERATE, + WARM + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java index f9954a10f..dd24cd7c6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java @@ -37,7 +37,8 @@ import java.util.Locale; import java.util.UUID; // TODO figure out how to do the generics here -public abstract class TemperatureVariantAnimal extends AnimalEntity implements VariantHolder { +public abstract class TemperatureVariantAnimal> extends AnimalEntity + implements VariantHolder { public TemperatureVariantAnimal(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -51,19 +52,8 @@ public abstract class TemperatureVariantAnimal extends AnimalEntity imp } @Override - public void setBedrockVariant(BuiltInVariant variant) { + public void setBedrockVariant(BedrockVariant variant) { propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, variant.name().toLowerCase(Locale.ROOT)); updateBedrockEntityProperties(); } - - @Override - public BuiltInVariant defaultVariant() { - return BuiltInVariant.TEMPERATE; - } - - public enum BuiltInVariant implements BuiltIn { - COLD, - TEMPERATE, - WARM - } } 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 dfbfb071c..bbc630c04 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,7 +40,9 @@ import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.living.animal.FrogEntity; import org.geysermc.geyser.entity.type.living.animal.VariantHolder; -import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; +import org.geysermc.geyser.entity.type.living.animal.farm.ChickenEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.CowEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.PigEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; @@ -101,9 +103,9 @@ public final class RegistryCache { register(JavaRegistries.FROG_VARIANT, cache -> cache.frogVariants, VariantHolder.reader(FrogEntity.BuiltInVariant.class)); register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, VariantHolder.reader(WolfEntity.BuiltInVariant.class)); - register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, VariantHolder.reader(TemperatureVariantAnimal.BuiltInVariant.class)); - register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, VariantHolder.reader(TemperatureVariantAnimal.BuiltInVariant.class)); - register(JavaRegistries.CHICKEN_VARIANT, cache -> cache.chickenVariants, VariantHolder.reader(TemperatureVariantAnimal.BuiltInVariant.class)); + register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, VariantHolder.reader(PigEntity.BuiltInVariant.class)); + register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, VariantHolder.reader(CowEntity.BuiltInVariant.class)); + register(JavaRegistries.CHICKEN_VARIANT, cache -> cache.chickenVariants, VariantHolder.reader(ChickenEntity.BuiltInVariant.class)); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); @@ -148,9 +150,9 @@ public final class RegistryCache { private final JavaRegistry frogVariants = new SimpleJavaRegistry<>(); private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); - private final JavaRegistry pigVariants = new SimpleJavaRegistry<>(); - private final JavaRegistry cowVariants = new SimpleJavaRegistry<>(); - private final JavaRegistry chickenVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry pigVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry cowVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry chickenVariants = new SimpleJavaRegistry<>(); public RegistryCache(GeyserSession session) { this.session = session; 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 index 732a2cc4a..5ee1ddb9a 100644 --- 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 @@ -28,7 +28,9 @@ package org.geysermc.geyser.session.cache.registry; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.entity.type.living.animal.FrogEntity; -import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; +import org.geysermc.geyser.entity.type.living.animal.farm.ChickenEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.CowEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.PigEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; @@ -59,9 +61,9 @@ public class JavaRegistries { public static final JavaRegistryKey FROG_VARIANT = create("frog_variant", RegistryCache::frogVariants); public static final JavaRegistryKey WOLF_VARIANT = create("wolf_variant", RegistryCache::wolfVariants); - public static final JavaRegistryKey PIG_VARIANT = create("pig_variant", RegistryCache::pigVariants); - public static final JavaRegistryKey COW_VARIANT = create("cow_variant", RegistryCache::cowVariants); - public static final JavaRegistryKey CHICKEN_VARIANT = create("chicken_variant", RegistryCache::chickenVariants); + public static final JavaRegistryKey PIG_VARIANT = create("pig_variant", RegistryCache::pigVariants); + public static final JavaRegistryKey COW_VARIANT = create("cow_variant", RegistryCache::cowVariants); + public static final JavaRegistryKey CHICKEN_VARIANT = create("chicken_variant", RegistryCache::chickenVariants); private static JavaRegistryKey create(String key, JavaRegistryKey.NetworkSerializer networkSerializer, JavaRegistryKey.NetworkDeserializer networkDeserializer) { JavaRegistryKey registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer); From 85f1a607533b9799036e95d76eddd9b4a0a94d2c Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sun, 23 Mar 2025 14:22:15 +0000 Subject: [PATCH 583/897] Changes to variants: - All entity variants in rc1 are sent as int IDs by java, holders are no longer used - Fixed reading of mooshroom variants - Temperature animal variants now look a lot cleaner It builds! --- .../kotlin/geyser.base-conventions.gradle.kts | 2 +- .../geyser/entity/EntityDefinitions.java | 2 +- .../entity/type/living/animal/FrogEntity.java | 7 ++-- .../type/living/animal/MooshroomEntity.java | 8 ++-- .../type/living/animal/VariantHolder.java | 41 ++++++++----------- .../type/living/animal/VariantIntHolder.java | 6 +-- .../living/animal/farm/ChickenEntity.java | 13 +----- .../type/living/animal/farm/CowEntity.java | 13 +----- .../type/living/animal/farm/PigEntity.java | 14 +------ .../animal/farm/TemperatureVariantAnimal.java | 21 ++++++++-- .../living/animal/tameable/CatEntity.java | 7 ++-- .../living/animal/tameable/WolfEntity.java | 7 ++-- .../geyser/session/cache/RegistryCache.java | 16 ++++---- .../cache/registry/JavaRegistries.java | 10 ++--- .../network/ScoreboardIssueTests.java | 2 +- 15 files changed, 67 insertions(+), 102 deletions(-) diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 3f7b48a2f..dca1bcef5 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -26,7 +26,7 @@ dependencies { } repositories { - mavenLocal() + // mavenLocal() mavenCentral() 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 f725a0a78..01206fa8d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -998,7 +998,7 @@ public final class EntityDefinitions { MOOSHROOM = EntityDefinition.inherited(MooshroomEntity::new, ageableEntityBase) .type(EntityType.MOOSHROOM) .height(1.4f).width(0.9f) - .addTranslator(MetadataTypes.STRING, MooshroomEntity::setVariant) + .addTranslator(MetadataTypes.INT, MooshroomEntity::setMooshroomVariant) .build(); OCELOT = EntityDefinition.inherited(OcelotEntity::new, ageableEntityBase) .type(EntityType.OCELOT) 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 ef126e8d9..3b5c28c7d 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 @@ -43,8 +43,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Object import java.util.OptionalInt; import java.util.UUID; -// TODO this is implementing VariantHolder until MCPL updates -public class FrogEntity extends AnimalEntity implements VariantIntHolder { +public class FrogEntity extends AnimalEntity implements VariantIntHolder { public FrogEntity(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); } @@ -69,7 +68,7 @@ public class FrogEntity extends AnimalEntity implements VariantIntHolder } @Override - public BuiltIn defaultVariant() { + public BuiltIn defaultVariant() { return BuiltInVariant.TEMPERATE; } @@ -93,7 +92,7 @@ public class FrogEntity extends AnimalEntity implements VariantIntHolder // Ordered by bedrock id // TODO: are these ordered correctly? - public enum BuiltInVariant implements BuiltIn { + public enum BuiltInVariant implements BuiltIn { TEMPERATE, COLD, WARM diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 622c599e7..3314344cb 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -37,7 +37,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; @@ -49,9 +49,9 @@ public class MooshroomEntity extends CowEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - public void setVariant(ObjectEntityMetadata entityMetadata) { - isBrown = entityMetadata.getValue().equals("brown"); - dirtyMetadata.put(EntityDataTypes.VARIANT, isBrown ? 1 : 0); + public void setMooshroomVariant(IntEntityMetadata metadata) { + isBrown = metadata.getPrimitiveValue() == 1; + dirtyMetadata.put(EntityDataTypes.VARIANT, metadata.getPrimitiveValue()); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java index 5f8da630f..b3390a3ed 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantHolder.java @@ -30,40 +30,35 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.Holder; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import java.util.Locale; import java.util.function.Function; /** - * Utility interface to help set up data-driven entity variants for mobs. + * Interface to help set up data-driven entity variants for mobs. * - *

    This interface is designed for mobs that have their variant wrapped in a {@link Holder}. Implementations usually have to - * implement {@link VariantHolder#variantRegistry()}, {@link VariantHolder#setBedrockVariant(BuiltIn)}, and {@link VariantHolder#defaultVariant()}, and should also + *

    Data-driven variants are sent as an int ID of their variant registry by Java, but can be a metadata ID or entity property on bedrock. + * This interface helps translate data-driven variants to built-in bedrock ones.

    + * + *

    Implementations usually have to implement {@link VariantHolder#variantRegistry()}, + * {@link VariantHolder#setBedrockVariant(BuiltIn)}, and {@link VariantHolder#defaultVariant()}, and should also * have an enum with built-in variants on bedrock (implementing {@link BuiltIn}).

    * - * @param the MCPL variant class that a {@link Holder} wraps. * @param the enum of Bedrock variants. */ -public interface VariantHolder> { +public interface VariantHolder { - default void setVariant(EntityMetadata, ? extends MetadataType>> variant) { - setVariant(variant.getValue()); + default void setVariant(IntEntityMetadata variant) { + setVariantFromJavaId(variant.getPrimitiveValue()); } /** - * Sets the variant of the entity. Defaults to {@link VariantHolder#defaultVariant()} for custom holders and non-vanilla IDs. + * Sets the variant of the entity. Defaults to {@link VariantHolder#defaultVariant()} for non-vanilla IDs. */ - default void setVariant(Holder variant) { - BedrockVariant builtInVariant; - if (variant.isId()) { - builtInVariant = variantRegistry().fromNetworkId(getSession(), variant.id()); - if (builtInVariant == null) { - builtInVariant = defaultVariant(); - } - } else { + default void setVariantFromJavaId(int variant) { + BedrockVariant builtInVariant = variantRegistry().fromNetworkId(getSession(), variant); + if (builtInVariant == null) { builtInVariant = defaultVariant(); } setBedrockVariant(builtInVariant); @@ -92,14 +87,14 @@ public interface VariantHolderThis reader simply matches the identifiers of registry entries with built-in variants. If no built-in variant matches, null is returned.

    */ - static >> Function reader(Class clazz) { + static > Function reader(Class clazz) { BuiltInVariant[] variants = clazz.getEnumConstants(); if (variants == null) { throw new IllegalArgumentException("Class is not an enum"); } return context -> { for (BuiltInVariant variant : variants) { - if (((BuiltIn) variant).javaIdentifier().equals(context.id())) { + if (((BuiltIn) variant).javaIdentifier().equals(context.id())) { return variant; } } @@ -111,10 +106,8 @@ public interface VariantHolderThe enum constants should be named the same as their Java identifiers.

    - * - * @param the same as the parent entity class. Used for type checking. */ - interface BuiltIn { + interface BuiltIn { String name(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantIntHolder.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantIntHolder.java index c2d7bae48..f1d45a447 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantIntHolder.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/VariantIntHolder.java @@ -30,10 +30,10 @@ package org.geysermc.geyser.entity.type.living.animal; * * @see VariantHolder */ -public interface VariantIntHolder extends VariantHolder> { +public interface VariantIntHolder extends VariantHolder { @Override - default void setBedrockVariant(BuiltIn variant) { + default void setBedrockVariant(BuiltIn variant) { setBedrockVariantId(variant.ordinal()); } @@ -47,7 +47,7 @@ public interface VariantIntHolder extends VariantHolder extends VariantHolder.BuiltIn { + interface BuiltIn extends VariantHolder.BuiltIn { int ordinal(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java index e5638dc17..4ee7175de 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/ChickenEntity.java @@ -37,7 +37,7 @@ import org.geysermc.geyser.session.cache.tags.Tag; import java.util.UUID; -public class ChickenEntity extends TemperatureVariantAnimal { +public class ChickenEntity extends TemperatureVariantAnimal { public ChickenEntity(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); @@ -53,15 +53,4 @@ public class ChickenEntity extends TemperatureVariantAnimal variantRegistry() { return JavaRegistries.CHICKEN_VARIANT; } - - @Override - public BuiltInVariant defaultVariant() { - return BuiltInVariant.TEMPERATE; - } - - public enum BuiltInVariant implements BuiltIn { - COLD, - TEMPERATE, - WARM - } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java index 442fb27aa..de79e9a52 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/CowEntity.java @@ -45,7 +45,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class CowEntity extends TemperatureVariantAnimal { +public class CowEntity extends TemperatureVariantAnimal { public CowEntity(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); @@ -82,15 +82,4 @@ public class CowEntity extends TemperatureVariantAnimal variantRegistry() { return JavaRegistries.COW_VARIANT; } - - @Override - public BuiltInVariant defaultVariant() { - return BuiltInVariant.TEMPERATE; - } - - public enum BuiltInVariant implements BuiltIn { - COLD, - TEMPERATE, - WARM - } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java index bf0416842..d6a8ece7c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/PigEntity.java @@ -48,13 +48,12 @@ 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; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PigVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class PigEntity extends TemperatureVariantAnimal implements Tickable, ClientVehicle { +public class PigEntity extends TemperatureVariantAnimal implements Tickable, ClientVehicle { private final BoostableVehicleComponent vehicleComponent = new BoostableVehicleComponent<>(this, 1.0f); public PigEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -155,15 +154,4 @@ public class PigEntity extends TemperatureVariantAnimal variantRegistry() { return JavaRegistries.PIG_VARIANT; } - - @Override - public BuiltInVariant defaultVariant() { - return BuiltInVariant.TEMPERATE; - } - - public enum BuiltInVariant implements BuiltIn { - COLD, - TEMPERATE, - WARM - } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java index dd24cd7c6..ed4336215 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/farm/TemperatureVariantAnimal.java @@ -32,13 +32,15 @@ import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.entity.type.living.animal.VariantHolder; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import java.util.Locale; import java.util.UUID; +import java.util.function.Function; -// TODO figure out how to do the generics here -public abstract class TemperatureVariantAnimal> extends AnimalEntity - implements VariantHolder { +public abstract class TemperatureVariantAnimal extends AnimalEntity implements VariantHolder { + + public static final Function VARIANT_READER = VariantHolder.reader(BuiltInVariant.class); public TemperatureVariantAnimal(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -52,8 +54,19 @@ public abstract class TemperatureVariantAnimal until MCPL updates -public class CatEntity extends TameableEntity implements VariantIntHolder { +public class CatEntity extends TameableEntity implements VariantIntHolder { private byte collarColor = 14; // Red - default @@ -96,7 +95,7 @@ public class CatEntity extends TameableEntity implements VariantIntHolder defaultVariant() { + public BuiltIn defaultVariant() { return BuiltInVariant.BLACK; // Default variant on Java } @@ -147,7 +146,7 @@ public class CatEntity extends TameableEntity implements VariantIntHolder { + public enum BuiltInVariant implements BuiltIn { WHITE, BLACK, RED, 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 a41e46793..753a6e3c4 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 @@ -47,7 +47,6 @@ 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; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; @@ -59,7 +58,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.Collections; import java.util.UUID; -public class WolfEntity extends TameableEntity implements VariantIntHolder { +public class WolfEntity extends TameableEntity implements VariantIntHolder { private byte collarColor = 14; // Red - default private HolderSet repairableItems = null; private boolean isCurseOfBinding = false; @@ -125,7 +124,7 @@ public class WolfEntity extends TameableEntity implements VariantIntHolder defaultVariant() { + public BuiltIn defaultVariant() { return BuiltInVariant.PALE; } @@ -199,7 +198,7 @@ public class WolfEntity extends TameableEntity implements VariantIntHolder { + public enum BuiltInVariant implements BuiltIn { PALE, ASHEN, BLACK, 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 bbc630c04..808ab7ee2 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,9 +40,7 @@ import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.living.animal.FrogEntity; import org.geysermc.geyser.entity.type.living.animal.VariantHolder; -import org.geysermc.geyser.entity.type.living.animal.farm.ChickenEntity; -import org.geysermc.geyser.entity.type.living.animal.farm.CowEntity; -import org.geysermc.geyser.entity.type.living.animal.farm.PigEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; @@ -103,9 +101,9 @@ public final class RegistryCache { register(JavaRegistries.FROG_VARIANT, cache -> cache.frogVariants, VariantHolder.reader(FrogEntity.BuiltInVariant.class)); register(JavaRegistries.WOLF_VARIANT, cache -> cache.wolfVariants, VariantHolder.reader(WolfEntity.BuiltInVariant.class)); - register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, VariantHolder.reader(PigEntity.BuiltInVariant.class)); - register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, VariantHolder.reader(CowEntity.BuiltInVariant.class)); - register(JavaRegistries.CHICKEN_VARIANT, cache -> cache.chickenVariants, VariantHolder.reader(ChickenEntity.BuiltInVariant.class)); + register(JavaRegistries.PIG_VARIANT, cache -> cache.pigVariants, TemperatureVariantAnimal.VARIANT_READER); + register(JavaRegistries.COW_VARIANT, cache -> cache.cowVariants, TemperatureVariantAnimal.VARIANT_READER); + register(JavaRegistries.CHICKEN_VARIANT, cache -> cache.chickenVariants, TemperatureVariantAnimal.VARIANT_READER); // Load from MCProtocolLib's classloader NbtMap tag = MinecraftProtocol.loadNetworkCodec(); @@ -150,9 +148,9 @@ public final class RegistryCache { private final JavaRegistry frogVariants = new SimpleJavaRegistry<>(); private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); - private final JavaRegistry pigVariants = new SimpleJavaRegistry<>(); - private final JavaRegistry cowVariants = new SimpleJavaRegistry<>(); - private final JavaRegistry chickenVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry pigVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry cowVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry chickenVariants = new SimpleJavaRegistry<>(); public RegistryCache(GeyserSession session) { this.session = session; 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 index 5ee1ddb9a..732a2cc4a 100644 --- 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 @@ -28,9 +28,7 @@ package org.geysermc.geyser.session.cache.registry; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.entity.type.living.animal.FrogEntity; -import org.geysermc.geyser.entity.type.living.animal.farm.ChickenEntity; -import org.geysermc.geyser.entity.type.living.animal.farm.CowEntity; -import org.geysermc.geyser.entity.type.living.animal.farm.PigEntity; +import org.geysermc.geyser.entity.type.living.animal.farm.TemperatureVariantAnimal; import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; @@ -61,9 +59,9 @@ public class JavaRegistries { public static final JavaRegistryKey FROG_VARIANT = create("frog_variant", RegistryCache::frogVariants); public static final JavaRegistryKey WOLF_VARIANT = create("wolf_variant", RegistryCache::wolfVariants); - public static final JavaRegistryKey PIG_VARIANT = create("pig_variant", RegistryCache::pigVariants); - public static final JavaRegistryKey COW_VARIANT = create("cow_variant", RegistryCache::cowVariants); - public static final JavaRegistryKey CHICKEN_VARIANT = create("chicken_variant", RegistryCache::chickenVariants); + public static final JavaRegistryKey PIG_VARIANT = create("pig_variant", RegistryCache::pigVariants); + public static final JavaRegistryKey COW_VARIANT = create("cow_variant", RegistryCache::cowVariants); + public static final JavaRegistryKey CHICKEN_VARIANT = create("chicken_variant", RegistryCache::chickenVariants); private static JavaRegistryKey create(String key, JavaRegistryKey.NetworkSerializer networkSerializer, JavaRegistryKey.NetworkDeserializer networkDeserializer) { JavaRegistryKey registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer); 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 040ceaa66..8311f1a5b 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 @@ -52,8 +52,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibilit import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundAddEntityPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityDataPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; import org.junit.jupiter.api.Test; From ae8062c5bc43e3bd6a1556536416e8c7c4eed344 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Tue, 25 Mar 2025 17:23:43 +0100 Subject: [PATCH 584/897] Revert api breaking change --- api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java b/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java index c83fce4c4..b6626aa6a 100644 --- a/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java +++ b/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java @@ -98,7 +98,7 @@ public abstract class PackCodec { * @since 2.1.1 */ @NonNull - public static PathPackCodec path(@NonNull Path path) { + public static PackCodec path(@NonNull Path path) { return GeyserApi.api().provider(PathPackCodec.class, path); } @@ -110,7 +110,7 @@ public abstract class PackCodec { * @since 2.6.2 */ @NonNull - public static UrlPackCodec url(@NonNull String url) { + public static PackCodec url(@NonNull String url) { return GeyserApi.api().provider(UrlPackCodec.class, url); } } From f2ec8d5cee9e7d87f8a3b78f9fb82a183d749221 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Mon, 24 Mar 2025 06:51:30 +0000 Subject: [PATCH 585/897] Random stuff to make it run --- .../geyser/inventory/click/ClickPlan.java | 12 ++- .../DataComponentRegistryPopulator.java | 7 +- .../populator/ItemRegistryPopulator.java | 89 +++++++++++-------- .../geyser/session/GeyserSession.java | 4 +- ...BedrockInventoryTransactionTranslator.java | 9 +- gradle/libs.versions.toml | 2 +- 6 files changed, 76 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index d4344f6e8..4d8af3882 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -41,6 +41,7 @@ import org.geysermc.geyser.util.thirdparty.Fraction; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerActionType; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; import org.geysermc.mcprotocollib.protocol.data.game.inventory.MoveToHotbarAction; +import org.geysermc.mcprotocollib.protocol.data.game.item.HashedStack; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSelectBundleItemPacket; @@ -50,6 +51,8 @@ import org.jetbrains.annotations.Contract; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; +import java.util.Map; +import java.util.Set; public final class ClickPlan { private final List plan = new ArrayList<>(); @@ -157,8 +160,8 @@ public final class ClickPlan { action.slot, action.click.actionType, action.click.action, - clickedItemStack, - changedItems + hashStack(clickedItemStack), + new Int2ObjectOpenHashMap<>() // TODO fixme ); session.sendDownstreamGamePacket(clickPacket); @@ -514,4 +517,9 @@ public final class ClickPlan { private record ClickAction(Click click, int slot, boolean force) { } + + // TODO probably move this + public static HashedStack hashStack(ItemStack stack) { + return stack == null ? null : new HashedStack(stack.getId(), stack.getAmount(), Map.of(), Set.of()); // TODO this is WRONG. figure out stack hashing + } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java index 29d85cdd2..1a247f609 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java @@ -75,8 +75,13 @@ public final class DataComponentRegistryPopulator { byte[] bytes = Base64.getDecoder().decode(encodedValue); ByteBuf buf = Unpooled.wrappedBuffer(bytes); int varInt = MinecraftTypes.readVarInt(buf); - System.out.println("int: " + varInt + " " + componentEntry.getKey()); + //System.out.println("int: " + varInt + " " + componentEntry.getKey()); DataComponentType dataComponentType = DataComponentTypes.from(varInt); + if (dataComponentType == DataComponentTypes.ENCHANTMENTS + || dataComponentType == DataComponentTypes.STORED_ENCHANTMENTS + || dataComponentType == DataComponentTypes.JUKEBOX_PLAYABLE) { + continue; // TODO Broken reading in MCPL + } DataComponent dataComponent = dataComponentType.readDataComponent(buf); map.put(dataComponentType, dataComponent); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 0b8d7f982..6de62ceac 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -112,46 +112,61 @@ public class ItemRegistryPopulator { } public static void populate() { + // 1.21.5 Map itemFallbacks = new HashMap<>(); - itemFallbacks.put(Items.PALE_OAK_PLANKS, Items.BIRCH_PLANKS); - itemFallbacks.put(Items.PALE_OAK_FENCE, Items.BIRCH_FENCE); - itemFallbacks.put(Items.PALE_OAK_FENCE_GATE, Items.BIRCH_FENCE_GATE); - itemFallbacks.put(Items.PALE_OAK_STAIRS, Items.BIRCH_STAIRS); - itemFallbacks.put(Items.PALE_OAK_DOOR, Items.BIRCH_DOOR); - itemFallbacks.put(Items.PALE_OAK_TRAPDOOR, Items.BIRCH_TRAPDOOR); - itemFallbacks.put(Items.PALE_OAK_SLAB, Items.BIRCH_SLAB); - itemFallbacks.put(Items.PALE_OAK_LOG, Items.BIRCH_LOG); - itemFallbacks.put(Items.STRIPPED_PALE_OAK_LOG, Items.STRIPPED_BIRCH_LOG); - itemFallbacks.put(Items.PALE_OAK_WOOD, Items.BIRCH_WOOD); - itemFallbacks.put(Items.PALE_OAK_LEAVES, Items.BIRCH_LEAVES); - itemFallbacks.put(Items.PALE_OAK_SAPLING, Items.BIRCH_SAPLING); - itemFallbacks.put(Items.STRIPPED_PALE_OAK_WOOD, Items.STRIPPED_BIRCH_WOOD); - itemFallbacks.put(Items.PALE_OAK_SIGN, Items.BIRCH_SIGN); - itemFallbacks.put(Items.PALE_OAK_HANGING_SIGN, Items.BIRCH_HANGING_SIGN); - itemFallbacks.put(Items.PALE_OAK_BOAT, Items.BIRCH_BOAT); - itemFallbacks.put(Items.PALE_OAK_CHEST_BOAT, Items.BIRCH_CHEST_BOAT); - itemFallbacks.put(Items.PALE_OAK_BUTTON, Items.BIRCH_BUTTON); - itemFallbacks.put(Items.PALE_OAK_PRESSURE_PLATE, Items.BIRCH_PRESSURE_PLATE); - itemFallbacks.put(Items.RESIN_CLUMP, Items.RAW_COPPER); - itemFallbacks.put(Items.RESIN_BRICK_WALL, Items.RED_SANDSTONE_WALL); - itemFallbacks.put(Items.RESIN_BRICK_STAIRS, Items.RED_SANDSTONE_STAIRS); - itemFallbacks.put(Items.RESIN_BRICK_SLAB, Items.RED_SANDSTONE_SLAB); - itemFallbacks.put(Items.RESIN_BLOCK, Items.RED_SANDSTONE); - itemFallbacks.put(Items.RESIN_BRICK, Items.BRICK); - itemFallbacks.put(Items.RESIN_BRICKS, Items.CUT_RED_SANDSTONE); - itemFallbacks.put(Items.CHISELED_RESIN_BRICKS, Items.CHISELED_RED_SANDSTONE); - itemFallbacks.put(Items.CLOSED_EYEBLOSSOM, Items.WHITE_TULIP); - itemFallbacks.put(Items.OPEN_EYEBLOSSOM, Items.OXEYE_DAISY); - itemFallbacks.put(Items.PALE_MOSS_BLOCK, Items.MOSS_BLOCK); - itemFallbacks.put(Items.PALE_MOSS_CARPET, Items.MOSS_CARPET); - itemFallbacks.put(Items.PALE_HANGING_MOSS, Items.HANGING_ROOTS); - itemFallbacks.put(Items.CREAKING_HEART, Items.CHISELED_POLISHED_BLACKSTONE); - itemFallbacks.put(Items.CREAKING_SPAWN_EGG, Items.HOGLIN_SPAWN_EGG); + itemFallbacks.put(Items.BUSH, Items.SHORT_GRASS); + itemFallbacks.put(Items.CACTUS_FLOWER, Items.BUBBLE_CORAL_FAN); + itemFallbacks.put(Items.FIREFLY_BUSH, Items.SHORT_GRASS); + itemFallbacks.put(Items.LEAF_LITTER, Items.PINK_PETALS); + itemFallbacks.put(Items.SHORT_DRY_GRASS, Items.DEAD_BUSH); + itemFallbacks.put(Items.TALL_DRY_GRASS, Items.TALL_GRASS); + itemFallbacks.put(Items.WILDFLOWERS, Items.PINK_PETALS); + itemFallbacks.put(Items.TEST_BLOCK, Items.STRUCTURE_BLOCK); + itemFallbacks.put(Items.TEST_INSTANCE_BLOCK, Items.JIGSAW); + itemFallbacks.put(Items.BLUE_EGG, Items.EGG); + itemFallbacks.put(Items.BROWN_EGG, Items.EGG); + + // 1.21.4 + Map oneTwentyFourFallbacks = new HashMap<>(itemFallbacks); + oneTwentyFourFallbacks.put(Items.PALE_OAK_PLANKS, Items.BIRCH_PLANKS); + oneTwentyFourFallbacks.put(Items.PALE_OAK_FENCE, Items.BIRCH_FENCE); + oneTwentyFourFallbacks.put(Items.PALE_OAK_FENCE_GATE, Items.BIRCH_FENCE_GATE); + oneTwentyFourFallbacks.put(Items.PALE_OAK_STAIRS, Items.BIRCH_STAIRS); + oneTwentyFourFallbacks.put(Items.PALE_OAK_DOOR, Items.BIRCH_DOOR); + oneTwentyFourFallbacks.put(Items.PALE_OAK_TRAPDOOR, Items.BIRCH_TRAPDOOR); + oneTwentyFourFallbacks.put(Items.PALE_OAK_SLAB, Items.BIRCH_SLAB); + oneTwentyFourFallbacks.put(Items.PALE_OAK_LOG, Items.BIRCH_LOG); + oneTwentyFourFallbacks.put(Items.STRIPPED_PALE_OAK_LOG, Items.STRIPPED_BIRCH_LOG); + oneTwentyFourFallbacks.put(Items.PALE_OAK_WOOD, Items.BIRCH_WOOD); + oneTwentyFourFallbacks.put(Items.PALE_OAK_LEAVES, Items.BIRCH_LEAVES); + oneTwentyFourFallbacks.put(Items.PALE_OAK_SAPLING, Items.BIRCH_SAPLING); + oneTwentyFourFallbacks.put(Items.STRIPPED_PALE_OAK_WOOD, Items.STRIPPED_BIRCH_WOOD); + oneTwentyFourFallbacks.put(Items.PALE_OAK_SIGN, Items.BIRCH_SIGN); + oneTwentyFourFallbacks.put(Items.PALE_OAK_HANGING_SIGN, Items.BIRCH_HANGING_SIGN); + oneTwentyFourFallbacks.put(Items.PALE_OAK_BOAT, Items.BIRCH_BOAT); + oneTwentyFourFallbacks.put(Items.PALE_OAK_CHEST_BOAT, Items.BIRCH_CHEST_BOAT); + oneTwentyFourFallbacks.put(Items.PALE_OAK_BUTTON, Items.BIRCH_BUTTON); + oneTwentyFourFallbacks.put(Items.PALE_OAK_PRESSURE_PLATE, Items.BIRCH_PRESSURE_PLATE); + oneTwentyFourFallbacks.put(Items.RESIN_CLUMP, Items.RAW_COPPER); + oneTwentyFourFallbacks.put(Items.RESIN_BRICK_WALL, Items.RED_SANDSTONE_WALL); + oneTwentyFourFallbacks.put(Items.RESIN_BRICK_STAIRS, Items.RED_SANDSTONE_STAIRS); + oneTwentyFourFallbacks.put(Items.RESIN_BRICK_SLAB, Items.RED_SANDSTONE_SLAB); + oneTwentyFourFallbacks.put(Items.RESIN_BLOCK, Items.RED_SANDSTONE); + oneTwentyFourFallbacks.put(Items.RESIN_BRICK, Items.BRICK); + oneTwentyFourFallbacks.put(Items.RESIN_BRICKS, Items.CUT_RED_SANDSTONE); + oneTwentyFourFallbacks.put(Items.CHISELED_RESIN_BRICKS, Items.CHISELED_RED_SANDSTONE); + oneTwentyFourFallbacks.put(Items.CLOSED_EYEBLOSSOM, Items.WHITE_TULIP); + oneTwentyFourFallbacks.put(Items.OPEN_EYEBLOSSOM, Items.OXEYE_DAISY); + oneTwentyFourFallbacks.put(Items.PALE_MOSS_BLOCK, Items.MOSS_BLOCK); + oneTwentyFourFallbacks.put(Items.PALE_MOSS_CARPET, Items.MOSS_CARPET); + oneTwentyFourFallbacks.put(Items.PALE_HANGING_MOSS, Items.HANGING_ROOTS); + oneTwentyFourFallbacks.put(Items.CREAKING_HEART, Items.CHISELED_POLISHED_BLACKSTONE); + oneTwentyFourFallbacks.put(Items.CREAKING_SPAWN_EGG, Items.HOGLIN_SPAWN_EGG); List paletteVersions = new ArrayList<>(2); - paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping)); - paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v766.CODEC.getProtocolVersion())); - paletteVersions.add(new PaletteVersion("1_21_60", Bedrock_v776.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), oneTwentyFourFallbacks, (item, mapping) -> mapping)); + paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v766.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping)); + paletteVersions.add(new PaletteVersion("1_21_60", Bedrock_v776.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping)); paletteVersions.add(new PaletteVersion("1_21_70", Bedrock_v786.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); 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 c1ca49af4..6ce811356 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1443,14 +1443,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * Sends a chat message to the Java server. */ public void sendChat(String message) { - sendDownstreamGamePacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, null, 0, new BitSet())); + sendDownstreamGamePacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, null, 0, new BitSet(), 0)); } /** * Sends a command to the Java server. */ public void sendCommand(String command) { - sendDownstreamGamePacket(new ServerboundChatCommandSignedPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet())); + sendDownstreamGamePacket(new ServerboundChatCommandSignedPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet(), (byte) 0)); } public void setClientRenderDistance(int clientRenderDistance) { 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 d3e2ba5df..404e213a7 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 @@ -52,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.click.ClickPlan; import org.geysermc.geyser.inventory.item.GeyserInstrument; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.BlockItem; @@ -84,7 +85,7 @@ 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.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.HashedStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.InstrumentComponent; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; @@ -132,7 +133,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator changedItem; + Int2ObjectMap changedItem; if (dropAll) { inventory.setItem(hotbarSlot, GeyserItemStack.EMPTY, session); changedItem = Int2ObjectMaps.singleton(hotbarSlot, null); @@ -142,11 +143,11 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator Date: Mon, 24 Mar 2025 08:35:29 +0000 Subject: [PATCH 586/897] Work on hashing components using their vanilla codecs Whoops remove this Pretty big refactor, looks a lot cleaner now More components hashing Hashers with registry access and more stuff Hasher helpers, NBT hashers Some hasher method renames Something something component hashing --- .../geyser/item/hashing/ComponentHashers.java | 115 +++++++++ .../geyser/item/hashing/MapHasher.java | 81 +++++++ .../item/hashing/MinecraftHashEncoder.java | 221 ++++++++++++++++++ .../geyser/item/hashing/MinecraftHasher.java | 108 +++++++++ .../cache/registry/JavaRegistries.java | 9 +- .../cache/registry/JavaRegistryKey.java | 16 +- 6 files changed, 546 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java create mode 100644 core/src/main/java/org/geysermc/geyser/item/hashing/MapHasher.java create mode 100644 core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHashEncoder.java create mode 100644 core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java new file mode 100644 index 000000000..9afcb1170 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025 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.item.hashing; + +import com.google.common.hash.HashCode; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.CustomModelData; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.FoodProperties; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.IntComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.TooltipDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.function.UnaryOperator; + +@SuppressWarnings("UnstableApiUsage") +public class ComponentHashers { + private static final Map, MinecraftHasher> hashers = new HashMap<>(); + + static { + register(DataComponentTypes.CUSTOM_DATA, hasher -> hasher.nbtMap(Function.identity())); + register(DataComponentTypes.MAX_STACK_SIZE); + register(DataComponentTypes.MAX_DAMAGE); + register(DataComponentTypes.DAMAGE); + register(DataComponentTypes.UNBREAKABLE); + + // TODO custom name, component + // TODO item name, component + + register(DataComponentTypes.ITEM_MODEL, MinecraftHasher.KEY); + + // TODO lore, component + + register(DataComponentTypes.RARITY, MinecraftHasher.RARITY); + register(DataComponentTypes.ENCHANTMENTS, MinecraftHasher.map(MinecraftHasher.ENCHANTMENT, MinecraftHasher.INT).convert(ItemEnchantments::getEnchantments)); + + // TODO can place on/can break on, complicated + // TODO attribute modifiers, attribute registry and equipment slot group hashers + + registerMap(DataComponentTypes.CUSTOM_MODEL_DATA, builder -> builder + .optionalList("floats", MinecraftHasher.FLOAT, CustomModelData::floats) + .optionalList("flags", MinecraftHasher.BOOL, CustomModelData::flags) + .optionalList("strings", MinecraftHasher.STRING, CustomModelData::strings) + .optionalList("colors", MinecraftHasher.INT, CustomModelData::colors)); + + registerMap(DataComponentTypes.TOOLTIP_DISPLAY, builder -> builder + .optional("hide_tooltip", MinecraftHasher.BOOL, TooltipDisplay::hideTooltip, false) + .optionalList("hidden_components", MinecraftHasher.DATA_COMPONENT_TYPE, TooltipDisplay::hiddenComponents)); + + register(DataComponentTypes.REPAIR_COST); + + register(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, MinecraftHasher.BOOL); + register(DataComponentTypes.INTANGIBLE_PROJECTILE); // TODO MCPL is wrong + + registerMap(DataComponentTypes.FOOD, builder -> builder + .accept("nutrition", MinecraftHasher.INT, FoodProperties::getNutrition) + .accept("saturation", MinecraftHasher.FLOAT, FoodProperties::getSaturationModifier) + .optional("can_always_eat", MinecraftHasher.BOOL, FoodProperties::isCanAlwaysEat, false)); + } + + private static void register(DataComponentType component) { + register(component, MinecraftHasher.UNIT); + } + + private static void register(IntComponentType component) { + register(component, MinecraftHasher.INT); + } + + private static void registerMap(DataComponentType component, UnaryOperator> builder) { + register(component, MinecraftHasher.mapBuilder(builder)); + } + + private static void register(DataComponentType component, MinecraftHasher hasher) { + if (hashers.containsKey(component)) { + throw new IllegalArgumentException("Tried to register a hasher for a component twice"); + } + hashers.put(component, hasher); + } + + public static HashCode hash(GeyserSession session, DataComponentType component, T value) { + MinecraftHasher hasher = (MinecraftHasher) hashers.get(component); + if (hasher == null) { + throw new IllegalStateException("Unregistered hasher for component " + component + "!"); + } + return hasher.hash(value, new MinecraftHashEncoder(session)); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MapHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MapHasher.java new file mode 100644 index 000000000..bea4e216e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MapHasher.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 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.item.hashing; + +import com.google.common.hash.HashCode; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Predicate; + +@SuppressWarnings("UnstableApiUsage") +public class MapHasher { + private final MinecraftHashEncoder encoder; + private final T object; + private final Map map; + + MapHasher(T object, MinecraftHashEncoder encoder) { + this.encoder = encoder; + this.object = object; + map = new HashMap<>(); + } + + public MapHasher accept(String key, HashCode hash) { + map.put(encoder.string(key), hash); + return this; + } + + public MapHasher accept(String key, MinecraftHasher hasher, Function extractor) { + return accept(key, hasher.hash(extractor.apply(object), encoder)); + } + + public MapHasher optional(String key, MinecraftHasher hasher, Function extractor, V defaultValue) { + V value = extractor.apply(object); + if (!value.equals(defaultValue)) { + accept(key, hasher.hash(value, encoder)); + } + return this; + } + + public MapHasher acceptList(String key, MinecraftHasher valueHasher, Function> extractor) { + return accept(key, valueHasher.list().hash(extractor.apply(object), encoder)); + } + + public MapHasher optionalList(String key, MinecraftHasher valueHasher, Function> extractor) { + List list = extractor.apply(object); + if (!list.isEmpty()) { + accept(key, valueHasher.list().hash(list, encoder)); + } + return this; + } + + public HashCode build() { + return encoder.map(map); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHashEncoder.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHashEncoder.java new file mode 100644 index 000000000..3697b7c3e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHashEncoder.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2025 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.item.hashing; + +import com.google.common.hash.HashCode; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +// Based off the HashOps in mojmap, hashes a component, TODO: documentation +@SuppressWarnings("UnstableApiUsage") +public class MinecraftHashEncoder { + private static final byte TAG_EMPTY = 1; + private static final byte TAG_MAP_START = 2; + private static final byte TAG_MAP_END = 3; + private static final byte TAG_LIST_START = 4; + private static final byte TAG_LIST_END = 5; + private static final byte TAG_BYTE = 6; + private static final byte TAG_SHORT = 7; + private static final byte TAG_INT = 8; + private static final byte TAG_LONG = 9; + private static final byte TAG_FLOAT = 10; + private static final byte TAG_DOUBLE = 11; + private static final byte TAG_STRING = 12; + private static final byte TAG_BOOLEAN = 13; + private static final byte TAG_BYTE_ARRAY_START = 14; + private static final byte TAG_BYTE_ARRAY_END = 15; + private static final byte TAG_INT_ARRAY_START = 16; + private static final byte TAG_INT_ARRAY_END = 17; + private static final byte TAG_LONG_ARRAY_START = 18; + private static final byte TAG_LONG_ARRAY_END = 19; + + private static final Comparator HASH_COMPARATOR = Comparator.comparingLong(HashCode::padToLong); + private static final Comparator> MAP_ENTRY_ORDER = Map.Entry.comparingByKey(HASH_COMPARATOR) + .thenComparing(Map.Entry.comparingByValue(HASH_COMPARATOR)); + + private static final byte[] EMPTY = new byte[]{TAG_EMPTY}; + private static final byte[] FALSE = new byte[]{TAG_BOOLEAN, 0}; + private static final byte[] TRUE = new byte[]{TAG_BOOLEAN, 1}; + + private final HashFunction hasher; + private final GeyserSession session; + + private final HashCode empty; + private final HashCode falseHash; + private final HashCode trueHash; + + public MinecraftHashEncoder(GeyserSession session) { + hasher = Hashing.crc32(); + this.session = session; + + empty = hasher.hashBytes(EMPTY); + falseHash = hasher.hashBytes(FALSE); + trueHash = hasher.hashBytes(TRUE); + } + + public GeyserSession session() { + return session; + } + + public HashCode empty() { + return empty; + } + + public HashCode number(Number number) { + if (number instanceof Byte b) { + return hasher.newHasher(2).putByte(TAG_BYTE).putByte(b).hash(); + } else if (number instanceof Short s) { + return hasher.newHasher(3).putByte(TAG_SHORT).putShort(s).hash(); + } else if (number instanceof Integer i) { + return hasher.newHasher(5).putByte(TAG_INT).putInt(i).hash(); + } else if (number instanceof Long l) { + return hasher.newHasher(9).putByte(TAG_LONG).putLong(l).hash(); + } else if (number instanceof Float f) { + return hasher.newHasher(5).putByte(TAG_FLOAT).putFloat(f).hash(); + } + + return hasher.newHasher(9).putByte(TAG_DOUBLE).putDouble(number.doubleValue()).hash(); + } + + public HashCode string(String string) { + return hasher.newHasher().putByte(TAG_STRING).putInt(string.length()).putUnencodedChars(string).hash(); + } + + public HashCode bool(boolean b) { + return b ? trueHash : falseHash; + } + + public HashCode map(Map map) { + Hasher mapHasher = hasher.newHasher(); + mapHasher.putByte(TAG_MAP_START); + map.entrySet().stream() + .sorted(MAP_ENTRY_ORDER) + .forEach(entry -> mapHasher.putBytes(entry.getKey().asBytes()).putBytes(entry.getValue().asBytes())); + mapHasher.putByte(TAG_MAP_END); + return mapHasher.hash(); + } + + public HashCode nbtMap(NbtMap map) { + Map hashed = new HashMap<>(); + for (String key : map.keySet()) { + HashCode hashedKey = string(key); + Object value = map.get(key); + if (value instanceof NbtList list) { + hashed.put(hashedKey, nbtList(list)); + } else { + map.listenForNumber(key, n -> hashed.put(hashedKey, number(n))); + map.listenForString(key, s -> hashed.put(hashedKey, string(s))); + map.listenForBoolean(key, b -> hashed.put(hashedKey, bool(b))); + map.listenForCompound(key, compound -> hashed.put(hashedKey, nbtMap(compound))); + + map.listenForByteArray(key, bytes -> hashed.put(hashedKey, byteArray(bytes))); + map.listenForIntArray(key, ints -> hashed.put(hashedKey, intArray(ints))); + map.listenForLongArray(key, longs -> hashed.put(hashedKey, longArray(longs))); + } + } + return map(hashed); + } + + public HashCode list(List list) { + Hasher listHasher = hasher.newHasher(); + listHasher.putByte(TAG_LIST_START); + list.forEach(hash -> listHasher.putBytes(hash.asBytes())); + listHasher.putByte(TAG_LIST_END); + return listHasher.hash(); + } + + // TODO can this be written better? + @SuppressWarnings("unchecked") + public HashCode nbtList(NbtList nbtList) { + NbtType type = nbtList.getType(); + List hashed = new ArrayList<>(); + + if (type == NbtType.BYTE) { + hashed.addAll(((List) nbtList).stream().map(this::number).toList()); + } else if (type == NbtType.SHORT) { + hashed.addAll(((List) nbtList).stream().map(this::number).toList()); + } else if (type == NbtType.INT) { + hashed.addAll(((List) nbtList).stream().map(this::number).toList()); + } else if (type == NbtType.LONG) { + hashed.addAll(((List) nbtList).stream().map(this::number).toList()); + } else if (type == NbtType.FLOAT) { + hashed.addAll(((List) nbtList).stream().map(this::number).toList()); + } else if (type == NbtType.DOUBLE) { + hashed.addAll(((List) nbtList).stream().map(this::number).toList()); + } else if (type == NbtType.STRING) { + hashed.addAll(((List) nbtList).stream().map(this::string).toList()); + } else if (type == NbtType.LIST) { + for (NbtList list : (List>) nbtList) { + hashed.add(nbtList(list)); + } + } else if (type == NbtType.COMPOUND) { + for (NbtMap compound : (List) nbtList) { + hashed.add(nbtMap(compound)); + } + } + + return list(hashed); + } + + public HashCode byteArray(byte[] bytes) { + Hasher arrayHasher = hasher.newHasher(); + arrayHasher.putByte(TAG_BYTE_ARRAY_START); + arrayHasher.putBytes(bytes); + arrayHasher.putByte(TAG_BYTE_ARRAY_END); + return arrayHasher.hash(); + } + + public HashCode intArray(int[] ints) { + Hasher arrayHasher = hasher.newHasher(); + arrayHasher.putByte(TAG_INT_ARRAY_START); + for (int i : ints) { + arrayHasher.putInt(i); + } + arrayHasher.putByte(TAG_INT_ARRAY_END); + return arrayHasher.hash(); + } + + public HashCode longArray(long[] longs) { + Hasher arrayHasher = hasher.newHasher(); + arrayHasher.putByte(TAG_LONG_ARRAY_START); + for (long l : longs) { + arrayHasher.putLong(l); + } + arrayHasher.putByte(TAG_LONG_ARRAY_END); + return arrayHasher.hash(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java new file mode 100644 index 000000000..98573824b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025 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.item.hashing; + +import com.google.common.hash.HashCode; +import net.kyori.adventure.key.Key; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.item.components.Rarity; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; + +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; + +@SuppressWarnings("UnstableApiUsage") +@FunctionalInterface +public interface MinecraftHasher { + + MinecraftHasher UNIT = (unit, encoder) -> encoder.empty(); + + MinecraftHasher BYTE = (b, encoder) -> encoder.number(b); + + MinecraftHasher SHORT = (s, encoder) -> encoder.number(s); + + MinecraftHasher INT = (i, encoder) -> encoder.number(i); + + MinecraftHasher LONG = (l, encoder) -> encoder.number(l); + + MinecraftHasher FLOAT = (f, encoder) -> encoder.number(f); + + MinecraftHasher DOUBLE = (d, encoder) -> encoder.number(d); + + MinecraftHasher STRING = (s, encoder) -> encoder.string(s); + + MinecraftHasher BOOL = (b, encoder) -> encoder.bool(b); + + MinecraftHasher NBT_MAP = (map, encoder) -> encoder.nbtMap(map); + + MinecraftHasher KEY = STRING.convert(Key::asString); + + MinecraftHasher RARITY = fromIdEnum(Rarity.values(), Rarity::getName); + + MinecraftHasher ENCHANTMENT = registry(JavaRegistries.ENCHANTMENT); + + MinecraftHasher> DATA_COMPONENT_TYPE = KEY.convert(DataComponentType::getKey); + + HashCode hash(T value, MinecraftHashEncoder encoder); + + default MinecraftHasher> list() { + return (list, encoder) -> encoder.list(list.stream().map(element -> hash(element, encoder)).toList()); + } + + default MinecraftHasher convert(Function converter) { + return (object, encoder) -> hash(converter.apply(object), encoder); + } + + default MinecraftHasher sessionConvert(BiFunction converter) { + return (object, encoder) -> hash(converter.apply(encoder.session(), object), encoder); + } + + static > MinecraftHasher fromIdEnum(T[] values, Function toName) { + return STRING.convert(id -> toName.apply(values[id])); + } + + static MinecraftHasher registry(JavaRegistryKey registry) { + return KEY.sessionConvert(registry::keyFromNetworkId); + } + + static MinecraftHasher mapBuilder(UnaryOperator> builder) { + return (object, encoder) -> builder.apply(new MapHasher<>(object, encoder)).build(); + } + + static MinecraftHasher> map(MinecraftHasher keyHasher, MinecraftHasher valueHasher) { + return (map, encoder) -> encoder.map(map.entrySet().stream() + .map(entry -> Map.entry(keyHasher.hash(entry.getKey(), encoder), valueHasher.hash(entry.getValue(), encoder))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + } +} 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 index 732a2cc4a..fe7f55b85 100644 --- 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 @@ -63,8 +63,9 @@ public class JavaRegistries { public static final JavaRegistryKey COW_VARIANT = create("cow_variant", RegistryCache::cowVariants); public static final JavaRegistryKey CHICKEN_VARIANT = create("chicken_variant", RegistryCache::chickenVariants); - private static JavaRegistryKey create(String key, JavaRegistryKey.NetworkSerializer networkSerializer, JavaRegistryKey.NetworkDeserializer networkDeserializer) { - JavaRegistryKey registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer); + private static JavaRegistryKey create(String key, JavaRegistryKey.NetworkSerializer networkSerializer, JavaRegistryKey.NetworkDeserializer networkDeserializer, + JavaRegistryKey.NetworkIdentifier networkIdentifier) { + JavaRegistryKey registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer, networkIdentifier); VALUES.add(registry); return registry; } @@ -74,7 +75,9 @@ public class JavaRegistries { } 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)); + return create(key, (session, object) -> getter.get(session.getRegistryCache()).byValue(object), + (session, id) -> getter.get(session.getRegistryCache()).byId(id), + (session, id) -> getter.get(session.getRegistryCache()).entryById(id).key()); } @Nullable 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 index 364d998ee..b5b40f606 100644 --- 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 @@ -29,6 +29,7 @@ import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.session.GeyserSession; +// TODO describe usage in component hashers in documentation /** * 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. @@ -40,9 +41,11 @@ import org.geysermc.geyser.session.GeyserSession; * @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 networkIdentifier a method that converts a network ID to its respective key in this registry. * @param the object type this registry holds. */ -public record JavaRegistryKey(Key registryKey, @Nullable NetworkSerializer networkSerializer, @Nullable NetworkDeserializer networkDeserializer) { +public record JavaRegistryKey(Key registryKey, @Nullable NetworkSerializer networkSerializer, @Nullable NetworkDeserializer networkDeserializer, + NetworkIdentifier networkIdentifier) { /** * Converts an object in this registry to its network ID. This will fail if this registry doesn't have a network serializer. @@ -64,6 +67,11 @@ public record JavaRegistryKey(Key registryKey, @Nullable NetworkSerializer return networkDeserializer.fromNetworkId(session, networkId); } + // TODO document + public Key keyFromNetworkId(GeyserSession session, int networkId) { + return networkIdentifier.keyFromNetworkId(session, networkId); + } + /** * @return true if this registry has a network serializer and deserializer. */ @@ -82,4 +90,10 @@ public record JavaRegistryKey(Key registryKey, @Nullable NetworkSerializer T fromNetworkId(GeyserSession session, int networkId); } + + @FunctionalInterface + public interface NetworkIdentifier { + + Key keyFromNetworkId(GeyserSession session, int networkId); + } } From 37f18d515d6a5396adae58fb1d7d3d5d4275b24e Mon Sep 17 00:00:00 2001 From: Eclipse Date: Mon, 24 Mar 2025 19:36:01 +0000 Subject: [PATCH 587/897] Some small refactors and a bunch of component hashers --- .../geyser/item/hashing/ComponentHashers.java | 30 ++++++- .../geyser/item/hashing/MapHasher.java | 17 +++- .../geyser/item/hashing/MinecraftHasher.java | 19 +++-- .../geyser/item/hashing/RegistryHasher.java | 78 +++++++++++++++++++ .../org/geysermc/geyser/item/type/Item.java | 5 ++ .../cache/registry/JavaRegistries.java | 16 +++- 6 files changed, 148 insertions(+), 17 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java index 9afcb1170..04ec5fece 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java @@ -27,14 +27,18 @@ package org.geysermc.geyser.item.hashing; import com.google.common.hash.HashCode; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.CustomModelData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.FoodProperties; import org.geysermc.mcprotocollib.protocol.data.game.item.component.IntComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.TooltipDisplay; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseCooldown; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; import java.util.HashMap; import java.util.Map; @@ -46,7 +50,7 @@ public class ComponentHashers { private static final Map, MinecraftHasher> hashers = new HashMap<>(); static { - register(DataComponentTypes.CUSTOM_DATA, hasher -> hasher.nbtMap(Function.identity())); + register(DataComponentTypes.CUSTOM_DATA, MinecraftHasher.NBT_MAP); register(DataComponentTypes.MAX_STACK_SIZE); register(DataComponentTypes.MAX_DAMAGE); register(DataComponentTypes.DAMAGE); @@ -60,7 +64,7 @@ public class ComponentHashers { // TODO lore, component register(DataComponentTypes.RARITY, MinecraftHasher.RARITY); - register(DataComponentTypes.ENCHANTMENTS, MinecraftHasher.map(MinecraftHasher.ENCHANTMENT, MinecraftHasher.INT).convert(ItemEnchantments::getEnchantments)); + register(DataComponentTypes.ENCHANTMENTS, MinecraftHasher.map(RegistryHasher.ENCHANTMENT, MinecraftHasher.INT).convert(ItemEnchantments::getEnchantments)); // TODO can place on/can break on, complicated // TODO attribute modifiers, attribute registry and equipment slot group hashers @@ -73,17 +77,35 @@ public class ComponentHashers { registerMap(DataComponentTypes.TOOLTIP_DISPLAY, builder -> builder .optional("hide_tooltip", MinecraftHasher.BOOL, TooltipDisplay::hideTooltip, false) - .optionalList("hidden_components", MinecraftHasher.DATA_COMPONENT_TYPE, TooltipDisplay::hiddenComponents)); + .optionalList("hidden_components", RegistryHasher.DATA_COMPONENT_TYPE, TooltipDisplay::hiddenComponents)); register(DataComponentTypes.REPAIR_COST); register(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, MinecraftHasher.BOOL); - register(DataComponentTypes.INTANGIBLE_PROJECTILE); // TODO MCPL is wrong + //register(DataComponentTypes.INTANGIBLE_PROJECTILE); // TODO MCPL is wrong registerMap(DataComponentTypes.FOOD, builder -> builder .accept("nutrition", MinecraftHasher.INT, FoodProperties::getNutrition) .accept("saturation", MinecraftHasher.FLOAT, FoodProperties::getSaturationModifier) .optional("can_always_eat", MinecraftHasher.BOOL, FoodProperties::isCanAlwaysEat, false)); + registerMap(DataComponentTypes.CONSUMABLE, builder -> builder + .optional("consume_seconds", MinecraftHasher.FLOAT, Consumable::consumeSeconds, 1.6F) + .optional("animation", MinecraftHasher.ITEM_USE_ANIMATION, Consumable::animation, Consumable.ItemUseAnimation.EAT) + .optional("sound", RegistryHasher.SOUND_EVENT, Consumable::sound, BuiltinSound.ENTITY_GENERIC_EAT) + .optional("has_consume_particles", MinecraftHasher.BOOL, Consumable::hasConsumeParticles, true)); // TODO consume effect needs identifier in MCPL + + // TODO use remainder needs item stack codec, recursion go brr + + registerMap(DataComponentTypes.USE_COOLDOWN, builder -> builder + .accept("seconds", MinecraftHasher.FLOAT, UseCooldown::seconds) + .optionalNullable("cooldown_group", MinecraftHasher.KEY, UseCooldown::cooldownGroup)); + registerMap(DataComponentTypes.DAMAGE_RESISTANT, builder -> builder + .accept("types", MinecraftHasher.TAG, Function.identity())); + registerMap(DataComponentTypes.TOOL, builder -> builder + .accept("rules", MinecraftHasher.TOOL_RULE.list(), ToolData::getRules) + .optional("default_mining_speed", MinecraftHasher.FLOAT, ToolData::getDefaultMiningSpeed, 1.0F) + .optional("damage_per_block", MinecraftHasher.INT, ToolData::getDamagePerBlock, 1) + .optional("can_destroy_blocks_in_creative", MinecraftHasher.BOOL, ToolData::isCanDestroyBlocksInCreative, true)); } private static void register(DataComponentType component) { diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MapHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MapHasher.java index bea4e216e..112b603f9 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/MapHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MapHasher.java @@ -30,9 +30,8 @@ import com.google.common.hash.HashCode; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; +import java.util.Optional; import java.util.function.Function; -import java.util.function.Predicate; @SuppressWarnings("UnstableApiUsage") public class MapHasher { @@ -55,6 +54,20 @@ public class MapHasher { return accept(key, hasher.hash(extractor.apply(object), encoder)); } + public MapHasher optionalNullable(String key, MinecraftHasher hasher, Function extractor) { + V value = extractor.apply(object); + if (value != null) { + accept(key, hasher.hash(value, encoder)); + } + return this; + } + + public MapHasher optional(String key, MinecraftHasher hasher, Function> extractor) { + Optional value = extractor.apply(object); + value.ifPresent(v -> accept(key, hasher.hash(v, encoder))); + return this; + } + public MapHasher optional(String key, MinecraftHasher hasher, Function extractor, V defaultValue) { V value = extractor.apply(object); if (!value.equals(defaultValue)) { diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java index 98573824b..53ae6b8ce 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java @@ -30,9 +30,8 @@ import net.kyori.adventure.key.Key; import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.registry.JavaRegistries; -import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; import java.util.List; @@ -68,11 +67,16 @@ public interface MinecraftHasher { MinecraftHasher KEY = STRING.convert(Key::asString); + MinecraftHasher TAG = STRING.convert(key -> "#" + key.asString()); + MinecraftHasher RARITY = fromIdEnum(Rarity.values(), Rarity::getName); - MinecraftHasher ENCHANTMENT = registry(JavaRegistries.ENCHANTMENT); + MinecraftHasher ITEM_USE_ANIMATION = fromEnum(); - MinecraftHasher> DATA_COMPONENT_TYPE = KEY.convert(DataComponentType::getKey); + MinecraftHasher TOOL_RULE = mapBuilder(builder -> builder + .accept("blocks", RegistryHasher.BLOCK.holderSet(), ToolData.Rule::getBlocks) + .optionalNullable("speed", MinecraftHasher.FLOAT, ToolData.Rule::getSpeed) + .optionalNullable("correct_for_drops", MinecraftHasher.BOOL, ToolData.Rule::getCorrectForDrops)); HashCode hash(T value, MinecraftHashEncoder encoder); @@ -92,8 +96,9 @@ public interface MinecraftHasher { return STRING.convert(id -> toName.apply(values[id])); } - static MinecraftHasher registry(JavaRegistryKey registry) { - return KEY.sessionConvert(registry::keyFromNetworkId); + // TODO: note that this only works correctly if enum constants are named appropriately + static > MinecraftHasher fromEnum() { + return STRING.convert(Enum::name); } static MinecraftHasher mapBuilder(UnaryOperator> builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java new file mode 100644 index 000000000..09948a9f1 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 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.item.hashing; + +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; +import org.geysermc.geyser.util.MinecraftKey; +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.level.sound.BuiltinSound; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.CustomSound; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; + +import java.util.Arrays; + +public interface RegistryHasher extends MinecraftHasher { + + RegistryHasher BLOCK = registry(JavaRegistries.BLOCK); + + RegistryHasher ENCHANTMENT = registry(JavaRegistries.ENCHANTMENT); + + MinecraftHasher> DATA_COMPONENT_TYPE = KEY.convert(DataComponentType::getKey); + + MinecraftHasher BUILTIN_SOUND = KEY.convert(sound -> MinecraftKey.key(sound.getName())); + + MinecraftHasher CUSTOM_SOUND = MinecraftHasher.mapBuilder(builder -> builder + .accept("sound_id", KEY, sound -> MinecraftKey.key(sound.getName())) + .optional("range", FLOAT, CustomSound::getRange, 16.0F)); + + MinecraftHasher SOUND_EVENT = (sound, encoder) -> { + if (sound instanceof BuiltinSound builtin) { + return BUILTIN_SOUND.hash(builtin, encoder); + } + return CUSTOM_SOUND.hash((CustomSound) sound, encoder); + }; + + static RegistryHasher registry(JavaRegistryKey registry) { + MinecraftHasher hasher = KEY.sessionConvert(registry::keyFromNetworkId); + return hasher::hash; + } + + default MinecraftHasher holderSet() { + return (holder, encoder) -> { + if (holder.getLocation() != null) { + return TAG.hash(holder.getLocation(), encoder); + } else if (holder.getHolders() != null) { + if (holder.getHolders().length == 1) { + return hash(holder.getHolders()[0], encoder); + } + return list().hash(Arrays.stream(holder.getHolders()).boxed().toList(), encoder); + } + throw new IllegalStateException("HolderSet must have either tag location or holders"); + }; + } +} 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 9919aa308..013aaab65 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 @@ -75,10 +75,15 @@ public class Item { this.attackDamage = builder.attackDamage; } + // TODO maybe deprecate? public String javaIdentifier() { return javaIdentifier.asString(); } + public Key javaKey() { + return javaIdentifier; + } + public int javaId() { return javaId; } 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 index fe7f55b85..0a50f63b8 100644 --- 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 @@ -47,11 +47,12 @@ 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. */ +// TODO for component hashing, elements should never be null (looking at you, animal variants) 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 BLOCK = create("block", BlockRegistries.JAVA_BLOCKS, Block::javaId, Block::javaIdentifier); + public static final JavaRegistryKey ITEM = create("item", Registries.JAVA_ITEMS, Item::javaId, Item::javaKey); public static final JavaRegistryKey ENCHANTMENT = create("enchantment", RegistryCache::enchantments); public static final JavaRegistryKey BANNER_PATTERN = create("banner_pattern", RegistryCache::bannerPatterns); @@ -70,8 +71,9 @@ public class JavaRegistries { 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, ListRegistry registry, RegistryNetworkMapper networkSerializer, RegistryIdentifierMapper identifierMapper) { + return create(key, (session, object) -> networkSerializer.get(object), + (session, id) -> registry.get(id), (session, id) -> identifierMapper.get(registry.get(id))); } private static JavaRegistryKey create(String key, RegistryGetter getter) { @@ -101,4 +103,10 @@ public class JavaRegistries { int get(T object); } + + @FunctionalInterface + interface RegistryIdentifierMapper { + + Key get(T object); + } } From 51cc5eb41a202ac38477c1e0279a0409a6b1827e Mon Sep 17 00:00:00 2001 From: Eclipse Date: Mon, 24 Mar 2025 21:15:59 +0000 Subject: [PATCH 588/897] Some fixes, and actually test everything --- .../geyser/item/hashing/ComponentHashers.java | 75 +++++++++++++++++++ .../item/hashing/MinecraftHashEncoder.java | 10 ++- .../geyser/item/hashing/MinecraftHasher.java | 2 +- .../player/JavaPlayerPositionTranslator.java | 3 + 4 files changed, 87 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java index 04ec5fece..fd6b012af 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java @@ -26,12 +26,20 @@ package org.geysermc.geyser.item.hashing; import com.google.common.hash.HashCode; +import net.kyori.adventure.key.Key; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.item.components.Rarity; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.CustomModelData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.FoodProperties; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.IntComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; @@ -41,6 +49,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseCooldown; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -134,4 +143,70 @@ public class ComponentHashers { } return hasher.hash(value, new MinecraftHashEncoder(session)); } + + public static void testHashing(GeyserSession session) { + // Hashed values generated by vanilla Java + + NbtMap customData = NbtMap.builder() + .putString("hello", "g'day") + .putBoolean("nice?", false) + .putByte("coolness", (byte) 100) + .putCompound("geyser", NbtMap.builder() + .putString("is", "very cool") + .build()) + .putList("a list", NbtType.LIST, List.of(new NbtList<>(NbtType.STRING, "in a list"))) + .build(); + + testHash(session, DataComponentTypes.CUSTOM_DATA, customData, -385053299); + + testHash(session, DataComponentTypes.MAX_STACK_SIZE, 64, 733160003); + testHash(session, DataComponentTypes.MAX_DAMAGE, 13, -801733367); + testHash(session, DataComponentTypes.DAMAGE, 459, 1211405277); + testHash(session, DataComponentTypes.UNBREAKABLE, Unit.INSTANCE, -982207288); + + testHash(session, DataComponentTypes.ITEM_MODEL, MinecraftKey.key("testing"), -689946239); + + testHash(session, DataComponentTypes.RARITY, Rarity.COMMON.ordinal(), 75150990); + testHash(session, DataComponentTypes.RARITY, Rarity.RARE.ordinal(), -1420566726); + testHash(session, DataComponentTypes.RARITY, Rarity.EPIC.ordinal(), -292715907); + + testHash(session, DataComponentTypes.ENCHANTMENTS, new ItemEnchantments(Map.of( + 0, 1 + ), false), 0); // TODO identifier lookup + + testHash(session, DataComponentTypes.CUSTOM_MODEL_DATA, + new CustomModelData(List.of(5.0F, 3.0F, -1.0F), List.of(false, true, false), List.of("1", "3", "2"), List.of(3424, -123, 345)), 1947635619); + + testHash(session, DataComponentTypes.CUSTOM_MODEL_DATA, + new CustomModelData(List.of(5.03F, 3.0F, -1.11F), List.of(true, true, false), List.of("2", "5", "7"), List.of()), -512419908); + + testHash(session, DataComponentTypes.TOOLTIP_DISPLAY, new TooltipDisplay(false, List.of(DataComponentTypes.CONSUMABLE, DataComponentTypes.DAMAGE)), -816418453); + testHash(session, DataComponentTypes.TOOLTIP_DISPLAY, new TooltipDisplay(true, List.of()), 14016722); + testHash(session, DataComponentTypes.TOOLTIP_DISPLAY, new TooltipDisplay(false, List.of()), -982207288); + + testHash(session, DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, true, -1019818302); + testHash(session, DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, false, 828198337); + + testHash(session, DataComponentTypes.FOOD, new FoodProperties(5, 1.4F, false), 445786378); + testHash(session, DataComponentTypes.FOOD, new FoodProperties(3, 5.7F, true), 1917653498); + testHash(session, DataComponentTypes.FOOD, new FoodProperties(7, 0.15F, false), -184166204); + + testHash(session, DataComponentTypes.DAMAGE_RESISTANT, Key.key("testing"), -1230493835); + + testHash(session, DataComponentTypes.TOOL, new ToolData(List.of(), 5.0F, 3, false), -1789071928); + testHash(session, DataComponentTypes.TOOL, new ToolData(List.of(), 3.0F, 1, true), -7422944); + testHash(session, DataComponentTypes.TOOL, new ToolData(List.of( + new ToolData.Rule(new HolderSet(Key.key("acacia_logs")), null, null), + new ToolData.Rule(new HolderSet(new int[]{Blocks.JACK_O_LANTERN.javaId(), Blocks.WALL_TORCH.javaId()}), 4.2F, true), + new ToolData.Rule(new HolderSet(new int[]{Blocks.PUMPKIN.javaId()}), 7.0F, false)), + 1.0F, 1, true), 2103678261); + + // Chunk errors are spamming logs and I don't need to log in anyway + session.disconnect("AAAAAA"); + } + + private static void testHash(GeyserSession session, DataComponentType component, T value, int expected) { + int got = hash(session, component, value).asInt(); + System.out.println("Testing hashing component " + component.getKey() + ", expected " + expected + ", got " + got + " " + (got == expected ? "PASS" : "ERROR")); + } } diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHashEncoder.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHashEncoder.java index 3697b7c3e..ab8ca435a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHashEncoder.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHashEncoder.java @@ -68,6 +68,7 @@ public class MinecraftHashEncoder { .thenComparing(Map.Entry.comparingByValue(HASH_COMPARATOR)); private static final byte[] EMPTY = new byte[]{TAG_EMPTY}; + public static final byte[] EMPTY_MAP = new byte[]{TAG_MAP_START, TAG_MAP_END}; private static final byte[] FALSE = new byte[]{TAG_BOOLEAN, 0}; private static final byte[] TRUE = new byte[]{TAG_BOOLEAN, 1}; @@ -75,14 +76,16 @@ public class MinecraftHashEncoder { private final GeyserSession session; private final HashCode empty; + private final HashCode emptyMap; private final HashCode falseHash; private final HashCode trueHash; public MinecraftHashEncoder(GeyserSession session) { - hasher = Hashing.crc32(); + hasher = Hashing.crc32c(); this.session = session; empty = hasher.hashBytes(EMPTY); + emptyMap = hasher.hashBytes(EMPTY_MAP); falseHash = hasher.hashBytes(FALSE); trueHash = hasher.hashBytes(TRUE); } @@ -95,6 +98,10 @@ public class MinecraftHashEncoder { return empty; } + public HashCode emptyMap() { + return emptyMap; + } + public HashCode number(Number number) { if (number instanceof Byte b) { return hasher.newHasher(2).putByte(TAG_BYTE).putByte(b).hash(); @@ -139,7 +146,6 @@ public class MinecraftHashEncoder { } else { map.listenForNumber(key, n -> hashed.put(hashedKey, number(n))); map.listenForString(key, s -> hashed.put(hashedKey, string(s))); - map.listenForBoolean(key, b -> hashed.put(hashedKey, bool(b))); map.listenForCompound(key, compound -> hashed.put(hashedKey, nbtMap(compound))); map.listenForByteArray(key, bytes -> hashed.put(hashedKey, byteArray(bytes))); diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java index 53ae6b8ce..61feaa4ef 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java @@ -45,7 +45,7 @@ import java.util.stream.Collectors; @FunctionalInterface public interface MinecraftHasher { - MinecraftHasher UNIT = (unit, encoder) -> encoder.empty(); + MinecraftHasher UNIT = (unit, encoder) -> encoder.emptyMap(); MinecraftHasher BYTE = (b, encoder) -> encoder.number(b); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java index d56c5d2d3..7ad560974 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java @@ -32,6 +32,7 @@ import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.RespawnPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.item.hashing.ComponentHashers; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.TeleportCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -83,6 +84,8 @@ public class JavaPlayerPositionTranslator extends PacketTranslator Date: Mon, 24 Mar 2025 22:53:20 +0000 Subject: [PATCH 589/897] A whole bunch more components and tests --- .../geyser/item/hashing/ComponentHashers.java | 98 ++++++++++++++++++- .../geyser/item/hashing/MinecraftHasher.java | 14 ++- .../geyser/item/hashing/RegistryHasher.java | 20 ++++ 3 files changed, 127 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java index fd6b012af..ca2b17c19 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java @@ -26,26 +26,35 @@ package org.geysermc.geyser.item.hashing; import com.google.common.hash.HashCode; -import net.kyori.adventure.key.Key; import org.cloudburstmc.nbt.NbtList; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.inventory.item.Potion; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.MinecraftKey; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; +import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.CustomModelData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Equippable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.FoodProperties; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.IntComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectDetails; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.TooltipDisplay; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseCooldown; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Weapon; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; import java.util.HashMap; @@ -111,10 +120,50 @@ public class ComponentHashers { registerMap(DataComponentTypes.DAMAGE_RESISTANT, builder -> builder .accept("types", MinecraftHasher.TAG, Function.identity())); registerMap(DataComponentTypes.TOOL, builder -> builder - .accept("rules", MinecraftHasher.TOOL_RULE.list(), ToolData::getRules) + .acceptList("rules", MinecraftHasher.TOOL_RULE, ToolData::getRules) .optional("default_mining_speed", MinecraftHasher.FLOAT, ToolData::getDefaultMiningSpeed, 1.0F) .optional("damage_per_block", MinecraftHasher.INT, ToolData::getDamagePerBlock, 1) .optional("can_destroy_blocks_in_creative", MinecraftHasher.BOOL, ToolData::isCanDestroyBlocksInCreative, true)); + registerMap(DataComponentTypes.WEAPON, builder -> builder + .optional("item_damage_per_attack", MinecraftHasher.INT, Weapon::itemDamagePerAttack, 1) + .optional("disable_blocking_for_seconds", MinecraftHasher.FLOAT, Weapon::disableBlockingForSeconds, 0.0F)); + registerMap(DataComponentTypes.ENCHANTABLE, builder -> builder + .accept("value", MinecraftHasher.INT, Function.identity())); + registerMap(DataComponentTypes.EQUIPPABLE, builder -> builder + .accept("slot", MinecraftHasher.EQUIPMENT_SLOT, Equippable::slot) + .optional("equip_sound", RegistryHasher.SOUND_EVENT, Equippable::equipSound, BuiltinSound.ITEM_ARMOR_EQUIP_GENERIC) + .optionalNullable("asset_id", MinecraftHasher.KEY, Equippable::model) + .optionalNullable("camera_overlay", MinecraftHasher.KEY, Equippable::cameraOverlay) + .optionalNullable("allowed_entities", RegistryHasher.ENTITY_TYPE.holderSet(), Equippable::allowedEntities) + .optional("dispensable", MinecraftHasher.BOOL, Equippable::dispensable, true) + .optional("swappable", MinecraftHasher.BOOL, Equippable::swappable, true) + .optional("damage_on_hurt", MinecraftHasher.BOOL, Equippable::damageOnHurt, true) + .optional("equip_on_interact", MinecraftHasher.BOOL, Equippable::equipOnInteract, false)); + registerMap(DataComponentTypes.REPAIRABLE, builder -> builder + .accept("items", RegistryHasher.ITEM.holderSet(), Function.identity())); + + register(DataComponentTypes.GLIDER); + register(DataComponentTypes.TOOLTIP_STYLE, MinecraftHasher.KEY); + + registerMap(DataComponentTypes.DEATH_PROTECTION, builder -> builder); // TODO consume effect needs identifier in MCPL + registerMap(DataComponentTypes.BLOCKS_ATTACKS, builder -> builder); // TODO needs damage types, add a way to cache identifiers without reading objects in registrycache + register(DataComponentTypes.STORED_ENCHANTMENTS, MinecraftHasher.map(RegistryHasher.ENCHANTMENT, MinecraftHasher.INT).convert(ItemEnchantments::getEnchantments)); // TODO duplicate code? + + register(DataComponentTypes.DYED_COLOR); + register(DataComponentTypes.MAP_COLOR); + register(DataComponentTypes.MAP_ID); + register(DataComponentTypes.MAP_DECORATIONS, MinecraftHasher.NBT_MAP); + + // TODO charged projectiles also need the recursionâ„¢ + // TODO same for bundle contents + + registerMap(DataComponentTypes.POTION_CONTENTS, builder -> builder + .optional("potion", RegistryHasher.POTION, PotionContents::getPotionId, -1) + .optional("custom_color", MinecraftHasher.INT, PotionContents::getCustomColor, -1) + .optionalList("custom_effects", MinecraftHasher.MOB_EFFECT_INSTANCE, PotionContents::getCustomEffects) + .optionalNullable("custom_name", MinecraftHasher.STRING, PotionContents::getCustomName)); + + register(DataComponentTypes.POTION_DURATION_SCALE, MinecraftHasher.FLOAT); } private static void register(DataComponentType component) { @@ -191,16 +240,57 @@ public class ComponentHashers { testHash(session, DataComponentTypes.FOOD, new FoodProperties(3, 5.7F, true), 1917653498); testHash(session, DataComponentTypes.FOOD, new FoodProperties(7, 0.15F, false), -184166204); - testHash(session, DataComponentTypes.DAMAGE_RESISTANT, Key.key("testing"), -1230493835); + testHash(session, DataComponentTypes.DAMAGE_RESISTANT, MinecraftKey.key("testing"), -1230493835); testHash(session, DataComponentTypes.TOOL, new ToolData(List.of(), 5.0F, 3, false), -1789071928); testHash(session, DataComponentTypes.TOOL, new ToolData(List.of(), 3.0F, 1, true), -7422944); testHash(session, DataComponentTypes.TOOL, new ToolData(List.of( - new ToolData.Rule(new HolderSet(Key.key("acacia_logs")), null, null), + new ToolData.Rule(new HolderSet(MinecraftKey.key("acacia_logs")), null, null), new ToolData.Rule(new HolderSet(new int[]{Blocks.JACK_O_LANTERN.javaId(), Blocks.WALL_TORCH.javaId()}), 4.2F, true), new ToolData.Rule(new HolderSet(new int[]{Blocks.PUMPKIN.javaId()}), 7.0F, false)), 1.0F, 1, true), 2103678261); + testHash(session, DataComponentTypes.WEAPON, new Weapon(5, 2.0F), -154556976); + testHash(session, DataComponentTypes.WEAPON, new Weapon(1, 7.3F), 885347995); + + testHash(session, DataComponentTypes.ENCHANTABLE, 3, -1834983819); + + testHash(session, DataComponentTypes.EQUIPPABLE, new Equippable(EquipmentSlot.BODY, BuiltinSound.ITEM_ARMOR_EQUIP_GENERIC, null, null, null, + true, true, true, false), 1294431019); + testHash(session, DataComponentTypes.EQUIPPABLE, new Equippable(EquipmentSlot.BODY, BuiltinSound.ITEM_ARMOR_EQUIP_CHAIN, MinecraftKey.key("testing"), null, null, + true, true, true, false), 1226203061); + testHash(session, DataComponentTypes.EQUIPPABLE, new Equippable(EquipmentSlot.BODY, BuiltinSound.AMBIENT_CAVE, null, null, null, + false, true, false, false), 1416408052); + testHash(session, DataComponentTypes.EQUIPPABLE, new Equippable(EquipmentSlot.BODY, BuiltinSound.ENTITY_BREEZE_WIND_BURST, null, MinecraftKey.key("testing"), + new HolderSet(new int[]{EntityType.ACACIA_BOAT.ordinal()}), false, true, false, false), 1711275245); + + testHash(session, DataComponentTypes.EQUIPPABLE, new Equippable(EquipmentSlot.HELMET, BuiltinSound.ITEM_ARMOR_EQUIP_GENERIC, null, null, null, + true, true, true, false), 497790992); // TODO broken because equipment slot names don't match + + testHash(session, DataComponentTypes.REPAIRABLE, new HolderSet(new int[]{Items.AMETHYST_BLOCK.javaId(), Items.PUMPKIN.javaId()}), -36715567); + + NbtMap mapDecorations = NbtMap.builder() + .putCompound("test_decoration", NbtMap.builder() + .putString("type", "minecraft:player") + .putDouble("x", 45.0) + .putDouble("z", 67.4) + .putFloat("rotation", 39.5F) + .build()) + .build(); + + testHash(session, DataComponentTypes.MAP_DECORATIONS, mapDecorations, -625782954); + + testHash(session, DataComponentTypes.POTION_CONTENTS, new PotionContents(Potion.FIRE_RESISTANCE.ordinal(), -1, List.of(), null), -772576502); + testHash(session, DataComponentTypes.POTION_CONTENTS, new PotionContents(-1, 20, + List.of(new MobEffectInstance(Effect.CONDUIT_POWER, new MobEffectDetails(0, 0, false, true, true, null))), + null), -902075187); + testHash(session, DataComponentTypes.POTION_CONTENTS, new PotionContents(-1, 96, + List.of(new MobEffectInstance(Effect.JUMP_BOOST, new MobEffectDetails(57, 17, true, false, false, null))), + null), -17231244); + testHash(session, DataComponentTypes.POTION_CONTENTS, new PotionContents(-1, 87, + List.of(new MobEffectInstance(Effect.SPEED, new MobEffectDetails(29, 1004, false, true, true, null))), + "testing"), 2007296036); + // Chunk errors are spamming logs and I don't need to log in anyway session.disconnect("AAAAAA"); } diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java index 61feaa4ef..b675a236e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java @@ -30,7 +30,9 @@ import net.kyori.adventure.key.Key; import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; @@ -78,6 +80,16 @@ public interface MinecraftHasher { .optionalNullable("speed", MinecraftHasher.FLOAT, ToolData.Rule::getSpeed) .optionalNullable("correct_for_drops", MinecraftHasher.BOOL, ToolData.Rule::getCorrectForDrops)); + MinecraftHasher EQUIPMENT_SLOT = fromEnum(); + + MinecraftHasher MOB_EFFECT_INSTANCE = mapBuilder(builder -> builder + .accept("id", RegistryHasher.EFFECT, MobEffectInstance::getEffect) + .optional("amplifier", BYTE, instance -> (byte) instance.getDetails().getAmplifier(), (byte) 0) + .optional("duration", INT, instance -> instance.getDetails().getDuration(), 0) + .optional("ambient", BOOL, instance -> instance.getDetails().isAmbient(), false) + .optional("show_particles", BOOL, instance -> instance.getDetails().isShowParticles(), true) + .accept("show_icon", BOOL, instance -> instance.getDetails().isShowIcon())); // TODO check this, also hidden effect but is recursive + HashCode hash(T value, MinecraftHashEncoder encoder); default MinecraftHasher> list() { @@ -98,7 +110,7 @@ public interface MinecraftHasher { // TODO: note that this only works correctly if enum constants are named appropriately static > MinecraftHasher fromEnum() { - return STRING.convert(Enum::name); + return STRING.convert(t -> t.name().toLowerCase()); } static MinecraftHasher mapBuilder(UnaryOperator> builder) { diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java index 09948a9f1..c30805952 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java @@ -25,9 +25,12 @@ package org.geysermc.geyser.item.hashing; +import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.session.cache.registry.JavaRegistries; import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.util.MinecraftKey; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; 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.level.sound.BuiltinSound; @@ -40,8 +43,16 @@ public interface RegistryHasher extends MinecraftHasher { RegistryHasher BLOCK = registry(JavaRegistries.BLOCK); + RegistryHasher ITEM = registry(JavaRegistries.ITEM); + + RegistryHasher ENTITY_TYPE = enumIdRegistry(EntityType.values()); + RegistryHasher ENCHANTMENT = registry(JavaRegistries.ENCHANTMENT); + MinecraftHasher EFFECT = enumRegistry(); + + RegistryHasher POTION = enumIdRegistry(Potion.values()); + MinecraftHasher> DATA_COMPONENT_TYPE = KEY.convert(DataComponentType::getKey); MinecraftHasher BUILTIN_SOUND = KEY.convert(sound -> MinecraftKey.key(sound.getName())); @@ -62,6 +73,15 @@ public interface RegistryHasher extends MinecraftHasher { return hasher::hash; } + static > MinecraftHasher enumRegistry() { + return KEY.convert(t -> MinecraftKey.key(t.name().toLowerCase())); + } + + static > RegistryHasher enumIdRegistry(T[] values) { + MinecraftHasher hasher = KEY.convert(i -> MinecraftKey.key(values[i].name().toLowerCase())); + return hasher::hash; + } + default MinecraftHasher holderSet() { return (holder, encoder) -> { if (holder.getLocation() != null) { From 4e06608f8402ca8c0e9f9b90de06cca40dd57220 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 25 Mar 2025 20:27:05 +0000 Subject: [PATCH 590/897] MCPL fixes, make it run --- .../geyser/entity/EntityDefinitions.java | 40 +++++++++---------- .../geyser/item/hashing/ComponentHashers.java | 5 +-- .../geyser/item/type/EnchantedBookItem.java | 2 +- .../entity/VaultBlockEntityTranslator.java | 2 +- gradle/libs.versions.toml | 2 +- 5 files changed, 24 insertions(+), 27 deletions(-) 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 01206fa8d..41d69f002 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -312,7 +312,7 @@ public final class EntityDefinitions { EntityDefinition entityBase = EntityDefinition.builder(Entity::new) .addTranslator(MetadataTypes.BYTE, Entity::setFlags) .addTranslator(MetadataTypes.INT, Entity::setAir) // Air/bubbles - .addTranslator(MetadataTypes.OPTIONAL_CHAT, Entity::setDisplayName) + .addTranslator(MetadataTypes.OPTIONAL_COMPONENT, Entity::setDisplayName) .addTranslator(MetadataTypes.BOOLEAN, Entity::setDisplayNameVisible) .addTranslator(MetadataTypes.BOOLEAN, Entity::setSilent) .addTranslator(MetadataTypes.BOOLEAN, Entity::setGravity) @@ -337,7 +337,7 @@ public final class EntityDefinitions { .type(EntityType.END_CRYSTAL) .heightAndWidth(2.0f) .identifier("minecraft:ender_crystal") - .addTranslator(MetadataTypes.OPTIONAL_POSITION, EnderCrystalEntity::setBlockTarget) + .addTranslator(MetadataTypes.OPTIONAL_BLOCK_POS, EnderCrystalEntity::setBlockTarget) .addTranslator(MetadataTypes.BOOLEAN, (enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal .build(); @@ -365,8 +365,8 @@ public final class EntityDefinitions { .type(EntityType.FIREWORK_ROCKET) .heightAndWidth(0.25f) .identifier("minecraft:fireworks_rocket") - .addTranslator(MetadataTypes.ITEM, FireworkEntity::setFireworkItem) - .addTranslator(MetadataTypes.OPTIONAL_VARINT, FireworkEntity::setPlayerGliding) + .addTranslator(MetadataTypes.ITEM_STACK, FireworkEntity::setFireworkItem) + .addTranslator(MetadataTypes.OPTIONAL_UNSIGNED_INT, FireworkEntity::setPlayerGliding) .addTranslator(null) // Shot at angle .build(); FISHING_BOBBER = EntityDefinition.inherited(null, entityBase) @@ -379,7 +379,7 @@ public final class EntityDefinitions { .type(EntityType.ITEM) .heightAndWidth(0.25f) .offset(0.125f) - .addTranslator(MetadataTypes.ITEM, ItemEntity::setItem) + .addTranslator(MetadataTypes.ITEM_STACK, ItemEntity::setItem) .build(); LEASH_KNOT = EntityDefinition.inherited(LeashKnotEntity::new, entityBase) .type(EntityType.LEASH_KNOT) @@ -428,7 +428,7 @@ public final class EntityDefinitions { .type(EntityType.TEXT_DISPLAY) .identifier("minecraft:armor_stand") .offset(-0.5f) - .addTranslator(MetadataTypes.CHAT, TextDisplayEntity::setText) + .addTranslator(MetadataTypes.COMPONENT, TextDisplayEntity::setText) .addTranslator(null) // Line width .addTranslator(null) // Background color .addTranslator(null) // Text opacity @@ -457,7 +457,7 @@ public final class EntityDefinitions { .build(); EntityDefinition throwableItemBase = EntityDefinition.inherited(ThrowableItemEntity::new, entityBase) - .addTranslator(MetadataTypes.ITEM, ThrowableItemEntity::setItem) + .addTranslator(MetadataTypes.ITEM_STACK, ThrowableItemEntity::setItem) .build(); EGG = EntityDefinition.inherited(ThrowableItemEntity::new, throwableItemBase) .type(EntityType.EGG) @@ -521,7 +521,7 @@ public final class EntityDefinitions { // Item frames are handled differently as they are blocks, not items, in Bedrock ITEM_FRAME = EntityDefinition.inherited(null, entityBase) .type(EntityType.ITEM_FRAME) - .addTranslator(MetadataTypes.ITEM, ItemFrameEntity::setItemInFrame) + .addTranslator(MetadataTypes.ITEM_STACK, ItemFrameEntity::setItemInFrame) .addTranslator(MetadataTypes.INT, ItemFrameEntity::setItemRotation) .build(); GLOW_ITEM_FRAME = EntityDefinition.inherited(ITEM_FRAME.factory(), ITEM_FRAME) @@ -547,7 +547,7 @@ public final class EntityDefinitions { COMMAND_BLOCK_MINECART = EntityDefinition.inherited(CommandBlockMinecartEntity::new, MINECART) .type(EntityType.COMMAND_BLOCK_MINECART) .addTranslator(MetadataTypes.STRING, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.COMMAND_BLOCK_NAME, entityMetadata.getValue())) - .addTranslator(MetadataTypes.CHAT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage(entityMetadata.getValue()))) + .addTranslator(MetadataTypes.COMPONENT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage(entityMetadata.getValue()))) .build(); FURNACE_MINECART = EntityDefinition.inherited(FurnaceMinecartEntity::new, MINECART) .type(EntityType.FURNACE_MINECART) @@ -623,19 +623,19 @@ public final class EntityDefinitions { (livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityDataTypes.EFFECT_AMBIENCE, (byte) (((BooleanEntityMetadata) entityMetadata).getPrimitiveValue() ? 1 : 0))) .addTranslator(null) // Arrow count .addTranslator(null) // Stinger count - .addTranslator(MetadataTypes.OPTIONAL_POSITION, LivingEntity::setBedPosition) + .addTranslator(MetadataTypes.OPTIONAL_BLOCK_POS, LivingEntity::setBedPosition) .build(); ARMOR_STAND = EntityDefinition.inherited(ArmorStandEntity::new, livingEntityBase) .type(EntityType.ARMOR_STAND) .height(1.975f).width(0.5f) .addTranslator(MetadataTypes.BYTE, ArmorStandEntity::setArmorStandFlags) - .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setHeadRotation) - .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setBodyRotation) - .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setLeftArmRotation) - .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setRightArmRotation) - .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setLeftLegRotation) - .addTranslator(MetadataTypes.ROTATION, ArmorStandEntity::setRightLegRotation) + .addTranslator(MetadataTypes.ROTATIONS, ArmorStandEntity::setHeadRotation) + .addTranslator(MetadataTypes.ROTATIONS, ArmorStandEntity::setBodyRotation) + .addTranslator(MetadataTypes.ROTATIONS, ArmorStandEntity::setLeftArmRotation) + .addTranslator(MetadataTypes.ROTATIONS, ArmorStandEntity::setRightArmRotation) + .addTranslator(MetadataTypes.ROTATIONS, ArmorStandEntity::setLeftLegRotation) + .addTranslator(MetadataTypes.ROTATIONS, ArmorStandEntity::setRightLegRotation) .build(); PLAYER = EntityDefinition.inherited(null, livingEntityBase) .type(EntityType.PLAYER) @@ -645,8 +645,8 @@ public final class EntityDefinitions { .addTranslator(null) // Player score .addTranslator(MetadataTypes.BYTE, PlayerEntity::setSkinVisibility) .addTranslator(null) // Player main hand - .addTranslator(MetadataTypes.NBT_TAG, PlayerEntity::setLeftParrot) - .addTranslator(MetadataTypes.NBT_TAG, PlayerEntity::setRightParrot) + .addTranslator(MetadataTypes.COMPOUND_TAG, PlayerEntity::setLeftParrot) + .addTranslator(MetadataTypes.COMPOUND_TAG, PlayerEntity::setRightParrot) .build(); EntityDefinition mobEntityBase = EntityDefinition.inherited(MobEntity::new, livingEntityBase) @@ -686,7 +686,7 @@ public final class EntityDefinitions { .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setCanMove) .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setActive) .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setIsTearingDown) - .addTranslator(MetadataTypes.OPTIONAL_POSITION, CreakingEntity::setHomePos) + .addTranslator(MetadataTypes.OPTIONAL_BLOCK_POS, CreakingEntity::setHomePos) .properties(VanillaEntityProperties.CREAKING) .build(); CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase) @@ -981,7 +981,7 @@ public final class EntityDefinitions { .type(EntityType.FROG) .heightAndWidth(0.5f) .addTranslator(MetadataTypes.FROG_VARIANT, FrogEntity::setVariant) - .addTranslator(MetadataTypes.OPTIONAL_VARINT, FrogEntity::setTongueTarget) + .addTranslator(MetadataTypes.OPTIONAL_UNSIGNED_INT, FrogEntity::setTongueTarget) .build(); HOGLIN = EntityDefinition.inherited(HoglinEntity::new, ageableEntityBase) .type(EntityType.HOGLIN) diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java index ca2b17c19..9cfd7e517 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java @@ -221,7 +221,7 @@ public class ComponentHashers { testHash(session, DataComponentTypes.ENCHANTMENTS, new ItemEnchantments(Map.of( 0, 1 - ), false), 0); // TODO identifier lookup + )), 0); // TODO identifier lookup testHash(session, DataComponentTypes.CUSTOM_MODEL_DATA, new CustomModelData(List.of(5.0F, 3.0F, -1.0F), List.of(false, true, false), List.of("1", "3", "2"), List.of(3424, -123, 345)), 1947635619); @@ -290,9 +290,6 @@ public class ComponentHashers { testHash(session, DataComponentTypes.POTION_CONTENTS, new PotionContents(-1, 87, List.of(new MobEffectInstance(Effect.SPEED, new MobEffectDetails(29, 1004, false, true, true, null))), "testing"), 2007296036); - - // Chunk errors are spamming logs and I don't need to log in anyway - session.disconnect("AAAAAA"); } private static void testHash(GeyserSession session, DataComponentType component, T value, int expected) { diff --git a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java index bc6dcde67..09dbca050 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/EnchantedBookItem.java @@ -95,7 +95,7 @@ public class EnchantedBookItem extends Item { } } if (!javaEnchantments.isEmpty()) { - components.put(DataComponentTypes.STORED_ENCHANTMENTS, new ItemEnchantments(javaEnchantments, true)); + components.put(DataComponentTypes.STORED_ENCHANTMENTS, new ItemEnchantments(javaEnchantments)); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java index 46a4b78bf..cff1f0bb7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/VaultBlockEntityTranslator.java @@ -145,6 +145,6 @@ public class VaultBlockEntityTranslator extends BlockEntityTranslator { } } } - components.put(DataComponentTypes.ENCHANTMENTS, new ItemEnchantments(enchantments, true)); + components.put(DataComponentTypes.ENCHANTMENTS, new ItemEnchantments(enchantments)); }); } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7aa0c9e75..a29969ab2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta6-20250324.162731-5" protocol-codec = "3.0.0.Beta6-20250324.162731-5" raknet = "1.0.0.CR3-20250218.160705-18" minecraftauth = "4.1.1" -mcprotocollib = "1.21.5-20250323.182633-13" +mcprotocollib = "1.21.5-20250325.093126-16" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" From 413be6c8b8038a44500bf26e13d3d03da5af1c48 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 25 Mar 2025 20:37:14 +0000 Subject: [PATCH 591/897] Some cleanups and stuff --- .../geyser/item/hashing/ComponentHashers.java | 23 ++++++++++--------- .../geyser/item/hashing/MinecraftHasher.java | 2 +- .../DataComponentRegistryPopulator.java | 7 ------ 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java index 9cfd7e517..3bcd6aa38 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java @@ -69,10 +69,10 @@ public class ComponentHashers { static { register(DataComponentTypes.CUSTOM_DATA, MinecraftHasher.NBT_MAP); - register(DataComponentTypes.MAX_STACK_SIZE); - register(DataComponentTypes.MAX_DAMAGE); - register(DataComponentTypes.DAMAGE); - register(DataComponentTypes.UNBREAKABLE); + registerInt(DataComponentTypes.MAX_STACK_SIZE); + registerInt(DataComponentTypes.MAX_DAMAGE); + registerInt(DataComponentTypes.DAMAGE); + registerUnit(DataComponentTypes.UNBREAKABLE); // TODO custom name, component // TODO item name, component @@ -97,7 +97,7 @@ public class ComponentHashers { .optional("hide_tooltip", MinecraftHasher.BOOL, TooltipDisplay::hideTooltip, false) .optionalList("hidden_components", RegistryHasher.DATA_COMPONENT_TYPE, TooltipDisplay::hiddenComponents)); - register(DataComponentTypes.REPAIR_COST); + registerInt(DataComponentTypes.REPAIR_COST); register(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, MinecraftHasher.BOOL); //register(DataComponentTypes.INTANGIBLE_PROJECTILE); // TODO MCPL is wrong @@ -142,16 +142,16 @@ public class ComponentHashers { registerMap(DataComponentTypes.REPAIRABLE, builder -> builder .accept("items", RegistryHasher.ITEM.holderSet(), Function.identity())); - register(DataComponentTypes.GLIDER); + registerUnit(DataComponentTypes.GLIDER); register(DataComponentTypes.TOOLTIP_STYLE, MinecraftHasher.KEY); registerMap(DataComponentTypes.DEATH_PROTECTION, builder -> builder); // TODO consume effect needs identifier in MCPL registerMap(DataComponentTypes.BLOCKS_ATTACKS, builder -> builder); // TODO needs damage types, add a way to cache identifiers without reading objects in registrycache register(DataComponentTypes.STORED_ENCHANTMENTS, MinecraftHasher.map(RegistryHasher.ENCHANTMENT, MinecraftHasher.INT).convert(ItemEnchantments::getEnchantments)); // TODO duplicate code? - register(DataComponentTypes.DYED_COLOR); - register(DataComponentTypes.MAP_COLOR); - register(DataComponentTypes.MAP_ID); + registerInt(DataComponentTypes.DYED_COLOR); + registerInt(DataComponentTypes.MAP_COLOR); + registerInt(DataComponentTypes.MAP_ID); register(DataComponentTypes.MAP_DECORATIONS, MinecraftHasher.NBT_MAP); // TODO charged projectiles also need the recursionâ„¢ @@ -166,11 +166,11 @@ public class ComponentHashers { register(DataComponentTypes.POTION_DURATION_SCALE, MinecraftHasher.FLOAT); } - private static void register(DataComponentType component) { + private static void registerUnit(DataComponentType component) { register(component, MinecraftHasher.UNIT); } - private static void register(IntComponentType component) { + private static void registerInt(IntComponentType component) { register(component, MinecraftHasher.INT); } @@ -193,6 +193,7 @@ public class ComponentHashers { return hasher.hash(value, new MinecraftHashEncoder(session)); } + // TODO better hashing, at the moment this is just called when the player is spawned public static void testHashing(GeyserSession session) { // Hashed values generated by vanilla Java diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java index b675a236e..0c84a2b6f 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java @@ -80,7 +80,7 @@ public interface MinecraftHasher { .optionalNullable("speed", MinecraftHasher.FLOAT, ToolData.Rule::getSpeed) .optionalNullable("correct_for_drops", MinecraftHasher.BOOL, ToolData.Rule::getCorrectForDrops)); - MinecraftHasher EQUIPMENT_SLOT = fromEnum(); + MinecraftHasher EQUIPMENT_SLOT = fromEnum(); // FIXME MCPL enum constants aren't right MinecraftHasher MOB_EFFECT_INSTANCE = mapBuilder(builder -> builder .accept("id", RegistryHasher.EFFECT, MobEffectInstance::getEffect) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java index 1a247f609..ef3168f41 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/DataComponentRegistryPopulator.java @@ -75,13 +75,7 @@ public final class DataComponentRegistryPopulator { byte[] bytes = Base64.getDecoder().decode(encodedValue); ByteBuf buf = Unpooled.wrappedBuffer(bytes); int varInt = MinecraftTypes.readVarInt(buf); - //System.out.println("int: " + varInt + " " + componentEntry.getKey()); DataComponentType dataComponentType = DataComponentTypes.from(varInt); - if (dataComponentType == DataComponentTypes.ENCHANTMENTS - || dataComponentType == DataComponentTypes.STORED_ENCHANTMENTS - || dataComponentType == DataComponentTypes.JUKEBOX_PLAYABLE) { - continue; // TODO Broken reading in MCPL - } DataComponent dataComponent = dataComponentType.readDataComponent(buf); map.put(dataComponentType, dataComponent); @@ -90,7 +84,6 @@ public final class DataComponentRegistryPopulator { defaultComponents.add(new DataComponents(ImmutableMap.copyOf(map))); } } catch (Exception e) { - // TODO 1.21.5 enchantment reading is broken throw new AssertionError("Unable to load or parse components", e); } From e78b6b431edd873a7d41ea78c5faaa954d4ce492 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 25 Mar 2025 20:49:33 +0000 Subject: [PATCH 592/897] Fix test --- .../geyser/scoreboard/network/ScoreboardIssueTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8311f1a5b..21424dcf3 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 @@ -209,7 +209,7 @@ public class ScoreboardIssueTests { // metadata set: invisible, custom name, custom name visible context.translate(setEntityDataTranslator, new ClientboundSetEntityDataPacket(1298, new EntityMetadata[]{ new ByteEntityMetadata(0, MetadataTypes.BYTE, (byte) 0x20), - new ObjectEntityMetadata<>(2, MetadataTypes.OPTIONAL_CHAT, Optional.of(Component.text("tesss"))), + new ObjectEntityMetadata<>(2, MetadataTypes.OPTIONAL_COMPONENT, Optional.of(Component.text("tesss"))), new BooleanEntityMetadata(3, MetadataTypes.BOOLEAN, true) })); From ba9544713a51f9e0294bcaaf45acf88093e67180 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 25 Mar 2025 21:29:28 +0000 Subject: [PATCH 593/897] Item stack, use remainder component hashers, update mappings --- .../geyser/item/hashing/ComponentHashers.java | 25 ++++++++++-- .../geyser/item/hashing/MinecraftHasher.java | 40 ++++++++++--------- .../geyser/item/hashing/RegistryHasher.java | 35 +++++++++++++++- core/src/main/resources/mappings | 2 +- 4 files changed, 77 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java index 3bcd6aa38..6d441bdb8 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHashers.java @@ -38,10 +38,12 @@ import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.CustomModelData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Equippable; import org.geysermc.mcprotocollib.protocol.data.game.item.component.FoodProperties; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; @@ -112,7 +114,7 @@ public class ComponentHashers { .optional("sound", RegistryHasher.SOUND_EVENT, Consumable::sound, BuiltinSound.ENTITY_GENERIC_EAT) .optional("has_consume_particles", MinecraftHasher.BOOL, Consumable::hasConsumeParticles, true)); // TODO consume effect needs identifier in MCPL - // TODO use remainder needs item stack codec, recursion go brr + register(DataComponentTypes.USE_REMAINDER, RegistryHasher.ITEM_STACK); registerMap(DataComponentTypes.USE_COOLDOWN, builder -> builder .accept("seconds", MinecraftHasher.FLOAT, UseCooldown::seconds) @@ -120,7 +122,7 @@ public class ComponentHashers { registerMap(DataComponentTypes.DAMAGE_RESISTANT, builder -> builder .accept("types", MinecraftHasher.TAG, Function.identity())); registerMap(DataComponentTypes.TOOL, builder -> builder - .acceptList("rules", MinecraftHasher.TOOL_RULE, ToolData::getRules) + .acceptList("rules", RegistryHasher.TOOL_RULE, ToolData::getRules) .optional("default_mining_speed", MinecraftHasher.FLOAT, ToolData::getDefaultMiningSpeed, 1.0F) .optional("damage_per_block", MinecraftHasher.INT, ToolData::getDamagePerBlock, 1) .optional("can_destroy_blocks_in_creative", MinecraftHasher.BOOL, ToolData::isCanDestroyBlocksInCreative, true)); @@ -160,7 +162,7 @@ public class ComponentHashers { registerMap(DataComponentTypes.POTION_CONTENTS, builder -> builder .optional("potion", RegistryHasher.POTION, PotionContents::getPotionId, -1) .optional("custom_color", MinecraftHasher.INT, PotionContents::getCustomColor, -1) - .optionalList("custom_effects", MinecraftHasher.MOB_EFFECT_INSTANCE, PotionContents::getCustomEffects) + .optionalList("custom_effects", RegistryHasher.MOB_EFFECT_INSTANCE, PotionContents::getCustomEffects) .optionalNullable("custom_name", MinecraftHasher.STRING, PotionContents::getCustomName)); register(DataComponentTypes.POTION_DURATION_SCALE, MinecraftHasher.FLOAT); @@ -185,10 +187,18 @@ public class ComponentHashers { hashers.put(component, hasher); } + public static MinecraftHasher hasherOrEmpty(DataComponentType component) { + MinecraftHasher hasher = (MinecraftHasher) hashers.get(component); + if (hasher == null) { + return MinecraftHasher.UNIT.convert(value -> Unit.INSTANCE); + } + return hasher; + } + public static HashCode hash(GeyserSession session, DataComponentType component, T value) { MinecraftHasher hasher = (MinecraftHasher) hashers.get(component); if (hasher == null) { - throw new IllegalStateException("Unregistered hasher for component " + component + "!"); + throw new IllegalStateException("Unregistered hasher for component " + component + "!"); // TODO we might not have hashers for every component, in which case, fix this } return hasher.hash(value, new MinecraftHashEncoder(session)); } @@ -241,6 +251,13 @@ public class ComponentHashers { testHash(session, DataComponentTypes.FOOD, new FoodProperties(3, 5.7F, true), 1917653498); testHash(session, DataComponentTypes.FOOD, new FoodProperties(7, 0.15F, false), -184166204); + testHash(session, DataComponentTypes.USE_REMAINDER, new ItemStack(Items.MELON.javaId(), 52), -1279684916); + + DataComponents specialComponents = new DataComponents(new HashMap<>()); + specialComponents.put(DataComponentTypes.ITEM_MODEL, MinecraftKey.key("testing")); + specialComponents.put(DataComponentTypes.MAX_STACK_SIZE, 44); + testHash(session, DataComponentTypes.USE_REMAINDER, new ItemStack(Items.PUMPKIN.javaId(), 32, specialComponents), 1991032843); + testHash(session, DataComponentTypes.DAMAGE_RESISTANT, MinecraftKey.key("testing"), -1230493835); testHash(session, DataComponentTypes.TOOL, new ToolData(List.of(), 5.0F, 3, false), -1789071928); diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java index 0c84a2b6f..cfab00504 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/MinecraftHasher.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.item.hashing; +import com.google.common.base.Suppliers; import com.google.common.hash.HashCode; import net.kyori.adventure.key.Key; import org.cloudburstmc.nbt.NbtMap; @@ -32,14 +33,13 @@ import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; import java.util.List; import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -75,21 +75,8 @@ public interface MinecraftHasher { MinecraftHasher ITEM_USE_ANIMATION = fromEnum(); - MinecraftHasher TOOL_RULE = mapBuilder(builder -> builder - .accept("blocks", RegistryHasher.BLOCK.holderSet(), ToolData.Rule::getBlocks) - .optionalNullable("speed", MinecraftHasher.FLOAT, ToolData.Rule::getSpeed) - .optionalNullable("correct_for_drops", MinecraftHasher.BOOL, ToolData.Rule::getCorrectForDrops)); - MinecraftHasher EQUIPMENT_SLOT = fromEnum(); // FIXME MCPL enum constants aren't right - MinecraftHasher MOB_EFFECT_INSTANCE = mapBuilder(builder -> builder - .accept("id", RegistryHasher.EFFECT, MobEffectInstance::getEffect) - .optional("amplifier", BYTE, instance -> (byte) instance.getDetails().getAmplifier(), (byte) 0) - .optional("duration", INT, instance -> instance.getDetails().getDuration(), 0) - .optional("ambient", BOOL, instance -> instance.getDetails().isAmbient(), false) - .optional("show_particles", BOOL, instance -> instance.getDetails().isShowParticles(), true) - .accept("show_icon", BOOL, instance -> instance.getDetails().isShowIcon())); // TODO check this, also hidden effect but is recursive - HashCode hash(T value, MinecraftHashEncoder encoder); default MinecraftHasher> list() { @@ -97,11 +84,15 @@ public interface MinecraftHasher { } default MinecraftHasher convert(Function converter) { - return (object, encoder) -> hash(converter.apply(object), encoder); + return (value, encoder) -> hash(converter.apply(value), encoder); } default MinecraftHasher sessionConvert(BiFunction converter) { - return (object, encoder) -> hash(converter.apply(encoder.session(), object), encoder); + return (value, encoder) -> hash(converter.apply(encoder.session(), value), encoder); + } + + static MinecraftHasher recursive(UnaryOperator> delegate) { + return new Recursive<>(delegate); } static > MinecraftHasher fromIdEnum(T[] values, Function toName) { @@ -114,7 +105,7 @@ public interface MinecraftHasher { } static MinecraftHasher mapBuilder(UnaryOperator> builder) { - return (object, encoder) -> builder.apply(new MapHasher<>(object, encoder)).build(); + return (value, encoder) -> builder.apply(new MapHasher<>(value, encoder)).build(); } static MinecraftHasher> map(MinecraftHasher keyHasher, MinecraftHasher valueHasher) { @@ -122,4 +113,17 @@ public interface MinecraftHasher { .map(entry -> Map.entry(keyHasher.hash(entry.getKey(), encoder), valueHasher.hash(entry.getValue(), encoder))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); } + + class Recursive implements MinecraftHasher { + private final Supplier> delegate; + + public Recursive(UnaryOperator> delegate) { + this.delegate = Suppliers.memoize(() -> delegate.apply(this)); + } + + @Override + public HashCode hash(T value, MinecraftHashEncoder encoder) { + return delegate.get().hash(value, encoder); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java index c30805952..2b09c50e3 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java @@ -31,8 +31,13 @@ import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; 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.HolderSet; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.CustomSound; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; @@ -49,11 +54,32 @@ public interface RegistryHasher extends MinecraftHasher { RegistryHasher ENCHANTMENT = registry(JavaRegistries.ENCHANTMENT); + MinecraftHasher> DATA_COMPONENT_TYPE = KEY.convert(DataComponentType::getKey); + + @SuppressWarnings({"unchecked", "rawtypes"}) // Java generics :( + MinecraftHasher> DATA_COMPONENT = (component, encoder) -> { + MinecraftHasher hasher = ComponentHashers.hasherOrEmpty(component.getType()); + return hasher.hash(component.getValue(), encoder); + }; + + MinecraftHasher DATA_COMPONENTS = MinecraftHasher.map(RegistryHasher.DATA_COMPONENT_TYPE, DATA_COMPONENT).convert(DataComponents::getDataComponents); // TODO component removals (needs unit value and ! component prefix) + + MinecraftHasher ITEM_STACK = MinecraftHasher.mapBuilder(builder -> builder + .accept("id", ITEM, ItemStack::getId) + .accept("count", INT, ItemStack::getAmount) + .optionalNullable("components", DATA_COMPONENTS, ItemStack::getDataComponentsPatch)); + MinecraftHasher EFFECT = enumRegistry(); - RegistryHasher POTION = enumIdRegistry(Potion.values()); + MinecraftHasher MOB_EFFECT_INSTANCE = MinecraftHasher.mapBuilder(builder -> builder + .accept("id", RegistryHasher.EFFECT, MobEffectInstance::getEffect) + .optional("amplifier", BYTE, instance -> (byte) instance.getDetails().getAmplifier(), (byte) 0) + .optional("duration", INT, instance -> instance.getDetails().getDuration(), 0) + .optional("ambient", BOOL, instance -> instance.getDetails().isAmbient(), false) + .optional("show_particles", BOOL, instance -> instance.getDetails().isShowParticles(), true) + .accept("show_icon", BOOL, instance -> instance.getDetails().isShowIcon())); // TODO check this, also hidden effect but is recursive - MinecraftHasher> DATA_COMPONENT_TYPE = KEY.convert(DataComponentType::getKey); + RegistryHasher POTION = enumIdRegistry(Potion.values()); MinecraftHasher BUILTIN_SOUND = KEY.convert(sound -> MinecraftKey.key(sound.getName())); @@ -68,6 +94,11 @@ public interface RegistryHasher extends MinecraftHasher { return CUSTOM_SOUND.hash((CustomSound) sound, encoder); }; + MinecraftHasher TOOL_RULE = MinecraftHasher.mapBuilder(builder -> builder + .accept("blocks", RegistryHasher.BLOCK.holderSet(), ToolData.Rule::getBlocks) + .optionalNullable("speed", MinecraftHasher.FLOAT, ToolData.Rule::getSpeed) + .optionalNullable("correct_for_drops", MinecraftHasher.BOOL, ToolData.Rule::getCorrectForDrops)); + static RegistryHasher registry(JavaRegistryKey registry) { MinecraftHasher hasher = KEY.sessionConvert(registry::keyFromNetworkId); return hasher::hash; diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 7654aabd9..a3a2a30fe 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 7654aabd95a06f02c3827fc212b819fea63d72bb +Subproject commit a3a2a30fe9b102bedf9097b5532176550bf3fd75 From 8cfe776363559cb3fcf495c894c88413b3132da1 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Wed, 26 Mar 2025 08:38:43 +0000 Subject: [PATCH 594/897] Some more components, still needs their tests, work on text component hashing --- .../geyser/item/hashing/ComponentHasher.java | 102 ++++++++++++++++++ ...Hashers.java => DataComponentHashers.java} | 22 ++-- .../geyser/item/hashing/MapBuilder.java | 32 ++++++ .../geyser/item/hashing/MapHasher.java | 12 ++- .../geyser/item/hashing/MinecraftHasher.java | 23 +++- .../geyser/item/hashing/RegistryHasher.java | 32 +++++- .../geyser/session/cache/RegistryCache.java | 3 +- .../cache/registry/JavaRegistries.java | 2 + .../player/JavaPlayerPositionTranslator.java | 4 +- 9 files changed, 220 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHasher.java rename core/src/main/java/org/geysermc/geyser/item/hashing/{ComponentHashers.java => DataComponentHashers.java} (94%) create mode 100644 core/src/main/java/org/geysermc/geyser/item/hashing/MapBuilder.java diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHasher.java new file mode 100644 index 000000000..7b2415b14 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/ComponentHasher.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 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.item.hashing; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; + +public interface ComponentHasher { + + MinecraftHasher COMPONENT = (value, encoder) -> encoder.empty(); // TODO + + MinecraftHasher NAMED_COLOR = MinecraftHasher.STRING.convert(NamedTextColor::toString); + + MinecraftHasher DIRECT_COLOR = MinecraftHasher.STRING.convert(TextColor::asHexString); + + MinecraftHasher COLOR = (value, encoder) -> { + if (value instanceof NamedTextColor named) { + return NAMED_COLOR.hash(named, encoder); + } + return DIRECT_COLOR.hash(value, encoder); + }; + + MinecraftHasher DECORATION_STATE = MinecraftHasher.BOOL.convert(state -> switch (state) { + case NOT_SET -> null; // Should never happen since we're using .optional() with NOT_SET as default value below + case FALSE -> false; + case TRUE -> true; + }); + + MinecraftHasher CLICK_EVENT_ACTION = MinecraftHasher.STRING.convert(ClickEvent.Action::toString); + + MinecraftHasher CLICK_EVENT = CLICK_EVENT_ACTION.dispatch("action", ClickEvent::action, action -> switch (action) { + case OPEN_URL -> builder -> builder.accept("url", MinecraftHasher.STRING, ClickEvent::value); + case OPEN_FILE -> builder -> builder.accept("path", MinecraftHasher.STRING, ClickEvent::value); + case RUN_COMMAND, SUGGEST_COMMAND -> builder -> builder.accept("command", MinecraftHasher.STRING, ClickEvent::value); + case CHANGE_PAGE -> builder -> builder.accept("page", MinecraftHasher.STRING, ClickEvent::value); + case COPY_TO_CLIPBOARD -> builder -> builder.accept("value", MinecraftHasher.STRING, ClickEvent::value); + }); + + MinecraftHasher> HOVER_EVENT_ACTION = MinecraftHasher.STRING.convert(HoverEvent.Action::toString); + + MinecraftHasher> HOVER_EVENT = HOVER_EVENT_ACTION.dispatch("action", HoverEvent::action, action -> { + if (action == HoverEvent.Action.SHOW_TEXT) { + + } else if (action == HoverEvent.Action.SHOW_ITEM) { + + } + return builder -> builder; + }); + + // TODO shadow colours - needs kyori bump + MinecraftHasher

    This method uses the + * continued fraction algorithm, computing a maximum of + * 25 convergents and bounding the denominator by 10,000.

    <8kA1=h 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 diff --git a/core/src/main/resources/bedrock/block_palette.1_21_20.nbt b/core/src/main/resources/bedrock/block_palette.1_21_20.nbt deleted file mode 100644 index 521ea3cc6fdded8adda60e2a1ad1ff35ab826dc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178977 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�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